Framework基礎(chǔ):源于異常的System_Server與受精卵Zygote的共存亡

凌亂.png

System_Server是系統(tǒng)進(jìn)程击罪,而Zygote是Android java世界的基石。這兩位都在Android中扮演著十分重要的角色。有個(gè)很形象的比喻疏日,Zygote是爸爸盈滴,System_Server是大兒子涯肩,應(yīng)用是一堆小兒子就不說了。今天來說說這兩位仁兄的兩個(gè)特性:
1.System_Server使用捕捉異常的方式啟動(dòng)巢钓。
2.Zygote與System_Server共存亡病苗。

System_Server使用捕捉異常的方式啟動(dòng)

源文件:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
入口是ZygoteInit的startSystemServer函數(shù),利用forkSystemServer函數(shù)產(chǎn)生了子進(jìn)程SystemServer,并且設(shè)置了SystemServer的pid症汹,uid硫朦,uidgroud等。但這時(shí)并沒有進(jìn)入SystemServer的main函數(shù)入口背镇,只是一個(gè)進(jìn)程跑起來了咬展,懂嗎。

    private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
        String args[] = {
            "--setuid=1000",   //SystemServer pid=1000,gid=1000,還設(shè)置了權(quán)限組
            "--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",    //SystemServer的類名
        };
         ...................
         ...................
         //會(huì)利用linux的fork函數(shù)產(chǎn)生SystemServer子進(jìn)程
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            //子進(jìn)程 SystemServer
            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }


進(jìn)入handleSystemServerProcess函數(shù),這里的parsedArgs.remainingArgs就是類名com.android.server.SystemServer

    private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller {
            ......
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
           ..................
        }
    }

/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
再進(jìn)入RuntimeInit類的zygoteInit函數(shù)

    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        commonInit();    //初始化時(shí)區(qū)啥的
        nativeZygoteInit();  //native的初始化啥的
        applicationInit(targetSdkVersion, argv, classLoader);  //參數(shù)argv是類名com.android.server.SystemServer
    }

再進(jìn)入applicationInit函數(shù)

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

再進(jìn)入invokeStaticMain函數(shù)瞒斩,在這里反射調(diào)用了SystemServer類破婆,并且獲取到main方法,但并沒有執(zhí)行胸囱,而是直接拋出一個(gè)異常throw new ZygoteInit.MethodAndArgsCaller荠割。

    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl;
       cl = Class.forName(className, true, classLoader);//反射獲取SystemServer類
       Method m;
        m = cl.getMethod("main", new Class[] { String[].class });  //獲取main方法
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);   //拋出異常,argv為空
    }

那這個(gè)異常是由誰來捕捉呢旺矾?其實(shí)是在ZygoteInit的main函數(shù)捕捉的蔑鹦,如下圖

異常捕捉.png

異常捕捉后,調(diào)用 caller.run();
這里caller是MethodAndArgsCaller類箕宙,是ZygoteInit的內(nèi)部類嚎朽。run方法會(huì)執(zhí)行SystemServer的main方法。從而完成SystemServer的啟動(dòng)柬帕。


    public static class MethodAndArgsCaller extends Exception
            implements Runnable {
        public void run() {
                mMethod.invoke(null, new Object[] { mArgs });
    }
}

為什么SystemServer要采用捕捉異常的方式啟動(dòng)呢哟忍?源碼里面其實(shí)有注釋,應(yīng)該是啟動(dòng)一個(gè)新進(jìn)程時(shí)陷寝,用來清除之前的堆棧信息的锅很。

Paste_Image.png

Zygote與System_Server共存亡

System_Server是一個(gè)很重要的進(jìn)程,如果掛了凤跑,Zygote必須重啟爆安,如果不重啟,手機(jī)就會(huì)進(jìn)入假死的狀態(tài),手機(jī)黑屏仔引,無聲扔仓,無法跟用戶交互等褐奥。
Zygote與System_Server共存亡是如何實(shí)現(xiàn)的呢?
入口:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
Zygote調(diào)用forkSystemServer產(chǎn)生子進(jìn)程SystemServer翘簇。

    private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
    }

/frameworks/base/core/java/com/android/internal/os/Zygote.java
進(jìn)入forkSystemServer函數(shù)看看

    public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        int pid = nativeForkSystemServer(
                uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
        return pid;
    }

會(huì)jni進(jìn)入native函數(shù)
/frameworks/base/core/jni/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) {
 ............................
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                      debug_flags, rlimits,
                                      permittedCapabilities, effectiveCapabilities,
                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                      NULL, NULL);
 ................................

}

繼續(xù)進(jìn)入ForkAndSpecializeCommon函數(shù)

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();   //注冊(cè)信號(hào)撬码,這里將關(guān)系共存亡

  pid_t pid = fork();//fork產(chǎn)生子進(jìn)程systemserver

  if (pid == 0) {
    .........                //子進(jìn)程的一些操作
  } else if (pid > 0) {
    // the parent process
  }
  return pid;
}

SetSigChldHandler用于注冊(cè)信號(hào),這里就是關(guān)系到Zygote與System_Server的共存亡版保。

static void SetSigChldHandler() {
  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = SigChldHandler;  //信號(hào)處理函數(shù)

  int err = sigaction(SIGCHLD, &sa, NULL);   
  if (err < 0) {
    ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
  }
}

SetSigChldHandler定義了信號(hào)處理函數(shù)SigChldHandler呜笑,當(dāng)信號(hào)SIGCHLD到來的時(shí)候,會(huì)進(jìn)入信號(hào)處理函數(shù)彻犁。
看看信號(hào)處理函數(shù)SigChldHandler叫胁,可以看到如果子進(jìn)程SystemServer掛了,Zygote就會(huì)自殺袖裕。從而完成了共存亡的光輝使命

static void SigChldHandler(int /*signal_number*/) {
  pid_t pid;
  int status;
 //Zygote監(jiān)聽所有子進(jìn)程的存亡
  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
 //某一個(gè)子進(jìn)程掛了
 if (WIFSIGNALED(status)) {
      if (WTERMSIG(status) != SIGKILL) {
        ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status));
      }
    }
   //如果掛掉的是SystemServer
    if (pid == gSystemServerPid) {
      ALOGE("Exit zygote because system server (%d) has terminated", pid);
      kill(getpid(), SIGKILL);   //Zygote自殺
    }
  }

}

總結(jié)

1.System_Server采用拋出異常和捕捉異常的方式啟動(dòng),可以清除進(jìn)程的堆棧溉瓶,減少內(nèi)存占用急鳄。
2.System_Server與Zygote共存亡是通過父進(jìn)程調(diào)用waitpid的方式監(jiān)聽子進(jìn)程System_Server的死亡,當(dāng)子進(jìn)程死亡的時(shí)候堰酿,父進(jìn)程就自殺

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疾宏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子触创,更是在濱河造成了極大的恐慌坎藐,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哼绑,死亡現(xiàn)場(chǎng)離奇詭異岩馍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)抖韩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門蛀恩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人茂浮,你說我怎么就攤上這事双谆。” “怎么了席揽?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵顽馋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我幌羞,道長(zhǎng)寸谜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任属桦,我火速辦了婚禮程帕,結(jié)果婚禮上住练,老公的妹妹穿的比我還像新娘。我一直安慰自己愁拭,他們只是感情好讲逛,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著岭埠,像睡著了一般盏混。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惜论,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天许赃,我揣著相機(jī)與錄音,去河邊找鬼馆类。 笑死混聊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的乾巧。 我是一名探鬼主播句喜,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼沟于!你這毒婦竟也來了咳胃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤旷太,失蹤者是張志新(化名)和其女友劉穎展懈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體供璧,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡存崖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了睡毒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片金句。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖吕嘀,靈堂內(nèi)的尸體忽然破棺而出违寞,到底是詐尸還是另有隱情,我是刑警寧澤偶房,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布趁曼,位于F島的核電站,受9級(jí)特大地震影響棕洋,放射性物質(zhì)發(fā)生泄漏挡闰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望摄悯。 院中可真熱鬧赞季,春花似錦、人聲如沸奢驯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘪阁。三九已至撒遣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間管跺,已是汗流浹背义黎。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豁跑,地道東北人廉涕。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像艇拍,于是被迫代替她去往敵國(guó)和親狐蜕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

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