Android USB相關流程解析(android4.4)
前言:
對於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相關的核心程式碼
可以看到SystemServer類中載入的USB相關的服務是 UsbServeice (路徑:\frameworks\base\services\java\com\android\server\usb\UsbService.java)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類 中在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<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
new HashMap<String, ServiceFetcher>();
由上我們看到,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<Object> mKeysAndObservers = new ArrayList<Object>();
private final ArrayList<UEventObserver> mTempObserversToSignal =
new ArrayList<UEventObserver>();
public UEventThread() {
super("UEventObserver");
}
@Override
public void run() {
nativeSetup();
while (true) {
String message = nativeWaitForNextEvent();
if (message != null) {
if (DEBUG) {
Log.d(TAG, message);
}
sendEvent(message);
}
}
}
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);
if (message.contains(key)) {
final UEventObserver observer =
(UEventObserver)mKeysAndObservers.get(i + 1);
mTempObserversToSignal.add(observer);
}
}
}
if (!mTempObserversToSignal.isEmpty()) {
final UEvent event = new UEvent(message);
final int N = mTempObserversToSignal.size();
for (int i = 0; i < N; i++) {
final UEventObserver observer = mTempObserversToSignal.get(i);
observer.onUEvent(event);
}
mTempObserversToSignal.clear();
}
}
public void addObserver(String match, UEventObserver observer) {
synchronized (mKeysAndObservers) {
mKeysAndObservers.add(match);
mKeysAndObservers.add(observer);
nativeAddMatch(match);
}
}
/** Removes every key/value pair where value=observer from mObservers */
public void removeObserver(UEventObserver observer) {
synchronized (mKeysAndObservers) {
for (int i = 0; i < mKeysAndObservers.size(); ) {
if (mKeysAndObservers.get(i + 1) == observer) {
mKeysAndObservers.remove(i + 1);
final String match = (String)mKeysAndObservers.remove(i);
nativeRemoveMatch(match);
} else {
i += 2;
}
}
}
}
}
分析第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),返回返回一個fdint 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相關的邏輯部分就分析到這裡。