UsbHostManager是Android USB处于Host模式时,用来管理外部接入的USB设备,如USB存储设置,USB鼠标/键盘,USB摄像头等,UsbHostManager主要用来处理这些设备的插入,移除等事件的处理。
UsbHostManager的初始化
UsbDeviceManager是在UsbService初始化的时候创建的。
public UsbService(Context context) {
mContext = context;
mUserManager = context.getSystemService(UserManager.class);
mSettingsManager = new UsbSettingsManager(context);
mAlsaManager = new UsbAlsaManager(context);
final PackageManager pm = mContext.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
mHostManager = new UsbHostManager(context, mAlsaManager, mSettingsManager);
...
}
然后在UsbService的systemReady中调用了UsbHostManager的systemReady函数。
public void systemReady() {
...
if (mHostManager != null) {
mHostManager.systemReady();
}
...
}
UsbHostManager的systemReady函数中会启动一个线程来监听USB Host Bus。
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();
}
}
UsbHostManager监控USB设备
monitorUsbHostBus
是一个本地函数,具体实现在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_init
和usb_host_run
都是libusbhost
库中的函数,该库位于system/core/libusbhost
目录。libusbhost
库主要提供与usb设备通信的接口,同时以
的方式来监控/dev/bus/usb/
目录并见设备变化通知到上层。
其中usb_host_init
函数会初始化一个usb_host_context
结构体,同时会初始化inotify
。
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;
}
usb_host_run
函数则会加载现有USB设备,同时监控USB设备文件变化。
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_load
函数会检已经存在的usb设备,并上报设备状态给上层。usb_host_read_event
函数循环读取inotify
的事件上报,将设备状态信息通过回调函数上报给上层, 其中usb_device_added_cb
回调函数用来回调通知USB设备插入事件,usb_device_removed_cb
回调函数用来处理USB设备移除事件。具体的函数,此处不再展开,要了解详细内容可以阅读源码。
回过头来继续看com_android_server_UsbHostManager.cpp
,当有USB设备插入时,usb_device_added
函数被回调,该函数又会回调Java层的UsbHostManager类的usbDeviceAdded
函数;USB设备拔出时,usb_device_removed
函数会被回调,该函数会回调Java层的UsbHostManager类的usbDeviceRemoved
函数。
USB设备插入处理
当有USB设备插入时,UsbHostManager的usbDeviceAdded
会被回调。该函数用来处理USB设备插入事件,函数具体内容如下:
private boolean usbDeviceAdded(String deviceAddress, int deviceClass, int deviceSubclass,
byte[] descriptors) {
if (DEBUG) {
Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
}
if (isBlackListed(deviceAddress)) {
if (DEBUG) {
Slog.d(TAG, "device address is black listed");
}
return false;
}
UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
logUsbDevice(parser);
if (isBlackListed(deviceClass, deviceSubclass)) {
if (DEBUG) {
Slog.d(TAG, "device class is black listed");
}
return false;
}
synchronized (mLock) {
if (mDevices.get(deviceAddress) != null) {
Slog.w(TAG, "device already on mDevices list: " + deviceAddress);
//TODO If this is the same peripheral as is being connected, replace
// it with the new connection.
return false;
}
UsbDevice newDevice = parser.toAndroidUsbDevice();
if (newDevice == null) {
Slog.e(TAG, "Couldn't create UsbDevice object.");
// Tracking
addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE,
parser.getRawDescriptors());
} else {
mDevices.put(deviceAddress, newDevice);
Slog.d(TAG, "Added device " + newDevice);
// 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);
}
mUsbAlsaManager.usbDeviceAdded(deviceAddress, newDevice, parser);
// Tracking
addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
parser.getRawDescriptors());
}
}
if (DEBUG) {
Slog.d(TAG, "beginUsbDeviceAdded(" + deviceAddress + ") end");
}
return true;
}
下面一步步来进行分析:
- 其中,
isBlackListed
函数判断该设备是否已加入黑名单,如果已经在黑名单则直接返回。 - 接下来会为设备创建
UsbDescriptorParser
,logUsbDevice
用来输出设备相关的log信息。 - 再次调用
isBlackListed
来判断是不是已经加入黑名单,这次传入的是deviceClass
和deviceSubclass
。 - 在当前设备map
mDevices
查找是否已经有这个设备,如果已经有了这个设备,那么就会直接返回。 - 通过
UsbDescriptorParser
将设备转换为UsbDevice
,如果转换失败,调用addConnectionRecord
将设备插入事件添加到ConnectionRecord
记录列表。 - 如果
UsbDevice
不为空,者加入到设备mapmDevices
。 - 通过
getUsbDeviceConnectionHandler
函数获取UsbDeviceConnectionHandler
获取到的是一个ComponentName
对象。 getCurrentUserSettings
函数用来获取当前用户UsbProfileGroupSettingsManager
public void setCurrentUserSettings(UsbProfileGroupSettingsManager settings) { synchronized (mSettingsLock) { mCurrentSettings = settings; } } private UsbProfileGroupSettingsManager getCurrentUserSettings() { synchronized (mSettingsLock) { return mCurrentSettings; } }
该配置信息是在UsbService
的onSwitchUser
函数中调用UsbHostManager
的setCurrentUserSettings
来设置的,用户配置信息变化时,该配置也会做现有的更新。
private void onSwitchUser(@UserIdInt int newUserId) {
synchronized (mLock) {
mCurrentUserId = newUserId;
UsbProfileGroupSettingsManager settings =
mSettingsManager.getSettingsForProfileGroup(UserHandle.of(newUserId));
if (mHostManager != null) {
mHostManager.setCurrentUserSettings(settings);
}
if (mDeviceManager != null) {
mDeviceManager.setCurrentUser(newUserId, settings);
}
}
}
getUsbDeviceConnectionHandler
返回null
会调用UsbProfileGroupSettingsManager
的deviceAttached
函数,否则调用deviceAttachedForFixedHandler
函数。UsbProfileGroupSettingsManager
的deviceAttached
函数中会发送广播来通知设备Attached。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 */); }
对应的Attached广播为:`UsbManager.ACTION_USB_DEVICE_ATTACHED`。广播具体定如下:
public static final String ACTION_USB_DEVICE_ATTACHED =
"android.hardware.usb.action.USB_DEVICE_ATTACHED";
`resolveActivity`函数则是选择使用哪个Activity来处理该USB设备插入事件,具体的此处不再分析。
mUsbAlsaManager
的usbDeviceAdded
函数,处理USB音频设备的插入事件。- 调用
addConnectionRecord
将设备插入事件添加到ConnectionRecord
记录列表。
USB设备移除处理
当有USB设备移除时,UsbHostManager的usbDeviceRemoved
会被回调。该函数用来处理USB设备移除事件,函数具体内容如下:
private void usbDeviceRemoved(String deviceAddress) {
synchronized (mLock) {
UsbDevice device = mDevices.remove(deviceAddress);
if (device != null) {
Slog.d(TAG, "Removed device at " + deviceAddress + ": " + device.getProductName());
mUsbAlsaManager.usbDeviceRemoved(deviceAddress/*device*/);
mSettingsManager.usbDeviceRemoved(device);
getCurrentUserSettings().usbDeviceRemoved(device);
// Tracking
addConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null);
} else {
Slog.d(TAG, "Removed device at " + deviceAddress + " was already gone");
}
}
}
移除设备时,处理相对简单:
- 将设备从当前设备map
mDevices
中移除。 - 调用
mUsbAlsaManager.usbDeviceRemoved
处理USB音频设备移除事件。 调用
mSettingsManager.usbDeviceRemoved
处理USB设备移除事件,该函数会以广播的形式来通知USB设备DETACHED事件。void usbDeviceRemoved(@NonNull UsbDevice device) { synchronized (mSettingsByUser) { for (int i = 0; i < mSettingsByUser.size(); i++) { // clear temporary permissions for the device mSettingsByUser.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); }
调用
UsbProfileGroupSettingsManager
的usbDeviceRemoved
函数,该函数很简单,只是音频相关的Notification。void usbDeviceRemoved(@NonNull UsbDevice device) { mMtpNotificationManager.hideNotification(device.getDeviceId()); }
- 调用
addConnectionRecord
将设备插入事件添加到ConnectionRecord
记录列表。