Android8.0 USB system framework

USB (Universal Serial Bus) host mode provides power to peripherals, enabling Android devices to drive the USB bus, and can use a variety of USB peripherals (including audio interfaces, storage, MIDI), both USB and Bluetooth low energy connections Used to transmit MIDI protocol. USB accessory mode, driven by peripheral power supply, including data transmission and charging. USB development mode, application debugging, the only visible peripheral function is Android fastboot or Android debug bridge (adb). The layers of fastboot and adb protocols are higher than those of USB bulk data transfer mode.

The Android platform supports the use of plug-and-play USB cameras (such as webcams), but only if these cameras use the standard Android Camera2 API and camera HIDL interface, the new USB camera HAL process is part of the external camera provider, the provider Listens for USB device availability and enumerates external camera devices accordingly. This process has similar permissions and SE policies as the built-in camera HAL process. Third-party webcam apps that communicate directly with USB devices require the same camera permissions as all regular camera apps to access UVC devices.

1. Usb service starts
frameworks\base\services\usb\java\com\android\server\usb\UsbService.java

public static class Lifecycle extends SystemService {         private UsbService mUsbService;         ......         @Override         public void onStart() { mUsbService = new UsbService(getContext());} //USB service initialization         @Override         public void onBootPhase(int phase) {             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {                 mUsbService.systemReady(); //system is ready             } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {                 mUsbService.bootCompleted();//system boot completed             }         }         ... ...     } 1 2 3 4 5



















6
7
8
9
10
11
12
13
14
15
frameworks\base\services\usb\java\com\android\server\usb\UsbService.java
initializes USB service

 public UsbService(Context context) {         mContext = context;         //multi-user management         mUserManager = context.getSystemService(UserManager.class);         //user management settings         mSettingsManager = new UsbSettingsManager(context);         //advanced audio management         mAlsaManager = new UsbAlsaManager( context);         //package management         final PackageManager pm = mContext.getPackageManager();         //USB host mode         if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {             mHostManager = new UsbHostManager(context, mAlsaManager, mSettingsManager);         }         //USB Device management         if (new File("/sys/class/android_usb").exists()) {















            mDeviceManager = new UsbDeviceManager(context, mAlsaManager, mSettingsManager);
        }
        //USB port management
        if (mHostManager != null || mDeviceManager != null) {             mPortManager = new UsbPortManager(context);         }         //Switch to system user         onSwitchUser(UserHandle .USER_SYSTEM);         //Register device agent management         final IntentFilter filter = new IntentFilter();         filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);         mContext.register Receiver(mReceiver, filter, null, null);     } 1 2 3 4














5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
frameworks\base\services\usb\java\com\android\server\usb\UsbService.java

 public void systemReady() {
        mAlsaManager.systemReady();

        if (mDeviceManager != null) {
            mDeviceManager.systemReady();
        }
        if (mHostManager != null) {
            mHostManager.systemReady();
        }
        if (mPortManager != null) {
            mPortManager.systemReady();
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
frameworks\base\services\usb\java\com\android\server\usb\UsbAlsaManager.java
frameworks\base\services\usb\java\com\android\server\usb\UsbDeviceManager.java
frameworks\base\services\usb\java\com\android\server\usb\UsbHostManager.java
frameworks\base\services\usb\java\com\android\server\usb\UsbPortManager.java

 //System audio service
public void systemReady() {         mAudioService = IAudioService.Stub.asInterface(                         ServiceManager.getService(Context.AUDIO_SERVICE));         mAlsaObserver.startWatching(); //Start advanced audio monitoring         ...     } // Create USB device Notification public void systemReady() {         mNotificationManager = (NotificationManager)                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);         // Ensure that the notification channels are set up         if (isTv()) {             // TV-specific notification channel             mNotificationManager. createNotificationChannel(





    








                    new NotificationChannel(ADB_NOTIFICATION_CHANNEL_ID_TV,
                            mContext.getString(
                                    com.android.internal.R.string
                                            .adb_debugging_notification_channel_tv),
                            NotificationManager.IMPORTANCE_HIGH));
        }
        ......
        mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
    }

//启动USB主机模式总线
public void systemReady() {
        synchronized (mLock) {
            // Create a thread to call into native code to wait for USB host events.
            // This thread will call us back on usbDeviceAdded and usbDeviceRemoved.
            Runnable runnable = new Runnable() {
                public void run() {
                    monitorUsbHostBus();
                }
            };
            new Thread(null, runnable, "UsbService host thread").start();
        }
    }

//Query the USB device port transfer status
public void systemReady() {         if (mProxy != null) {             try {                 mProxy.queryPortStatus();             } catch (RemoteException e) {               .......             }         }         mSystemReady = true;     } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28





































29
30
31 32
33
34
35 36
37 38 39
40
41 42 43 44 45 46 47 48 49 50 51 2. USB device open frameworks
\ base\core\java\android\hardware\ usb \UsbManager.java














public UsbDeviceConnection openDevice(UsbDevice device) {         try {             String deviceName = device.getDeviceName();             //Open the USB device and return the file descriptor FD             ParcelFileDescriptor pfd = mService.openDevice(deviceName);             if (pfd != null) {                 // Create a Socket connection channel for data instruction transmission                 UsbDeviceConnection connection = new UsbDeviceConnection(device);                 boolean result = connection.open(deviceName, pfd, mContext);                 pfd.close();                 if (result) {                     return connection;                 }             }         } catch (Exception e) {














            Log.e(TAG, "exception in UsbManager.openDevice", e);
        }
        return null;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
frameworks\base\services\usb\java\com\android\server\usb\UsbService.java

/* Opens the specified USB device (host mode) */
    @Override
    public ParcelFileDescriptor openDevice(String deviceName) {
        ParcelFileDescriptor fd = null;

        if (mHostManager != null) {
            synchronized (mLock) {
                if (deviceName != null) {
                    int userIdInt = UserHandle.getCallingUserId();
                    boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked();
                    //以主机模式打开制定USB
                    if (isCurrentUser) {
                        fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt));
                    } else {
                        Slog.w(TAG, "Cannot open " + deviceName + " for user " + userIdInt +
                               " as user is not active.");
                    }
                }
            }
        }

        return fd;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
frameworks\base\services\usb\java\com\android\server\usb\UsbHostManager.java

    /* Opens the specified USB device */
    public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings) {         synchronized (mLock) {             if (isBlackListed(deviceName)) {                 throw new SecurityException("USB device is on a restricted bus");             }             / / Find a             UsbDevice from the list of existing USB devices device = mDevices.get(deviceName);             ......             settings.checkPermission(device);             return nativeOpenDevice(deviceName);         }     } 1 2 3 4 5 6 7 8 9 10





















11
12
13
frameworks\base\services\core\jni\com_android_server_UsbHostManager.cpp

static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* thiz */,
                                                        jstring deviceName)
{     const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);     //Call the USB device open function provided by the system     struct usb_device* device = usb_de vice_open (deviceNameStr);     env->ReleaseStringUTFChars(deviceName, deviceNameStr);     //Get the file descriptor of the USB device     int fd = usb_device_get_fd(device);     if (fd < 0) {         usb_device_close(device);         return NULL;     }     int newFD = dup(fd);     usb_device_close(device);











    jobject fileDescriptor = jniCreateFileDescriptor(env, newFD);
    if (fileDescriptor == NULL) {
        return NULL;
    }
    return env->NewObject(gParcelFileDescriptorOffsets.mClass,
        gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
system\core\libusbhost\usbhost.c

struct usb_device *usb_device_open(const char *dev_name)
{
    int fd, did_retry = 0, writeable = 1;

    D("usb_device_open %s\n", dev_name);

retry:
    fd = open(dev_name, O_RDWR); //打开设备
    if (fd < 0) {
        /* if we fail, see if have read-only access */
        //失败则以只读模式打开
        fd = open(dev_name, O_RDONLY);
        D("usb_device_open open returned %d errno %d\n", fd, errno);
        if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) {
            /* work around race condition between inotify and permissions management */
            sleep(1);
            did_retry = 1;
            goto retry;
        }

        if (fd < 0)
            return NULL;
        writeable = 0;
        D("[ usb open read-only %s fd = %d]\n", dev_name, fd);
    }
    //新建一个USB设备
    struct usb_device* result = usb_device_new(dev_name, fd);
    if (result)
        result->writeable = writeable;
    return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
system\core\libusbhost\usbhost.c

struct usb_device *usb_device_new(const char *dev_name, int fd)
{
    struct usb_device *device = calloc(1, sizeof(struct usb_device)); //分配内存
    int length;

    D("usb_device_new %s fd: %d\n", dev_name, fd);

    if (lseek(fd, 0, SEEK_SET) != 0)
        goto failed;
    length = read(fd, device->desc, sizeof(device->desc)); //读取设备描述符长度
    D("usb_device_new read returned %d errno %d\n", length, errno);
    if (length < 0)
        goto failed;

    strncpy(device->dev_name, dev_name, sizeof(device->dev_name) - 1);
    device->fd = fd;
    device->desc_length = length;
    // assume we are writeable, since usb_device_get_fd will only return writeable fds
    device->writeable = 1;
    return device;

failed:
    close(fd);
    free(device);
    return NULL;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
frameworks\base\core\java\android\hardware\usb\UsbDeviceConnection.java

public UsbDeviceConnection(UsbDevice device) {
        mDevice = device;
    }
    /* package */ boolean open(String name, ParcelFileDescriptor pfd, @NonNull Context context) {
        mContext = context.getApplicationContext();
        boolean wasOpened = native_open(name, pfd.getFileDescriptor());
        ......
        return wasOpened;
    }
1
2
3
4
5
6
7
8
9
frameworks\base\core\jni\android_hardware_UsbDeviceConnection.cpp
调用JNI层打开指定的USB设备

static jboolean
android_hardware_UsbDeviceConnection_open(JNIEnv *env, jobject thiz, jstring deviceName,
        jobject fileDescriptor)
{
    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
    fd = dup(fd);
    if (fd < 0)
        return JNI_FALSE;

    const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
    struct usb_device* device = usb_device_new(deviceNameStr, fd); //新建
    if (device) {
        env->SetLongField(thiz, field_context, (jlong)device);
    } else {
        ALOGE("usb_device_open failed for %s", deviceNameStr);
        close(fd);
    }

    env->ReleaseStringUTFChars(deviceName, deviceNameStr);
    return (device != NULL) ? JNI_TRUE : JNI_FALSE;
}
1
2
3
4
5
6
7
8
9 10
11
12 13 14 15 16 17 18 19 20 21 22 3. USB device detection frameworks\base\services\usb\java\com\android\server\usb\UsbPortManager.java device port management













 public UsbPortManager(Context context) {
        mContext = context;
        try {
        //HIDL层的Service
            boolean ret = IServiceManager.getService()
                    .registerForNotifications("[email protected]::IUsb",
                            "", mServiceNotification);
            ......
        } catch (RemoteException e) {
            ......
            return;
        }
        connectToProxy(null);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
frameworks\base\services\usb\java\com\android\server\usb\UsbPortManager.java

private void connectToProxy(IndentingPrintWriter pw) {         synchronized (mLock) {             try {                 //Get HIDL service                 mProxy = IUsb.getService();                  mProxy.linkToDeath(new DeathRecipient(pw), USB_HAL_DEATH_COOKIE);                 //Set callback, look back later                 mProxy.setCallback(mHALCallback);                  mProxy.queryPortStatus();             } catch (NoSuchElementException e) {                ......             }         }     } 1 2 3 4 5 6 7 8 9 10 11 12

























13
14
hardware\interfaces\usb\1.0\default\Usb.cpp

Return<void> Usb::setCallback(const sp<IUsbCallback>& callback) {

    pthread_mutex_lock(&mLock);
    if ((mCallback == NULL && callback == NULL) ||
            (mCallback != NULL && callback != NULL)) {
        mCallback = callback;
        pthread_mutex_unlock(&mLock);
        return Void();
    }
    ......
    destroyThread = false;
    signal(SIGUSR1, sighandler);
    //创建线程,运行work
    if (pthread_create(&mPoll, NULL, work, this)) {
        ALOGE("pthread creation failed %d", errno);
        mCallback = NULL;
    }
    pthread_mutex_unlock(&mLock);
    return Void();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 17
18
19
20 hardware\interfaces\usb\1.0\default\Usb.cpp uses EPOLL
, UEVENT mechanism, multi-channel IO blocking multiplexing

void* work(void* param) {     int epoll_fd, uevent_fd;     struct epoll_event ev;     int nevents = 0;     struct data payload;     uevent_fd = uevent_open_socket(64*1024, true); //create socket     //payload is a conversion structure     payload.uevent_fd = uevent_fd;     payload.usb = (android::hardware::usb::V1_0::implementation::Usb *)param;     fcntl(uevent_fd, F_SETFL, O_NONBLOCK);     ev.events = EPOLLIN;     //binding Event processing function uevent_event     ev.data.ptr = (void *)uevent_event;     epoll_fd = epoll_create(64);     //Cycle wait for UEVENT event     while (!destroyThread) {         struct epoll_event events[64];
















        nevents = epoll_wait(epoll_fd, events, 64, -1);
        for (int n = 0; n < nevents; ++n) {
            if (events[n].data.ptr)
                (*(void (*)(int, struct data *payload))events[n].data.ptr)
                    (events[n].events, &payload);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
hardware\interfaces\usb\1.0\default\Usb.cpp
Handle USB driver events from the kernel

static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
    char msg[UEVENT_MSG_LEN + 2];
    char *cp;
    int n;
    n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
    if (n <= 0)
        return;
    if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
        return;
    msg[n] = '\0';
    msg[n + 1] = '\0';
    cp = msg;
    //如果有数据,继续处理
    while (*cp) {
        if (!strcmp(cp, "SUBSYSTEM=dual_role_usb")) {
            ALOGE("uevent received %s", cp);
            if (payload->usb->mCallback != NULL) {
                hidl_vec<PortStatus> currentPortStatus;
                Status status = getPortStatusHelper(currentPortStatus);
                //执行上层的回调
                Return<void> ret =
                    payload->usb->mCallback->notifyPortStatusChange(currentPortStatus, status);
            }
            break;
        }
        /* advance to after the next \0 */
        while (*cp++);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
frameworks\base\services\usb\java\com\android\server\usb\UsbPortManager.java
Now let's take a look at the mHALCallback we just encountered

 private static class HALCallback extends IUsbCallback.Stub {
        public IndentingPrintWriter pw;
        public UsbPortManager portManager;
        .......
        public void notifyPortStatusChange(ArrayList<PortStatus> currentPortStatus, int retval) {
            ArrayList<RawPortInfo> newPortInfo = new ArrayList<RawPortInfo>();
            //处理USB端口状态
            for (PortStatus current : currentPortStatus) {
                RawPortInfo temp = new RawPortInfo(current.portName,
                        current.supportedModes, current.currentMode,
                        current.canChangeMode, current.currentPowerRole,
                        current.canChangePowerRole,
                        current.currentDataRole, current.canChangeDataRole);
                newPortInfo.add(temp);
                logAndPrint(Log.INFO, pw, "ClientCallback: " + current.portName);
            }
            //转给UsbPortManager的Handler来处理
            Message message = portManager.mHandler.obtainMessage();
            Bundle bundle = new Bundle();
            bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
            message.what = MSG_UPDATE_PORTS;
            message.setData(bundle);
            portManager.mHandler.sendMessage(message);
            return;
        }
        ......
    };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
frameworks\base\services\usb\java\com\android\server\usb\UsbPortManager.java

 private final Handler mHandler = new Handler(FgThread.get().getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_UPDATE_PORTS: {
                    Bundle b = msg.getData();
                    ArrayList<RawPortInfo> PortInfo = b.getParcelableArrayList(PORT_INFO);
                    synchronized (mLock) {
                        updatePortsLocked(null, PortInfo);
                    }
                    break;
                }
            }
        }
    };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
frameworks\base\services\usb\java\com\android\server\usb\UsbPortManager.java

private void updatePortsLocked(IndentingPrintWriter pw, ArrayList<RawPortInfo> newPortInfo) {
        //处理USB设备的插入删除移除
        // Process the updates.
        // Once finished, the list of ports will only contain ports in DISPOSITION_READY.
        for (int i = mPorts.size(); i-- > 0; ) {
            final PortInfo portInfo = mPorts.valueAt(i);
            switch (portInfo.mDisposition) {
                case PortInfo.DISPOSITION_ADDED:
                    handlePortAddedLocked(portInfo, pw);
                    portInfo.mDisposition = PortInfo.DISPOSITION_READY;
                    break;
                case PortInfo.DISPOSITION_CHANGED:
                    handlePortChangedLocked(portInfo, pw);
                    portInfo.mDisposition = PortInfo.DISPOSITION_READY;
                    break;
                case PortInfo.DISPOSITION_REMOVED:
                    mPorts.removeAt(i);
                    portInfo.mUsbPortStatus = null; // must do this early
                    handlePortRemovedLocked(portInfo, pw);
                    break;
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
frameworks\base\services\usb\java\com\android\server\usb\UsbPortManager.java
finally sent a broadcast to send out the port status information

 private void sendPortChangedBroadcastLocked(PortInfo portInfo) {
        final Intent intent = new Intent(UsbManager.ACTION_USB_PORT_CHANGED);
        intent.addFlags(
                Intent.FLAG_RECEIVER_FOREGROUND |
                        Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        intent.putExtra(UsbManager.EXTRA_PORT, portInfo.mUsbPort);
        intent.putExtra(UsbManager.EXTRA_PORT_STATUS, portInfo.mUsbPortStatus);

        // Guard against possible reentrance by posting the broadcast from the handler
        // instead of from within the critical section.
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
            }
        });
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
4. USB设备事务处理
frameworks\base\services\usb\java\com\android\server\usb\UsbDeviceManager.java

  public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
            UsbSettingsManager settingsManager) {         //USB accessory mode check         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);         if (nativeIsStartRequested()) {             if (DEBUG) S log.d(TAG, "accessory attached at boot");             startAccessoryMode();         }         mHandler = new UsbHandler(FgThread.get().getLooper());         //Adb debugging is enabled by the developer         boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false );         boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));










        if (secureAdbEnabled && !dataEncrypted) {             mDebuggingManager = new UsbDebuggingManager(context); //usb debugging management         }         //corresponding to the broadcast sent above         mContext.registerReceiver(mHostReceiver,                 new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));         mContext.registerRecei ver(mChargingReceiver,                 new IntentFilter(Intent. ACTION_BATTERY_CHANGED));     } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21





























frameworks\base\services\usb\java\com\android\server\usb\UsbDeviceManager.java
listens for message forwarding and processing transactions

 //adb debug mode switch monitor
 private class AdbSettingsObserver extends ContentObserver {         public AdbSettingsObserver() {             super(null);         }


        @Override
        public void onChange(boolean selfChange) {
            boolean enable = (Settings.Global.getInt(mContentResolver,
                    Settings.Global.ADB_ENABLED, 0) > 0);
            mHandler.sendMessage(MSG_ENABLE_ADB, enable);
        }
    }

    //监听来自内核的Uevent
    private final UEventObserver mUEventObserver = new UEventObserver() {
        @Override
        public void onUEvent(UEventObserver.UEvent event) {
            if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());

            String state = event.get("USB_STATE");
            String accessory = event.get("ACCESSORY");
            if (state != null) {
                mHandler.updateState(state);
            } else if ("START".equals(accessory)) {
                if (DEBUG) Slog.d(TAG, "got accessory start");
                startAccessoryMode();
            }
        }
    };

    //Receive USB status change
    private final BroadcastReceiver mHostReceiver = new BroadcastReceiver() {         @Override         public void onReceive(Context context, Intent intent) {             UsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);             UsbPortStatus status = intent.get ParcelableExtra(UsbManager. EXTRA_PORT_STATUS);             mHandler.updateHostState(port, status); //Pass it to the internal Handler for processing, no more in-depth} };         //     Accept     USB unplugging status     private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() {         @Override         public void onReceive( Context context, Intent intent) {











            int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
            boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
            mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
        }
    };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Finally, UsbHandler handles affairs including MIDI, host/accessory mode, audio, adb debugging, status Notification, device increase and decrease status changes, etc. I won't go into details about it in detail, and I will analyze it later.


————————————————
Copyright statement: This article is an original article of CSDN blogger "SherlockCharlie", following the CC 4.0 BY-SA copyright agreement, please attach the original source link and this statement for reprinting .
Original link: https://blog.csdn.net/u013928208/article/details/84586238

Guess you like

Origin blog.csdn.net/grf123/article/details/102970960