分享

绕过android usb主机permision确认对话框

 quasiceo 2016-01-09

绕过android usb host permision(权限)确认对话框

   近段时间android开发中遇到一个难题,按照之前的《 

android 3.0以上对usb设备的访问USB

》博客去处理有关USB设备访问的问题。这个google android官网上有说明,原文链接中指的就是官网的说明。

    +++但是当每一次自己的android应用运行之后都会弹出确认权限对话框。+++

  1. Allow the app "MyAPP" to access the USB device ?  
  2. [checkmark]Use by default for this USB device  
  3. Cancel            OK  

即使点击default的checkbox框在设备重启之后依然会弹出该对话框。

     弹出对话框的原因是因为requestPermission函数。官方有详细说明:

  1. when you call requestPermission(). The call to requestPermission() displays a dialog to the user asking for permission to connect to the device.   
      每次都弹出该对话框用户体验极差,也没人愿意每次开机都去给该设备授权。可否绕过该对话框呢?通过分析android源码可知:当你点击OK按钮的时候做了三个动作分别是:

  1. intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);  
  2. IBinder b = ServiceManager.getService(USB_SERVICE);  
  3. IUsbManager service = IUsbManager.Stub.asInterface(b);  
  4. service.grantDevicePermission(mDevice, mUid);  
  5. intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, mPermissionGranted);  

具体的分析就自己看android的源码(UsbPermissionActivity.java);

快哭了可是以下这三句话在上层应用中是没有办法用的。因为:ServiceManager is android.os.ServiceManager and thus isn't a public API.

  1. IBinder b = ServiceManager.getService(USB_SERVICE);  
  2. IUsbManager service = IUsbManager.Stub.asInterface(b);  
  3. service.grantDevicePermission(mDevice, uid);  
  大笑不绕弯子了,以下是我的解决方案,也是参考了大量的资料。再次感谢那些有共享精神的技术牛人。所有的解决方案还是围绕着那三句话。其中最后一句中的mDevice即使你要添加权限的USB设备,uid是你的应用程序的id号
  1. final PackageManager pm = getPackageManager();  
  2. ApplicationInfo aInfo = pm.getApplicationInfo(getPackageName(),0);  

   1.唯一的要求就是你的应用是系统级应用,将应用拷贝在/system/app下面并且保证设备已经ROOT并且没有问题。

   2.在你的工程中增加包名为android.hardware.usb的包,并且添加IUsbManager.java文件。

  1. package android.hardware.usb;  
  2.   
  3. public interface IUsbManager extends android.os.IInterface {  
  4.     /** Local-side IPC implementation stub class. */  
  5.     public static abstract class Stub extends android.os.Binder implements  
  6.             android.hardware.usb.IUsbManager {  
  7.         /** Construct the stub at attach it to the interface. */  
  8.         public Stub() {  
  9.             throw new RuntimeException("Stub!");  
  10.         }  
  11.   
  12.         /** 
  13.          * Cast an IBinder object into an android.hardware.usb.IUsbManager 
  14.          * interface, generating a proxy if needed. 
  15.          */  
  16.         public static android.hardware.usb.IUsbManager asInterface(  
  17.                 android.os.IBinder obj) {  
  18.             throw new RuntimeException("Stub!");  
  19.         }  
  20.   
  21.         public android.os.IBinder asBinder() {  
  22.             throw new RuntimeException("Stub!");  
  23.         }  
  24.   
  25.         public boolean onTransact(int code, android.os.Parcel data,  
  26.                 android.os.Parcel reply, int flags)  
  27.                 throws android.os.RemoteException {  
  28.             throw new RuntimeException("Stub!");  
  29.         }  
  30.   
  31.         static final int TRANSACTION_getDeviceList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);  
  32.         static final int TRANSACTION_openDevice = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);  
  33.         static final int TRANSACTION_getCurrentAccessory = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);  
  34.         static final int TRANSACTION_openAccessory = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);  
  35.         static final int TRANSACTION_setDevicePackage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);  
  36.         static final int TRANSACTION_setAccessoryPackage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);  
  37.         static final int TRANSACTION_hasDevicePermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);  
  38.         static final int TRANSACTION_hasAccessoryPermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);  
  39.         static final int TRANSACTION_requestDevicePermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);  
  40.         static final int TRANSACTION_requestAccessoryPermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 9);  
  41.         static final int TRANSACTION_grantDevicePermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 10);  
  42.         static final int TRANSACTION_grantAccessoryPermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 11);  
  43.         static final int TRANSACTION_hasDefaults = (android.os.IBinder.FIRST_CALL_TRANSACTION + 12);  
  44.         static final int TRANSACTION_clearDefaults = (android.os.IBinder.FIRST_CALL_TRANSACTION + 13);  
  45.         static final int TRANSACTION_setCurrentFunction = (android.os.IBinder.FIRST_CALL_TRANSACTION + 14);  
  46.         static final int TRANSACTION_setMassStorageBackingFile = (android.os.IBinder.FIRST_CALL_TRANSACTION + 15);  
  47.     }  
  48.   
  49.     /* Returns a list of all currently attached USB devices */  
  50.     public void getDeviceList(android.os.Bundle devices)  
  51.             throws android.os.RemoteException;  
  52.   
  53.     /* 
  54.      * Returns a file descriptor for communicating with the USB device. The 
  55.      * native fd can be passed to usb_device_new() in libusbhost. 
  56.      */  
  57.     public android.os.ParcelFileDescriptor openDevice(  
  58.             java.lang.String deviceName) throws android.os.RemoteException;  
  59.   
  60.     /* Returns the currently attached USB accessory */  
  61.     public android.hardware.usb.UsbAccessory getCurrentAccessory()  
  62.             throws android.os.RemoteException;  
  63.   
  64.     /* 
  65.      * Returns a file descriptor for communicating with the USB accessory. This 
  66.      * file descriptor can be used with standard Java file operations. 
  67.      */  
  68.     public android.os.ParcelFileDescriptor openAccessory(  
  69.             android.hardware.usb.UsbAccessory accessory)  
  70.             throws android.os.RemoteException;  
  71.   
  72.     /* 
  73.      * Sets the default package for a USB device (or clears it if the package 
  74.      * name is null) 
  75.      */  
  76.     public void setDevicePackage(android.hardware.usb.UsbDevice device,  
  77.             java.lang.String packageName) throws android.os.RemoteException;  
  78.   
  79.     /* 
  80.      * Sets the default package for a USB accessory (or clears it if the package 
  81.      * name is null) 
  82.      */  
  83.     public void setAccessoryPackage(  
  84.             android.hardware.usb.UsbAccessory accessory,  
  85.             java.lang.String packageName) throws android.os.RemoteException;  
  86.   
  87.     /* Returns true if the caller has permission to access the device. */  
  88.     public boolean hasDevicePermission(android.hardware.usb.UsbDevice device)  
  89.             throws android.os.RemoteException;  
  90.   
  91.     /* Returns true if the caller has permission to access the accessory. */  
  92.     public boolean hasAccessoryPermission(  
  93.             android.hardware.usb.UsbAccessory accessory)  
  94.             throws android.os.RemoteException;  
  95.   
  96.     /* 
  97.      * Requests permission for the given package to access the device. Will 
  98.      * display a system dialog to query the user if permission had not already 
  99.      * been given. 
  100.      */  
  101.     public void requestDevicePermission(android.hardware.usb.UsbDevice device,  
  102.             java.lang.String packageName, android.app.PendingIntent pi)  
  103.             throws android.os.RemoteException;  
  104.   
  105.     /* 
  106.      * Requests permission for the given package to access the accessory. Will 
  107.      * display a system dialog to query the user if permission had not already 
  108.      * been given. Result is returned via pi. 
  109.      */  
  110.     public void requestAccessoryPermission(  
  111.             android.hardware.usb.UsbAccessory accessory,  
  112.             java.lang.String packageName, android.app.PendingIntent pi)  
  113.             throws android.os.RemoteException;  
  114.   
  115.     /* Grants permission for the given UID to access the device */  
  116.     public void grantDevicePermission(android.hardware.usb.UsbDevice device,  
  117.             int uid) throws android.os.RemoteException;  
  118.   
  119.     /* Grants permission for the given UID to access the accessory */  
  120.     public void grantAccessoryPermission(  
  121.             android.hardware.usb.UsbAccessory accessory, int uid)  
  122.             throws android.os.RemoteException;  
  123.   
  124.     /* 
  125.      * Returns true if the USB manager has default preferences or permissions 
  126.      * for the package 
  127.      */  
  128.     public boolean hasDefaults(java.lang.String packageName)  
  129.             throws android.os.RemoteException;  
  130.   
  131.     /* Clears default preferences and permissions for the package */  
  132.     public void clearDefaults(java.lang.String packageName)  
  133.             throws android.os.RemoteException;  
  134.   
  135.     /* Sets the current USB function. */  
  136.     public void setCurrentFunction(java.lang.String function,  
  137.             boolean makeDefault) throws android.os.RemoteException;  
  138.   
  139.     /* Sets the file path for USB mass storage backing file. */  
  140.     public void setMassStorageBackingFile(java.lang.String path)  
  141.             throws android.os.RemoteException;  
  142. }  


   3.在增加包名为android.os的包,并且添加ServiceManager.java文件

  1. package android.os;  
  2.   
  3. import java.util.Map;  
  4.   
  5. public final class ServiceManager {  
  6.     public static IBinder getService(String name) {  
  7.         throw new RuntimeException("Stub!");  
  8.     }  
  9.   
  10.     /** 
  11.      * Place a new @a service called @a name into the service manager. 
  12.      *  
  13.      * @param name 
  14.      *            the name of the new service 
  15.      * @param service 
  16.      *            the service object 
  17.      */  
  18.     public static void addService(String name, IBinder service) {  
  19.         throw new RuntimeException("Stub!");  
  20.     }  
  21.   
  22.     /** 
  23.      * Retrieve an existing service called @a name from the service manager. 
  24.      * Non-blocking. 
  25.      */  
  26.     public static IBinder checkService(String name) {  
  27.         throw new RuntimeException("Stub!");  
  28.     }  
  29.   
  30.     public static String[] listServices() throws RemoteException {  
  31.         throw new RuntimeException("Stub!");  
  32.     }  
  33.   
  34.     /** 
  35.      * This is only intended to be called when the process is first being 
  36.      * brought up and bound by the activity manager. There is only one thread in 
  37.      * the process at that time, so no locking is done. 
  38.      *  
  39.      * @param cache 
  40.      *            the cache of service references 
  41.      * @hide 
  42.      */  
  43.     public static void initServiceCache(Map<String, IBinder> cache) {  
  44.         throw new RuntimeException("Stub!");  
  45.     }  
  46. }  


最后还得在你的工程中添加如下的权限:

  1. <uses-permission android:name="android.permission.MANAGE_USB" />  


eclipse如果报错直接Clean就行了,因为加上这句话后会提醒你需要应用得到system授权。忽略直接clean,如果有报错的clean就行了,不必惊慌....

附:


将APK拷贝到/system/app的方法是:

  1. #adb shell  
  2. # mount -o remount,rw -t ext4 /dev/block/mtdblock3 /system // 让分区可写。  
  3. //windows回到命令提示符下  
  4. >adb push xxx.apk /system/app/  

我的代码片段关于绕开确认对话框:

  1. <span style="color:#333333">// Register receiver for USB permission  
  2.         mPermissionIntent = PendingIntent.getBroadcast(this0new Intent(  
  3.                 ACTION_USB_PERMISSION), 0);  
  4.         Intent intent = new Intent();  
  5.         intent.setAction(ACTION_USB_PERMISSION);  
  6.         IntentFilter filter = new IntentFilter();  
  7.         filter.addAction(ACTION_USB_PERMISSION);  
  8.         filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);  
  9.         registerReceiver(mReceiver, filter);  
  10.         // Request permission  
  11.         for (UsbDevice device : mManager.getDeviceList().values()) {  
  12.             intent.putExtra(UsbManager.EXTRA_DEVICE, device);  
  13.             intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);  
  14.   
  15.             final PackageManager pm = getPackageManager();  
  16.             try {  
  17.                 ApplicationInfo aInfo = pm.getApplicationInfo(getPackageName(),  
  18.                         0);  
  19.                 try {  
  20.                     </span><span style="color:#ff0000">IBinder b = ServiceManager.getService(USB_SERVICE);  
  21.                     IUsbManager service = IUsbManager.Stub.asInterface(b);  
  22.                     service.grantDevicePermission(device, aInfo.uid);</span><span style="color:#333333">  
  23.                 } catch (RemoteException e) {  
  24.                     // TODO Auto-generated catch block  
  25.                     e.printStackTrace();  
  26.                 }  
  27.             } catch (NameNotFoundException e) {  
  28.                 // TODO Auto-generated catch block  
  29.                 e.printStackTrace();  
  30.             }  
  31.   
  32.             getAppContext().sendBroadcast(intent);  
  33. //          mManager.requestPermission(device, mPermissionIntent);  
  34.             logMsg("UsbManager.EXTRA_DEVICE 11111111111111======"  
  35.                     + mManager.openDevice(device));  
  36.         }  
  37.     }  
  38. </span>  


广播接收器:

  1. private final BroadcastReceiver mReceiver = new BroadcastReceiver() {  
  2.         public void onReceive(Context context, Intent intent) {  
  3.             String action = intent.getAction();  
  4.             if (ACTION_USB_PERMISSION.equals(action)) {  
  5.                 synchronized (this) {  
  6.                     UsbDevice device = (UsbDevice) intent  
  7.                             .getParcelableExtra(UsbManager.EXTRA_DEVICE);  
  8.                     logMsg("UsbManager.EXTRA_DEVICE 22222222222222222 ========"  
  9.                             + intent.getParcelableExtra(UsbManager.EXTRA_DEVICE));  
  10.                     logMsg("是否有权限了??????   " + mManager.hasPermission(device));  
  11.                     if (intent.getBooleanExtra(  
  12.                             UsbManager.EXTRA_PERMISSION_GRANTED, false)) {  
  13.                         if (device != null) {  
  14.                             // Open reader  
  15.                             logMsg("Opening reader: " + device.getDeviceName()  
  16.                                     + "...");  
  17.                             new OpenTask().execute(device);  
  18.                         }  
  19.                     } else {  
  20.                         if (device != null) {  
  21.                             logMsg("Permission no EXTRA_PERMISSION_GRANTED for device "  
  22.                                     + device.getDeviceName());  
  23.                         }  
  24.   
  25.                     }  
  26.                 }  
  27.             } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {  
  28.                 synchronized (this) {  
  29.                     // Close reader  
  30.                     /* logMsg("Closing reader..."); */  
  31.                     new CloseTask().execute();  
  32.                 }  
  33.             }  
  34.         }  
  35.     };  


通过我的代码片段大家应该已经知道了,我处理该问题时自己伪造了一个假的广播,也就是对话框OK按钮所做的工作被我提前封好了,直接发送广播让自己接收,就绕开了那个对话框。

这样做就可以绕开该对话框。唯一可能麻烦的就是你的应用得弄成系统级应用,如果没有办法root就没招了!

希望大家有更好的方法....

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多