Android USB 在framework相关源码浅析
来源:互联网 发布:协同过滤推荐算法实例 编辑:程序博客网 时间:2024/05/21 06:13
Android USB 在framework相关源码分析
USB插拔这一块内容比较多,在实际开发过程中,暴露出来的问题也比较多,而且有些问题还比较不好解决,定位过程中不能一下就定位出是framework层还是kernal层部分的问题(就比如遇到的一个平板连接多设备,有打印机,2D扫描类Hub的方式)。因此,对于做frameowork开发来讲,深入理解这一块(至少在App/Framework层要理解透彻)是非常有必要的。
由于在写这篇博客的时候,是以写->补->写->补的方式来的,没有按照一定的顺序,比如遵循从kernal—>framework—>到app,或者app—>framework—>kernal有条理的来,而只是按照了一些小的流程线来说的,源码看到哪,就说哪。
第一节
Kernal 与 Framework层交互 UEventObserver;插入与拔出USB设备,事件监听以及上报.UEventObserver
涉及到的类文件:
- android_os_UEventObserver.cpp
./frameworks/base/core/jni/android_os_UEventObserver.cpp
- UEventObserver.java
./frameworks/base/core/java/android/os/UEventObserver.java
插拔U盘,usb事件上报
在UsbDeviceManager.java的构造方法中,添加了USB_STATE_MATCH和ACCESSORY_START_MATCH监听。因此,下面我们就按照源码跟踪framework与kernal交互的这段边界部分。
... // Watch for USB configuration changes mUEventObserver.startObserving(USB_STATE_MATCH); mUEventObserver.startObserving(); ...
下面我们转到UEventObserver中,UEventObserver 是一个Interface,定义了一个回调方法,onUEvent,通过它将kernal 上报事件传递至app/framework层、
/*mUEventObserver的声明: * Listens for uevent messages from the kernel to monitor the USB state */ private final UEventObserver mUEventObserver = new UEventObserver() { @Override public void onUEvent(UEventObserver.UEvent event) { //这里从UEventThead String state = event.get("USB_STATE"); String accessory = event.get("ACCESSORY"); if (state != null) { mHandler.updateState(state); //更新USB当前的状态,CONNECTED ,DISCONNECTED,CONFIGURED } else if ... } };
先看UEventObserver中的startObservering方法
public final void startObserving(String match) { ... //The UEventThread is Singleton pattern. final UEventThread t = getThread(); t.addObserver(match, this); //this参数,当onUEvent回调时,则回调到注册的这个Observer中。 }
接下来,startObserving方法转到了UEventThread中。UEventThread是个线程是UEventObserver的内部类,run方法中是个死循环,不断地监听UEvent,当有事件从Kernal上报时,则通过Handler一步步上传。UEventThread 在UEventObserver中以单例模式存在。
//Create the thread and start it private static UEventThread getThread() { synchronized (UEventObserver.class) { //keep it sysncronized if (sThread == null) { sThread = new UEventThread(); //第一次创建并start sThread.start(); } return sThread; } }
UEventThread:
private static final class UEventThread extends Thread { /** Many to many mapping of string match to observer. * Multimap would be better, but not available in android, so use * an ArrayList where even elements are the String match and odd * elements the corresponding(相关的) UEventObserver observer */ private final ArrayList<Object> mKeysAndObservers = new ArrayList<Object>(); private final ArrayList<UEventObserver> mTempObserversToSignal = new ArrayList<UEventObserver>(); public UEventThread() { super("UEventObserver"); } @Override public void run() { nativeSetup(); while (true) {// a loop to get Event everytime String message = nativeWaitForNextEvent();//wait for the next Event if (message != null) { sendEvent(message); } } }//向上层发送Event private void sendEvent(String message) { synchronized (mKeysAndObservers) { final int N = mKeysAndObservers.size(); for (int i = 0; i < N; i += 2) { final String key = (String)mKeysAndObservers.get(i); // the match String index is i //遍历list中所有的match String if (message.contains(key)) { final UEventObserver observer = (UEventObserver)mKeysAndObservers.get(i + 1); // then , the Observer object in ArrayList index is (i+1) mTempObserversToSignal.add(observer); } } } if (!mTempObserversToSignal.isEmpty()) { final UEvent event = new UEvent(message); //mTempObserversToSignal存储是的与该message相配套的Observer,所以这里遍历后,将message全部发出去。 final int N = mTempObserversToSignal.size(); for (int i = 0; i < N; i++) { final UEventObserver observer = mTempObserversToSignal.get(i); observer.onUEvent(event); //找到与回调回去了 } //发出去完了,等待下一波 mTempObserversToSignal.clear(); } } // “matchA”,ObserverA ;"matchB",ObserverB ... // 这里的match String 和 Observer Object是成双成对的,如果我取到了match String index 为 i,则Observer object 的index 为 (i+1) // 这里 match是不会一致的,否则就重复了,但是Observer 是会有可能同一个 public void addObserver(String match, UEventObserver observer) { synchronized (mKeysAndObservers) { //mKeyAndroidObservers key to value mKeysAndObservers.add(match); mKeysAndObservers.add(observer); nativeAddMatch(match); } } ...
在UEventThread中,有两个ArrayList,一个是mKeysAndObservers,虽然是个List但是它扮演的是Map的角色,里面的match (String) , Observer(Object) 一一对应,这里就有疑问了?为何不直接使用map呢?map不正好是key-value对应的吗? 我的认为是,list里面match (String) 与Obsever的对应是存在重复的情况。但是map中是不允许key重复的。这应该是没有使用Map的原因吧。另外一个是mTempObserversToSignal ,作为临时变量。framework/base/core/jni/android_os_UEventObserver.cpp
那UEvent从哪里来呢?从nativeWaitForNextEvent这里来。后面的部分暂时不继续往下跟了。
static jstring nativeWaitForNextEvent(JNIEnv *env, jclass clazz) { char buffer[1024]; for (;;) { int length = uevent_next_event(buffer, sizeof(buffer) - 1); if (length <= 0) { return NULL; } buffer[length] = '\0'; ALOGV("Received uevent message: %s", buffer); if (isMatch(buffer, length)) { // Assume the message is ASCII. jchar message[length]; for (int i = 0; i < length; i++) { message[i] = buffer[i]; } return env->NewString(message, length); } }}
- UsbInterface,UsbConfigration,UsbDevice 的创建
- USB相关Notification的显示流程,源码解析
从上面的分析我们看到,当有新的UEvent从kernal 过来后,UEventObserver回调在UsbDeviceManager中,此时我们通过Handler消息机制,更新Notification的显示。具体过程如下:
private final UEventObserver mUEventObserver = new UEventObserver() { @Override public void onUEvent(UEventObserver.UEvent event) { //这里从UEventThead if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString()); String state = event.get("USB_STATE"); String accessory = event.get("ACCESSORY"); if (state != null) { mHandler.updateState(state); } else if {...} } };mHandler中的updateState: public void updateState(String state) { int connected, configured; if ("DISCONNECTED".equals(state)) { //断开连接 connected = 0; configured = 0; } else if ("CONNECTED".equals(state)) { //连接上 connected = 1; configured = 0; } else if ("CONFIGURED".equals(state)) { connected = 1; configured = 1; } else { Slog.e(TAG, "unknown state " + state); return; } removeMessages(MSG_UPDATE_STATE); //avoid MSG repeated Message msg = Message.obtain(this, MSG_UPDATE_STATE); msg.arg1 = connected; msg.arg2 = configured; // debounce disconnects to avoid problems bringing up USB tethering sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0); }
此处对MSG_UPDATE_STATE 的处理是关键。
@Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_UPDATE_STATE: mConnected = (msg.arg1 == 1); mConfigured = (msg.arg2 == 1); updateUsbNotification(); // 更新USB Notification updateAdbNotification(); if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) { updateCurrentAccessory(); } else if (!mConnected) { // restore defaults when USB is disconnected setEnabledFunctions(getDefaultFunctions(), false); } if (mSystemReady) { updateUsbState(); updateAudioSourceFunction(); } break; ...
接下来我们只看updateUsbNotification方法。这个方法很简单,就是更新Notification,就是我们平时插上USB连接线的时候,顶部通知栏会显示的通知。
如果你要添加声音或者振动,或者更改图标等,算是找对地方了。
private void updateUsbNotification() { if (mNotificationManager == null || !mUseUsbNotification) return; int id = 0; Resources r = mContext.getResources(); if (mConnected) { if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) { id = com.android.internal.R.string.usb_mtp_notification_title; //作为USB设备链接 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) { id = com.android.internal.R.string.usb_ptp_notification_title;//作为相机链接 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MASS_STORAGE)) { id = com.android.internal.R.string.usb_cd_installer_notification_title; //作为安装应用程序 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) { id = com.android.internal.R.string.usb_accessory_notification_title; // 已链接到USB配件 } else { // There is a different notification for USB tethering so we don't need one here //if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) { // Slog.e(TAG, "No known USB function in updateUsbNotification"); //} } } if (id != mUsbNotificationId) { // clear notification if title needs changing if (mUsbNotificationId != 0) { //当前正在显示的notification id mNotificationManager.cancelAsUser(null,mUsbNotificationId,UserHandle.ALL); mUsbNotificationId = 0; } if (id != 0) { CharSequence message = r.getText( com.android.internal.R.string.usb_notification_message); //触摸可以显示其他USB选项 CharSequence title = r.getText(id); Notification notification = new Notification(); notification.icon = com.android.internal.R.drawable.stat_sys_data_usb; notification.when = 0; notification.flags = Notification.FLAG_ONGOING_EVENT; notification.tickerText = title; //如果我们需要添加声音,是否振动或者更改显示的图标,可以修改这里。 notification.defaults = 0; // please be quiet notification.sound = null; notification.vibrate = null; //设置优先级 notification.priority = Notification.PRIORITY_MIN; //点击通知栏后的操作 Intent intent = Intent.makeRestartActivityTask( new ComponentName("com.android.settings", "com.android.settings.UsbSettings")); PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0, null, UserHandle.CURRENT); notification.color = mContext.getResources().getColor( com.android.internal.R.color.system_notification_accent_color); notification.setLatestEventInfo(mContext, title, message, pi); notification.visibility = Notification.VISIBILITY_PUBLIC; mNotificationManager.notifyAsUser(null, id, notification, UserHandle.ALL); mUsbNotificationId = id; } } } ......
Kernal —> Framework UEvent这部分,并插拔USB时,Notification的更新就先讲到这里了。
第二节
SystemServer启动UsbService
涉及到的类文件
UsbService.java:
./frameworks/base/services/usb/java/com/android/server/usb/UsbService.java
UsbManager.java:
./frameworks/base/core/java/android/hardware/usb/UsbManager.java
UsbDeviceManager.java:
./frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
UsbHostManager.java: ./frameworks/base/services/usb/java/com/android/server/usb/UsbHostManager.java
SystemServer.java
./frameworks/base/services/java/com/android/server/SystemServer.java
SystemServiceManager.java
./frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
ActivityManagerService.java
./frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
首先我们看下SystemServer中启动UsbService服务以及UsbDeviceManager,UsbHostManager的初始化。
SystemServer.java 中UsbService启动代码:
... if (!disableNonCoreServices) { if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST) || mPackageManager.hasSystemFeature( PackageManager.FEATURE_USB_ACCESSORY)) { //注意Feature_USB_HOST 和 FEATURE_USB_ACCESSORY // Manage USB host and device support mSystemServiceManager.startService(USB_SERVICE_CLASS); }
注意这里的USB_SERVICE_CLASS变量定义:
private static final String USB_SERVICE_CLASS = “com.android.server.usb.UsbService$Lifecycle”;
可以看到实际这个USB_SERVICE_CLASS,是Lifecycle这个内部类。
另外, SystemServiceManager的startService方法是通过反射机制,创建并调用对应方法,来初始化对应的Service. 实现代码重用,这个地方是和低版本有区别。因此,下面先看下通过反射创建实例并启动Service。
首先看到SystemServiceManager的startService方法,该方法仅仅创建了Class实例
public SystemService startService(String className) { final Class<SystemService> serviceClass; try { //通过Class反射机制获得className所对应的Service class实例 serviceClass = (Class<SystemService>) Class.forName(className); } catch (ClassNotFoundException ex) { ... //do not find balabala } return startService(serviceClass); }
然后将Class实例作为参数继续转到startService的重载方法:
isAssignableFrom 这个方法是检查主与参数的关系是否来自于同一个parent。放到这里来说,也就是参数serviceClass必须是SystemService的衍生类才行,否则就会抛出运行时异常。
public <T extends SystemService> T startService(Class<T> serviceClass) { final String name = serviceClass.getName(); Slog.i(TAG, "Starting the name of the SystemService : " + name); // Create the service. //extends or not . if (!SystemService.class.isAssignableFrom(serviceClass)) { throw new RuntimeException("Failed to create " + name + ": service must extend " + SystemService.class.getName()); } final T service; try { //获得构造方法对象 Constructor<T> constructor = serviceClass.getConstructor(Context.class); //创建实例 service = constructor.newInstance(mContext); } catch ... // Register it. mServices.add(service); //添加到list中 // Start it. try { service.onStart();//调用onStart方法,转到Service内部流程中... } catch ... return service; }
接下来我们转到UsbService.java&Lifecycle中 ,Lifecycle是UsbService.java的一个静态内部类,显式持有外部类UsbService的对象引用mUsbService。在它的onStart方法中创建UsbService,但是这里仅仅只创建UsbService类对象做一部分简单的初始化操作(创建UsbDeviceManager,注册广播等),而真正的初始化时发生在systemReady方法中,该方法在onBootPhase方法中调用。那service的onSystemReady何时被调用呢?
public static class Lifecycle extends SystemService { private UsbService mUsbService; public Lifecycle(Context context) { super(context); } @Override public void onStart() { //创建Service实例,并添加到ServiceManager中。 mUsbService = new UsbService(getContext()); publishBinderService(Context.USB_SERVICE, mUsbService); } @Override public void onBootPhase(int phase) { if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { mUsbService.systemReady(); } } }
这里要说一下SystemServiceManager.java中startService中 mServices.add(service); 这句,从SystemServer.java中我们可以看到系统service添加到了mServices list中。
先看SystemServiceManager.java中startBootPhase方法
/** * Starts the specified boot phase for all system services that have been started up to * this point. * * @param phase The boot phase to start. */ public void startBootPhase(final int phase) { if (phase <= mCurrentPhase) { throw new IllegalArgumentException("Next phase must be larger than previous"); } mCurrentPhase = phase; //遍历mServices,分别调用Service的onBootPhase方法 final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); try { service.onBootPhase(mCurrentPhase); } catch ... }
再看ActivityManagerService.java中的finishBooting方法,这个方法是开机启动完成后调用。
final void finishBooting() { ... // Let system services know. mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED); ... }
PHASE_BOOT_COMPLETED这个变量按照官方的解释是代替开机广播,开机即刻完成所有service的启动,减少了广播的延迟等待的时间。
/** * After receiving this boot phase, services can allow user interaction with the device. * This phase occurs when boot has completed and the home application has started. * System services may prefer to listen to this phase rather than registering a * broadcast receiver for ACTION_BOOT_COMPLETED to reduce overall latency. * */ public static final int PHASE_BOOT_COMPLETED = 1000;
第三节
Usb多设备连接(类似于HUB)
本来想把最近遇到的一个critical bug 放上来一起写一下,但是发现比较麻烦信息不太全就算了吧。
涉及到的类文件
- UsbDeviceManager.java:
./frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
- UsbHostManager.java: ./frameworks/base/services/usb/java/com/android/server/usb/UsbHostManager.java
- UsbDevice.java
./framework/base/core/java/android/hardware/usb/UsbDevice.java
有2个点必须要提一下
(一)在UsbDevice.java中
public static final Parcelable.Creator<UsbDevice> CREATOR = new Parcelable.Creator<UsbDevice>() { public UsbDevice createFromParcel(Parcel in) { ... Parcelable[] configurations = in.readParcelableArray(UsbInterface.class.getClassLoader()); ... return device; } ... };
public void writeToParcel(Parcel parcel, int flags) { ... parcel.writeParcelableArray(mConfigurations, 0);}
从Parceable接口实现规则中可以知道,read和write是要对应的。而在这里,readParcelableArray和writeParcelableArray是明显不一致的。这样写是有问题的我认为。这里值得推敲一下。
(二) UsbHostManager.java代码分析
当新连接一个设备之后,UsbHostManager.java中会依次从jni回调beginUsbDeviceAdded—>addUsbConfiguration—>addUsbInterface—>addUsbEndpoint—>endUsbDeviceAdded 这几个方法,分别创建UsbDevice,UsbConfigration,UsbInterface,UsbEndpoint Parcebale 对象。而这些对象是一对多的方式(这样说应该是可以理解的吧,i think…),说白了就是类似于二叉树的方式。
其中在endUsbDeviceAdded这个方法最后没有把mNewInterface置为null ,没有把mNewConfigration置为null,并且在addUsbConfiguration和addUsbInterface加了判空,这里我的理解是,进入这些if块是在下一个UsbDevice添加的时候才会走进去,但是此时mNewInterface,mNewConfigration是上一轮数据而且后面有创建新的UsbConfigration和UsbInterface,并且在endUsbDeviceAdded方法的开头有当前一轮创建的Configration和Interface分别set到对象中,所以前面的判断显得多余。
private void addUsbInterface(int id, String name, int altSetting, int Class, int subClass, int protocol) { //有疑问代码块 start if (mNewInterface != null) { mNewInterface.setEndpoints( mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()])); mNewEndpoints.clear(); } //有疑问代码块 end ...}
private void addUsbConfiguration(int id, String name, int attributes, int maxPower) { //有疑问代码块 start if (mNewConfiguration != null) { mNewConfiguration.setInterfaces( mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()])); mNewInterfaces.clear(); } //有疑问代码块 end ... }
/* Called from JNI in monitorUsbHostBus() to finish adding a new device */private void endUsbDeviceAdded() { if (DEBUG) { Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()"); } // 往Interface中添加endpoint start if (mNewInterface != null) { mNewInterface.setEndpoints( mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()])); } // 往Interface中添加endpoint end //往Configration中添加Interface start if (mNewConfiguration != null) { mNewConfiguration.setInterfaces( mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()])); } //往Configration中添加Interface start //往Device中添加Configration start synchronized (mLock) { if (mNewDevice != null) { mNewDevice.setConfigurations( mNewConfigurations.toArray(new UsbConfiguration[mNewConfigurations.size()])); mDevices.put(mNewDevice.getDeviceName(), mNewDevice); Slog.d(TAG, "Added device " + mNewDevice); getCurrentSettings().deviceAttached(mNewDevice); mUsbAudioManager.deviceAdded(mNewDevice); } else { Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded"); } //往Device中添加Configration end //这里,没有把mNewInterface置为null ,没有把mNewConfigration置为null mNewDevice = null; mNewConfigurations = null; mNewInterfaces = null; mNewEndpoints = null; // 修复 start mNewConfigration = null ; mNewInterface = null ; // 修复 end }}
读者可以仔细阅读这个类文件的代码,不多也就那么几行。
第四节
从Activity中获取service
通常情况下我们从Activity中获取一个Service实例,然后调用它的方法。
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); HashMap<Strinng,UsbDevice> deviceHashMap = usbManager.getDeviceList() ;
在ContextImpl.java类中有static初始化块。
// This one's defined separately and given a variable name so it // can be re-used by getWallpaperManager(), avoiding a HashMap // lookup. private static ServiceFetcher WALLPAPER_FETCHER = new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new WallpaperManager(ctx.getOuterContext(), ctx.mMainThread.getHandler()); }}; ... registerService(CAPTIONING_SERVICE, new ServiceFetcher() { public Object getService(ContextImpl ctx) { return new CaptioningManager(ctx); }}); ...
在registerService方法中,将所有service缓存到SYSTEM_SERVICE_MAP中。
private static void registerService(String serviceName, ServiceFetcher fetcher) { ... SYSTEM_SERVICE_MAP.put(serviceName, fetcher); }
因此,getSystemService方法即是从map中取出service实例。
@Override public Object getSystemService(String name) { ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); }
之前喜欢把一些工作总结写到CSDN,最近越来越喜欢MarkDown越来越喜欢简书,所以就开始放到这里来,这是处女篇,希望各位看官多多指点,你的批评是我进步的阶梯。
Thanks very much for your actions .
- Android USB 在framework相关源码浅析
- Android Battery 在framework相关介绍
- Android Battery 在framework相关介绍
- Android framework浅析
- 浅析Android Framework
- 如何编译android 4.1 的源码并在android的ADT里面调试framework相关的代码
- 【Android】【USB】USB相关开发
- Android应用Preference相关及源码浅析(SharePreferences篇)
- android平台USB相关
- android framework浅析之activityManager:
- 浅析Android Framework框架层
- 【Android】【Framework】ActivityThread相关
- Android FrameWork源码浅析之(一)--handler,looper,messagequeue
- Android FrameWork源码浅析之(二)--转发一篇文章讲binder
- 在android源码framework里添加的资源文件!
- android framework 源码结构图
- android framework 源码结构图
- android framework 源码结构图
- springMVC整合FastJson实现RestFul风格API
- 如何提高自己的知识水平?
- IndentationError: unindent does not match any outer indentation level(Python你是猪头吗?)
- CentOs6.5 通过vncserver安装oracle
- 简单的AIDL的使用
- Android USB 在framework相关源码浅析
- 自定义表单构件
- windows条件下,Ping加上时间戳,并保存到文件,适用于测试网络
- </li></ul>横向排列
- 【点分治】3365: [Usaco2004 Feb]Distance Statistics 路程统计
- centos6.5编译mcrypt
- C# PropertyInfo 将一个对象赋值到另一个相同名称的对象
- 过滤器(当前登录人的信息(session过期时)进行重新登录)
- 生成openfpyxl html格式帮助文档