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

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

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

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

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

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

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

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

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

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

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

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

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

IBinder b = ServiceManager.getService(USB_SERVICE);
IUsbManager service = IUsbManager.Stub.asInterface(b);
service.grantDevicePermission(mDevice, uid);

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

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

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

package android.hardware.usb;

public interface IUsbManager extends android.os.IInterface {
	/** Local-side IPC implementation stub class. */
	public static abstract class Stub extends android.os.Binder implements
			android.hardware.usb.IUsbManager {
		/** Construct the stub at attach it to the interface. */
		public Stub() {
			throw new RuntimeException("Stub!");
		}

		/**
		 * Cast an IBinder object into an android.hardware.usb.IUsbManager
		 * interface, generating a proxy if needed.
		 */
		public static android.hardware.usb.IUsbManager asInterface(
				android.os.IBinder obj) {
			throw new RuntimeException("Stub!");
		}

		public android.os.IBinder asBinder() {
			throw new RuntimeException("Stub!");
		}

		public boolean onTransact(int code, android.os.Parcel data,
				android.os.Parcel reply, int flags)
				throws android.os.RemoteException {
			throw new RuntimeException("Stub!");
		}

		static final int TRANSACTION_getDeviceList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
		static final int TRANSACTION_openDevice = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
		static final int TRANSACTION_getCurrentAccessory = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
		static final int TRANSACTION_openAccessory = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
		static final int TRANSACTION_setDevicePackage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
		static final int TRANSACTION_setAccessoryPackage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
		static final int TRANSACTION_hasDevicePermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
		static final int TRANSACTION_hasAccessoryPermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
		static final int TRANSACTION_requestDevicePermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
		static final int TRANSACTION_requestAccessoryPermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 9);
		static final int TRANSACTION_grantDevicePermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 10);
		static final int TRANSACTION_grantAccessoryPermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 11);
		static final int TRANSACTION_hasDefaults = (android.os.IBinder.FIRST_CALL_TRANSACTION + 12);
		static final int TRANSACTION_clearDefaults = (android.os.IBinder.FIRST_CALL_TRANSACTION + 13);
		static final int TRANSACTION_setCurrentFunction = (android.os.IBinder.FIRST_CALL_TRANSACTION + 14);
		static final int TRANSACTION_setMassStorageBackingFile = (android.os.IBinder.FIRST_CALL_TRANSACTION + 15);
	}

	/* Returns a list of all currently attached USB devices */
	public void getDeviceList(android.os.Bundle devices)
			throws android.os.RemoteException;

	/*
	 * Returns a file descriptor for communicating with the USB device. The
	 * native fd can be passed to usb_device_new() in libusbhost.
	 */
	public android.os.ParcelFileDescriptor openDevice(
			java.lang.String deviceName) throws android.os.RemoteException;

	/* Returns the currently attached USB accessory */
	public android.hardware.usb.UsbAccessory getCurrentAccessory()
			throws android.os.RemoteException;

	/*
	 * Returns a file descriptor for communicating with the USB accessory. This
	 * file descriptor can be used with standard Java file operations.
	 */
	public android.os.ParcelFileDescriptor openAccessory(
			android.hardware.usb.UsbAccessory accessory)
			throws android.os.RemoteException;

	/*
	 * Sets the default package for a USB device (or clears it if the package
	 * name is null)
	 */
	public void setDevicePackage(android.hardware.usb.UsbDevice device,
			java.lang.String packageName) throws android.os.RemoteException;

	/*
	 * Sets the default package for a USB accessory (or clears it if the package
	 * name is null)
	 */
	public void setAccessoryPackage(
			android.hardware.usb.UsbAccessory accessory,
			java.lang.String packageName) throws android.os.RemoteException;

	/* Returns true if the caller has permission to access the device. */
	public boolean hasDevicePermission(android.hardware.usb.UsbDevice device)
			throws android.os.RemoteException;

	/* Returns true if the caller has permission to access the accessory. */
	public boolean hasAccessoryPermission(
			android.hardware.usb.UsbAccessory accessory)
			throws android.os.RemoteException;

	/*
	 * Requests permission for the given package to access the device. Will
	 * display a system dialog to query the user if permission had not already
	 * been given.
	 */
	public void requestDevicePermission(android.hardware.usb.UsbDevice device,
			java.lang.String packageName, android.app.PendingIntent pi)
			throws android.os.RemoteException;

	/*
	 * Requests permission for the given package to access the accessory. Will
	 * display a system dialog to query the user if permission had not already
	 * been given. Result is returned via pi.
	 */
	public void requestAccessoryPermission(
			android.hardware.usb.UsbAccessory accessory,
			java.lang.String packageName, android.app.PendingIntent pi)
			throws android.os.RemoteException;

	/* Grants permission for the given UID to access the device */
	public void grantDevicePermission(android.hardware.usb.UsbDevice device,
			int uid) throws android.os.RemoteException;

	/* Grants permission for the given UID to access the accessory */
	public void grantAccessoryPermission(
			android.hardware.usb.UsbAccessory accessory, int uid)
			throws android.os.RemoteException;

	/*
	 * Returns true if the USB manager has default preferences or permissions
	 * for the package
	 */
	public boolean hasDefaults(java.lang.String packageName)
			throws android.os.RemoteException;

	/* Clears default preferences and permissions for the package */
	public void clearDefaults(java.lang.String packageName)
			throws android.os.RemoteException;

	/* Sets the current USB function. */
	public void setCurrentFunction(java.lang.String function,
			boolean makeDefault) throws android.os.RemoteException;

	/* Sets the file path for USB mass storage backing file. */
	public void setMassStorageBackingFile(java.lang.String path)
			throws android.os.RemoteException;
}


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

package android.os;

import java.util.Map;

public final class ServiceManager {
	public static IBinder getService(String name) {
		throw new RuntimeException("Stub!");
	}

	/**
	 * Place a new @a service called @a name into the service manager.
	 * 
	 * @param name
	 *            the name of the new service
	 * @param service
	 *            the service object
	 */
	public static void addService(String name, IBinder service) {
		throw new RuntimeException("Stub!");
	}

	/**
	 * Retrieve an existing service called @a name from the service manager.
	 * Non-blocking.
	 */
	public static IBinder checkService(String name) {
		throw new RuntimeException("Stub!");
	}

	public static String[] listServices() throws RemoteException {
		throw new RuntimeException("Stub!");
	}

	/**
	 * This is only intended to be called when the process is first being
	 * brought up and bound by the activity manager. There is only one thread in
	 * the process at that time, so no locking is done.
	 * 
	 * @param cache
	 *            the cache of service references
	 * @hide
	 */
	public static void initServiceCache(Map cache) {
		throw new RuntimeException("Stub!");
	}
}


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


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

附:


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

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

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

// Register receiver for USB permission
		mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(
				ACTION_USB_PERMISSION), 0);
		Intent intent = new Intent();
		intent.setAction(ACTION_USB_PERMISSION);
		IntentFilter filter = new IntentFilter();
		filter.addAction(ACTION_USB_PERMISSION);
		filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
		registerReceiver(mReceiver, filter);
		// Request permission
		for (UsbDevice device : mManager.getDeviceList().values()) {
			intent.putExtra(UsbManager.EXTRA_DEVICE, device);
			intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);

			final PackageManager pm = getPackageManager();
			try {
				ApplicationInfo aInfo = pm.getApplicationInfo(getPackageName(),
						0);
				try {
					IBinder b = ServiceManager.getService(USB_SERVICE);
					IUsbManager service = IUsbManager.Stub.asInterface(b);
					service.grantDevicePermission(device, aInfo.uid);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} catch (NameNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			getAppContext().sendBroadcast(intent);
//			mManager.requestPermission(device, mPermissionIntent);
			logMsg("UsbManager.EXTRA_DEVICE 11111111111111======"
					+ mManager.openDevice(device));
		}
	}


广播接收器:

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (ACTION_USB_PERMISSION.equals(action)) {
				synchronized (this) {
					UsbDevice device = (UsbDevice) intent
							.getParcelableExtra(UsbManager.EXTRA_DEVICE);
					logMsg("UsbManager.EXTRA_DEVICE 22222222222222222 ========"
							+ intent.getParcelableExtra(UsbManager.EXTRA_DEVICE));
					logMsg("是否有权限了??????   " + mManager.hasPermission(device));
					if (intent.getBooleanExtra(
							UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
						if (device != null) {
							// Open reader
							logMsg("Opening reader: " + device.getDeviceName()
									+ "...");
							new OpenTask().execute(device);
						}
					} else {
						if (device != null) {
							logMsg("Permission no EXTRA_PERMISSION_GRANTED for device "
									+ device.getDeviceName());
						}

					}
				}
			} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
				synchronized (this) {
					// Close reader
					/* logMsg("Closing reader..."); */
					new CloseTask().execute();
				}
			}
		}
	};


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

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

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


你可能感兴趣的:(Android,USB相关研究)