绕过 android usb 主机权限确认对话框 android 5.1

bypass android usb host permission confirmation dialog for android 5.1

我想在工业上使用android,

我可以毫无问题地使用 slickdevlabs.com 库连接到 Profilic 和 Ftdi USB 到串行芯片。

应用程序有一个服务,它在启动时启动,连接到 usb 串行端口并执行其他操作。

我的问题是主机设备与用户没有任何交互,

所以当 android 问

允许应用 "MyAPP" 访问 USB 设备? [复选标记]此 USB 设备默认使用 取消 确定 没有人点击确定

即使我选中默认使用...复选框,如果我重新插入 USB,或重新启动主机设备,它会在下次启动时再次询问。

答案在这个 link 中提到: bypass android usb host permission confirmation dialog 但代码适用于: "Note that interfaces of these classes may change depending on the version of Android. In my case the version is 4.0.3. So if you have another version of Android and this code doesn't work you will have to check the source code for your particular version of OS."

所以我需要 android 5.1 的相同代码

您是否尝试过在清单中使用 intent-filter,如下所述:https://developer.android.com/guide/topics/connectivity/usb/host.html#using-intents

我遇到了类似的问题 - 如果您以编程方式请求 USB 权限,它似乎会忽略勾选的复选框并每次都再次询问您。

编辑: 如果您因服务而遇到问题,您可能还想阅读以下内容:

你问这个问题已经有一段时间了......但如果它可以帮助别人,我的答案就是这里。

初始问题中接受的答案是:

So if you have another version of Android and this code doesn't work you will have to check the source code for your particular version of OS.

所以您应该直接从 android 源代码中获取您需要的文件。你可以 download the source code relative to your version or browse directly from the repo.

您搜索的IUsbManager接口一般在: /frameworks/base/android-branch-name/core/java/android/hardware/usb。至于服务管理器,它可以在以下位置找到: /frameworks/base/android-branch-name/core/java/android/os/

我没有 post 代码,因为我想你在 2 年后不再搜索它了:)

=== 编辑 ===

根据要求,这是代码。我让它适用于 6.0.0 版,但我认为函数调用与 5.1 版相同。待验证。

首先,这是您将获得的 android 项目结构:

在 android.harware.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, int userId) 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;


}

然后在android.os中创建javaclassServiceManager.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<String, IBinder> cache )
    {
        throw new RuntimeException( "Stub!" );
    }
}

完成后,不要忘记在 AndroidManifest 中添加 android.permission.MANAGE_USB。

然后你可以使用那些函数调用:

/**
 * Verify if the application is a system app and has MANAGE_USB permission
 * before granting the USB permission for you specific USB devices
 */
private void manageUSBPermissions() {
    if ((this.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
        Log.i(TAG,"This is a system application");
        if (getApplicationContext().checkCallingOrSelfPermission("android.permission.MANAGE_USB") == PackageManager.PERMISSION_GRANTED) {
            Log.i(TAG,"I have android.permission.MANAGE_USB");
            grantUsbPermissions();
        } else {
            Log.i(TAG,"I do not have android.permission.MANAGE_USB");
        }
    } else {
        Log.i(TAG,"This is not a system application");
    }
}

/**
 * This is to avoid the android usb host permission confirmation dialog
 * The application need to be a system app and have MANAGE_USB permission for it to work
 */
private void grantUsbPermissions() {
    try {
        PackageManager pm = getPackageManager();
        ApplicationInfo ai = pm.getApplicationInfo( "com.your.package", 0 );
        if( ai != null ) {
            UsbManager manager = (UsbManager) getSystemService( Context.USB_SERVICE );
            IBinder b = ServiceManager.getService( Context.USB_SERVICE );
            IUsbManager service = IUsbManager.Stub.asInterface( b );

            HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
            Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
            while( deviceIterator.hasNext() ) {
                UsbDevice device = deviceIterator.next();
                if ( device.getVendorId() == 0x1234 ) {
                    service.grantDevicePermission( device, ai.uid );
                    service.setDevicePackage( device, "com.your.package", ai.uid );
                }
            }
        }
    }
    catch ( Exception e ) {
        Log.e(TAG, "Error granting USB permissions: " + e);
    }
}

检查您的应用程序是否是系统应用程序,是否具有正确的权限,否则将无法运行。

另请注意,您的供应商 ID 不是十六进制的,而是十进制的。