Android 6.0 usb解析(二)UsbHostManager

    xiaoxiao2021-03-25  89

    之前在Android5.1的时候我们分析过UsbDevicemanager,现在Android6.0我们不准备分析UsbDevicemanager了,因为大致原理差不多。而UsbDeviceManager是将手机作为一个设备,比如手机连上电脑,使用adb、mtp等。而这里准备分析的UsbHostManager,是将手机作为一个host,比如手机连接usb鼠标、usb摄像头等。

    UsbHostManager的初始化

    UsbHostManager和UsbDeviceManager一样都是在UsbService中新建的。

    [cpp] view plain copy 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函数。

    [cpp] view plain copy public void systemReady() {      mAlsaManager.systemReady();        if (mDeviceManager != null) {          mDeviceManager.systemReady();      }      if (mHostManager != null) {          mHostManager.systemReady();      }      if (mPortManager != null) {          mPortManager.systemReady();      }  }   UsbHostManager的构造函数就是新建一些对象,我们直接看systemReady函数。这个函数在新的线程中调用了monitorUsbHostBus函数。 [cpp] view plain copy 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 = new Runnable() {              public void run() {                  monitorUsbHostBus();              }          };          new Thread(null, runnable, "UsbService host thread").start();      }  }  

    而monitorUsbHostBus函数是一个JNI函数。

    [cpp] view plain copy private native void monitorUsbHostBus();  

    UsbHostManager的hal层

    monitorUsbHostBus对应的JNI函数是在com_android_server_UsbHostManager.cpp的android_server_UsbHostManager_monitorUsbHostBus函数,在这个函数调用了usb_host_init函数,创建了一个INotify的fd,以及创建了一个usb_host_context对象。usb_host_run函数就是循环读取INotify的fd的事件,我们把usb_device_added, usb_device_removed两个回调函数也传入了usb_host_run函数了。

    [cpp] view plain copy 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是在system\core\libusbhost\usbhost.c文件中,这个函数中新建一个usb_host_context对象,还有新建了一个INotify,并且usb_host_context的fd就是INotify的fd。

    [cpp] view plain copy struct usb_host_context *usb_host_init()  {      struct usb_host_context *context = calloc(1, sizeof(struct usb_host_context));//新建一个usb_host_context对象      if (!context) {          fprintf(stderr, "out of memory in usb_host_context\n");          return NULL;      }      context->fd = inotify_init();//新建一个INotify      if (context->fd < 0) {          fprintf(stderr, "inotify_init failed\n");          free(context);          return NULL;      }      return context;  }   我们再来看看usb_host_run函数。先调用了usb_host_load函数,这个函数主要把add和remove的回调,放到context相应的成员变量中,然后增加了dev目录放入INotify的观察。下面循环调用usb_host_read_event函数去读取INotify fd的事件。 [cpp] view plain copy 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函数先把add和remove的两个回调设置到usb_host_context 中,然后将dev目录放入INotify观察。然后调用watch_existing_subdirs将/dev/bus/usb下的目录都添加到INotify中观察,最后再调用find_existing_devices函数,把找到的设备调用added_cb(增加的回调函数) [cpp] view plain copy int usb_host_load(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 = 0;      int i;        context->cb_added = added_cb;//回调赋值      context->cb_removed = removed_cb;      context->data = client_data;        D("Created device discovery thread\n");        /* watch for files added and deleted within USB_FS_DIR */      context->wddbus = -1;      for (i = 0; i < MAX_USBFS_WD_COUNT; i++)          context->wds[i] = -1;        /* watch the root for new subdirectories */      context->wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);//将dev目录放入INotify观察      if (context->wdd < 0) {          fprintf(stderr, "inotify_add_watch failed\n");          if (discovery_done_cb)              discovery_done_cb(client_data);          return done;      }        watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);        /* check for existing devices first, after we have inotify set up */      done = find_existing_devices(added_cb, client_data);      if (discovery_done_cb)          done |= discovery_done_cb(client_data);        return done;  }    watch_existing_subdirs,就是将/dev/bus/usb下的设备目录(001开始到MAX_USBFS_WD_COUNT值都inotify_add_watch)都添加到INotify中去。 [cpp] view plain copy static void watch_existing_subdirs(struct usb_host_context *context,                                     int *wds, int wd_count)  {      char path[100];      int i, ret;        wds[0] = inotify_add_watch(context->fd, USB_FS_DIR, IN_CREATE | IN_DELETE);      if (wds[0] < 0)          return;        /* watch existing subdirectories of USB_FS_DIR */      for (i = 1; i < wd_count; i++) {          snprintf(path, sizeof(path), USB_FS_DIR "/d", i);          ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);          if (ret >= 0)              wds[i] = ret;      }  }   然后我们再来看find_existing_devices函数,就是遍历dev/bus/usb的目录然后再调用find_existing_devices_bus函数 [cpp] view plain copy static int find_existing_devices(usb_device_added_cb added_cb,                                    void *client_data)  {      char busname[32];      DIR *busdir;      struct dirent *de;      int done = 0;        busdir = opendir(USB_FS_DIR);      if(busdir == 0) return 0;        while ((de = readdir(busdir)) != 0 && !done) {          if(badname(de->d_name)) continue;            snprintf(busname, sizeof(busname), USB_FS_DIR "/%s", de->d_name);          done = find_existing_devices_bus(busname, added_cb,                                           client_data);      } //end of busdir while      closedir(busdir);        return done;  }   find_existing_devices_bus函数,就是将dev/bus/usb下的目录比如001,然后001目录里面的文件,作为一个设备(组成一个devname),再调用added_cb(增加设备的回调函数) [cpp] view plain copy static int find_existing_devices_bus(char *busname,                                       usb_device_added_cb added_cb,                                       void *client_data)  {      char devname[32];      DIR *devdir;      struct dirent *de;      int done = 0;        devdir = opendir(busname);      if(devdir == 0) return 0;        while ((de = readdir(devdir)) && !done) {          if(badname(de->d_name)) continue;            snprintf(devname, sizeof(devname), "%s/%s", busname, de->d_name);          done = added_cb(devname, client_data);      } // end of devdir while      closedir(devdir);        return done;  }   因此总结下usb_host_load函数就是把增加、去除设备的回调赋值到usb_host_context 的相关变量中,然后增加相关目录的观察,最后查找已经存在的设备调用added_cb(增加设备的回调函数)。

    然后我们再来看看usb_host_read_event函数,这个函数就是去INotify中的fd读取相关的事件。具体分析我们就看注释,有一点我们要注意了,除了增加bus目录失败返回的done是1,其他的返回的done都是0.也就是我们的usb_host_run函数会在while循环中一直循环。

    [cpp] view plain copy int usb_host_read_event(struct usb_host_context *context)  {      struct inotify_event* event;      char event_buf[512];      char path[100];      int i, ret, done = 0;      int offset = 0;      int wd;        ret = read(context->fd, event_buf, sizeof(event_buf));      if (ret >= (int)sizeof(struct inotify_event)) {          while (offset < ret && !done) {              event = (struct inotify_event*)&event_buf[offset];              done = 0;              wd = event->wd;              if (wd == context->wdd) {                  if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {//增加bus目录,并且将bus目录也增加到watch中                      context->wddbus = inotify_add_watch(context->fd, DEV_BUS_DIR, IN_CREATE | IN_DELETE);                      if (context->wddbus < 0) {                          done = 1;//增加bus目录失败                      } else {                          watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);                          done = find_existing_devices(context->cb_added, context->data);                      }                  }              } else if (wd == context->wddbus) {                  if ((event->mask & IN_CREATE) && !strcmp(event->name, "usb")) {//如果是dev/bus目录的事件                      watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);//将dev/bus/usb目录再增加到watch                      done = find_existing_devices(context->cb_added, context->data);//然后再看看usb下面时候有设备,有就调用添加函数                  } else if ((event->mask & IN_DELETE) && !strcmp(event->name, "usb")) {                      for (i = 0; i < MAX_USBFS_WD_COUNT; i++) {                          if (context->wds[i] >= 0) {                              inotify_rm_watch(context->fd, context->wds[i]);//是删除事件,就把这个watch删除了                              context->wds[i] = -1;                          }                      }                  }              } else if (wd == context->wds[0]) {//是第一个wds,也就是dev/bus/usb目录的事件                  i = atoi(event->name);                  snprintf(path, sizeof(path), USB_FS_DIR "/%s", event->name);                  D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?                          "new" : "gone", path, i);                  if (i > 0 && i < MAX_USBFS_WD_COUNT) {                      int local_ret = 0;                      if (event->mask & IN_CREATE) {                          local_ret = inotify_add_watch(context->fd, path,//我们需要把usb下新增的目录也增加到watch中                                  IN_CREATE | IN_DELETE);                          if (local_ret >= 0)                              context->wds[i] = local_ret;                          done = find_existing_devices_bus(path, context->cb_added,//然后再看看是否有已经存在的设备                                  context->data);                      } else if (event->mask & IN_DELETE) {                          inotify_rm_watch(context->fd, context->wds[i]);                          context->wds[i] = -1;                      }                  }              } else {                  for (i = 1; (i < MAX_USBFS_WD_COUNT) && !done; i++) {//最后剩下的肯定是dev/bus/usb下目录的事件                      if (wd == context->wds[i]) {                          snprintf(path, sizeof(path), USB_FS_DIR "/d/%s", i, event->name);                          if (event->mask == IN_CREATE) {//这里就直接调用增加设备或者删除设备的回调函数。                              D("new device %s\n", path);                              done = context->cb_added(path, context->data);                          } else if (event->mask == IN_DELETE) {                              D("gone device %s\n", path);                              done = context->cb_removed(path, context->data);                          }                      }                  }              }                offset += sizeof(struct inotify_event) + event->len;//读取的字节数增加          }      }        return done;  }   

    usb_device_added函数会调用UsbHostManager的beginUsbDeviceAdded和endUsbDeviceAdded函数,在UsbHostManager中会新建一个UsbDevice,然后放入mDevices中。

    [cpp] view plain copy static int usb_device_added(const char *devname, void* client_data) {      struct usb_descriptor_header* desc;      struct usb_descriptor_iter iter;        struct usb_device *device = usb_device_open(devname);      if (!device) {          ALOGE("usb_device_open failed\n");          return 0;      }        JNIEnv* env = AndroidRuntime::getJNIEnv();      jobject thiz = (jobject)client_data;      const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device);        char *manufacturer = usb_device_get_manufacturer_name(device);      char *product = usb_device_get_product_name(device);      int version = usb_device_get_version(device);      char *serial = usb_device_get_serial(device);        jstring deviceName = env->NewStringUTF(devname);      jstring manufacturerName = AndroidRuntime::NewStringLatin1(env, manufacturer);      jstring productName = AndroidRuntime::NewStringLatin1(env, product);      jstring serialNumber = AndroidRuntime::NewStringLatin1(env, serial);        jboolean result = env->CallBooleanMethod(thiz, method_beginUsbDeviceAdded,              deviceName, usb_device_get_vendor_id(device), usb_device_get_product_id(device),              deviceDesc->bDeviceClass, deviceDesc->bDeviceSubClass, deviceDesc->bDeviceProtocol,              manufacturerName, productName, version, serialNumber);        env->DeleteLocalRef(serialNumber);      env->DeleteLocalRef(productName);      env->DeleteLocalRef(manufacturerName);      env->DeleteLocalRef(deviceName);      free(manufacturer);      free(product);      free(serial);        if (!result) goto fail;        usb_descriptor_iter_init(device, &iter);        while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {          if (desc->bDescriptorType == USB_DT_CONFIG) {              struct usb_config_descriptor *config = (struct usb_config_descriptor *)desc;              char *name = usb_device_get_string(device, config->iConfiguration);              jstring configName = AndroidRuntime::NewStringLatin1(env, name);                env->CallVoidMethod(thiz, method_addUsbConfiguration,                      config->bConfigurationValue, configName, config->bmAttributes,                      config->bMaxPower);                env->DeleteLocalRef(configName);              free(name);          } else if (desc->bDescriptorType == USB_DT_INTERFACE) {              struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;              char *name = usb_device_get_string(device, interface->iInterface);              jstring interfaceName = AndroidRuntime::NewStringLatin1(env, name);                env->CallVoidMethod(thiz, method_addUsbInterface,                      interface->bInterfaceNumber, interfaceName, interface->bAlternateSetting,                      interface->bInterfaceClass, interface->bInterfaceSubClass,                      interface->bInterfaceProtocol);                env->DeleteLocalRef(interfaceName);              free(name);          } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {              struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)desc;                env->CallVoidMethod(thiz, method_addUsbEndpoint,                      endpoint->bEndpointAddress, endpoint->bmAttributes,                      __le16_to_cpu(endpoint->wMaxPacketSize), endpoint->bInterval);          }      }        env->CallVoidMethod(thiz, method_endUsbDeviceAdded);    fail:      usb_device_close(device);      checkAndClearExceptionFromCallback(env, __FUNCTION__);        return 0;  }  

    去除函数,也会调用UsbHostManager的usbDeviceRemoved函数,注意这个函数返回就是0

    [cpp] view plain copy static int usb_device_removed(const char *devname, void* client_data) {      JNIEnv* env = AndroidRuntime::getJNIEnv();      jobject thiz = (jobject)client_data;        jstring deviceName = env->NewStringUTF(devname);      env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceName);      env->DeleteLocalRef(deviceName);      checkAndClearExceptionFromCallback(env, __FUNCTION__);      return 0;  }  

    UsbHostManager的usbDeviceRemoved函数,会把mDevices相关的设备去除。

    [cpp] view plain copy private void usbDeviceRemoved(String deviceName) {      synchronized (mLock) {          UsbDevice device = mDevices.remove(deviceName);          if (device != null) {              mUsbAlsaManager.usbDeviceRemoved(device);              getCurrentSettings().deviceDetached(device);          }      }  }  

    UsbManager中调用usb设备

    我们来看USBManager中关于获取Usb设备,以及使用它们的函数。getDeviceList可以得到一个设备名,以及对应的UsbDevice。而openDevice会得到一个UsbDeviceConnection对象。

    [cpp] view plain copy public HashMap<String,UsbDevice> getDeviceList() {      Bundle bundle = new Bundle();      try {          mService.getDeviceList(bundle);          HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>();          for (String name : bundle.keySet()) {              result.put(name, (UsbDevice)bundle.get(name));          }          return result;      } catch (RemoteException e) {          Log.e(TAG, "RemoteException in getDeviceList", e);          return null;      }  }    /**  * Opens the device so it can be used to send and receive  * data using {@link android.hardware.usb.UsbRequest}.  *  * @param device the device to open  * @return a {@link UsbDeviceConnection}, or {@code null} if open failed  */  public UsbDeviceConnection openDevice(UsbDevice device) {      try {          String deviceName = device.getDeviceName();          ParcelFileDescriptor pfd = mService.openDevice(deviceName);          if (pfd != null) {              UsbDeviceConnection connection = new UsbDeviceConnection(device);              boolean result = connection.open(deviceName, pfd);              pfd.close();              if (result) {                  return connection;              }          }      } catch (Exception e) {          Log.e(TAG, "exception in UsbManager.openDevice", e);      }      return null;  }  

    UsbHostManager的getDeviceList函数,就是把mDevices中的数据返回,然后是通过Bundle对象来传输的。

    [cpp] view plain copy public void getDeviceList(Bundle devices) {      synchronized (mLock) {          for (String name : mDevices.keySet()) {              devices.putParcelable(name, mDevices.get(name));          }      }  }  

    而当用户进程通过UsbManger获取到设备名后,可以通过openDevice来获取ParcelFileDescriptor ,在UsbManager中又会新建一个UsbDeviceConnection,然后把ParcelFileDescriptor 作为参数调用这个UsbDeviceConnection的open函数。

    [cpp] view plain copy public ParcelFileDescriptor openDevice(String deviceName) {      synchronized (mLock) {          if (isBlackListed(deviceName)) {              throw new SecurityException("USB device is on a restricted bus");          }          UsbDevice device = mDevices.get(deviceName);          if (device == null) {              // if it is not in mDevices, it either does not exist or is blacklisted              throw new IllegalArgumentException(                      "device " + deviceName + " does not exist or is restricted");          }          getCurrentSettings().checkPermission(device);          return nativeOpenDevice(deviceName);      }  }  

    我们来看下UsbHostManager的openDevice函数,最后也是调用了JNI函数nativeOpenDevice

    [cpp] view plain copy public ParcelFileDescriptor openDevice(String deviceName) {      synchronized (mLock) {          if (isBlackListed(deviceName)) {              throw new SecurityException("USB device is on a restricted bus");          }          UsbDevice device = mDevices.get(deviceName);          if (device == null) {              // if it is not in mDevices, it either does not exist or is blacklisted              throw new IllegalArgumentException(                      "device " + deviceName + " does not exist or is restricted");          }          getCurrentSettings().checkPermission(device);          return nativeOpenDevice(deviceName);      }  }  

    android_server_UsbHostManager_openDevice就是对应的JNI函数,这里主要调用了usb_device_open函数,并且返回一个usb_device,最后我们通过usb_device来获取其fd,并且把它封装在Java层ParcelFileDescriptor类中。

    [cpp] view plain copy static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* thiz */,                                                          jstring deviceName)  {      const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);      struct usb_device* device = usb_device_open(deviceNameStr);      env->ReleaseStringUTFChars(deviceName, deviceNameStr);        if (!device)          return NULL;        int fd = usb_device_get_fd(device);      if (fd < 0) {          usb_device_close(device);          return NULL;      }      int newFD = dup(fd);      usb_device_close(device);        jobject fileDescriptor = jniCreateFileDescriptor(env, newFD);      if (fileDescriptor == NULL) {          return NULL;      }      return env->NewObject(gParcelFileDescriptorOffsets.mClass,          gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);  }  

    usb_device_open函数就是打开对应的设备

    [cpp] view plain copy struct usb_device *usb_device_open(const char *dev_name)  {      int fd, did_retry = 0, writeable = 1;        D("usb_device_open %s\n", dev_name);    retry:      fd = open(dev_name, O_RDWR);      if (fd < 0) {          /* if we fail, see if have read-only access */          fd = open(dev_name, O_RDONLY);          D("usb_device_open open returned %d errno %d\n", fd, errno);          if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) {              /* work around race condition between inotify and permissions management */              sleep(1);              did_retry = 1;              goto retry;          }            if (fd < 0)              return NULL;          writeable = 0;          D("[ usb open read-only %s fd = %d]\n", dev_name, fd);      }        struct usb_device* result = usb_device_new(dev_name, fd);      if (result)          result->writeable = writeable;      return result;  }  

    然后我们再来看看UsbManager的openDevice使用的UsbDeviceConnection对象。

    [cpp] view plain copy public UsbDeviceConnection openDevice(UsbDevice device) {      try {          String deviceName = device.getDeviceName();          ParcelFileDescriptor pfd = mService.openDevice(deviceName);          if (pfd != null) {              UsbDeviceConnection connection = new UsbDeviceConnection(device);              boolean result = connection.open(deviceName, pfd);              pfd.close();              if (result) {                  return connection;              }          }      } catch (Exception e) {          Log.e(TAG, "exception in UsbManager.openDevice", e);      }      return null;  }   UsbDeviceConnection的构造函数就是把UsbDevice保存到mDevice,然后调用了native_open函数 [cpp] view plain copy public UsbDeviceConnection(UsbDevice device) {      mDevice = device;  }    /* package */ boolean open(String name, ParcelFileDescriptor pfd) {      return native_open(name, pfd.getFileDescriptor());  }  

    native_open函数是JNI函数,对应函数如下。根据之前打开设备的fd新建了一个usb_device,然后保存在了UsbDeviceConnection的mNativeContext对象中了。

    [cpp] view plain copy static jboolean  android_hardware_UsbDeviceConnection_open(JNIEnv *env, jobject thiz, jstring deviceName,          jobject fileDescriptor)  {      int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);      // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy      fd = dup(fd);      if (fd < 0)          return JNI_FALSE;        const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);      struct usb_device* device = usb_device_new(deviceNameStr, fd);      if (device) {          env->SetLongField(thiz, field_context, (jlong)device);      } else {          ALOGE("usb_device_open failed for %s", deviceNameStr);          close(fd);      }        env->ReleaseStringUTFChars(deviceName, deviceNameStr);      return (device != NULL) ? JNI_TRUE : JNI_FALSE;  }  

    最后用户进程获取的对象就是UsbDeviceConnection,我们可以调用其getFileDescriptor,来获取设备的fd。我们直接看下这个函数

    [cpp] view plain copy public int getFileDescriptor() {      return native_get_fd();  }   而这个函数就是一个JNI函数,最后就是通过之前保存在UsbDeviceConnection的mNativeContext,把它变成一个usb_device,然后再获取其fd。 [cpp] view plain copy static jint  android_hardware_UsbDeviceConnection_get_fd(JNIEnv *env, jobject thiz)  {      struct usb_device* device = get_device_from_object(env, thiz);      if (!device) {          ALOGE("device is closed in native_get_fd");          return -1;      }      return usb_device_get_fd(device);  }   get_device_from_object就是获取UsbDeviceConnection的mNativeContext对象(实际是之前保存的usb_device对象) [cpp] view plain copy struct usb_device* get_device_from_object(JNIEnv* env, jobject connection)  {      return (struct usb_device*)env->GetLongField(connection, field_context);  }  

    这样通过UsbDeviceConnection的getFileDescriptor函数,用户进程拿到了自己需要的usb设备的fd了。

    时序图参考:https://blog.csdn.net/q1183345443/article/details/80989438

    转载http://blog.csdn.net/kc58236582/article/details/54691334

    转载请注明原文地址: https://ju.6miu.com/read-21693.html

    最新回复(0)