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

你可能感兴趣的:(android)