大概意思就是UsbHostManager启动监控线程,monitorUsbHostBus会调用usb_host_run函数(使用inotify来监听USB设备的插拔)不停的读取bus总线,读取到以后,当
1、设备插入:发送 广播ACTION_USB_DEVICE_ATTACHED
2、设备拔出: 发送广播ACTION_USB_DEVICE_DETACHED
本篇只分析插入广播的发送,拔出广播类似,读者可自行分析。
UsbHostManager是在UsbService中新建的。
public UsbService(Context context) {
mContext = context;
mAlsaManager = new UsbAlsaManager(context);
final PackageManager pm = mContext.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
mHostManager = new UsbHostManager(context, mAlsaManager);
}
..........
然后在UsbService的systemReady中调用了UsbHostManager的systemReady函数。
public void systemReady() {
mAlsaManager.systemReady();
if (mDeviceManager != null) {
mDeviceManager.systemReady();
}
if (mHostManager != null) {
mHostManager.systemReady();
}
if (mPortManager != null) {
mPortManager.systemReady();
}
}
UsbHostManager的构造函数就是新建一些对象,我们直接看其systemReady函数。这个函数在新的线程中调用了monitorUsbHostBus函数。
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();
}
}
这里重点看monitorUsbHostBus,monitorUsbHostBus函数是一个JNI函数。
private native void monitorUsbHostBus();
monitorUsbHostBus对应的JNI函数是在com_android_server_UsbHostManager.cpp的android_server_UsbHostManager_monitorUsbHostBus函数,
static const JNINativeMethod method_table[] = {
{ "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus },
{ "nativeOpenDevice", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
(void*)android_server_UsbHostManager_openDevice },
};
在这个函数调用了usb_host_init函数,创建了一个INotify的fd,以及创建了一个usb_host_context对象。usb_host_run函数就是循环读取INotify的fd的事件,我们把usb_device_added, usb_device_removed两个回调函数也传入了usb_host_run函数了。
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);
}
关于inotify机制相关的东西,这里简单介绍一下。
Inotify 是一个 Linux 内核特性,它监控文件系统,并且及时向专门的应用程序发出相关的事件警告,比如删除、读、写和卸载操作等。还可以跟踪活动的源头和目标等细节。使用 inotify 很简单:创建一个文件描述符,附加一个或多个监视器(一个监视器是一个路径和一组事件),然后使用 read() 方法从描述符获取事件信息。read() 并不会用光整个周期,它在事件发生之前是被阻塞的。更好的是,因为 inotify 通过传统的文件描述符工作,可以利用传统的 select() 系统调用来被动地监控监视器和许多其他输入源。两种方法 — 阻塞文件描述符和使用 select() 都避免了繁忙轮询。
usb_host_run()进来之后直接就调用了usb_host_load函数,同时将两个函数指针传了进去(discovery_done_cb为NULL),我们接着看usb_host_load函数,也是在usbhost.c中,如下:
190 int usb_host_load(struct usb_host_context *context,
191 usb_device_added_cb added_cb,
192 usb_device_removed_cb removed_cb,
193 usb_discovery_done_cb discovery_done_cb,
194 void *client_data)
195 {
196 int done = 0;
197 int i;
198
199 context->cb_added = added_cb;
200 context->cb_removed = removed_cb;
201 context->data = client_data;
202
203 D("Created device discovery thread\n");
204
205 /* watch for files added and deleted within USB_FS_DIR */
206 context->wddbus = -1;
207 for (i = 0; i < MAX_USBFS_WD_COUNT; i++)
208 context->wds[i] = -1;
209 /* 查看根目录是否有新的子目录 #define DEV_DIR "/dev" */
210 /* watch the root for new subdirectories */
211 context->wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);
212 if (context->wdd < 0) {
213 fprintf(stderr, "inotify_add_watch failed\n");
214 if (discovery_done_cb)
215 discovery_done_cb(client_data);
216 return done;
217 }
218
219 watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
220
221 /* check for existing devices first, after we have inotify set up */
222 done = find_existing_devices(added_cb, client_data);
223 if (discovery_done_cb)
224 done |= discovery_done_cb(client_data);
225
226 return done;
227 } /* usb_host_load() */
在usb_host_load中,首先将两个函数指针赋值给struct usb_host_context中的成员变量,client_data是在JNI中传入的thiz指针,discovery_done_cb传入的值为NULL。
接着是inotify_add_watch函数,这里添加了一个目录watch("/dev"),其事件掩码设置为IN_CREATE | IN_DELETE(即观察创建和删除事件),并将这个watch的描述符储存在usb_host_context的成员变量wdd中。后面紧接着就调用watch_existing_subdirs函数,该函数也在usbhost.c中,如下所示:
144 static void watch_existing_subdirs(struct usb_host_context *context,
145 int *wds, int wd_count)
146 {
147 char path[100];
148 int i, ret;
149 //#define USB_FS_DIR "/dev/bus/usb"
150 wds[0] = inotify_add_watch(context->fd, USB_FS_DIR, IN_CREATE | IN_DELETE);
151 if (wds[0] < 0)
152 return;
153 /* 查看USB_FS_DIR的现有子目录 #define USB_FS_DIR "/dev/bus/usb" */
154 /* watch existing subdirectories of USB_FS_DIR */
155 for (i = 1; i < wd_count; i++) {
156 snprintf(path, sizeof(path), USB_FS_DIR "/%03d", i);
157 ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
158 if (ret >= 0)
159 wds[i] = ret;
160 }
161 }
wds是usb_host_context中的一个int数组,其长度为MAX_USBFS_WD_COUNT。这里又添加了一个目录watch("/dev/usb"),其事件掩码也设置为IN_CREATE | IN_DELETE,然后将watch描述符储存在wds[0]的位置。紧接着就是一个for循环,该for循环将"/dev/bus/usb"目录下的设备目录(从001开始到MAX_USBFS_WD_COUNT),都添加到inotify中去,作为目录watch进行观察,然后各个watch描述符依次存放在wds数组剩余的位置中。
watch_existing_subdirs函数返回之后,在usb_host_load函数中接着又调用了find_existing_devices函数。(usbhost.c)如下所示:
120 /* returns true if one of the callbacks indicates we are done */
121 static int find_existing_devices(usb_device_added_cb added_cb,
122 void *client_data)
123 {
124 char busname[32];
125 DIR *busdir;
126 struct dirent *de;
127 int done = 0;
128
//#define USB_FS_DIR "/dev/bus/usb"
129 busdir = opendir(USB_FS_DIR);
130 if(busdir == 0) return 0;
131
132 while ((de = readdir(busdir)) != 0 && !done) {
133 if(badname(de->d_name)) continue;
134
135 snprintf(busname, sizeof(busname), USB_FS_DIR "/%s", de->d_name);
136 done = find_existing_devices_bus(busname, added_cb,
137 client_data);
138 } //end of busdir while
139 closedir(busdir);
140
141 return done;
142 }
该函数首先打开"/dev/bus/usb"目录,然后对该目录下的目录调用find_existing_devices_bus函数(usbhost.c),如下:
97 static int find_existing_devices_bus(char *busname,
98 usb_device_added_cb added_cb,
99 void *client_data)
100 {
101 char devname[32];
102 DIR *devdir;
103 struct dirent *de;
104 int done = 0;
105
106 devdir = opendir(busname);
107 if(devdir == 0) return 0;
108
109 while ((de = readdir(devdir)) && !done) {
110 if(badname(de->d_name)) continue;
111
112 snprintf(devname, sizeof(devname), "%s/%s", busname, de->d_name);
113 done = added_cb(devname, client_data);
114 } // end of devdir while
115 closedir(devdir);
116
117 return done;
118 }
该函数会打开之前传入的目录,例如:"/dev/bus/usb/001",然后会遍历该目录下的所有文件,将文件名和之前的目录路径组合到一起就可以得到准确的文件位置,这个文件就代表了一个USB设备,该USB设备是在UsbHostManager运行之前就挂载好了的,所以此时上层还不知道该USB设备的存在,所以需要对该USB设备向上层做补充的通知,即通过added_cb函数指针调用usb_device_added函数。
这里我们还是先不分析usb_device_added函数,只需要知道find_existing_devices函数的作用是,将"/dev/bus/usb"子目录下,在UsbHostManager运行之前就挂载好了的USB设备向上做补充的通知,让上层感知到这些USB设备的存在。
这样usb_host_load函数就返回了,该函数返回之后,usb_host_run会进入一个while循环去执行usb_host_read_event函数(usbhost.c),usb_host_read_event函数非常的长如下:
229 int usb_host_read_event(struct usb_host_context *context)
230 {
231 struct inotify_event* event;
232 char event_buf[512];
233 char path[100];
234 int i, ret, done = 0;
235 int offset = 0;
236 int wd;
237
238 ret = read(context->fd, event_buf, sizeof(event_buf));
239 if (ret >= (int)sizeof(struct inotify_event)) {
240 while (offset < ret && !done) {
241 event = (struct inotify_event*)&event_buf[offset];
242 done = 0;
243 wd = event->wd;
244 if (wd == context->wdd) {
245 if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {
246 context->wddbus = inotify_add_watch(context->fd, DEV_BUS_DIR, IN_CREATE | IN_DELETE);
247 if (context->wddbus < 0) {
248 done = 1;
249 } else {
250 watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
251 done = find_existing_devices(context->cb_added, context->data);
252 }
253 }
254 } else if (wd == context->wddbus) {
255 if ((event->mask & IN_CREATE) && !strcmp(event->name, "usb")) {
256 watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
257 done = find_existing_devices(context->cb_added, context->data);
258 } else if ((event->mask & IN_DELETE) && !strcmp(event->name, "usb")) {
259 for (i = 0; i < MAX_USBFS_WD_COUNT; i++) {
260 if (context->wds[i] >= 0) {
261 inotify_rm_watch(context->fd, context->wds[i]);
262 context->wds[i] = -1;
263 }
264 }
265 }
266 } else if (wd == context->wds[0]) {
267 i = atoi(event->name);
268 snprintf(path, sizeof(path), USB_FS_DIR "/%s", event->name);
269 D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
270 "new" : "gone", path, i);
271 if (i > 0 && i < MAX_USBFS_WD_COUNT) {
272 int local_ret = 0;
273 if (event->mask & IN_CREATE) {
274 local_ret = inotify_add_watch(context->fd, path,
275 IN_CREATE | IN_DELETE);
276 if (local_ret >= 0)
277 context->wds[i] = local_ret;
278 done = find_existing_devices_bus(path, context->cb_added,
279 context->data);
280 } else if (event->mask & IN_DELETE) {
281 inotify_rm_watch(context->fd, context->wds[i]);
282 context->wds[i] = -1;
283 }
284 }
285 } else {
286 for (i = 1; (i < MAX_USBFS_WD_COUNT) && !done; i++) {
287 if (wd == context->wds[i]) {
288 snprintf(path, sizeof(path), USB_FS_DIR "/%03d/%s", i, event->name);
289 if (event->mask == IN_CREATE) {
290 D("new device %s\n", path);
291 done = context->cb_added(path, context->data);
292 } else if (event->mask == IN_DELETE) {
293 D("gone device %s\n", path);
294 done = context->cb_removed(path, context->data);
295 }
296 }
297 }
298 }
299
300 offset += sizeof(struct inotify_event) + event->len;
301 }
302 }
303
304 return done;
305 } /* usb_host_read_event() */
大致就是使用read调用去读取context->fd中的数据,这个fd就是一开始创建的inotify的fd,可以对这个fd做select、poll()等操作。read读到的数据可以转换为struct inotify_event类型的结构体,通过这个结构体中的一些字段来走不同的分支,这里先关注最后一个分支,即是wds数组中,索引0之外的watch描述符发生了变化就会走该分支,根据mask来判断是发生了IN_CREATE事件还是IN_DELETE事件,前者调用usb_device_added函数,后者调用usb_device_removed函数。
当mask为IN_CREATE会调用该回调函数(frameworks/base/services/core/jni/com_android_server_UsbHostManager.cpp)。
56 static int usb_device_added(const char *devAddress, void* clientData) {
57 struct usb_device *device = usb_device_open(devAddress);
58 if (!device) {
59 ALOGE("usb_device_open failed\n");
60 return 0;
61 }
62
63 const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device);
64 int classID = deviceDesc->bDeviceClass;
65 int subClassID = deviceDesc->bDeviceSubClass;
66
67 // get the raw descriptors
68 int numBytes = usb_device_get_descriptors_length(device);
69 if (numBytes > 0) {
70 JNIEnv* env = AndroidRuntime::getJNIEnv();
71 jobject thiz = (jobject)clientData;
72 jstring deviceAddress = env->NewStringUTF(devAddress);
73
74 jbyteArray descriptorsArray = env->NewByteArray(numBytes);
75 const jbyte* rawDescriptors = (const jbyte*)usb_device_get_raw_descriptors(device);
76 env->SetByteArrayRegion(descriptorsArray, 0, numBytes, rawDescriptors);
77
78 env->CallBooleanMethod(thiz, method_usbDeviceAdded,
79 deviceAddress, classID, subClassID, descriptorsArray);
80
81 env->DeleteLocalRef(descriptorsArray);
82 env->DeleteLocalRef(deviceAddress);
83
84 checkAndClearExceptionFromCallback(env, __FUNCTION__);
85 } else {
86 // TODO return an error code here?
87 ALOGE("error reading descriptors\n");
88 }
89
90 usb_device_close(device);
91
92 return 0;
93 }
参数devAddress为发生变化的文件的路径,clientData为android_server_UsbHostManager_monitorUsbHostBus时设置的jobject thiz指针。该函数通过JNI调用UsbHostManager.java中的usbDeviceAdded方法:
343 private boolean usbDeviceAdded(String deviceAddress, int deviceClass, int deviceSubclass,
344 byte[] descriptors) {
345 if (DEBUG) {
346 Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
347 }
348
349 if (isBlackListed(deviceAddress)) {
350 if (DEBUG) {
351 Slog.d(TAG, "device address is black listed");
352 }
353 return false;
354 }
355 UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
356 logUsbDevice(parser);
357
358 if (isBlackListed(deviceClass, deviceSubclass)) {
359 if (DEBUG) {
360 Slog.d(TAG, "device class is black listed");
361 }
362 return false;
363 }
364
365 synchronized (mLock) {
366 if (mDevices.get(deviceAddress) != null) {
367 Slog.w(TAG, "device already on mDevices list: " + deviceAddress);
368 //TODO If this is the same peripheral as is being connected, replace
369 // it with the new connection.
370 return false;
371 }
372
373 UsbDevice newDevice = parser.toAndroidUsbDevice();
374 if (newDevice == null) {
375 Slog.e(TAG, "Couldn't create UsbDevice object.");
376 // Tracking
377 addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE,
378 parser.getRawDescriptors());
379 } else {
380 mDevices.put(deviceAddress, newDevice);
381 Slog.d(TAG, "Added device " + newDevice);
382
383 // It is fine to call this only for the current user as all broadcasts are
384 // sent to all profiles of the user and the dialogs should only show once.
385 ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
386 if (usbDeviceConnectionHandler == null) {
387 getCurrentUserSettings().deviceAttached(newDevice);
388 } else {
389 getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
390 usbDeviceConnectionHandler);
391 }
392
393 mUsbAlsaManager.usbDeviceAdded(deviceAddress, newDevice, parser);
394
395 // Tracking
396 addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
397 parser.getRawDescriptors());
398 }
399 }
400
401 if (DEBUG) {
402 Slog.d(TAG, "beginUsbDeviceAdded(" + deviceAddress + ") end");
403 }
404
405 return true;
406 }
在UsbDeviceAdded方法中可以看到Slog.d(TAG, "Added device " + newDevice); 可以看到实际log输出如下:
UsbHostManager: Added device UsbDevice[mName=/dev/bus/usb/001/002,mVendorId=1121,
mProductId=20052,mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=PixArt,
mProductName=Tiger USB Optical Mouse,mVersion=1.00,mSerialNumber=null,mConfigurations=[
继续执行 getCurrentUserSettings().deviceAttached(newDevice);
getCurrentUserSettings返回的是UsbProfileGroupSettingsManager的一个对象,对应文件是
frameworks\base\services\usb\java\com\android\server\usb\UsbProfileGroupSettingsManager.java
655 public void deviceAttached(UsbDevice device) {
656 final Intent intent = createDeviceAttachedIntent(device);
657
658 // Send broadcast to running activities with registered intent
659 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
660
661 resolveActivity(intent, device, true /* showMtpNotification */);
662 }
首先看createDeviceAttachedIntent函数
1165 private static Intent createDeviceAttachedIntent(UsbDevice device) {
1166 Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
1167 intent.putExtra(UsbManager.EXTRA_DEVICE, device);
1168 intent.addFlags(
1169 Intent.FLAG_ACTIVITY_NEW_TASK |
1170 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1171 return intent;
1172 }
1173 }
至此已经很明显了,createDeviceAttachedIntent创建了UsbManager.ACTION_USB_DEVICE_ATTACHED的Intent,后面再去sendBroadcastAsUser取发出广播,app就可以接收到广播去做相应的逻辑处理即可!