特別聲明:本系列文章LiAnLab.org著作權所有,轉載請註明出處。by @宋寶華Barry
上回書我們說到Android裡的init會監測init.rc中啟動的service並根據情況重啟之。今回書我們說Android中生死與共的Zygote和SystemServer。
第二隻狗:忠犬八公
方今之世,正道不昌,邪魔叢生。撞傷不如撞死,因此各種難以理解之行為層出不窮,撞後用天涯明月刀殺人者有之,撞後人民女教師裸體阻救援者有之,這是怎樣地一種非人間的濃厚的悲涼?對人生命權的尊重實為最基礎之人性,殘殺同類,見死阻救,實為喪失最基礎之人性。熱淚在心中,匯成河流。我們曾經以無限崇高的主義,無比正義的革命的名義殺人,肆意踐踏人最基本的尊嚴,而悲劇的後果是,熱血已成過去,激情亦然淡去,主義仍如浩渺 ,人性卻遭淪喪。
人性已泯,狗性依然,如太平洋的風。本回書,我們說第二隻狗,忠犬八公。1925年5月,八公的主人上野因病猝然去世,然而八公犬並不懂人事,依然每天到澀穀站去等候主人的歸來。直到最後死去。1935年3月,八公因患絲蟲性象皮病而死亡。十年生死兩茫茫,不思量,自難忘。所謂愛者,大抵如此。在這個小三流行的世界,什麼樣的人還珍視婚姻的責任和當初的誓言?
本回書我們要談的是Zygote和SystemServer的生死與共,執子之手,與子偕老,Zygote和SystemServer用全部的生命來演繹這段忠貞的愛情,當死去時,與子成蝶,如果有來生,我們還在一起。
Zygote是Android系統的核心,受精卵的意思,Android framework大家族的祖先。她的媽貴姓呢?就是上回書裡說的init。Zygote是Java世界的生產者,Android的女媧,她通過runSelectLoopMode()不斷監聽來自應用程式的透過ActivityManagerService的啟動需求,並fork出相應的進程。而SystemServer是Android世界裡的核心價值,SurfaceFlinger以及Java服務如PowerManagerService、 WindowManagerService、ActivityManagerService等都是他啟動的,並成為他的一部分,他帶的嗷嗷叫的兵,共同運行於SystemServer進程空間。可以說,SystemServer的崩潰基本意味著Android的Framework的崩潰。SystemServer是Android裡兵馬大元帥。基本上,在Android的世界裡,能與SystemServer和Zygote彼此相配的,也就只有對方。那麼SystemServer百戰而死後,Zygote應該是萬念俱灰,其實真地沒有活著的必要。
在Android中,SystemServer是由 Zygote分叉出來的,相關代碼位於dalvik/vm/native/dalvik_system_Zygote.c中:
static void Dalvik_dalvik_system_Zygote_forkSystemServer( const u4* args, JValue* pResult){ pid_t pid; pid = forkAndSpecializeCommon(args, true); /* The zygote process checks whether the child process has died or not. */ if (pid > 0) { int status; LOGI("System server process %d has been created", pid); gDvm.systemServerPid = pid; /* There is a slight window that the system server process has crashed * but it went unnoticed because we haven't published its pid yet. So * we recheck here just to make sure that all is well. */ if (waitpid(pid, &status, WNOHANG) == pid) { LOGE("System server process %d has died. Restarting Zygote!", pid); kill(getpid(), SIGKILL); } } RETURN_INT(pid);}
其中的forkAndSpecializeCommon()會fork出SystemServer,Zygote馬上用waitpid(pid, &status,WNOHANG)等待SystemServer的死亡,注意其中的參數為WNOHANG,意思就是說等不等地到SystemServer退出,waitpid()都不會阻塞,如果發現SystemServer死了,它會無條件調用kill(getpid(), SIGKILL)殉情。這個瞬間的等待按照注釋是為了防止很小的一段時間視窗裡,真正等SystemServer死的代碼還沒注意到SystemServer的PID。SIGKILL牛就牛在是不能被忽略的訊號,這點和CTRL+C對應的SIGINT不同。
有些同學就要問了,一個進程莫名其妙地kill掉了自己,有時候我們還強行用kill命令去殺死Linux的進程,這個時候它原本申請的記憶體什麼的,不是泄露了嗎?譬如我malloc了一些記憶體,你殺死我的時候我還沒free,這些記憶體不是側露了嗎?我已經反覆在各個公司演講的時候說了,記憶體泄露分為兩種境界,一個是人死了,錢還沒花完,你malloc的記憶體還沒釋放進程就死了,我們說,這個問題在Linux不存在,進程是個資源封裝的單位,進程掛的時候,資源會被核心釋放掉的,死的時候還僅僅有個殭屍而已。第二個境界是,人活著,錢沒了,這個問題才是Linux真正擔心的,一個多線程的程式,運行過程中反覆申請和釋放記憶體,但是釋放的與申請的不對應,就慢慢地吃記憶體,這個進程的記憶體消耗曲線振蕩上升,直到耗盡記憶體。所以,在Linux世界裡,我們不用擔心人死了,錢還沒花完的問題
,黨會幫我們處理的。我們要擔心的是,人活著,錢沒了的問題。
話說HTC Android手機號稱的1秒快速啟動,根據我們的跟蹤就是關機時候殺進程,然後suspend,之後resume回來,由於前面進程都殺了,所以你看到個乾淨的案頭。所以,神馬都是浮雲啊。你收回了黃岩島,油價還是要漲的,他們會說我們是花了錢收回來的。
廢話少說,你剛才還說Zygote和SystemServer 生死與共,怎麼就才等了一下呢?不是要負責一輩子的嗎?我們回到forkAndSpecializeCommon(),繼續挖掘:
static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer){ … setSignalHandler(); dvmDumpLoaderStats("zygote"); pid = fork(); if (pid == 0) { int err; /* The child process */ … } return pid;}
其中的setSignalHandler()會設定SIGCHLD的訊號處理函數,而這個訊號處理函數就會判斷是否SystemServer死了,如果是,就自殺殉情:
static void setSignalHandler(){ int err; struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigchldHandler; err = sigaction (SIGCHLD, &sa, NULL); if (err < 0) { LOGW("Error setting SIGCHLD handler: %s", strerror(errno)); }}static void sigchldHandler(int s){ pid_t pid; int status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { … /* * If the just-crashed process is the system_server, bring down zygote * so that it is restarted by init and system server will be restarted * from there. */ if (pid == gDvm.systemServerPid) { LOG(LOG_INFO, ZYGOTE_LOG_TAG, "Exit zygote because system server (%d) has terminated\n", (int) pid); kill(getpid(), SIGKILL); } } …}
當SystemServer死去,Zygote的花轎在它墳前路過,見Zygote走出轎來,脫去紅裝,一身素服,緩緩地走到墳前, 跪下來放聲大哭,霎時間風雨飄搖,雷聲大作,“轟”的一聲,墳墓裂開了,Zygote似乎又見到了SystemServer那溫柔的面龐,她微笑著縱身跳了進去。接著又是一聲巨響,墳墓合上了。這時風消雲散,雨過天晴,各種野花在風中輕柔地搖曳,一對美麗的蝴蝶從墳頭飛出來,在陽光下自由地翩翩起舞。
當Zygote也死去,由於Zygote是有戶口的,上回書中的第一隻狗, 肩負其使命,會重啟Zygote,於是SystemServer也隨Zygote重啟,生生世世不分離。
這裡要特別說明的是,當zygote死去的時候,上回書中的init中的wait_for_one_process()會透過給 “- zygote_pid”發SIGKILL,從而殺死Zygote對應的進程組,因此整個Java世界都宣告結束:
static int wait_for_one_process(int block){ ... while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR ); ... if (!(svc->flags & SVC_ONESHOT)) { kill(-pid, SIGKILL); NOTICE("process '%s' killing any children in process group\n", svc->name); } ...}
由於幾乎所有的Java應用都依賴於SystemServer中的service,如果SystemServer崩潰,Zygote不死並且不導致整個Java世界死亡,實際上系統沒有任何辦法把狀態恢複到SystemServer崩潰之前的狀態 ,那麼各個apk所看到的SystemServer中各個service的狀態也無法恢複,所以整個Java世界死亡並重啟就成為唯一的選擇。
本回書就說到這裡,下回書我們說SystemServer的看門狗。欲知後事如何,請聽下回分解。
謹以本回,獻給全天下的有情人,願有情人終成眷屬。對金錢與物質的無限度的追求,讓我們迷失了方向,而真正的幸福,是與你的愛人平凡的終生相守。
相思似海深,舊事如天遠。
淚滴千千萬萬行,更使人、愁腸斷。
要見無因見,拚了終難拚。
若是前生未有緣,待重結、來生願。
——宋寶華