Android架構縱橫談之——軟體自愈能力 (2)

來源:互聯網
上載者:User

特別聲明:本系列文章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的看門狗。欲知後事如何,請聽下回分解。

謹以本回,獻給全天下的有情人,願有情人終成眷屬。對金錢與物質的無限度的追求,讓我們迷失了方向,而真正的幸福,是與你的愛人平凡的終生相守。

 

相思似海深,舊事如天遠。
淚滴千千萬萬行,更使人、愁腸斷。
要見無因見,拚了終難拚。
若是前生未有緣,待重結、來生願。

——宋寶華

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.