Android啟動過程詳解(4)——SystemServer

上一篇博客介紹了ZygoteService的啟動過程示姿,在Zygote的啟動后首先就會啟動SystemServer栈戳,所以SystemServer可以看做是Zygote嫡長子览露。能夠成為嫡長子的必然有著非常重要的作用荧琼,的確是這樣,Android應(yīng)用框架中的各種Service,例如ActivityManagerService命锄,PacakgeManagerService堰乔,WindowManagerService等等重要的系統(tǒng)服務(wù)都是在SystemServer中啟動的。這篇博客我們就來看看SystemServer的啟動過程脐恩。

1.SystemServer啟動

SystemServer是通過Zygote.startSystemServer來啟動的镐侯,所以首先來看看對應(yīng)的代碼,其對應(yīng)的實現(xiàn)在dalvik_system_Zygote.c中,這是一個native函數(shù):

[-->dalvik_system_Zygote.c]
static voidDalvik_dalvik_system_Zygote_forkSystemServer(
                        const u4* args, JValue* pResult)
{
     pid_tpid;
    //根據(jù)參數(shù)驶冒,fork一個子進程
    pid =forkAndSpecializeCommon(args);

    if (pid > 0) {
       int status;
       gDvm.systemServerPid = pid;//保存system_server的進程id
      //函數(shù)退出前須先檢查剛創(chuàng)建的子進程是否退出了。
        if(waitpid(pid, &status, WNOHANG) == pid) {
           //如果system_server退出了骗污,Zygote直接干掉了自己
           //看來Zygote和SS的關(guān)系異常緊密崇猫,簡直是生死與共!
            kill(getpid(), SIGKILL);
        }
    }
   RETURN_INT(pid);
}

通過上面的代碼可以看出需忿,Zygote會fork出一個進程作為SystemServer的宿主诅炉,具體的操作是在forkAndSpecializeCommon中完成。在完成創(chuàng)建SystemServer的進程之后屋厘,Zygote會檢查其對應(yīng)的進程是否退出涕烧,如果退出了,Zygote也會殺死自己汗洒。
下面议纯,再看看forkAndSpecializeCommon,代碼如下所示:

[-->dalvik_system_Zygote.c]
static pid_t forkAndSpecializeCommon(const u4*args)
{
    pid_tpid;
    uid_tuid = (uid_t) args[0];
    gid_tgid = (gid_t) args[1];
   ArrayObject* gids = (ArrayObject *)args[2];
    u4debugFlags = args[3];
   ArrayObject *rlimits = (ArrayObject *)args[4];

   //設(shè)置信號處理溢谤,待會兒要看看這個函數(shù)瞻凤。  
   setSignalHandler();     
    pid =fork(); //fork子進程
   if (pid== 0) {
     //對子進程要根據(jù)傳入的參數(shù)做一些處理,例如設(shè)置進程名溯香,設(shè)置各種id(用戶id鲫构,組id等)
   }
......
}

最后看看setSignalHandler函數(shù),它由Zygote在fork子進程前調(diào)用玫坛,代碼如下所示:

[-->dalvik_system_Zygote.c]
static void setSignalHandler()
{
    interr;
    structsigaction sa;
   memset(&sa, 0, sizeof(sa));
   sa.sa_handler = sigchldHandler;
    err =sigaction (SIGCHLD, &sa, NULL);//設(shè)置信號處理函數(shù)结笨,該信號是子進程死亡的信號
}

直接看這個信號處理函數(shù)sigchldHandler

static void sigchldHandler(int s)
{
    pid_tpid;
    intstatus;

    while((pid = waitpid(-1, &status, WNOHANG)) > 0) {
             } else if (WIFSIGNALED(status)) {
          }
        }
        //如果死去的子進程是SS,則Zygote把自己也干掉了湿镀,這樣就做到了生死與共炕吸!
        if(pid == gDvm.systemServerPid) {
           kill(getpid(), SIGKILL);
        }
   }

2.SystemServer的作用

接下來看看SystemServer在啟動的過程中具體做了些什么。

pid =Zygote.forkSystemServer();
     if(pid == 0) { //子進程處理邏輯:
           handleSystemServerProcess(parsedArgs);
    }

從代碼中可以看到勉痴,當(dāng)SystemServer被fork出來之后赫模,會調(diào)用handleSystemServerProcess來處理自身的啟動邏輯。

[-->ZygoteInit.java]
private static void handleSystemServerProcess(
       ZygoteConnection.ArgumentsparsedArgs)
      throws ZygoteInit.MethodAndArgsCaller {
      //關(guān)閉從Zygote那里繼承下來的Socket蒸矛。 
      closeServerSocket();
      //設(shè)置SS進程的一些參數(shù)瀑罗。
      setCapabilities(parsedArgs.permittedCapabilities,
                   parsedArgs.effectiveCapabilities);
        //調(diào)用ZygoteInit函數(shù)胸嘴。
      RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
  }

好了,SS走到RuntimeInit了斩祭,它的代碼在RuntimeInit.java中劣像,如下所示:

[-->RuntimeInit.java]
public static final void zygoteInit(String[]argv)
           throws ZygoteInit.MethodAndArgsCaller {
     //做一些常規(guī)初始化
     commonInit();
     //①native層的初始化。
    zygoteInitNative();
     intcurArg = 0;
     for (/* curArg */ ; curArg < argv.length; curArg++) {
           String arg = argv[curArg];
           if (arg.equals("--")) {
               curArg++;
               break;
           } else if (!arg.startsWith("--")) {
               break;
           } else if (arg.startsWith("--nice-name=")) {
               String niceName = arg.substring(arg.indexOf('=') + 1);
               //設(shè)置進程名為niceName摧玫,也就是"system_server"
               Process.setArgV0(niceName);
           }
        }
       //startClass名為"com.android.server.SystemServer"
       String startClass = argv[curArg++];
       String[] startArgs = new String[argv.length - curArg];
       System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);
       //②調(diào)用startClass耳奕,也就是com.android.server.SystemServer類的main函數(shù)。
       invokeStaticMain(startClass, startArgs);
}

上面的代碼有兩個地方比較重要:

  • zygoteInitNative诬像,執(zhí)行native層的初始化
  • invokeStaticMain(startClass, startArgs):執(zhí)行SystemServer的main函數(shù)屋群。
    接下來分別講一下以上兩點:

2.1 zygoteInitNative

該函數(shù)最終會調(diào)用AppMain的onZygoteInit函數(shù):

[-->App_main.cpp]
   virtual void onZygoteInit()
    {
        //下面這些東西和Binder有關(guān)系
       sp<ProcessState> proc = ProcessState::self();
        if(proc->supportsProcesses()) {
            proc->startThreadPool();//啟動一個線程,用于Binder通信坏挠。
       }      
}

2.2 invokeStaticMain

[-->RuntimeInit.java]
private static void invokeStaticMain(StringclassName, String[] argv)
           throws ZygoteInit.MethodAndArgsCaller {
      ......
      //className為"com.android.server.SystemServer"
       Class<?> cl;
       
       try {
           cl = Class.forName(className);
        }catch (ClassNotFoundException ex) {
           throw new RuntimeException(
                    "Missing class wheninvoking static main " + className,
                    ex);
        }

       Method m;
       try {
           //找到com.android.server.SystemServer類的main函數(shù)芍躏,肯定有地方要調(diào)用它
           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))) {
           ......
        }
        //拋出一個異常
       throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }

這個函數(shù)比較奇怪的一點是,在加載到com.android.server.SystemServer類以及找到其對應(yīng)的main函數(shù)之后癞揉,并沒有直接啟動該函數(shù)纸肉,而是拋出了一個異常溺欧,這個異常會在ZygoteInit的main函數(shù)中catch喊熟,然后才啟動對應(yīng)的面函數(shù)。這樣做的原因是為了清空堆棧姐刁,讓用戶看到堆棧的棧頂是ZygoteInit.main芥牌。

接下來再來看看Zygote在啟動后都干了些什么,首先來看看main函數(shù):

[-->SystemServer.java]
public static void main(String[] args) {
   ......
   //加載libandroid_servers.so
   System.loadLibrary("android_servers");
   //調(diào)用native的init1函數(shù)聂使。
   init1(args);
}

所以啟動過程轉(zhuǎn)移到了init1函數(shù)中:
init1是native函數(shù)壁拉,在com_android_server_SystemServer.cpp中實現(xiàn):

[-->com_android_server_SystemServer.cpp]
extern "C" int system_init();
static voidandroid_server_SystemServer_init1(JNIEnv* env, jobject clazz)
{
   system_init();//調(diào)用另外一個函數(shù)。
}

system_init的實現(xiàn)在system_init.cpp中柏靶,它的代碼如下所示:

[-->system_init.cpp]
extern "C" status_t system_init()
{
   //下面這些調(diào)用和Binder有關(guān)弃理,我們會在第6章中講述,這里先不必管它屎蜓。
   sp<ProcessState> proc(ProcessState::self());
   sp<IServiceManager> sm = defaultServiceManager();
   sp<GrimReaper>grim = new GrimReaper();
   sm->asBinder()->linkToDeath(grim, grim.get(), 0);
   charpropBuf[PROPERTY_VALUE_MAX];
   property_get("system_init.startsurfaceflinger", propBuf,"1");

    if(strcmp(propBuf, "1") == 0) {
        //SurfaceFlinger服務(wù)在system_server進程創(chuàng)建
       SurfaceFlinger::instantiate();
    }
     ......

    //調(diào)用com.android.server.SystemServer類的init2函數(shù)
   AndroidRuntime* runtime =   AndroidRuntime::getRuntime();
   runtime->callStatic("com/android/server/SystemServer","init2");

//下面這幾個函數(shù)調(diào)用和Binder通信有關(guān)痘昌。

    if (proc->supportsProcesses()) {
        ProcessState::self()->startThreadPool();
       //調(diào)用joinThreadPool后,當(dāng)前線程也加入到Binder通信的大潮中
       IPCThreadState::self()->joinThreadPool();
       }
    returnNO_ERROR;
}

init1函數(shù)創(chuàng)建了一些系統(tǒng)服務(wù)炬转,然后把調(diào)用線程加入Binder通信中辆苔。不過其間還通過JNI調(diào)用了com.android.server.SystemServer類的init2函數(shù),下面就來看看這個init2函數(shù)扼劈。init2在Java層驻啤,代碼在SystemServer.java中:

[-->SystemServer.java]
public static final void init2() {
   Threadthr = new ServerThread();
   thr.setName("android.server.ServerThread");
   thr.start();//啟動一個ServerThread
}

啟動了一個ServerThread線程。請直接看它的run函數(shù)荐吵。這個函數(shù)比較長骑冗,大概看看它干了什么即可赊瞬。

[-->SystemServer.java::ServerThread的run函數(shù)]
public void run(){
             ....
  //啟動Entropy Service
  ServiceManager.addService("entropy",new EntropyService());
  //啟動電源管理服務(wù)
  power =new PowerManagerService();
 ServiceManager.addService(Context.POWER_SERVICE, power);
  //啟動電池管理服務(wù)。
  battery= new BatteryService(context);
 ServiceManager.addService("battery", battery);

   //初始化看門狗
   Watchdog.getInstance().init(context,battery, power, alarm,
                               ActivityManagerService.self());

  //啟動WindowManager服務(wù)
  wm =WindowManagerService.main(context, power,
                    factoryTest !=SystemServer.FACTORY_TEST_LOW_LEVEL);
 ServiceManager.addService(Context.WINDOW_SERVICE,wm);         

  //啟動ActivityManager服務(wù)
(ActivityManagerService)ServiceManager.getService("activity")).setWindowManager(wm);
  ......//系統(tǒng)各種重要服務(wù)都在這里啟動

   Looper.loop();  //進行消息循環(huán)贼涩,然后處理消息森逮。關(guān)于這部分內(nèi)容參見第5章。
}

init2函數(shù)比較簡單磁携,就是單獨創(chuàng)建一個線程褒侧,用以啟動系統(tǒng)各項服務(wù)。至此谊迄,SystemServer啟動完畢闷供。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市统诺,隨后出現(xiàn)的幾起案子歪脏,更是在濱河造成了極大的恐慌,老刑警劉巖粮呢,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婿失,死亡現(xiàn)場離奇詭異,居然都是意外死亡啄寡,警方通過查閱死者的電腦和手機豪硅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挺物,“玉大人懒浮,你說我怎么就攤上這事∈短伲” “怎么了砚著?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長痴昧。 經(jīng)常有香客問我稽穆,道長,這世上最難降的妖魔是什么赶撰? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任舌镶,我火速辦了婚禮,結(jié)果婚禮上扣囊,老公的妹妹穿的比我還像新娘乎折。我一直安慰自己,他們只是感情好侵歇,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布骂澄。 她就那樣靜靜地躺著,像睡著了一般惕虑。 火紅的嫁衣襯著肌膚如雪坟冲。 梳的紋絲不亂的頭發(fā)上磨镶,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音健提,去河邊找鬼琳猫。 笑死,一個胖子當(dāng)著我的面吹牛私痹,可吹牛的內(nèi)容都是我干的脐嫂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼紊遵,長吁一口氣:“原來是場噩夢啊……” “哼账千!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起暗膜,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤匀奏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后学搜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體娃善,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冠场。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖咧最,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情御雕,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布滥搭,位于F島的核電站酸纲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瑟匆。R本人自食惡果不足惜闽坡,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望愁溜。 院中可真熱鬧疾嗅,春花似錦、人聲如沸冕象。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽渐扮。三九已至论悴,卻和暖如春掖棉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背膀估。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工幔亥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人察纯。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓帕棉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親饼记。 傳聞我的和親對象是個殘疾皇子笤昨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

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