绕过Android 5.1的USB主机权限确认对话框

3

我希望在工业中使用Android。

我可以使用slickdevlabs.com库连接Profilic和Ftdi USB到串口芯片,没有任何问题。

该应用程序有一个服务,并在启动时启动,连接到usb串口并完成其他工作。

我的问题是主机设备没有任何与用户的交互,所以当Android询问:

允许应用程序"MyAPP"访问USB设备? [√]默认使用此USB设备 取消 确定 没有人点击确定。

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

答案在以下链接中提到: bypass android usb host permission confirmation dialog 但代码适用于以下情况: “请注意,这些类的接口可能会根据Android版本而更改。在我的情况下,版本是4.0.3。因此,如果你有另一个版本的Android,而这些代码不起作用,你将不得不检查你特定版本OS的源代码。”

所以我需要Android 5.1的相同代码。


@david soft,看起来你没有仔细阅读我的问题,因为我已经提到了这个答案和链接,并且说它不起作用。感谢你的尝试帮助我,请仔细阅读我的问题和尝试过的答案。请注意,我仍然需要帮助,因为我必须在内核中进行绕过,如果你能在Android层面上给我提供方法,我将不胜感激,而不是在Linux层面上。 - Milad Metias
2个回答

4

虽然你提出了这个问题已经有一段时间了...但是如果可以帮助到其他人,这里是我的答案。

在最初的问题中,被接受的答案陈述:

因此,如果您有另一个版本的Android,并且此代码不起作用,则必须检查特定版本操作系统的源代码。

因此,您应该直接从android源代码获取所需的文件。您可以下载与您的版本相关的源代码,或者直接从存储库浏览。

您正在搜索的IUsbManager接口通常位于: /frameworks/base/android-branch-name/core/java/android/hardware/usb。至于Service Manager,则可以在以下位置找到: /frameworks/base/android-branch-name/core/java/android/os/

我没有发布代码,因为我认为您在2年多后不再寻找它:)

=== 编辑 ===

如要求,这里是代码。我使其适用于版本6.0.0,但我认为函数调用与5.1相同。待验证。

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

在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中创建Java类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<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不是十六进制的,而是十进制的。


我们公司雇了一个自由职业者,他按照你说的做了,但是我们没有得到代码。你的回答很好,如果你有时间分享代码,那就太棒了,谢谢。 - Milad Metias
如果您有代码,请分享。这将有助于我们并节省我们的时间。 - Nikhil Jogdand
@MiladMetias 你还在寻找5.1版本吗?最近我用6.0.0做了一个项目,所以我可以轻松分享。我认为它基本相同。 - lmarceau
找到了 Android 9 的解决方案 https://dev59.com/ebXna4cB1Zd3GeqPNJFi#57622623 - user924
如果这个应用不是系统应用,那我们什么也没做! - W.M.

1

你是否也尝试过第二个链接中提供的带有隐藏活动的解决方案(因为服务无法正确接收USB意图)?当然,在首次安装后运行应用程序时,将显示弹出窗口。只有在您勾选复选框并允许访问后,它才会记住。 - AZOM
1
重启设备后,您需要再次获取权限(或者再次拔插 USB 设备),因此意图过滤器和设备过滤器都是无用的东西。 - user924
愚蠢的Android!我想在没有所有那些Android安全功能的情况下使用它。 - W.M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接