/* 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 麥克風的廣播。