Android绕过usb主机permision确认对话框framework修改方案

最近在看Android USB主从设备通讯(下载Demo)相关的东西,调试时每次运行都弹下面的框,即使勾选“默认情况下用于该USB设备”,还是会弹出,在调试阶段频繁弹框影响开发效率。

1. 做过相关开发的都见过下面代码

[java]  view plain  copy
  1. // Check whether we have permission to access the device.  
  2. if (!mUsbManager.hasPermission(device)) {  
  3.     Intent intent = new Intent(ACTION_USB_DEVICE_PERMISSION);  
  4.     intent.setPackage(getPackageName());  
  5.     PendingIntent pendingIntent = PendingIntent.getBroadcast(this0,  
  6.             intent, PendingIntent.FLAG_ONE_SHOT);  
  7.     mUsbManager.requestPermission(device, pendingIntent);  
  8.     return;  
  9. }  
意思在没有权限的情况下,请求权限才弹的框。

2. 分析弹框流程

mUsbManager.requestPermission(UsbDevice device...);//以UsbDevice为例,UsbAccessory同理


                a. frameworks/base/core/java/android/hardware/usb/UsbManager.java=>requestPermission

[java]  view plain  copy
  1. public void requestPermission(UsbDevice device, PendingIntent pi) {  
  2.     try {  
  3.         mService.requestDevicePermission(device, mContext.getPackageName(), pi);  
  4.     } catch (RemoteException e) {  
  5.         throw e.rethrowFromSystemServer();  
  6.     }  
  7. }  

               b. frameworks/base/core/java/android/hardware/usb/UsbDevice.java=>requestDevicePermission

[java]  view plain  copy
  1. @Override  
  2. public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {  
  3.     final int userId = UserHandle.getCallingUserId();  
  4.     getSettingsForUser(userId).requestPermission(device, packageName, pi);  
  5. }  
getSettingsForUser UsbDevice成员函数

[java]  view plain  copy
  1. private UsbSettingsManager getSettingsForUser(int userId) {  
  2.     synchronized (mLock) {  
  3.         UsbSettingsManager settings = mSettingsByUser.get(userId);  
  4.         if (settings == null) {  
  5.             settings = new UsbSettingsManager(mContext, new UserHandle(userId));  
  6.             mSettingsByUser.put(userId, settings);  
  7.         }  
  8.         return settings;  
  9.     }  
  10. }  
               c. frameworks/base/services/java/com/android/server/usb/UsbSettingsManager.java=> requestPermission

[java]  view plain  copy
  1.     public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) {  
  2.       Intent intent = new Intent();  
  3.   
  4.   
  5.         // respond immediately if permission has already been granted  
  6.       if (hasPermission(device)) {  
  7.             intent.putExtra(UsbManager.EXTRA_DEVICE, device);  
  8.             intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);  
  9.             try {  
  10.                 pi.send(mUserContext, 0, intent);  
  11.             } catch (PendingIntent.CanceledException e) {  
  12.                 if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");  
  13.             }  
  14.             return;  
  15.         }  
  16.   
  17.   
  18.         // start UsbPermissionActivity so user can choose an activity  
  19.         intent.putExtra(UsbManager.EXTRA_DEVICE, device);  
  20.         requestPermissionDialog(intent, packageName, pi);  
  21.     }  
接着调成员函数requestPermissionDialog

[java]  view plain  copy
  1. private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {  
  2.     final int uid = Binder.getCallingUid();  
  3.   
  4.     // compare uid with packageName to foil apps pretending to be someone else  
  5.     try {  
  6.         ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);  
  7.         if (aInfo.uid != uid) {  
  8.             throw new IllegalArgumentException("package " + packageName +  
  9.                     " does not match caller's uid " + uid);  
  10.         }  
  11.     } catch (PackageManager.NameNotFoundException e) {  
  12.         throw new IllegalArgumentException("package " + packageName + " not found");  
  13.     }  
  14.   
  15.     long identity = Binder.clearCallingIdentity();  
  16.     intent.setClassName("com.android.systemui",  
  17.             "com.android.systemui.usb.UsbPermissionActivity");  
  18.     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  19.     intent.putExtra(Intent.EXTRA_INTENT, pi);  
  20.     intent.putExtra("package", packageName);  
  21.     intent.putExtra(Intent.EXTRA_UID, uid);  
  22.     try {  
  23.         mUserContext.startActivityAsUser(intent, mUser);  
  24.     } catch (ActivityNotFoundException e) {  
  25.         Slog.e(TAG, "unable to start UsbPermissionActivity");  
  26.     } finally {  
  27.         Binder.restoreCallingIdentity(identity);  
  28.     }  
  29. }  
由此看最终显示框的地方在SystemUI的UsbPermissionActivity。


3. 屏蔽弹框

a. 看到有博客说在UsbPermissionActivity的onCreate显示Dialog(setupAlert)时替换点击确定的代码

相当于自动点击确定

[java]  view plain  copy
  1. @Override  
  2. public void onCreate(Bundle icicle) {  
  3.     ...  
  4.     //setupAlert();  
  5.     mPermissionGranted = true;  
  6.     finish();  
  7. }  

[java]  view plain  copy
  1.     @Override  
  2.     public void onCreate(Bundle icicle) {  
  3.         ...  
  4.         mAlwaysUse.setOnCheckedChangeListener(this);  
  5.         mAlwaysUse.setChecked(true);  
  6.         ...  
  7.         setupAlert();  
  8.         onClick(this, AlertDialog.BUTTON_POSITIVE);  
  9.     }  
上述两种方法虽然能达到自动授权,个人觉得这种屏蔽方法不理想,下面介绍更好方法。


b. 直接让mUsbManager.hasPermission返回true(自动授权),不更彻底?!

下面列下函数调用关系

①. frameworks/base/core/java/android/hardware/usb/UsbManager.java=>hasPermission

[java]  view plain  copy
  1. public boolean hasPermission(UsbDevice device) {  
  2.     try {  
  3.         return mService.hasDevicePermission(device);  
  4.     } catch (RemoteException e) {  
  5.         throw e.rethrowFromSystemServer();  
  6.     }  
  7. }  
②.  frameworks/base/core/java/android/hardware/usb/UsbDevice.java =>hasDevicePermission
[java]  view plain  copy
  1. public boolean hasDevicePermission(UsbDevice device) {  
  2.     final int userId = UserHandle.getCallingUserId();  
  3.     return getSettingsForUser(userId).hasPermission(device);  
  4. }  
③.  frameworks/base/services/java/com/android/server/usb/UsbSettingsManager.java=>hasPermission

[java]  view plain  copy
  1.     // Android L(5.x)及之后的版本  
  2.     public boolean hasPermission(UsbDevice device) {  
  3.         synchronized (mLock) {  
  4.             int uid = Binder.getCallingUid();  
  5.             if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {  
  6.                 return true;  
  7.             }  
  8.             SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());  
  9.             if (uidList == null) {  
  10.                 return false;  
  11.             }  
  12.             return uidList.get(uid);  
  13.         }  
  14.     }  

让条件(uid == Process.SYSTEM_UID || mDisablePermissionDialogs)为真即可

第一种方式:在AndroidManifest.xml里加上android:sharedUserId="android.uid.system",但是apk需打系统签名

第二种方式:让mDisablePermissionDialogs为真

[java]  view plain  copy
  1. mDisablePermissionDialogs = context.getResources().getBoolean(  
  2.         com.android.internal.R.bool.config_disableUsbPermissionDialogs);  
frameworks/base/core/res/res/values/config.xml
[html]  view plain  copy
  1. <!-- If true, then we do not ask user for permission for apps to connect to USB devices.  
  2.      Do not set this to true for production devices. Doing so will cause you to fail CTS. -->  
  3. <bool name="config_disableUsbPermissionDialogs">true</bool>  

[java]  view plain  copy
  1. // Android KK(4.4)及之前的版本  
  2. public boolean hasPermission(UsbDevice device) {  
  3.     synchronized (mLock) {  
  4.         int uid = Binder.getCallingUid();  
  5.         if (uid == Process.SYSTEM_UID) {  
  6.             return true;  
  7.         }  
  8.         SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());  
  9.         if (uidList == null) {  
  10.             return false;  
  11.         }  
  12.         return uidList.get(uid);  
  13.     }  
  14. }  
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值