Android 10 USB Host - Can't connect to device, permission not granted (but should be)
Asked Answered
D

1

7

I've been following guidance from here, in order to connect to a usb device, with the Android phone as a host. https://developer.android.com/guide/topics/connectivity/usb/host.html

From the paragraph below, I believe so long as I correctly set up an intent filter for the USB_Device_Attached action, and filter for my device - I should have all the permissions I need to connect to it already.

Note: If your application uses an intent filter to discover USB devices as they're connected, it automatically receives permission if the user allows your application to handle the intent. If not, you must request permission explicitly in your application before connecting to the device.

My simple example:

public class MainActivity extends Activity {
    private final static String TAG = "USB_HOST_EXAMPLE";
    UsbManager usbManager;
    UsbDeviceConnection connection;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
        Intent intent = getIntent();
        if (intent != null) {
            UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
            if (device != null) {
                Log.w(TAG, "Started activty from intent filter, using device: " + device.getProductName());
                connection = usbManager.openDevice(device);
            }
        }
    }
}

Current behaviour:

  1. App is closed
  2. Connect USB device
  3. Pop up asking if I wish to open my app to use this USB device. (So my intent filter must be working)
  4. App opens.
  5. App goes to connect to device.
  6. App fails to connect, responding with the following exception:
 java.lang.SecurityException: User has not given 10277/com.example.basic_usb_host permission to access device /dev/bus/usb/001/002

I have also tried enumerating for devices and requesting permissions, as described here, but when I've found my USB device, and go to request permissions, the "pop-up" which should show when calling

usbManager.requestPermission(device, permissionIntent);

doesn't show, and the broadcast receiver returns with

permission denied for device UsbDevice.....

I'm on Android 10, and have experienced the same issue with a Pixel 2 and Pixel 3a (the 3a is rooted).

Dissemblance answered 11/5, 2020 at 16:29 Comment(5)
Have you tried with any other Android versions?Countermand
No, unfortunately I don't have any dev phones running pre-Android 10Dissemblance
Sorry what USB permission setting do you mean? I've looked and am not aware of any manifest usb permission.Dissemblance
Any luck on this ?Underground
How did you solve it ? want the bypass the usb permission using android 10.Goodrum
D
0

Before you can connect to a USB device, you must first request permission to access it... after doing whatever is described in the link https://developer.android.com/guide/topics/connectivity/usb/host.html.

    //Request user permission. The response will be received in the BroadcastReceiver
    private void requestUserPermission(final UsbDevice usbDevice) {
        PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0,
                new Intent(UsbSerialService.INTENT_ACTION_USB_PERMISSION), 0);
        mUsbManager.requestPermission(usbDevice, mPendingIntent);
    }

Set up intent filters for the broadcast receiver...

public class UsbSerialService extends Service {
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        openSerialPort();

        return Service.START_STICKY;
    }

    @Override
    public void onCreate() {

        //Initialize executors (using sequential executors to prevent concurrency issues)
        mSerialPortExecutor = Executors.newSingleThreadExecutor();

        //Initialize other variables
        mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

        IntentFilter mUsbIntentFilter = new IntentFilter();
        mUsbIntentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        mUsbIntentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        mUsbIntentFilter.addAction(UsbSerialService.INTENT_ACTION_USB_PERMISSION);


        //Register a broadcast receiver to listen for Android system USB intents
        getBaseContext().registerReceiver(mUsbReceiver, mUsbIntentFilter);

        // whatever required to be performed here

        super.onCreate();
    }
    
    @Override
    public void onDestroy() {

        closeSerialPort();
        
        // whatever required to be performed here

        super.onDestroy();
    }
    
    // the rest...
    
}

Below is the broadcast receiver...

    //Different USB notifications are received here (USB attached, detached, permission responses)
    private BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
    
        @Override
        public void onReceive(Context context, Intent intent) {
        
            Log.d(UsbSerialService.TAG, "Intent Action: " + intent.getAction());
            
            if (intent.getAction() != null && intent.getAction().equals(UsbSerialService.INTENT_ACTION_USB_PERMISSION)) {
            
                boolean permissionGranted = false;
                
                if (intent.getExtras() != null) {
                
                    permissionGranted = intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
                    
                }
                
                if (permissionGranted) {

                    // User accepted our USB connection. Try to open the device as a USB port
                    
                    getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_USB_PERMISSION_GRANTED)
                            .putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
                            .putExtra(UsbSerialService.EXTRA_USB_FAILED_STATE, UsbSerialService.isUsbFailed())
                            .putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
                            .putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
                            .putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));

                    UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                    //Run USB port opening operation on a separate thread
                    mSerialPortExecutor.execute(new SerialPortOpener(device));

                } else {
                
                    //Send out an intent to notify that the user denies access to the USB connection
                    
                    getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_USB_PERMISSION_NOT_GRANTED)
                            .putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
                            .putExtra(UsbSerialService.EXTRA_USB_FAILED_STATE, UsbSerialService.isUsbFailed())
                            .putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
                            .putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
                            .putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
                }
                
            } else if (intent.getAction() != null && intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {

                // A USB device has been attached. Try to open it as a Serial port

                closeSerialPort();

                Log.d(UsbSerialService.TAG, "openSerialPort(USB) called upon attached");
                
                openSerialPort();

            } else if (intent.getAction() != null && intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {

                // @TODO Usb device disconnected. Stop listening for data input & close usb port
                
                if (!Tools.isEmpty(UsbSerialService.getUsbId())) {
                    getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_USB_DISCONNECTED)
                            .putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
                            .putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
                            .putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
                            .putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
                } else {
                    getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_USB_NOT_SUPPORTED)
                            .putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
                            .putExtra(UsbSerialService.EXTRA_USB_FAILED_STATE, UsbSerialService.isUsbFailed())
                            .putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
                            .putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
                            .putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
                }

                Log.e(UsbSerialService.TAG, "closeSerialPort(USB) called upon detached");
                
                closeSerialPort();
            }
        }
    };

The open USB device port method...

    //Attempts to open the first encountered usb device connected, excluding usb root hubs
    private void openSerialPort() {
    
        if (!settings.isUsbDisabled()) {
        
            Log.e(UsbSerialService.TAG, "openSerialPort(USB) is running...");

            try {
                HashMap<String, UsbDevice> usbDevices = mUsbManager.getDeviceList();

                if (!usbDevices.isEmpty()) {
                    boolean deviceChosen = false;
                    if (!mSerialPortConnected) {
                        for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
                        
                            UsbDevice usbDevice = entry.getValue();
                            
                            //If there is a USB device connected, try to open it as a Serial port.

                            //1d6b  Linux Foundation
                            //      0001  1.1 root hub
                            //      0002  2.0 root hub
                            //      0003  3.0 root hub
                            //      0100  PTP Gadget
                            //      0101  Audio Gadget
                            //      0102  EEM Gadget
                            //      0103  NCM (Ethernet) Gadget
                            //      0104  Multifunction Composite Gadget
                            //      0105  FunctionFS Gadget
                            //      0200  Qemu Audio Device
                            if (
                                    (usbDevice.getVendorId() != 0x1d6b /*UsbId.VENDOR_LINUX*/
                                            && usbDevice.getProductId() != 0x0001
                                            && usbDevice.getProductId() != 0x0002
                                            && usbDevice.getProductId() != 0x0003)) {

                                if (Constants.ENABLE_USB_DEVICE_INFO) {

                                    String info = String.format("DEV ID = %s\nVID = %d\nPID = %d",
                                            usbDevice.getDeviceName(),
                                            usbDevice.getVendorId(),
                                            usbDevice.getProductId());
                                            
                                    //do something to display USB device info...

                                }

                                requestUserPermission(usbDevice);
                                
                                deviceChosen = true;
                            }
                        }
                    }
                }
                else {
                
                    //If there are no USB devices connected, notify other app components
                    
                    getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_NO_USB)
                            .putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
                            .putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
                            .putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
                            .putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
                }
                
            } catch (NullPointerException e) {
                //Catch statement to make it possible to run the app in an emulator (no USB)
                
                e.printStackTrace();
            }
        }
        else {
            Log.e(UsbSerialService.TAG, "Invalid USB open state!");
        }
    }

The close USB device port method...

    //Closes the USB serial connection
    private void closeSerialPort() {
    
        if (!settings.isUsbDisabled()) {
        
            if (mSerialPortConnected) {
            
                // Usb device disconnected. Stop listening for RAP input & close serial port

                getBaseContext().sendBroadcast(new Intent(UsbSerialService.INTENT_ACTION_USB_DISCONNECTED)
                        .putExtra(UsbSerialService.EXTRA_USB_CONNECTION_STATE, UsbSerialService.isSerialPortConnected())
                        .putExtra(UsbSerialService.EXTRA_USB_ID, UsbSerialService.getUsbId())
                        .putExtra(UsbSerialService.EXTRA_USB_MID, UsbSerialService.getUsbMid())
                        .putExtra(UsbSerialService.EXTRA_USB_SID, UsbSerialService.getUsbSid()));
            } else {
                Log.e(UsbSerialService.TAG, "closeSerialPort(USB) is not running...");
            }

            //Run serial port closing operation on a separate thread
            mSerialPortExecutor.execute(new SerialPortCloser());

        } else {
            Log.e(UsbSerialService.TAG, "Invalid USB close state!");
        }
    }

The UsbSerialService mentioned in the preceding codes is my custom Service class that handles the serial connection to a USB device. It manages the push notification events and other behaviors as described in the intent names using another broadcast receiver.

Dorcy answered 14/9, 2022 at 5:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.