前言:
对于USB的一些常量属性,比如:UsbManager. USB_FUNCTION_RNDIS(USB的模式)等,现在也是一个比较模糊的概念,只能具体问题具体分析,我们重点说的是类结构,与USB整个框架(仅限于framework层)的逻辑。本来想画一张流程图呢。画来画去好像都跟实际情况有出入。就只能用文字叙述了。
一、调用:
我们从最常见与USB相关的界面说起。当手机连接电脑时,有如下界面:
这个界面是设置里面的一个界面,源码就不贴了,核心代码
获取 UsbManager类的对象:
mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
切换USB连接的模式。比如上图中的,把USB设置为仅充电:
function = UsbManager.USB_FUNCTION_CHARGE_ONLY;
mUsbManager.setCurrentFunction(function, true);
(在android系统源码中的路径:\frameworks\base\core\java\android\hardware\usb\UsbManager.java)
下面我们就围绕这两行代码进行分析。
二、UsbManager 如何获得的
1、首先,android 启动的时候会加载SystemServer.java(路径:\frameworks\base\services\java\com\android\server\SystemServer.java),在SystemServer 类中,调用
initAndLoop()方法加载各种服务,USB相关的核心代码
public void initAndLoop() {
......
UsbService usb = null;
......
try {
Slog.i(TAG, "USB Service");
// Manage USB host and device support
usb = new UsbService(context);
ServiceManager.addService(Context.USB_SERVICE, usb);
} catch (Throwable e) {
reportWtf("starting UsbService", e);
}
.....
}
可以看到SystemServer类中加载的USB相关的服务是 UsbServeice (路径:\frameworks\base\services\java\com\android\server\usb\UsbService.java)
我们这里记着:SystemServer类 中在initAndLoop()方法中,把UsbServeice 加到了 ServiceManager中。
2、其次,我们看ContextImpl.java (路径:\frameworks\base\core\java\android\app\ContextImpl.java)
static{
...
registerService(USB_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(USB_SERVICE);
return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
}});
...
}
registerService()方法的代码:
private static void registerService(String serviceName, ServiceFetcher fetcher) {
if (!(fetcher instanceof StaticServiceFetcher)) {
fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
}
SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}
SYSTEM_SERVICE_MAP 对象
private static final HashMap SYSTEM_SERVICE_MAP =
new HashMap();
由上我们看到,ContextImpl 类中有一个static 块,从ServiceManager 把usbService取出来,然后注册到ContextImpl类中,其实是放到你个HashMap中。
我们在上文“调用”中执行的代码,
mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
这句是在Activity中调用的,而Activity中都有一个关联的ContextImpl 对象,ContextImpl 是对Context的实现类,当在Activity中调用getSystemService(),其实调用的就是ContextImpl类中的getSystemService()。 这个ContextImpl 与Activity的关系我就不说了,可以看下源码,或者网上搜索,比如 http://www.cnblogs.com/android100/p/Android-Context.html 中就有相关的说明。
我们看下ContextImpl类中的getSystemService()
@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
好吧,其实就是从HashMap中把UsbManager取出来了。
三、UsbManager 的使用
我们先分析下整个USB的类结构了。
首先,我们来一个大体的概念。UsbManager类里面引用了一个UsbService的对象,而UsbService里面又引用了UsbDeviceManager与UsbHostManager的对象,而UsbDeviceManager与UsbHostManager中又分别引用了UsbSettingsManager的对象,而UsbDeviceManager中又引用了UsbDebuggingManager类的对象。大体情况如下图:
这里所说的类的路径都在android 系统源码\frameworks\base\services\java\com\android\server\usb 目录下。
这里插一句:USB分两种模式(这里所说的模式是针对于手机与其所连接的设备所扮演的角色,而我们通篇说的模式是USB选择的功能,如仅充电,PTP,MTP,大容量存储)
usb host 模式:举一例,手机插上键盘之类的外设,手机充当host角色,而UsbHostManager就是跟这个模式相关的,来管理外接设备。
usb Accessory模式:举一例,手机连上电脑,电脑充当host角色,手机是电脑的附件。而UsbDeviceManager就是跟这个模式相关的。而我们通篇都是针对于这种模式来讲解的。
从上图,我们可以清晰的看出类之间的引用关系,接着我回到我们的主题
我们在上文“调用”中执行的代码,
function = UsbManager.USB_FUNCTION_CHARGE_ONLY;
mUsbManager.setCurrentFunction(function, true);
是设置USB为仅充电模式。那么这句调用是如何执行的呢。先看setCurrentFunction()方法
public void setCurrentFunction(String function, boolean makeDefault) {
try {
mService.setCurrentFunction(function, makeDefault);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in setCurrentFunction", e);
}
}
这里面的mService就是UsbService的对象,看下UsbService中的setCurrentFunction()方法
@Override
public void setCurrentFunction(String function, boolean makeDefault) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
if (mDeviceManager != null) {
mDeviceManager.setCurrentFunctions(function, makeDefault);
} else {
throw new IllegalStateException("USB device mode not supported");
}
}
private UsbDeviceManager mDeviceManager;
其实调用的是UsbDeviceManager 中的setCurrentFunctions()方法
public void setCurrentFunctions(String functions, boolean makeDefault) {
if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ") default: " + makeDefault);
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault);
}
这里又通过handler机制发送MSG_SET_CURRENT_FUNCTIONS 消息来处理的。我们看下这个消息的处理
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
......
case MSG_SET_CURRENT_FUNCTIONS:
String functions = (String)msg.obj;
boolean makeDefault = (msg.arg1 == 1);
setEnabledFunctions(functions, makeDefault);
break;
}
}
setEnabledFunctions()方法:
private void setEnabledFunctions(String functions, boolean makeDefault) {
if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions
+ " makeDefault: " + makeDefault);
// Do not update persystent.sys.usb.config if the device is booted up
// with OEM specific mode.
if (functions != null && makeDefault && !needsOemUsbOverride()) {
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
}
if (!mDefaultFunctions.equals(functions)) {
mInUsbSetting = true;
if (!setUsbConfig("none")) {
Slog.e(TAG, "Failed to disable USB");
// revert to previous configuration if we fail
setUsbConfig(mCurrentFunctions);
mInUsbSetting = false;
return;
}
// setting this property will also change the current USB state
// via a property trigger
SystemProperties.set("persist.sys.usb.config", functions);
if (waitForState(functions)) {
mCurrentFunctions = functions;
mDefaultFunctions = functions;
} else {
Slog.e(TAG, "Failed to switch persistent USB config to " + functions);
// revert to previous configuration if we fail
SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
}
mInUsbSetting = false;
}
} else {
boolean rndisTetherSetting = UsbManager.USB_FUNCTION_RNDIS.equals(functions);
if (functions == null) {
functions = mDefaultFunctions;
}
// Override with bootmode specific usb mode if needed
functions = processOemUsbOverride(functions);
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
}
if (!mCurrentFunctions.equals(functions) || rndisTetherSetting) {
if (rndisTetherSetting && containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) {
functions = mCurrentFunctions;
}
mInUsbSetting = true;
if (!setUsbConfig("none")) {
Slog.e(TAG, "Failed to disable USB");
// revert to previous configuration if we fail
setUsbConfig(mCurrentFunctions);
mInUsbSetting = false;
return;
}
if (setUsbConfig(functions)) {
mCurrentFunctions = functions;
} else {
Slog.e(TAG, "Failed to switch USB config to " + functions);
// revert to previous configuration if we fail
setUsbConfig(mCurrentFunctions);
}
mInUsbSetting = false;
}
}
我们看下三个判断条件:
functions != null:设置的USB功能不为空;而当传如的参数为null的话,就是恢复默认功能。
makeDefault:“如果函数应设置为新的默认功能,makeDefault为true。“根据以上代码,当makeDefault为true的时候,会把mDefaultFunctions这个全局变量改为你这次的设置,这个全局变量的作用是,而当你断开连接时,或者传入参数functions为null的情况下,会用这个全局变量来设置USB功能。
needsOemUsbOverride():是否用厂商的属性覆盖。
知道了这三个判断条件,就能很清楚的看到其实执行到这里,就是把functions 写入到了系统属性中,推测kernel会监听这个属性,来改变USB功能。
....
SystemProperties.set("persist.sys.usb.config", functions);
.....
private boolean setUsbConfig(String config) {
if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
// set the new configuration
SystemProperties.set("sys.usb.config", config);
return waitForState(config);
}
好了,从应用层调用,一直追溯到这里,就知道了USB是模式切换是怎么实现的了,其实就是到最后,就是把要设置USB当前的模式写入到系统属性文件中。
四、USB查上电脑或者断开,上层会做些什么。
核心的类就是UsbDeviceManager类了。当插上或者断开USB的时候,这个类会监听底层上报的事件,然后上层根据这个事件来做一系列的动作。至于如何监听的,就是UEventObserver类了,UEventObserver是androidJava层利用uevent与获取Kernel层状态变化的机制,这里我们可以看到使用前必须先初始化一个新的UEventObserver类来处理事件,实现函数onUEvent,这是一个回调函数,之后我们会看到他是怎么被调用的
上代码:
private final UEventObserver mUEventObserver = new UEventObserver() {
@Override
public void onUEvent(UEventObserver.UEvent event) {
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 ("START".equals(accessory)) {
if (DEBUG) Slog.d(TAG, "got accessory start");
startAccessoryMode();
}
}
};
private final class UsbHandler extends Handler {
......
public UsbHandler(Looper looper) {
super(looper);
try {
.....
mUEventObserver.startObserving(USB_STATE_MATCH);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);
.....
} catch (Exception e) {
Slog.e(TAG, "Error initializing UsbHandler", e);
}
}
}
UsbHandler 是UsbDeviceManager中的一个内部类,设置一个UEventObserver监听Usb连接断开的状态,然后通过Handler机制来让上层做一系列的动作,如:弹出通知栏(Notification),或者发送UsbManager.ACTION_USB_STATE 的广播等。
接着就要说UEventObserver机制了,上述代码中:
1、调用startObserving()启动,传入的参数是标记事件的,就是一个Key。
mUEventObserver.startObserving(USB_STATE_MATCH);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);
2、UEventObserver类中的startObserving()方法
public final void startObserving(String match) {
if (match == null || match.isEmpty()) {
throw new IllegalArgumentException("match substring must be non-empty");
}
final UEventThread t = getThread();
t.addObserver(match, this);
}
3、getThread()方法
private static UEventThread getThread() {
synchronized (UEventObserver.class) {
if (sThread == null) {
sThread = new UEventThread();
sThread.start();
}
return sThread;
}
}
4、上面getThread就是new了一个UEventThread 对象。看一下UEventThread
private static final class UEventThread extends Thread {
private final ArrayList
分析第1、2步,首先获取UEventThread的一个对象,然后启动,之后调用addObserver()把键值对放入一个集合中。线程启动当然是执行Run()方法了,Run()方法中是一个死循环来等待消息,然后调用 sendEvent(message)发送出去,这个发送就是回调onUEvent(UEvent event)。就是mUEventObserver实现的方法。
Run()方法,调用了两个native方法(JNI),我们来分析一下:
nativeSetup();
nativeWaitForNextEvent();
UEventObserver中所有的JNI调用的方法所在的文件是android_os_UEventObserver.cpp
路径:\frameworks\base\core\jni\android_os_UEventObserver.cpp
static void nativeSetup(JNIEnv *env, jclass clazz) {
if (!uevent_init()) {
jniThrowException(env, "java/lang/RuntimeException",
"Unable to open socket for UEventObserver");
}
}
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);
}
}
}
看到这两个JNI方法的调用,很明显的看出来,nativeSetup();主要调用的是uevent_init() ;而nativeWaitForNextEvent()主要调用的是uevent_next_event()方法,这两个方法是在在uevent.c 中,android_os_UEventObserver.cpp是通过#include "hardware_legacy/uevent.h" 来载入的。路径:\hardware\libhardware_legacy\uevent\uevent.c
int uevent_init()
{
struct sockaddr_nl addr;
int sz = 64*1024;
int s;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = 0xffffffff;
s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if(s < 0)
return 0;
setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(s);
return 0;
}
fd = s;
return (fd > 0);
}
会创建一个socket ,定义内核事件向用户态通知(NETLINK_KOBJECT_UEVENT),返回返回一个fd
int uevent_next_event(char* buffer, int buffer_length)
{
while (1) {
struct pollfd fds;
int nr;
fds.fd = fd;
fds.events = POLLIN;
fds.revents = 0;
nr = poll(&fds, 1, -1);
if(nr > 0 && (fds.revents & POLLIN)) {
int count = recv(fd, buffer, buffer_length, 0);
if (count > 0) {
struct uevent_handler *h;
pthread_mutex_lock(&uevent_handler_list_lock);
LIST_FOREACH(h, &uevent_handler_list, list)
h->handler(h->handler_data, buffer, buffer_length);
pthread_mutex_unlock(&uevent_handler_list_lock);
return count;
}
}
}
// won't get here
return 0;
}
是用Linux poll 机制,等待事件的通知,有数据来的话接收到buffer里,然后返回。(到这一层我已经有些说不明白了,如果说错的话,请指正。)
总结一下:底层通过Poll与socket获取消息,然后到上层android_os_UEventObserver.cpp 类中,然后到UEventObserver中,UEventObserver回调UsbDeviceManager类中mUEventObserver实现的函数onUEvent,然后上层做处理,无论是发通知,或者发广播。
5、编译android源码默认开启USB调试模式
当android源码编译时,会执行\build\tools\post_process_props.py (Python语言)文件来配置属性,有一段代码是这样的:
if prop.get("ro.debuggable") == "1":
val = prop.get("persist.sys.usb.config")
if val == "":
val = "adb"
else:
val = val + ",adb"
prop.put("persist.sys.usb.config", val)
如果ro.debuggable 值为1的话,就在属性里增加adb,就是开启USB调试模式
所以,你可以在你的属性配置文件里配置这个属性为1就行了。
比如我的配置文件prod_xxxxxx.mk中
#Add for adb debug open
PRODUCT_PROPERTY_OVERRIDES += \
ro.debuggable=1
到此,USB相关的逻辑部分就分析到这里。