/* USB管理 */
frameworks/base/services/usb/java/com/android/server/usb/UsbSettingsManager.java
在 Android 系统中是用 广播的方式来通知系统, USB 麦克风的热插拔。
Linux 内核的设备热插拔:
-
Linux 采用一种特殊类的的文件描述符(套结字)专门用于Linux内核跟用户空间之间的异步通信,这种技术通常被成为NETLINK。
- Uevent是一种在内核空间和用户空间之间通信的机制,主要用于热插拔事件(hotplug)
如 kobject 中检测的设备的几种状态:
// include/linux/kobject.h
enum kobject_action
{
KOBJ_ADD,
KOBJ_REMOVE,
KOBJ_CHANGE,
KOBJ_MOVE,
KOBJ_ONLINE,
KOBJ_OFFLINE,
KOBJ_MAX
};
这些动作对应的事件相应有以下几种:
// include/linux/kobject.h
static const char *kobject_actions[] =
{
[KOBJ_ADD] = "add",
[KOBJ_REMOVE] = "remove",
[KOBJ_CHANGE] = "change",
[KOBJ_MOVE] = "move",
[KOBJ_ONLINE] = "online",
};
linux 内核通过 add remove move 等动作来完成热插拔动的检测和事件上报。
Android 是 Linux 的事件机制上加入了 intent (广播)。
下面来分析Android usb 麦克风热插拔的 intent 广播:
usb 麦克风插入/拔出的事件:
- UsbManager.ACTION_USB_DEVICE_ATTACHED - 插入广播
- UsbManager.ACTION_USB_DEVICE_DETACHED - 拔出广播
在 APP 中检查系统中的 UsbManager 的广播来判断 usb 麦克风是否插入或拔出。
usb麦克风插入,UsbManager调用:
从函数名上推测 deviceAttached 是检测设备插入, deviceAttached 调用 createDeviceAttachedIntent , 发出usb设备插入的广播 - UsbManager.ACTION_USB_DEVICE_ATTACHED 。
// frameworks/base/services/usb/java/com/android/server/usb/UsbSettingsManager.java
public void deviceAttached(UsbDevice device)
{
final Intent intent = createDeviceAttachedIntent(device);
// Send broadcast to running activity with registered intent
mUserContext.sendBroadcast(intent);
if(MtpNotificationManager.shouldShowNotification(mPackageManager, device))
{
// Show notification if the device is MTP storage.
mMtpNotificationManager.showNotification(device);
}
else
{
resolveActivity(intent, device);
}
}
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);
return intent;
}
同理usb麦克风拔出,UsbManager调用: deviceDetached 发出usb设备拔出的广播 - UsbManager.ACTION_USB_DEVICE_DETACHED 。
// frameworks/base/services/usb/java/com/android/server/usb/UsbSettingsManager.java
public void deviceDetached(UsbDevice device)
{
// clear temporary permissions for the device
mDevicePermissionMap.remove(device.getDeviceName());
Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
if(DEBUG) Slog.d(TAG, "usbDeviceRemoved, sending " + intent);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
mMtpNotificationManager.hideNotification(device.getDeviceId());
}
APP 中添加接收处理 usb 设备的类,打印 usb 麦克风插入/拔出状态。
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbManager;
import android.util.Log;
/**
* Created by huangsj on 2019/1/7.
*/
public class UsbReceiver extends BroadcastReceiver {
private static final String TAG = "UsbReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive: "+intent.getAction());
switch (intent.getAction()) {
case UsbManager.ACTION_USB_DEVICE_DETACHED: {
Log.d(TAG, "onReceive: ACTION_USB_DEVICE_DETACHED");
break;
}
case UsbManager.ACTION_USB_DEVICE_ATTACHED: {
Log.d(TAG, "onReceive: ACTION_USB_DEVICE_ATTACHED");
break;
}
default:
break;
}
}
}
通过 intent.getAction() 接收广播,并判断是否是 usb 麦克风的广播。