1. 程式人生 > >Android USB相關流程解析(android4.4)

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相關的核心程式碼

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<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),返回返回一個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相關的邏輯部分就分析到這裡。