您的位置:首页 > 其它

深度解决 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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: