Android系统的开机画面显示过程分析(8)
生活随笔
收集整理的這篇文章主要介紹了
Android系统的开机画面显示过程分析(8)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
??? ?3. 第三個(gè)開機(jī)畫面的顯示過程 ?? ? ? ?第三個(gè)開機(jī)畫面是由應(yīng)用程序bootanimation來負(fù)責(zé)顯示的。應(yīng)用程序bootanimation在啟動腳本init.rc中被配置成了一個(gè)服務(wù),如下所示: service?bootanim?/system/bin/bootanimation?? ????user?graphics?? ????group?graphics?? ????disabled?? ????oneshot?? ?? ? ? 應(yīng)用程序bootanimation的用戶和用戶組名稱分別被設(shè)置為graphics。注意,?用來啟動應(yīng)用程序bootanimation的服務(wù)是disable的,即init進(jìn)程在啟動的時(shí)候,不會主動將應(yīng)用程序bootanimation啟動起來。當(dāng)SurfaceFlinger服務(wù)啟動的時(shí)候,它會通過修改系統(tǒng)屬性ctl.start的值來通知init進(jìn)程啟動應(yīng)用程序bootanimation,以便可以顯示第三個(gè)開機(jī)畫面,而當(dāng)System進(jìn)程將系統(tǒng)中的關(guān)鍵服務(wù)都啟動起來之后,ActivityManagerService服務(wù)就會通知SurfaceFlinger服務(wù)來修改系統(tǒng)屬性ctl.stop的值,以便可以通知init進(jìn)程停止執(zhí)行應(yīng)用程序bootanimation,即停止顯示第三個(gè)開機(jī)畫面。接下來我們就分別分析第三個(gè)開機(jī)畫面的顯示過程和停止過程。 ?? ? ?從前面Android系統(tǒng)進(jìn)程Zygote啟動過程的源代碼分析一文可以知道,Zygote進(jìn)程在啟動的過程中,會將System進(jìn)程啟動起來,而從前面Android應(yīng)用程序安裝過程源代碼分析一文又可以知道,System進(jìn)程在啟動的過程(Step 3)中,會調(diào)用SurfaceFlinger類的靜態(tài)成員函數(shù)instantiate來啟動SurfaceFlinger服務(wù)。Sytem進(jìn)程在啟動SurfaceFlinger服務(wù)的過程中,首先會創(chuàng)建一個(gè)SurfaceFlinger實(shí)例,然后再將這個(gè)實(shí)例注冊到Service Manager中去。在注冊的過程,前面創(chuàng)建的SurfaceFlinger實(shí)例會被一個(gè)sp指針引用。從前面Android系統(tǒng)的智能指針(輕量級指針、強(qiáng)指針和弱指針)的實(shí)現(xiàn)原理分析一文可以知道,當(dāng)一個(gè)對象第一次被智能指針引用的時(shí)候,這個(gè)對象的成員函數(shù)onFirstRef就會被調(diào)用。由于SurfaceFlinger重寫了父類RefBase的成員函數(shù)onFirstRef,因此,在注冊SurfaceFlinger服務(wù)的過程中,將會調(diào)用SurfaceFlinger類的成員函數(shù)onFirstRef。在調(diào)用的過程,就會創(chuàng)建一個(gè)線程來啟動第三個(gè)開機(jī)畫面。 ?? ? ??SurfaceFlinger類實(shí)現(xiàn)在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp 中,它的成員函數(shù)onFirstRef的實(shí)現(xiàn)如下所示: void?SurfaceFlinger::onFirstRef()?? {?? ????run("SurfaceFlinger",?PRIORITY_URGENT_DISPLAY);?? ?? ????//?Wait?for?the?main?thread?to?be?done?with?its?initialization?? ????mReadyToRunBarrier.wait();?? }?? ?? ? ? ?SurfaceFlinger類繼承了Thread類,當(dāng)它的成員函數(shù)run被調(diào)用的時(shí)候,系統(tǒng)就會創(chuàng)建一個(gè)新的線程。這個(gè)線程在第一次運(yùn)行之前,會調(diào)用SurfaceFlinger類的成員函數(shù)readyToRun來通知SurfaceFlinger,它準(zhǔn)備就緒了。當(dāng)這個(gè)線程準(zhǔn)備就緒之后,它就會循環(huán)執(zhí)行SurfaceFlinger類的成員函數(shù)threadLoop,直到這個(gè)成員函數(shù)的返回值等于false為止。 ?? ? ? ?注意,SurfaceFlinger類的成員函數(shù)onFirstRef是在System進(jìn)程的主線程中調(diào)用的,它需要等待前面創(chuàng)建的線程準(zhǔn)備就緒之后,再繼續(xù)往前執(zhí)行,這個(gè)通過調(diào)用SurfaceFlinger類的成員變量mReadytoRunBarrier所描述的一個(gè)Barrier對象的成員函數(shù)wait來實(shí)現(xiàn)的。每一個(gè)Barrier對象內(nèi)問都封裝了一個(gè)條件變量(Condition Variable),而條件變量是用來同步線程的。 ?? ? ? ?接下來,我們繼續(xù)分析SurfaceFlinger類的成員函數(shù)readyToRun的實(shí)現(xiàn),如下所示: status_t?SurfaceFlinger::readyToRun()?? {?? ????LOGI(???"SurfaceFlinger's?main?thread?ready?to?run.?"?? ????????????"Initializing?graphics?H/W...");?? ?????? ????......?? ?? ????mReadyToRunBarrier.open();?? ?? ????/*? ?????*??We're?now?ready?to?accept?clients...? ?????*/?? ?? ????//?start?boot?animation?? ????property_set("ctl.start",?"bootanim");?? ?? ????return?NO_ERROR;?? }??
?? ? ? 前面創(chuàng)建的線程用作SurfaceFlinger的主線程。這個(gè)線程在啟動的時(shí)候,會對設(shè)備主屏幕以及OpenGL庫進(jìn)行初始化。初始化完成之后,接著就會調(diào)用SurfaceFlinger類的成員變量mReadyToRunBarrier所描述的一個(gè)Barrier對象的成員函數(shù)open來喚醒System進(jìn)程的主線程,以便它可以繼續(xù)往前執(zhí)行。最后,SurfaceFlinger類的成員函數(shù)readyToRun的成員函數(shù)會調(diào)用函數(shù)property_set來將系統(tǒng)屬性“ctl.start”的值設(shè)置為“bootanim”,表示要將應(yīng)用程序bootanimation啟動起來,以便可以顯示第三個(gè)開機(jī)畫面。 ?? ? ? 前面在介紹第二個(gè)開機(jī)畫面的時(shí)候提到,當(dāng)系統(tǒng)屬性發(fā)生改變時(shí),init進(jìn)程就會接收到一個(gè)系統(tǒng)屬性變化通知,這個(gè)通知最終是由在init進(jìn)程中的函數(shù)handle_property_set_fd來處理的。 ?? ? ? 函數(shù)handle_property_set_fd實(shí)現(xiàn)在文件system/core/init/property_service.c中,如下所示: void?handle_property_set_fd()?? {?? ????prop_msg?msg;?? ????int?s;?? ????int?r;?? ????int?res;?? ????struct?ucred?cr;?? ????struct?sockaddr_un?addr;?? ????socklen_t?addr_size?=?sizeof(addr);?? ????socklen_t?cr_size?=?sizeof(cr);?? ?? ????if?((s?=?accept(property_set_fd,?(struct?sockaddr?*)?&addr,?&addr_size))?<?0)?{?? ????????return;?? ????}?? ?? ????/*?Check?socket?options?here?*/?? ????if?(getsockopt(s,?SOL_SOCKET,?SO_PEERCRED,?&cr,?&cr_size)?<?0)?{?? ????????close(s);?? ????????ERROR("Unable?to?recieve?socket?options\n");?? ????????return;?? ????}?? ?? ????r?=?recv(s,?&msg,?sizeof(msg),?0);?? ????close(s);?? ????if(r?!=?sizeof(prop_msg))?{?? ????????ERROR("sys_prop:?mis-match?msg?size?recieved:?%d?expected:?%d\n",?? ??????????????r,?sizeof(prop_msg));?? ????????return;?? ????}?? ?? ????switch(msg.cmd)?{?? ????case?PROP_MSG_SETPROP:?? ????????msg.name[PROP_NAME_MAX-1]?=?0;?? ????????msg.value[PROP_VALUE_MAX-1]?=?0;?? ?? ????????if(memcmp(msg.name,"ctl.",4)?==?0)?{?? ????????????if?(check_control_perms(msg.value,?cr.uid,?cr.gid))?{?? ????????????????handle_control_message((char*)?msg.name?+?4,?(char*)?msg.value);?? ????????????}?else?{?? ????????????????ERROR("sys_prop:?Unable?to?%s?service?ctl?[%s]?uid:?%d?pid:%d\n",?? ????????????????????????msg.name?+?4,?msg.value,?cr.uid,?cr.pid);?? ????????????}?? ????????}?else?{?? ????????????if?(check_perms(msg.name,?cr.uid,?cr.gid))?{?? ????????????????property_set((char*)?msg.name,?(char*)?msg.value);?? ????????????}?else?{?? ????????????????ERROR("sys_prop:?permission?denied?uid:%d??name:%s\n",?? ??????????????????????cr.uid,?msg.name);?? ????????????}?? ????????}?? ????????break;?? ?? ????default:?? ????????break;?? ????}?? }??
?? ? ? ?init進(jìn)程是通過一個(gè)socket來接收系統(tǒng)屬性變化事件的。每一個(gè)系統(tǒng)屬性變化事件的內(nèi)容都是通過一個(gè)prop_msg對象來描述的。在prop_msg對象對,成員變量name用來描述發(fā)生變化的系統(tǒng)屬性的名稱,而成員變量value用來描述發(fā)生變化的系統(tǒng)屬性的值。系統(tǒng)屬性分為兩種類型,一種是普通類型的系統(tǒng)屬性,另一種是控制類型的系統(tǒng)屬性(屬性名稱以“ctl.”開頭)。控制類型的系統(tǒng)屬性在發(fā)生變化時(shí),會觸發(fā)init進(jìn)程執(zhí)行一個(gè)命令,而普通類型的系統(tǒng)屬性就不具有這個(gè)特性。注意,改變系統(tǒng)屬性是需要權(quán)限,因此,函數(shù)handle_property_set_fd在處理一個(gè)系統(tǒng)屬性變化事件之前,首先會檢查修改系統(tǒng)屬性的進(jìn)程是否具有相應(yīng)的權(quán)限,這是通過調(diào)用函數(shù)check_control_perms或者check_perms來實(shí)現(xiàn)的。 ?? ? ? ?從前面的調(diào)用過程可以知道,當(dāng)前發(fā)生變化的系統(tǒng)屬性的名稱為“ctl.start”,它的值被設(shè)置為“bootanim”。由于這是一個(gè)控制類型的系統(tǒng)屬性,因此,在通過了權(quán)限檢查之后,另外一個(gè)函數(shù)handle_control_message就會被調(diào)用,以便可以執(zhí)行一個(gè)名稱為“bootanim”的命令。
本文轉(zhuǎn)自 Luoshengyang 51CTO博客,原文鏈接:http://blog.51cto.com/shyluo/967040,如需轉(zhuǎn)載請自行聯(lián)系原作者
?? ? ? 前面創(chuàng)建的線程用作SurfaceFlinger的主線程。這個(gè)線程在啟動的時(shí)候,會對設(shè)備主屏幕以及OpenGL庫進(jìn)行初始化。初始化完成之后,接著就會調(diào)用SurfaceFlinger類的成員變量mReadyToRunBarrier所描述的一個(gè)Barrier對象的成員函數(shù)open來喚醒System進(jìn)程的主線程,以便它可以繼續(xù)往前執(zhí)行。最后,SurfaceFlinger類的成員函數(shù)readyToRun的成員函數(shù)會調(diào)用函數(shù)property_set來將系統(tǒng)屬性“ctl.start”的值設(shè)置為“bootanim”,表示要將應(yīng)用程序bootanimation啟動起來,以便可以顯示第三個(gè)開機(jī)畫面。 ?? ? ? 前面在介紹第二個(gè)開機(jī)畫面的時(shí)候提到,當(dāng)系統(tǒng)屬性發(fā)生改變時(shí),init進(jìn)程就會接收到一個(gè)系統(tǒng)屬性變化通知,這個(gè)通知最終是由在init進(jìn)程中的函數(shù)handle_property_set_fd來處理的。 ?? ? ? 函數(shù)handle_property_set_fd實(shí)現(xiàn)在文件system/core/init/property_service.c中,如下所示:
?? ? ? ?init進(jìn)程是通過一個(gè)socket來接收系統(tǒng)屬性變化事件的。每一個(gè)系統(tǒng)屬性變化事件的內(nèi)容都是通過一個(gè)prop_msg對象來描述的。在prop_msg對象對,成員變量name用來描述發(fā)生變化的系統(tǒng)屬性的名稱,而成員變量value用來描述發(fā)生變化的系統(tǒng)屬性的值。系統(tǒng)屬性分為兩種類型,一種是普通類型的系統(tǒng)屬性,另一種是控制類型的系統(tǒng)屬性(屬性名稱以“ctl.”開頭)。控制類型的系統(tǒng)屬性在發(fā)生變化時(shí),會觸發(fā)init進(jìn)程執(zhí)行一個(gè)命令,而普通類型的系統(tǒng)屬性就不具有這個(gè)特性。注意,改變系統(tǒng)屬性是需要權(quán)限,因此,函數(shù)handle_property_set_fd在處理一個(gè)系統(tǒng)屬性變化事件之前,首先會檢查修改系統(tǒng)屬性的進(jìn)程是否具有相應(yīng)的權(quán)限,這是通過調(diào)用函數(shù)check_control_perms或者check_perms來實(shí)現(xiàn)的。 ?? ? ? ?從前面的調(diào)用過程可以知道,當(dāng)前發(fā)生變化的系統(tǒng)屬性的名稱為“ctl.start”,它的值被設(shè)置為“bootanim”。由于這是一個(gè)控制類型的系統(tǒng)屬性,因此,在通過了權(quán)限檢查之后,另外一個(gè)函數(shù)handle_control_message就會被調(diào)用,以便可以執(zhí)行一個(gè)名稱為“bootanim”的命令。
本文轉(zhuǎn)自 Luoshengyang 51CTO博客,原文鏈接:http://blog.51cto.com/shyluo/967040,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的Android系统的开机画面显示过程分析(8)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jq localStorage
- 下一篇: Android GridView Lru