Android系統啟動流程(三)解析SyetemServer程式啟動過程

劉望舒發表於2017-03-23

相關文章
Android系統架構與系統原始碼目錄
Android系統啟動流程(一)解析init程式啟動過程
Android系統啟動流程(二)解析Zygote程式啟動過程

前言

上一篇我們學習了Zygote程式,並且知道Zygote程式啟動了SyetemServer程式,那麼這一篇我們就來學習Android7.0版本的SyetemServer程式。

1.Zygote啟動SyetemServer程式

在上一篇文章中我們講到在ZygoteInit.java的startSystemServer函式中啟動了SyetemServer程式,如下所示。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

 private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
     ...
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            handleSystemServerProcess(parsedArgs);
        }
        return true;
    }複製程式碼

在startSystemServer函式中呼叫handleSystemServerProcess來啟動SyetemServer程式。

2.SyetemServer程式啟動過程

handleSystemServerProcess函式的程式碼如下所示。

  private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller {
        closeServerSocket();//1
      ...
        if (parsedArgs.invokeWith != null) {
           ...
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                cl = createSystemServerClassLoader(systemServerClasspath,
                                                   parsedArgs.targetSdkVersion);
                Thread.currentThread().setContextClassLoader(cl);
            }
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);//2
        }
    }複製程式碼

SyetemServer程式是複製了Zygote程式的地址空間,因此也會得到Zygote程式建立的Socket,這個Socket對於SyetemServer程式沒有用處,因此,需要註釋1處的程式碼來關閉該Socket。在註釋2處呼叫RuntimeInit的zygoteInit函式,它的程式碼如下所示。

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
        redirectLogStreams();
        commonInit();
        nativeZygoteInit();//1
        applicationInit(targetSdkVersion, argv, classLoader);//2
    }複製程式碼

註釋1處呼叫nativeZygoteInit函式,一看函式的名稱就知道呼叫Native層的程式碼。

啟動Binder執行緒池

接著我們來檢視nativeZygoteInit函式對用的JNI檔案,如下所示。
frameworks/base/core/jni/AndroidRuntime.cpp

static const JNINativeMethod gMethods[] = {
    { "nativeFinishInit", "()V",
        (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
    { "nativeZygoteInit", "()V",
        (void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
    { "nativeSetExitWithoutCleanup", "(Z)V",
        (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
};複製程式碼

通過JNI的gMethods陣列,可以看出nativeZygoteInit函式對應的是JNI檔案AndroidRuntime.cpp的com_android_internal_os_RuntimeInit_nativeZygoteInit函式:

...
static AndroidRuntime* gCurRuntime = NULL;
...
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}複製程式碼

這裡gCurRuntime是AndroidRuntime型別的指標,AndroidRuntime的子類AppRuntime在app_main.cpp中定義,我們來檢視AppRuntime的onZygoteInit函式,程式碼如下所示。
frameworks/base/cmds/app_process/app_main.cpp

 virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();//1
    }複製程式碼

註釋1處的程式碼用來啟動一個Binder執行緒池,這樣SyetemServer程式就可以使用Binder來與其他程式進行通訊了。看到這裡我們知道RuntimeInit.java的nativeZygoteInit函式主要做的就是啟動Binder執行緒池。

invokeStaticMain

我們再回到RuntimeInit.java的程式碼,在註釋2處呼叫了applicationInit函式,程式碼如下所示。

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

  private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
...
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }複製程式碼

applicationInit函式中主要呼叫了invokeStaticMain函式:

   private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl;
        try {
            cl = Class.forName(className, true, classLoader);//1
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }
        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });//2
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException(
                    "Problem getting static main on " + className, ex);
        }
        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);//3
    }複製程式碼

註釋1處className為“com.android.server.SystemServer",因此通過反射返回的cl為SystemServer類。註釋2處找到SystemServer中的main函式。在註釋3處將找到的main函式傳入到MethodAndArgsCaller異常中並丟擲該異常。截獲MethodAndArgsCaller異常的程式碼在ZygoteInit.java的main函式中,如下所示。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

  public static void main(String argv[]) {
       ...
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();//1
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }複製程式碼

在註釋1處呼叫了MethodAndArgsCaller的run函式:

   public void run() {
        try {
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
         ...
        }
    }
}複製程式碼

這裡mMethod指的就是SystemServer的main函式,因此main函式被動態呼叫。

3.解析SyetemServer程式

我們先來檢視SystemServer的main函式:
frameworks/base/services/java/com/android/server/SystemServer.java

 public static void main(String[] args) {
        new SystemServer().run();
    }複製程式碼

main函式中只呼叫了SystemServer的run函式,如下所示。

 private void run() {
        ...
            System.loadLibrary("android_servers");//1
        ...
            mSystemServiceManager = new SystemServiceManager(mSystemContext);//2
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        ...    
         try {
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
            startBootstrapServices();//3
            startCoreServices();//4
            startOtherServices();//5
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
        ...
    }複製程式碼

run函式程式碼很多,關鍵就是在註釋1處載入了libandroid_servers.so。接下來在註釋2處建立SystemServiceManager,它會對系統的服務進行建立、啟動和生命週期管理。啟動系統的各種服務,在註釋3中的startBootstrapServices函式中用SystemServiceManager啟動了ActivityManagerService、PowerManagerService、PackageManagerService等服務。在註釋4處的函式中則啟動了BatteryService、UsageStatsService和WebViewUpdateService。註釋5處的startOtherServices函式中則啟動了CameraService、AlarmManagerService、VrManagerService等服務,這些服務的父類為SystemService。從註釋3、4、5的函式可以看出,官方把系統服務分為了三種型別,分別是引導服務、核心服務和其他服務,其中其他服務為一些非緊要和一些不需要立即啟動的服務。系統服務大約有80多個,這裡列出部分系統服務以及它們的作用如下表所示:

引導服務 作用
Installer 系統安裝apk時的一個服務類,啟動完成Installer服務之後才能啟動其他的系統服務
ActivityManagerService 負責四大元件的啟動、切換、排程。
PowerManagerService 計算系統中和Power相關的計算,然後決策系統應該如何反應
LightsService 管理和顯示背光LED
DisplayManagerService 用來管理所有顯示裝置
UserManagerService 多使用者模式管理
SensorService 為系統提供各種感應器服務
PackageManagerService 用來對apk進行安裝、解析、刪除、解除安裝等等操作
核心服務
BatteryService 管理電池相關的服務
UsageStatsService 收集使用者使用每一個APP的頻率、使用時常
WebViewUpdateService WebView更新服務
其他服務
CameraService 攝像頭相關服務
AlarmManagerService 全域性定時器管理服務
InputManagerService 管理輸入事件
WindowManagerService 視窗管理服務
VrManagerService VR模式管理服務
BluetoothService 藍芽管理服務
NotificationManagerService 通知管理服務
DeviceStorageMonitorService 儲存相關管理服務
LocationManagerService 定位管理服務
AudioService 音訊相關管理服務
... ....

比如要啟動PowerManagerService則會呼叫如下程式碼:

mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);複製程式碼

SystemServiceManager的startService函式啟動了PowerManagerService,startService函式如下所示。

frameworks/base/services/core/java/com/android/server/SystemServiceManager.java

  public <T extends SystemService> T startService(Class<T> serviceClass) {
  ...
            final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);//1
            } catch (InstantiationException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service could not be instantiated", ex);
            }
...
            // Register it.
            mServices.add(service);//2
            // Start it.
            try {
                service.onStart();
            } catch (RuntimeException ex) {
                throw new RuntimeException("Failed to start service " + name
                        + ": onStart threw an exception", ex);
            }
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }複製程式碼

註釋1處的程式碼用來建立SystemService,這裡的SystemService是PowerManagerService,在註釋2處將PowerManagerService新增到mServices中,這裡mServices是一個儲存SystemService型別的ArrayList。接著呼叫PowerManagerService的onStart函式啟動PowerManagerService並返回,這樣就完成了PowerManagerService啟動的過程。
除了用mSystemServiceManager的startService函式來啟動系統服務外,也可以通過如下形式來啟動系統服務,以PackageManagerService為例:

 mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);複製程式碼

直接呼叫了PackageManagerService的main函式:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    // Self-check for initial settings.
    PackageManagerServiceCompilerMapping.checkProperties();
    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);//1
    m.enableSystemUserPackages();
    // Disable any carrier apps. We do this very early in boot to prevent the apps from being
    // disabled after already being started.
    CarrierAppUtils.disableCarrierAppsUntilPrivileged(context.getOpPackageName(), m,
            UserHandle.USER_SYSTEM);
    ServiceManager.addService("package", m);//2
    return m;
}複製程式碼

註釋1處直接建立PackageManagerService並在註釋2處將PackageManagerService註冊到ServiceManager中,ServiceManager用來管理系統中的各種Service,用於系統C/S架構中的Binder機制通訊:Client端要使用某個Service,則需要先到ServiceManager查詢Service的相關資訊,然後根據Service的相關資訊與Service所在的Server程式建立通訊通路,這樣Client端就可以使用Service了。還有的服務是直接註冊到ServiceManager中的,如下所示。

frameworks/base/services/java/com/android/server/SystemServer.java

  telephonyRegistry = new TelephonyRegistry(context);
  ServiceManager.addService("telephony.registry", telephonyRegistry);複製程式碼

4.總結SyetemServer程式

SyetemServer在啟動時做了如下工作:
1.啟動Binder執行緒池,這樣就可以與其他程式進行通訊。
2.建立SystemServiceManager用於對系統的服務進行建立、啟動和生命週期管理。
3.啟動各種系統服務。


歡迎關注我的微信公眾號,第一時間獲得部落格更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,即可關注。

Android系統啟動流程(三)解析SyetemServer程式啟動過程

相關文章