深度解决 SecurityException: User has not given permission to device UsbDevice
2016-07-07 21:13
876 查看
深度解决 SecurityException: User has not given permission to device UsbDevice
在Android上直接使用USB端口会出现如下权限相关错误:UsbManager: exception in UsbManager.openDevice java.lang.SecurityException: User has not given permission to device UsbDevice[mName=/dev/bus/usb/001/017,mVendorId=1208,mProductId=7,mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=EPSON,mProductName=USB2.0 Printer (Hi-speed),mVersion=2.0,mSerialNumber=5458554B3135393861,mConfigurations=[ UsbConfiguration[mId=1,mName=null,mAttributes=192,mMaxPower=1,mInterfaces=[ UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=7,mSubclass=1,mProtocol=2,mEndpoints=[ UsbEndpoint[mAddress=4,mAttributes=2,mMaxPacketSize=512,mInterval=0] UsbEndpoint[mAddress=133,mAttributes=2,mMaxPacketSize=512,mInterval=0]]]] at android.os.Parcel.readException(Parcel.java:1602) at android.os.Parcel.readException(Parcel.java:1555) at android.hardware.usb.IUsbManager$Stub$Proxy.openDevice(IUsbManager.java:418) at android.hardware.usb.UsbManager.openDevice(UsbManager.java:327) at com.example.tony.usbprinter.MainActivity.setPrinterInterface(MainActivity.java:127) at com.example.tony.usbprinter.MainActivity.onCreate(MainActivity.java:63) at android.app.Activity.performCreate(Activity.java:6367) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2397) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2504) at android.app.ActivityThread.access$900(ActivityThread.java:165) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1368) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:150) at android.app.ActivityThread.main(ActivityThread.java:5546) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684)
具体是以下抛出的异常:
/** * Opens the device so it can be used to send and receive * data using {@link android.hardware.usb.UsbRequest}. * * @param device the device to open * @return a {@link UsbDeviceConnection}, or {@code null} if open failed */ public UsbDeviceConnection openDevice(UsbDevice device) { try { String deviceName = device.getDeviceName(); ParcelFileDescriptor pfd = mService.openDevice(deviceName); if (pfd != null) { UsbDeviceConnection connection = new UsbDeviceConnection(device); boolean result = connection.open(deviceName, pfd); pfd.close(); if (result) { return connection; } } } catch (Exception e) { Log.e(TAG, "exception in UsbManager.openDevice", e); } return null; }
一般解决方案
所以无法在应用层进行try catch这个异常。要解决这个需要申请权限,来自【已解决】android程序运行出错:UsbManager(4294): exception in UsbManager.openDevice,java.lang.SecurityException: User has not given permission to device UsbDevice.import android.widget.Toast; import android.content.Intent; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; public class SomeActivity extends BaseActivity { private static UsbManager mUsbManager; private void openUsbDevice(){ //before open usb device //should try to get usb permission tryGetUsbPermission(); } private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; private void tryGetUsbPermission(){ mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(mUsbPermissionActionReceiver, filter); PendingIntent mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); //here do emulation to ask all connected usb device for permission for (final UsbDevice usbDevice : mUsbManager.getDeviceList().values()) { //add some conditional check if necessary //if(isWeCaredUsbDevice(usbDevice)){ if(mUsbManager.hasPermission(usbDevice)){ //if has already got permission, just goto connect it //that means: user has choose yes for your previously popup window asking for grant perssion for this usb device //and also choose option: not ask again afterGetUsbPermission(usbDevice); }else{ //this line will let android popup window, ask user whether to allow this app to have permission to operate this usb device mUsbManager.requestPermission(usbDevice, mPermissionIntent); } //} } } private void afterGetUsbPermission(UsbDevice usbDevice){ //call method to set up device communication Toast.makeText(context, String.valueOf("Got permission for usb device: " + usbDevice), Toast.LENGTH_LONG).show(); Toast.makeText(context, String.valueOf("Found USB device: VID=" + usbDevice.getVendorId() + " PID=" + usbDevice.getProductId()), Toast.LENGTH_LONG).show(); doYourOpenUsbDevice(usbDevice); } private void doYourOpenUsbDevice(UsbDevice usbDevice){ //now follow line will NOT show: User has not given permission to device UsbDevice UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice); //add your operation code here } private final BroadcastReceiver mUsbPermissionActionReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_PERMISSION.equals(action)) { synchronized (this) { UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { //user choose YES for your previously popup window asking for grant perssion for this usb device if(null != usbDevice){ afterGetUsbPermission(usbDevice); } } else { //user choose NO for your previously popup window asking for grant perssion for this usb device Toast.makeText(context, String.valueOf("Permission denied for device" + usbDevice), Toast.LENGTH_LONG).show(); } } } } }; }
高级解决方案
在一些场合,根本没有「用户」存在,这种使用时向用户申请权限的方式就比较麻烦,所以要从其它方面实现这个功能。所谓高级方案就是「设法绕过USB权限弹窗」,目标明确后就需要了解一下内部Android系统对USB权限的处理是怎样的,这里基于5.0源码进行分析,通过标题进行搜索得出在platform_frameworks_base这个子仓的services/usb/java/com/android/server/usb/UsbSettingsManager.java文件中的checkPermission方法中打印出来的:
public void checkPermission(UsbDevice device) { if (!hasPermission(device)) { throw new SecurityException("User has not given permission to device " + device); } }
追踪hasPermission()到:
public boolean hasPermission(UsbDevice device) { synchronized (mLock) { int uid = Binder.getCallingUid(); if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { return true; } SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName()); if (uidList == null) { return false; } return uidList.get(uid); } }
这里有3个条件可以触发返回true,uidList不为空(简单讲就是弹窗用户进行了允许);uid为Process.SYSTEM_UID;mDisablePermissionDialogs为true。只能从后两者中找出突破口。
方案1:uidList不为空(简单讲就是弹窗用户进行了允许)
这个为上述的一般方案,这里不再做讨论。
方案2:uid为Process.SYSTEM_UID
…
方案3: mDisablePermissionDialogs为true
注:该方案需要重新编译Android系统源码,需要有一定源码编译经验才能做到。
因为这个变量读取的是
com.android.internal.R.bool.config_disableUsbPermissionDialogs变量值,该值为于
frameworks/base/core/res/res/values/config.xml中,属于framworks-res.apk这个系统资源程序。,,
# 1. 将`config_disableUsbPermissionDialogs`由`false`改为`true` # 2. 重新编译framworks-res.apk程序 mmm frameworks/base/core/res/ # 3. 替换系统framworks-res.apk adb push out/target/product/nanopi2/system/framework/framework-res.apk /system/framework/
相关文章推荐
- jdk安装详解
- FSS指定磁盘布局进行vxvm的mirror-stripe(raid01)卷的制作
- Codeforces Round #361 (Div. 2) D Friends and Subsequences
- 如何解决mathpage.dll或MathType.dll文件找不到问题
- Codeforces Round #361 (Div. 2)E. Mike and Geometry Problem
- Leetcode Delete Node in a Linked List
- 集群管理脚本
- 外键约束
- 多线程面试必须掌握的
- systemctl 启动成功却提示没有权限(解决)
- LoadRunner如何在脚本运行时修改log设置选项
- AndroidStudio完美解决"Activity使用Handler时出现警告信息"的问题
- 微软2016实习生笔试--第三题Demo Day
- Android textview 文字中间加上图片
- 八大渲染引擎(如VRAY)的分析
- js笔记4-事件基础
- 在 windows 环境下部署redislive监控redis
- PHP中使用CURL实现GET和POST请求
- 视频压缩编解码标准综述
- Spring注解