[Boot]Android系統啟動-SystemServer上篇

本文轉載自Gityuan的博客,原文地址為:http://gityuan.com/2016/02/14/android-system-server/
轉載請注明作者及原文鏈接。

基于Android 6.0的源碼剖析, 分析Android啟動過程的system_server進程

/frameworks/base/core/java/com/android/internal/os/
  - ZygoteInit.java
  - RuntimeInit.java
  - Zygote.java

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

/frameworks/base/core/jni/
  - com_android_internal_os_Zygote.cpp
  - AndroidRuntime.cpp

/frameworks/base/cmds/app_process/App_main.cpp

啟動流程

SystemServer的在Android體系中所處的地位,SystemServer由Zygote fork生成的,進程名為system_server,該進程承載著framework的核心服務。 Android系統啟動-zygote篇中講到Zygote啟動過程中會調用startSystemServer(),可知startSystemServer()函數是system_server啟動流程的起點, 啟動流程圖如下:

在這里插入圖片描述

上圖前4步驟(即顏色為紫色的流程)運行在是Zygote進程,從第5步(即顏色為藍色的流程)ZygoteInit.handleSystemServerProcess開始是運行在新創建的system_server,這是fork機制實現的(fork會返回2次)。下面從startSystemServer()開始講解詳細啟動流程。

1. startSystemServer

[–>ZygoteInit.java]

private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException {
    ...
    //參數準備
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server",
        "--runtime-args",
        "com.android.server.SystemServer",
    };

    ZygoteConnection.Arguments parsedArgs = null;
    int pid;
    try {
        //用于解析參數,生成目標格式
        parsedArgs = new ZygoteConnection.Arguments(args);
        ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

        // fork子進程,該進程是system_server進程【見小節2】
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    //進入子進程system_server
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }
        // 完成system_server進程剩余的工作 【見小節5】
        handleSystemServerProcess(parsedArgs);
    }
    return true;
}

準備參數并fork新進程,從上面可以看出system server進程參數信息為uid=1000,gid=1000,進程名為sytem_server,從zygote進程fork新進程后,需要關閉zygote原有的socket。另外,對于有兩個zygote進程情況,需等待第2個zygote創建完成。

2 forkSystemServer

[–>Zygote.java]

public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
    VM_HOOKS.preFork();
    // 調用native方法fork system_server進程【見小節3】
    int pid = nativeForkSystemServer(
            uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
    if (pid == 0) {
        Trace.setTracingEnabled(true);
    }
    VM_HOOKS.postForkCommon();
    return pid;
}

nativeForkSystemServer()方法在AndroidRuntime.cpp中注冊的,調用com_android_internal_os_Zygote.cpp中的register_com_android_internal_os_Zygote()方法建立native方法的映射關系,所以接下來進入如下方法。

3. nativeForkSystemServer

[–>com_android_internal_os_Zygote.cpp]

static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
        jlong effectiveCapabilities) {
  //fork子進程,見【見小節4】
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                      debug_flags, rlimits,
                                      permittedCapabilities, effectiveCapabilities,
                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                      NULL, NULL);
  if (pid > 0) {
      // zygote進程,檢測system_server進程是否創建
      gSystemServerPid = pid;
      int status;
      if (waitpid(pid, &status, WNOHANG) == pid) {
          //當system_server進程死亡后,重啟zygote進程
          RuntimeAbort(env);
      }
  }
  return pid;
}

當system_server進程創建失敗時,將會重啟zygote進程。這里需要注意,對于Android 5.0以上系統,有兩個zygote進程,分別是zygote、zygote64兩個進程,system_server的父進程,一般來說64位系統其父進程是zygote64進程

  1. 當kill system_server進程后,只重啟zygote64和system_server,不重啟zygote;
  2. 當kill zygote64進程后,只重啟zygote64和system_server,也不重啟zygote;
  3. 當kill zygote進程,則重啟zygote、zygote64以及system_server。

4. ForkAndSpecializeCommon

[–>com_android_internal_os_Zygote.cpp]

static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, jint debug_flags, jobjectArray javaRlimits, jlong permittedCapabilities, jlong effectiveCapabilities, jint mount_external, jstring java_se_info, jstring java_se_name, bool is_system_server, jintArray fdsToClose, jstring instructionSet, jstring dataDir) {
  SetSigChldHandler(); //設置子進程的signal信號處理函數
  pid_t pid = fork(); //fork子進程
  if (pid == 0) {
    //進入子進程
    DetachDescriptors(env, fdsToClose); //關閉并清除文件描述符

    if (!is_system_server) {
        //對于非system_server子進程,則創建進程組
        int rc = createProcessGroup(uid, getpid());
    }
    SetGids(env, javaGids); //設置設置group
    SetRLimits(env, javaRlimits); //設置資源limit

    int rc = setresgid(gid, gid, gid);
    rc = setresuid(uid, uid, uid);

    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
    SetSchedulerPolicy(env); //設置調度策略

     //selinux上下文
    rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);

    if (se_info_c_str == NULL && is_system_server) {
      se_name_c_str = "system_server";
    }
    if (se_info_c_str != NULL) {
      SetThreadName(se_name_c_str); //設置線程名為system_server,方便調試
    }
    UnsetSigChldHandler(); //設置子進程的signal信號處理函數為默認函數
    //等價于調用zygote.callPostForkChildHooks()
    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                              is_system_server ? NULL : instructionSet);
    ...

  } else if (pid > 0) {
    //進入父進程,即zygote進程
  }
  return pid;
}

fork()創建新進程,采用copy on write方式,這是linux創建進程的標準方法,會有兩次return,對于pid==0為子進程的返回,對于pid>0為父進程的返回。 到此system_server進程已完成了創建的所有工作,接下來開始了system_server進程的真正工作。在前面startSystemServer()方法中,zygote進程執行完forkSystemServer()后,新創建出來的system_server進程便進入handleSystemServerProcess()方法。關于fork(),可查看另一個文章理解Android進程創建流程

5. handleSystemServerProcess

[–>ZygoteInit.java]

private static void handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs) throws ZygoteInit.MethodAndArgsCaller {

    closeServerSocket(); //關閉父進程zygote復制而來的Socket

    Os.umask(S_IRWXG | S_IRWXO);

    if (parsedArgs.niceName != null) {
        Process.setArgV0(parsedArgs.niceName); //設置當前進程名為"system_server"
    }

    final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
    if (systemServerClasspath != null) {
        //執行dex優化操作【見小節6】
        performSystemServerDexOpt(systemServerClasspath);
    }

    if (parsedArgs.invokeWith != null) {
        String[] args = parsedArgs.remainingArgs;

        if (systemServerClasspath != null) {
            String[] amendedArgs = new String[args.length + 2];
            amendedArgs[0] = "-cp";
            amendedArgs[1] = systemServerClasspath;
            System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
        }
        //啟動應用進程
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                VMRuntime.getCurrentInstructionSet(), null, args);
    } else {
        ClassLoader cl = null;
        if (systemServerClasspath != null) {
            // 創建類加載器,并賦予當前線程
            cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
            Thread.currentThread().setContextClassLoader(cl);
        }

        //system_server故進入此分支【見小節7】
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
    }

    /* should never reach here */
}

此處systemServerClasspath環境變量主要有/system/framework/目錄下的services.jar,ethernet-service.jar, wifi-service.jar這3個文件

6. performSystemServerDexOpt

[–>ZygoteInit.java]

private static void performSystemServerDexOpt(String classPath) {
    final String[] classPathElements = classPath.split(":");
    //創建一個與installd的建立socket連接
    final InstallerConnection installer = new InstallerConnection();
    //執行ping操作,直到與installd服務端連通為止
    installer.waitForConnection();
    final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();

    try {
        for (String classPathElement : classPathElements) {
            final int dexoptNeeded = DexFile.getDexOptNeeded(
                    classPathElement, "*", instructionSet, false /* defer */);
            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                //以system權限,執行dex文件優化
                installer.dexopt(classPathElement, Process.SYSTEM_UID, false,
                        instructionSet, dexoptNeeded);
            }
        }
    } catch (IOException ioe) {
        throw new RuntimeException("Error starting system_server", ioe);
    } finally {
        installer.disconnect(); //斷開與installd的socket連接
    }
}

將classPath字符串中的apk,分別進行dex優化操作。真正執行優化工作通過socket通信將相應的命令參數,發送給installd來完成。

7. zygoteInit

[–>RuntimeInit.java]

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
    redirectLogStreams(); //重定向log輸出

    commonInit(); // 通用的一些初始化【見小節8】
    nativeZygoteInit(); // zygote初始化 【見小節9】
    applicationInit(targetSdkVersion, argv, classLoader); // 應用初始化【見小節10】
}

8. commonInit

[–>RuntimeInit.java]

private static final void commonInit() {
    // 設置默認的未捕捉異常處理方法
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());

    // 設置市區,中國時區為"Asia/Shanghai"
    TimezoneGetter.setInstance(new TimezoneGetter() {
        @Override
        public String getId() {
            return SystemProperties.get("persist.sys.timezone");
        }
    });
    TimeZone.setDefault(null);

    //重置log配置
    LogManager.getLogManager().reset();
    new AndroidConfig();

    // 設置默認的HTTP User-agent格式,用于 HttpURLConnection。
    String userAgent = getDefaultUserAgent();
    System.setProperty("http.agent", userAgent);

    // 設置socket的tag,用于網絡流量統計
    NetworkManagementSocketTagger.install();
}

默認的HTTP User-agent格式,例如:

 "Dalvik/1.1.0 (Linux; U; Android 6.0.1;LenovoX3c70 Build/LMY47V)".

9. nativeZygoteInit

nativeZygoteInit()方法在AndroidRuntime.cpp中,進行了jni映射,對應下面的方法。

[–>AndroidRuntime.cpp]

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz) {
    //此處的gCurRuntime為AppRuntime,是在AndroidRuntime.cpp中定義的
    gCurRuntime->onZygoteInit();
}

[–>app_main.cpp]

virtual void onZygoteInit() {
    sp<ProcessState> proc = ProcessState::self();
    proc->startThreadPool(); //啟動新binder線程
}

ProcessState::self()是單例模式,主要工作是調用open()打開/dev/binder驅動設備,再利用mmap()映射內核的地址空間,將Binder驅動的fd賦值ProcessState對象中的變量mDriverFD,用于交互操作。startThreadPool()是創建一個新的binder線程,不斷進行talkWithDriver(),在binder系列文章中的注冊服務(addService)詳細這兩個方法的執行原理。

10. applicationInit

[–>RuntimeInit.java]

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
    //true代表應用程序退出時不調用AppRuntime.onExit(),否則會在退出前調用
    nativeSetExitWithoutCleanup(true);

    //設置虛擬機的內存利用率參數值為0.75
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

    final Arguments args;
    try {
        args = new Arguments(argv); //解析參數
    } catch (IllegalArgumentException ex) {
        return;
    }

    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    //調用startClass的static方法 main() 【見小節11】
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

在startSystemServer()方法中通過硬編碼初始化參數,可知此處args.startClass為”com.android.server.SystemServer”。

11. invokeStaticMain

[–>RuntimeInit.java]

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl = Class.forName(className, true, classLoader);
    ...

    Method m;
    try {
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        ...
    } catch (SecurityException ex) {
        ...
    }

    int modifiers = m.getModifiers();
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
        ...
    }

    //通過拋出異常,回到ZygoteInit.main()。這樣做好處是能清空棧幀,提高棧幀利用率。【見小節12】
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

12. MethodAndArgsCaller

Android系統啟動-zygote篇中遺留了一個問題沒有講解,如下:

[–>ZygoteInit.java]

public static void main(String argv[]) {
    try {
        startSystemServer(abiList, socketName);//啟動system_server
        ....
    } catch (MethodAndArgsCaller caller) {
        caller.run(); //【見小節13】
    } catch (RuntimeException ex) {
        closeServerSocket();
        throw ex;
    }
}

現在已經很明顯了,是invokeStaticMain()方法中拋出的異常MethodAndArgsCaller,從而進入caller.run()方法。

[–>ZygoteInit.java]

public static class MethodAndArgsCaller extends Exception implements Runnable {

    public void run() {
        try {
            //根據傳遞過來的參數,可知此處通過反射機制調用的是SystemServer.main()方法
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        } catch (InvocationTargetException ex) {
            Throwable cause = ex.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            }
            throw new RuntimeException(ex);
        }
    }
}

到此,總算是進入到了SystemServer類的main()方法, 在文章Android系統啟動-SystemServer下篇中會緊接著這里開始講述。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容