Android USB插拔广播

Android USB插拔广播

最近在适配新机型,发现没有USB插拔事件,大概跟踪下源码,看广播的发送。

PS.没有发送插拔广播是系统问题或者是设备的问题,与新版本无关,这是个bug。新版本没有取消广播。

USB的相关介绍本文不描述,包括host client之类的描述。

USB 概要

Android里面与USB相关的几个重要类包括:

UsbService:核心类,系统服务,
UsbManager:核心类,系统服务,app层API打交道主要类。This class allows you to access the state of USB and communicate with USB devices.Currently only host mode is supported in the public API.
UsbDeviceManager:UsbDeviceManager manages USB state in device mode.
UsbHostManager:作为host的时候管理类。UsbHostManager manages USB state in host mode.
UsbPortManager:
UsbAlsaManager:
UsbSettingsManager:
UsbPermissionManager:

上面关于类的描述,以后慢慢补充,暂时没有看完。
插拔设备的时候,android肯定是作为host,所以我们看usbhostmanager。

启动

UsbService里面有这个一个类,继承自SystemService。

 public static class Lifecycle extends SystemService {
        private UsbService mUsbService;
        private final CompletableFuture<Void> mOnStartFinished = new CompletableFuture<>();
        private final CompletableFuture<Void> mOnActivityManagerPhaseFinished =
                new CompletableFuture<>();

        public Lifecycle(Context context) {
            super(context);
        }

        @Override
        public void onStart() {
            SystemServerInitThreadPool.submit(() -> {
                mUsbService = new UsbService(getContext());
                publishBinderService(Context.USB_SERVICE, mUsbService);
                mOnStartFinished.complete(null);
            }, "UsbService$Lifecycle#onStart");
        }

        @Override
        public void onBootPhase(int phase) {
            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
                SystemServerInitThreadPool.submit(() -> {
                    mOnStartFinished.join();
                    mUsbService.systemReady();
                    mOnActivityManagerPhaseFinished.complete(null);
                }, "UsbService$Lifecycle#onBootPhase");
            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
                mOnActivityManagerPhaseFinished.join();
                mUsbService.bootCompleted();
            }
        }

        @Override
        public void onUserSwitching(TargetUser from, TargetUser to) {
            FgThread.getHandler()
                    .postAtFrontOfQueue(() -> mUsbService.onSwitchUser(to.getUserIdentifier()));
        }

        @Override
        public void onUserStopping(TargetUser userInfo) {
            mUsbService.onStopUser(userInfo.getUserHandle());
        }

        @Override
        public void onUserUnlocking(TargetUser userInfo) {
            mUsbService.onUnlockUser(userInfo.getUserIdentifier());
        }
    }

UsbService的启动是onStart,关键初始化就是在onBootPhase。关于这个状态的描述:

 /** @hide */
    @IntDef(flag = true, prefix = { "PHASE_" }, value = {
            PHASE_WAIT_FOR_DEFAULT_DISPLAY,
            PHASE_LOCK_SETTINGS_READY,
            PHASE_SYSTEM_SERVICES_READY,
            PHASE_DEVICE_SPECIFIC_SERVICES_READY,
            PHASE_ACTIVITY_MANAGER_READY,
            PHASE_THIRD_PARTY_APPS_CAN_START,
            PHASE_BOOT_COMPLETED
    })

UsbHostManager的初始化。

 if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
            mHostManager = new UsbHostManager(context, mAlsaManager, mPermissionManager);
        }

这里是说,机器是否支持作为host。

然后就是 mUsbService.systemReady();

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

        if (mDeviceManager != null) {
            mDeviceManager.systemReady();
        }
        if (mHostManager != null) {
            mHostManager.systemReady();
        }
        if (mPortManager != null) {
            mPortManager.systemReady();
        }
    }

进入到 mHostManager.systemReady();

 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 = this::monitorUsbHostBus;
            new Thread(null, runnable, "UsbService host thread").start();
        }
    }

这里直接运行一个thread,然后thread运行的是native的方法。
进入到:com_android_server_UsbHostManager.cpp

static void android_server_UsbHostManager_monitorUsbHostBus(JNIEnv* /* env */, jobject thiz)
{
    struct usb_host_context* context = usb_host_init();
    if (!context) {
        ALOGE("usb_host_init failed");
        return;
    }
    // this will never return so it is safe to pass thiz directly
    usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)thiz);
}

usb_host_run这个方法是在usbhost.c。前面的那个usb_host_init也是在这里。

struct usb_host_context *usb_host_init()
{
    struct usb_host_context *context = calloc(1, sizeof(struct usb_host_context));
    if (!context) {
        fprintf(stderr, "out of memory in usb_host_context\n");
        return NULL;
    }
    context->fd = inotify_init();
    if (context->fd < 0) {
        fprintf(stderr, "inotify_init failed\n");
        free(context);
        return NULL;
    }
    return context;
}
void usb_host_run(struct usb_host_context *context,
                  usb_device_added_cb added_cb,
                  usb_device_removed_cb removed_cb,
                  usb_discovery_done_cb discovery_done_cb,
                  void *client_data)
{
    int done;

    done = usb_host_load(context, added_cb, removed_cb, discovery_done_cb, client_data);

    while (!done) {

        done = usb_host_read_event(context);
    }
} /* usb_host_run() */

这个部分可以不用细看,可以理解成有设备增加调用added_cb,设备移除调用removed_cb。对应我们需要查找的USB插拔事件。
然后:added_cb,removed_cb是什么?
com_android_server_UsbHostManager.cpp

 jclass clazz = env->FindClass("com/android/server/usb/UsbHostManager");
    if (clazz == NULL) {
        ALOGE("Can't find com/android/server/usb/UsbHostManager");
        return -1;
    }
    method_usbDeviceAdded =
            env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;II[B)Z");
    if (method_usbDeviceAdded == NULL) {
        ALOGE("Can't find beginUsbDeviceAdded");
        return -1;
    }
    method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved",
            "(Ljava/lang/String;)V");
    if (method_usbDeviceRemoved == NULL) {
        ALOGE("Can't find usbDeviceRemoved");
        return -1;
    }

对应于Java层的UsbHostManager的usbDeviceAdded和usbDeviceRemoved。

 "usbDeviceAdded"  "(Ljava/lang/String;II[B)Z" string,int,int byte数组,返回boolean
 private boolean usbDeviceAdded(String deviceAddress, int deviceClass, int deviceSubclass,
            byte[] descriptors) 
"usbDeviceRemoved" "(Ljava/lang/String;)V string,无返回
private void usbDeviceRemoved(String deviceAddress)

对下方法签名。转换规则如上,盗图请见谅。

以上明确了,设备插拔到Java层的路径。

设备插入

我们需要的关注的部分,其他的操作大家有兴趣可以自己去看。

 // It is fine to call this only for the current user as all broadcasts are
                // sent to all profiles of the user and the dialogs should only show once.
                ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
                if (usbDeviceConnectionHandler == null) {
                    getCurrentUserSettings().deviceAttached(newDevice);
                } else {
                    getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
                            usbDeviceConnectionHandler);
                }

UsbProfileGroupSettingsManager

 private static Intent createDeviceAttachedIntent(UsbDevice device) {
        Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        intent.putExtra(UsbManager.EXTRA_DEVICE, device);
        intent.addFlags(
                Intent.FLAG_ACTIVITY_NEW_TASK |
                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        return intent;
    }

创建广播的intent,有FLAG_RECEIVER_INCLUDE_BACKGROUND所以后台也可以收到。
上面两个分支发送广播:

  public void deviceAttached(UsbDevice device) {
        final Intent intent = createDeviceAttachedIntent(device);

        // Send broadcast to running activities with registered intent
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);

        resolveActivity(intent, device, true /* showMtpNotification */);
    }
public void deviceAttachedForFixedHandler(UsbDevice device, ComponentName component) {
        final Intent intent = createDeviceAttachedIntent(device);

        // Send broadcast to running activity with registered intent
        mContext.sendBroadcastAsUser(intent, UserHandle.of(ActivityManager.getCurrentUser()));

        ApplicationInfo appInfo;
        try {
            // Fixed handlers are always for parent user
            appInfo = mPackageManager.getApplicationInfoAsUser(component.getPackageName(), 0,
                    mParentUser.getIdentifier());
        } catch (NameNotFoundException e) {
            Slog.e(TAG, "Default USB handling package (" + component.getPackageName()
                    + ") not found  for user " + mParentUser);
            return;
        }

        mSettingsManager.mUsbService.getPermissionsForUser(UserHandle.getUserId(appInfo.uid))
                .grantDevicePermission(device, appInfo.uid);

        Intent activityIntent = new Intent(intent);
        activityIntent.setComponent(component);
        try {
            mContext.startActivityAsUser(activityIntent, mParentUser);
        } catch (ActivityNotFoundException e) {
            Slog.e(TAG, "unable to start activity " + activityIntent);
        }
    }

都是发送广播,启动activity。具体的区别暂时没有关注,有空补。

设备移除

 mUsbAlsaManager.usbDeviceRemoved(deviceAddress);
mPermissionManager.usbDeviceRemoved(device);
 getCurrentUserSettings().usbDeviceRemoved(device);

这里的操作有点意思: getCurrentUserSettings().usbDeviceRemoved(device);只是移除通知栏。
mPermissionManager.usbDeviceRemoved(device);才是发送广播。为啥这么玩,不明白。
发送广播:

    void usbDeviceRemoved(@NonNull UsbDevice device) {
        synchronized (mPermissionsByUser) {
            for (int i = 0; i < mPermissionsByUser.size(); i++) {
                // clear temporary permissions for the device
                mPermissionsByUser.valueAt(i).removeDevicePermissions(device);
            }
        }

        Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        intent.putExtra(UsbManager.EXTRA_DEVICE, device);

        if (DEBUG) {
            Slog.d(LOG_TAG, "usbDeviceRemoved, sending " + intent);
        }
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    }

同样有FLAG_RECEIVER_INCLUDE_BACKGROUND这个标志。

总结

以上,USB设备插拔广播部分完毕。所以android 11关于USB的广播没有变化,跟文档描述一直。具体广播的发送部分,后续文章研究。谢谢!

本文地址:https://blog.csdn.net/qunimaode/article/details/111867728

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐