Android Usb在framework的相關(guān)源碼分析

Android USB 在framework相關(guān)源碼分析

USB插拔這一塊內(nèi)容比較多并蝗,在實際開發(fā)過程中仁热,暴露出來的問題也比較多,而且有些問題還比較不好解決郎楼,定位過程中不能一下就定位出是framework層還是kernal層部分的問題(就比如遇到的一個平板連接多設備辆雾,有打印機肪笋,2D掃描類Hub的方式)。因此度迂,對于做frameowork開發(fā)來講藤乙,深入理解這一塊(至少在App/Framework層要理解透徹)是非常有必要的。

由于在寫這篇博客的時候惭墓,是以寫->補->寫->補的方式來的坛梁,沒有按照一定的順序,比如遵循從kernal—>framework—>到app腊凶,或者app—>framework—>kernal有條理的來划咐,而只是按照了一些小的流程線來說的,源碼看到哪钧萍,就說哪褐缠。

第一節(jié)

Kernal 與 Framework層交互 UEventObserver;插入與拔出USB設備风瘦,事件監(jiān)聽以及上報.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的構(gòu)造方法中,添加了USB_STATE_MATCH和ACCESSORY_START_MATCH監(jiān)聽弛秋。因此器躏,下面我們就按照源碼跟蹤framework與kernal交互的這段邊界部分俐载。

    ...
    // Watch for USB configuration changes
    mUEventObserver.startObserving(USB_STATE_MATCH);    
    mUEventObserver.startObserving();
    ...

下面我們轉(zhuǎn)到UEventObserver中蟹略,UEventObserver 是一個Interface,定義了一個回調(diào)方法遏佣,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當前的狀態(tài)状婶,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參數(shù)意敛,當onUEvent回調(diào)時,則回調(diào)到注冊的這個Observer中膛虫。

    }

接下來草姻,startObserving方法轉(zhuǎn)到了UEventThread中。UEventThread是個線程是UEventObserver的內(nèi)部類稍刀,run方法中是個死循環(huán)撩独,不斷地監(jiān)聽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(); //第一次創(chuàng)建并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(相關(guān)的) 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);
                }
            }
        }
//向上層發(fā)送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全部發(fā)出去。
                final int N = mTempObserversToSignal.size();
                for (int i = 0; i < N; i++) {
                    final UEventObserver observer = mTempObserversToSignal.get(i);
                    observer.onUEvent(event); //找到與回調(diào)回去了
                }
                //發(fā)出去完了败富,等待下一波
                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這里來俐芯。后面的部分暫時不繼續(xù)往下跟了棵介。

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);
        }
    }}
  1. UsbInterface,UsbConfigration,UsbDevice 的創(chuàng)建
  2. USB相關(guān)Notification的顯示流程,源碼解析

從上面的分析我們看到吧史,當有新的UEvent從kernal 過來后邮辽,UEventObserver回調(diào)在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 的處理是關(guān)鍵。

        @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;
                    //設置優(yōu)先級
                    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的更新就先講到這里了痴腌。

第二節(jié)

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這個內(nèi)部類。

另外士聪, SystemServiceManager的startService方法是通過反射機制锦援,創(chuàng)建并調(diào)用對應方法,來初始化對應的Service. 實現(xiàn)代碼重用剥悟,這個地方是和低版本有區(qū)別灵寺。因此,下面先看下通過反射創(chuàng)建實例并啟動Service区岗。

首先看到SystemServiceManager的startService方法略板,該方法僅僅創(chuàng)建了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實例作為參數(shù)繼續(xù)轉(zhuǎn)到startService的重載方法:

isAssignableFrom 這個方法是檢查主與參數(shù)的關(guān)系是否來自于同一個parent。放到這里來說慈缔,也就是參數(shù)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 {
            //獲得構(gòu)造方法對象
         Constructor<T> constructor = serviceClass.getConstructor(Context.class);
            //創(chuàng)建實例
            service = constructor.newInstance(mContext);
        } catch ...

        // Register it.
        mServices.add(service); //添加到list中
        // Start it.
        try {
            service.onStart();//調(diào)用onStart方法藐鹤,轉(zhuǎn)到Service內(nèi)部流程中...
        } catch ...
        return service;
    }

接下來我們轉(zhuǎn)到UsbService.java&Lifecycle中 瓤檐,Lifecycle是UsbService.java的一個靜態(tài)內(nèi)部類,顯式持有外部類UsbService的對象引用mUsbService娱节。在它的onStart方法中創(chuàng)建UsbService挠蛉,但是這里僅僅只創(chuàng)建UsbService類對象做一部分簡單的初始化操作(創(chuàng)建UsbDeviceManager,注冊廣播等)括堤,而真正的初始化時發(fā)生在systemReady方法中碌秸,該方法在onBootPhase方法中調(diào)用绍移。那service的onSystemReady何時被調(diào)用呢悄窃?

    public static class Lifecycle extends SystemService {
        private UsbService mUsbService;
        public Lifecycle(Context context) {
            super(context);
        }
        @Override
        public void onStart() { //創(chuàng)建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中我們可以看到系統(tǒng)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瞬测,分別調(diào)用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方法横媚,這個方法是開機啟動完成后調(diào)用纠炮。

    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;

第三節(jié)

Usb多設備連接(類似于HUB)

本來想把最近遇到的一個critical bug 放上來一起寫一下,但是發(fā)現(xiàn)比較麻煩信息不太全就算了吧穷躁。
涉及到的類文件

  • 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接口實現(xiàn)規(guī)則中可以知道耕肩,read和write是要對應的。而在這里问潭,readParcelableArray和writeParcelableArray是明顯不一致的猿诸。這樣寫是有問題的我認為。這里值得推敲一下狡忙。

(二) UsbHostManager.java代碼分析

當新連接一個設備之后梳虽,UsbHostManager.java中會依次從jni回調(diào)beginUsbDeviceAdded—>addUsbConfiguration—>addUsbInterface—>addUsbEndpoint—>endUsbDeviceAdded 這幾個方法,分別創(chuàng)建UsbDevice灾茁,UsbConfigration,UsbInterface,UsbEndpoint Parcebale 對象窜觉。而這些對象是一對多的方式(這樣說應該是可以理解的吧,i think...)北专,說白了就是類似于二叉樹的方式竖螃。

其中在endUsbDeviceAdded這個方法最后沒有把mNewInterface置為null ,沒有把mNewConfigration置為null,并且在addUsbConfiguration和addUsbInterface加了判空逗余,這里我的理解是特咆,進入這些if塊是在下一個UsbDevice添加的時候才會走進去,但是此時mNewInterface录粱,mNewConfigration是上一輪數(shù)據(jù)而且后面有創(chuàng)建新的UsbConfigration和UsbInterface腻格,并且在endUsbDeviceAdded方法的開頭有當前一輪創(chuàng)建的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
    }
}

讀者可以仔細閱讀這個類文件的代碼,不多也就那么幾行旗闽。

第四節(jié)

從Activity中獲取service

通常情況下我們從Activity中獲取一個Service實例酬核,然后調(diào)用它的方法。

 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);
    }

之前喜歡把一些工作總結(jié)寫到CSDN,最近越來越喜歡MarkDown越來越喜歡簡書蔬螟,所以就開始放到這里來,這是處女篇汽畴,希望各位看官多多指點旧巾,你的批評是我進步的階梯耸序。
Thanks very much for your actions .

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鲁猩,隨后出現(xiàn)的幾起案子坎怪,更是在濱河造成了極大的恐慌,老刑警劉巖廓握,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芋忿,死亡現(xiàn)場離奇詭異,居然都是意外死亡疾棵,警方通過查閱死者的電腦和手機戈钢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來是尔,“玉大人殉了,你說我怎么就攤上這事∧饷叮” “怎么了薪铜?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長恩溅。 經(jīng)常有香客問我隔箍,道長,這世上最難降的妖魔是什么脚乡? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任蜒滩,我火速辦了婚禮,結(jié)果婚禮上奶稠,老公的妹妹穿的比我還像新娘俯艰。我一直安慰自己,他們只是感情好锌订,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布竹握。 她就那樣靜靜地躺著,像睡著了一般辆飘。 火紅的嫁衣襯著肌膚如雪啦辐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天蜈项,我揣著相機與錄音芹关,去河邊找鬼。 笑死战得,一個胖子當著我的面吹牛充边,可吹牛的內(nèi)容都是我干的庸推。 我是一名探鬼主播常侦,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼浇冰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了聋亡?” 一聲冷哼從身側(cè)響起肘习,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎坡倔,沒想到半個月后漂佩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡罪塔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年投蝉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瘩缆。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖佃蚜,靈堂內(nèi)的尸體忽然破棺而出庸娱,到底是詐尸還是另有隱情,我是刑警寧澤谐算,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布熟尉,位于F島的核電站,受9級特大地震影響洲脂,放射性物質(zhì)發(fā)生泄漏斤儿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一恐锦、第九天 我趴在偏房一處隱蔽的房頂上張望雇毫。 院中可真熱鬧,春花似錦踩蔚、人聲如沸棚放。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽飘蚯。三九已至,卻和暖如春福也,著一層夾襖步出監(jiān)牢的瞬間局骤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工暴凑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留峦甩,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像凯傲,于是被迫代替她去往敵國和親犬辰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容