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