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

问题描述 投票:27回答:12

我想在工业中使用android,

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

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

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

所以当android问

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

没有人点击确定。

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

我使用SuperUser模式运行服务和应用程序,但没有区别,它再次询问。

我添加了意图过滤但没有区别,它每次都会问我。

        <intent-filter>
            <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
        </intent-filter>

        <meta-data
            android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
            android:resource="@xml/device_filter" />
        <meta-data
            android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"
            android:resource="@xml/device_filter" />

任何意见如何绕过或禁用它?

我有root和SU访问权限。

android permissions usb root usbserial
12个回答
25
投票

我知道有点晚了,但还是......

我遇到了同样的问题,我想我已经设法解决了这个问题。 Android内部使用的服务允许管理USB设备和配件。此服务对第三方开发人员隐藏,未记录。如果您检查UsbPermissionActivity的源代码,您将能够弄清楚该服务的调用方式。为了调用服务,使用IUsbManager接口和ServiceManager类。这些都是隐藏的,所以你不能直接使用它们。但是你可以做的是创建具有完全相同名称和相应名称空间(包)的存根。然后,您将能够编译该代码,而运行时环境将使用真实的东西。

唯一的要求是您的应用程序必须是系统应用程序 - 它必须位于/ system / app /目录中。由于您的设备已植根,这应该不是问题。

所以你必须在你的项目中添加一个包:“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;
}

然后是另一个包:“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<String, IBinder> cache )
    {
        throw new RuntimeException( "Stub!" );
    }
}

请注意,这些类的接口可能会根据Android的版本而更改。在我的情况下,版本是4.0.3。因此,如果您有另一个版本的Android并且此代码不起作用,则必须检查特定操作系统版本的源代码。

以下是使用该服务向所有FTDI设备授予权限的示例:

import java.util.HashMap;
import java.util.Iterator;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.IBinder;
import android.os.ServiceManager;

public class LaunchReceiver extends BroadcastReceiver
{
    public void onReceive( Context context, Intent intent )
    {
        String action = intent.getAction();
        if( action != null && action.equals( Intent.ACTION_BOOT_COMPLETED ) )
        {
            try
            {
                PackageManager pm = context.getPackageManager();
                ApplicationInfo ai = pm.getApplicationInfo( YOUR_APP_PACKAGE_NAMESPACE, 0 );
                if( ai != null )
                {
                    UsbManager manager = (UsbManager) context.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() == 0x0403 )
                            {
                                service.grantDevicePermission( device, ai.uid );
                                service.setDevicePackage( device, YOUR_APP_PACKAGE_NAMESPACE );
                            }
                    }
                }
            }
            catch( Exception e )
            {
                trace( e.toString() );
            }
        }
    }
}

还有一件事 - 您必须向清单添加以下权限(Lint可能不喜欢它,但您可以随时更改项目属性中的严重性级别):

<uses-permission android:name="android.permission.MANAGE_USB" />

0
投票

第一次,当需要确认时,您可以选择“始终”,然后即使Android设备断电并启动,您的应用仍然有权访问USB2Serial。只是说,只有一次确认!


0
投票

我遇到了同样的问题,每次插上USB线时都会出现权限弹出窗口,为了解决这个问题,我只是在清单中添加了过滤器,并为VID和PID添加了xml文件,只需确保按照建议设置USB设备过滤即可。上面的SO链接或这里记录的,你把好的VID和PID。这是我的问题,我没有把VID和PID与我的设备匹配


0
投票

如果您可以访问Android源代码,则可以使用以下代码来禁用权限对话框

https://gitlab.tubit.tu-berlin.de/justus.beyer/streamagame_platform_frameworks_base/commit/e97b62ed0d4050acacbf54781435686ea28edd73

上面的代码更新创建了一个可以使用的配置选项,或者您可以使用mDisablePermissionDialogs的值true来对其进行硬编码以禁用权限对话框。

services/usb/java/com/android/server/usb/UsbSettingsManager.java


10
投票

@d_d_t答案很棒,但它不适用于Android> 4.2.2。使用此界面:

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 {
    private static final java.lang.String DESCRIPTOR = "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!" );
    }

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

    @Override
    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);
    static final int TRANSACTION_allowUsbDebugging = (android.os.IBinder.FIRST_CALL_TRANSACTION + 16);
    static final int TRANSACTION_denyUsbDebugging = (android.os.IBinder.FIRST_CALL_TRANSACTION + 17);
}

/* 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, int userId)
        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, int userId)
        throws android.os.RemoteException;

/* Clears default preferences and permissions for the package */
public void clearDefaults(java.lang.String packageName, int userId)
        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;

/*
 * Allow USB debugging from the attached host. If alwaysAllow is true, add
 * the the public key to list of host keys that the user has approved.
 */
public void allowUsbDebugging(boolean alwaysAllow,
        java.lang.String publicKey) throws android.os.RemoteException;

/* Deny USB debugging from the attached host */
public void denyUsbDebugging() throws android.os.RemoteException;
}

并修改添加用户ID的代码:

...
service.setDevicePackage( usbDevice, YOUR_APP_PACKAGE_NAMESPACE, ai.uid ); 
....

6
投票

我在弹出窗口中遇到了同样的问题,没有人点击它。但我发现了一种不同的解决方案(对于有根设备)。弹出窗口由android在类UsbPermissionActivity中生成(并且UsbPermissionActivity由UsbSettingsManager启动)。查看Android源代码,了解最新情况。这里的好处是,我们可以操作UsbPermissionActivity的字节码来接受所有的UsbDevices。你需要工具Smali / Baksmali这样做。 https://code.google.com/p/smali/

  1. 在您的设备上找到文件SystemUI.apk
  2. 使用adb pull path/to/SystemUI.apk将其复制到您的计算机
  3. 解压缩apk
  4. java -jar baksmali.jar classes.dex反汇编classes.dex文件
  5. 找到文件UsbPermissionActivity,在其中找到所说的行 invoke-virtual {p0}, Lcom/android/systemui/usb/UsbPermissionActivity;->setupAlert()V
  6. 通过注释并添加两个新行来改变它

#invoke-virtual {p0}, Lcom/android/systemui/usb/UsbPermissionActivity;->setupAlert()V const/4 v0, 0x1 iput-boolean v0, p0, Lcom/android/systemui/usb/UsbPermissionActivity;->mPermissionGranted:Z invoke-virtual {p0}, Lcom/android/systemui/usb/UsbPermissionActivity;->finish()V

  1. java -jar smali.jar -o classes.dex out组装它
  2. 替换原来的classes.dex并将所有内容再次压缩到SystemUI.apk
  3. 使用adb push services.jar path/to/SystemUI.apk替换设备上的原始SystemUI.apk,或者如果它不适用于文件管理器应用程序

5
投票

如果您可以选择编译Android系统,那么您无法做任何事情。

你可以加

public void onStart() {
    super.onStart();
    mPermissionGranted = true;

    finish();
}

到frameworks / base / packages / SystemUI / src / com / android / systemui / usb / UsbPermissionActivity.java

绕过权限确认弹出窗口。


4
投票

Android实际上并不是为了支持开箱即用的这种用法而设计的。就个人而言,对于非交互式使用,我很想考虑在linux内核中使用USB串行驱动程序并跳过android USB apis。但你必须能够认真修改android安装 - 更改内核配置和/或加载模块,创建设备文件并设置他们的权限或所有者,可能添加unix组和Android允许的应用程序权限访问它。

或者你可以浏览android源码并禁用用户确认;但如果你没有设备的源代码android构建,这可能比linux级别的想法更棘手,因为适应开源android在供应商设备上运行可能是非常重要的(除非某人已经提供了一个来自-source构建,对于有问题的设备而言功能足够)

显然,root / su访问不适用于应用程序本身 - 它只意味着知道如何运行你的root hack留下的任何工具的应用程序可以启动一个以root身份运行的帮助程序,但应用程序本身不会和不能。使用root在系统分区上安装应用程序可能会获得一些非典型的android权限,但你必须检查是否有任何可以帮助你使用usb。


4
投票

我认为提前白色列出您正在使用的配件将是最佳解决方案。为此,您需要在此位置/ data / system / users / 0添加文件usb_device_manager.xml //请注意,0是用户ID,如果您未在Android中添加更多用户,则可能为0,但如果您确实更改了此ID

这是文件的外观:

<settings>
<preference package="<PACKAGE NAME OF APP YOU WANT TO START ON CONNECTIONCTION>">
    <usb-accessory manufacturer="<NAME OF MANUFECTURER LIKE ONE REGISTERED IN meta-data in the manifest>" model="<MODEL NAME LIKE ONE REGISTERED IN meta-data in the manifest>" version="<VERSION LIKE ONE REGISTERED IN meta-data in the manifest>" />
</preference>

对于这样的董事会http://www.embeddedartists.com/products/app/aoa_kit.php它是:

 <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<settings>
<preference package="com.embeddedartists.aoa">
    <usb-accessory manufacturer="Embedded Artists AB" model="AOA Board - Basic" version="1.0" />
</preference>


2
投票

实现这一目标的一种方法,请注意,这实际上没有摆脱确认,将指出checkbox的位置,并使用Android等效的Robot类来选择它,然后选择OK。您可以编写一个在后台运行的应用程序,它甚至可以由您提到的启动服务调用,特别是为此目的。


2
投票

根据Android开发者的文档,当您的应用程序通过您的清单意图过滤器启动时,您已经拥有连接的USB设备的权限。也许你应该尝试这种方法并编写一个过滤器来精确匹配你想要使用的设备,以防止其他应用程序也想与设备通信。

请参阅http://developer.android.com/guide/topics/connectivity/usb/host.html#permission-d上的“注意”


0
投票

我想我们可以通过在/etc/udev进行一些修改来做到这一点。我们可以将供应商ID和设备ID添加到51-android.rules文件中。

© www.soinside.com 2019 - 2024. All rights reserved.