Bypass Android Usb Host Permission Confirmation Dialog

bypass android usb host permission confirmation dialog

I know it's a bit late, but still...

I had the same kind of problem and I think I've managed to solve it. There's a service that Android uses internally that allows to manage USB devices and accessories.
This service is hidden from thrid party developers and is not documented. If you check the source code for UsbPermissionActivity you'll be able to figure out how that service is called.
In order to call the service IUsbManager interface and ServiceManager class are employed. These are both hidden too, so you can't use them directly. But what you can do is to
create their stubs with exactly the same names and in corresponding namespaces (packages). Then you'll be able to compile that code, while the runtime environment will use the real things.

The only requirement is that your application has to be a system one - that is it has to be located in /system/app/ directory. Since your device is rooted that shouldn't be a problem.

So you will have to add a package to your project: "android.hardware.usb" and put a file in it named "IUsbManager.java" with the following content:

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;
}

Then another package: "android.os" with "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!" );
}
}

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.

Here's an example of using the service to grant permissions to all FTDI devices:

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() );
}
}
}
}

One more thing - you will have to add the following permission to your manifest (Lint might not like it but you can always change severity level in your project's properties):

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

Bypass android usb host permission confirmation dialog on Android 9

We can solve it by entering:

adb shell
su
settings put global hidden_api_policy_pre_p_apps 1
settings put global hidden_api_policy_p_apps 1

Restrictions on non-SDK interfaces (Android 9): https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces

And then grantDevicePermission method will be available again through reflection on Android 9:

public static boolean grantAutomaticUsbPermissionRoot(Context context, UsbDevice usbDevice) {
try {
PackageManager pkgManager = context.getPackageManager();
ApplicationInfo appInfo = pkgManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);

Class serviceManagerClass = Class.forName("android.os.ServiceManager");
Method getServiceMethod = serviceManagerClass.getDeclaredMethod("getService", String.class);
getServiceMethod.setAccessible(true);
android.os.IBinder binder = (android.os.IBinder)getServiceMethod.invoke(null, Context.USB_SERVICE);

Class iUsbManagerClass = Class.forName("android.hardware.usb.IUsbManager");
Class stubClass = Class.forName("android.hardware.usb.IUsbManager$Stub");
Method asInterfaceMethod = stubClass.getDeclaredMethod("asInterface", android.os.IBinder.class);
asInterfaceMethod.setAccessible(true);
Object iUsbManager=asInterfaceMethod.invoke(null, binder);

final Method grantDevicePermissionMethod = iUsbManagerClass.getDeclaredMethod("grantDevicePermission", UsbDevice.class, int.class);
grantDevicePermissionMethod.setAccessible(true);
grantDevicePermissionMethod.invoke(iUsbManager, usbDevice,appInfo.uid);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

p.s. you need root of course and systemize your app (move to /system/priv-app/)

bypass android usb host permission confirmation dialog for android 5.1

It's been a while since you asked this... but in case it can help someone here is my answer.

The accepted answer in the initial question states:

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.

So you should get the files you need directly from the android source code. You can download the source code relative to your version or browse directly from the repo.

The IUsbManager interface you are searching for is normally under:
/frameworks/base/android-branch-name/core/java/android/hardware/usb. As for the Service Manager it can be found under:
/frameworks/base/android-branch-name/core/java/android/os/

I didn't post the code since I suppose you're not searching for it anymore after 2 years+ :)

=== EDIT ===

As asked, here is the code. I made it work for version 6.0.0, but I think functions calls are the same as 5.1. To be verified.

First, here is the android project structure you will get:
Sample Image

Create the interface IUsbManager.java in android.harware.usb:

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;

}

Then create the java class ServiceManager.java in android.os:

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!" );
}
}

Once this is done, don't forget to add the android.permission.MANAGE_USB in you AndroidManifest.

Then you can use those function calls:

/**
* 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);
}
}

There's a check on whether your application is a system application and if it has the correct permission, otherwise it would not work.

Also be aware that your vendor id is not in hexadecimal but in decimal.

Android 10 bypass USB Dialog Permission

i used this solution and added this command to terminal

to use non-sdk api's in android 10:

Adb shell  settings put global hidden_api_policy 1

Remove USB Accessory permission dialog

According to the Android USB host documentation, your application has permission to access the device until the device is disconnected. This question provides a solution to suppress the permission dialog. Create an intent filter in your manifest file and provide the device information in an xml file. This would enable enumerating the device using a broadcast receiver.

Another reference is this question. The latter is meant for rooted devices and I haven't tried it personally.

Edit:

Manifest File: I register my Broadcast Receiver in the manifest file.

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

For the sake of convenience, I have my Broadcast Receiver in a separate class:

public class PmrtReceiver extends BroadcastReceiver {

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();
if(UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)){

Toast.makeText(context, "Device Detected",Toast.LENGTH_LONG).show();

} else if(UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)){

Toast.makeText(context, "Device Detached",Toast.LENGTH_LONG).show();

}

}

};

I did not have to do anything else to suppress the permission dialog.

Look into the USB Missile Launcher example from the Android Samples. Your device filtr should be something like this:

<?xml version="1.0" encoding="utf-8"?>

<resources>
<usb-device vendor-id="1234" product-id="5678" />
</resources>

You have the VID and PID as hexadecimal numbers.



Related Topics



Leave a reply



Submit