一. Android系統(tǒng)啟動(dòng)流程是什么杆故?(提示:BootLoader -> Linux內(nèi)核 init進(jìn)程 -> Zygote進(jìn)程 –> SystemServer進(jìn)程 –> 各種系統(tǒng)服務(wù) –> 應(yīng)用進(jìn)程)
Android系統(tǒng)啟動(dòng)的核心流程如下:
- 啟動(dòng)電源以及系統(tǒng)啟動(dòng):當(dāng)電源按下時(shí)引導(dǎo)芯片從預(yù)定義的地方(固化在ROM)開始執(zhí)行越走,加載引導(dǎo)程序BootLoader到RAM蜡娶,然后執(zhí)行,開始拉起Linux OS母廷。
引導(dǎo)程序BootLoader:BootLoader是在Android系統(tǒng)開始運(yùn)行前的一個(gè)小程序斑举,主要用于把系統(tǒng)OS拉起來并運(yùn)行。 - Linux內(nèi)核啟動(dòng):當(dāng)內(nèi)核啟動(dòng)時(shí)脊奋,設(shè)置緩存熬北、被保護(hù)存儲(chǔ)器、計(jì)劃列表诚隙、加載驅(qū)動(dòng)讶隐。當(dāng)其完成系統(tǒng)設(shè)置時(shí),會(huì)先在系統(tǒng)文件中尋找init.rc文件久又,并啟動(dòng)init進(jìn)程巫延。
總結(jié)一下,init進(jìn)程啟動(dòng)后做了哪幾件事:
(1)創(chuàng)建和掛載啟動(dòng)所需要的文件和目錄
(2)初始化和啟動(dòng)屬性服務(wù)地消。
(3)解析init.rc配置文件炉峰,并且啟動(dòng)了Zygote進(jìn)程 - init進(jìn)程啟動(dòng):初始化和啟動(dòng)屬性服務(wù),并且啟動(dòng)Zygote進(jìn)程脉执。
最后再總結(jié)一下Zygote進(jìn)程啟動(dòng)中做了幾件事:
1.創(chuàng)建AndroidRuntime并調(diào)用其start方法疼阔,啟動(dòng)Zygote進(jìn)程。
2.創(chuàng)建Java虛擬機(jī)并為Java虛擬機(jī)注冊(cè)JNI方法。
3.通過JNI調(diào)用ZygoteInit的main函數(shù)進(jìn)入Zygote的java框架層婆廊。
4.通過registerZygoteSocket方法創(chuàng)建服務(wù)端Socket迅细,并通過runSelectLoop方法等待AMS的請(qǐng)求來創(chuàng)建新的應(yīng)用程序進(jìn)程。
5.啟動(dòng)SystemServer否彩。 - Zygote進(jìn)程啟動(dòng):創(chuàng)建JVM并為其注冊(cè)JNI方法疯攒,創(chuàng)建服務(wù)器端Socket,啟動(dòng)SystemServer進(jìn)程列荔。
最后總結(jié)一下SystemServer進(jìn)程:
1.啟動(dòng)Binder線程池
2.創(chuàng)建了SystemServiceManager(用于對(duì)系統(tǒng)服務(wù)進(jìn)行創(chuàng)建敬尺、啟動(dòng)和生命周期管理)
3.啟動(dòng)了各種服務(wù) - SystemServer進(jìn)程啟動(dòng):啟動(dòng)Binder線程池和SystemServiceManager,并且啟動(dòng)各種系統(tǒng)服務(wù)贴浙。
- Launcher啟動(dòng):被SystemServer進(jìn)程啟動(dòng)的AMS會(huì)啟動(dòng)Launcher砂吞,Launcher啟動(dòng)后會(huì)將已安裝應(yīng)用的快捷圖標(biāo)顯示到系統(tǒng)桌面上。
Android系統(tǒng)啟動(dòng)流程之init進(jìn)程啟動(dòng)
Android系統(tǒng)啟動(dòng)流程之Zygote進(jìn)程啟動(dòng)
Android系統(tǒng)啟動(dòng)流程之SystemServer進(jìn)程啟動(dòng)
Android系統(tǒng)啟動(dòng)流程之Launcher進(jìn)程啟動(dòng)
二. APP打包流程
.apk文件
.apk文件其實(shí)就是一個(gè)壓縮文件崎溃,把文件的后綴改成.zip就可以用windows解壓軟件解壓了蜻直,解壓后里面的文件如下:
上圖里面都是什么文件:
lib 文件夾里面存放的是so動(dòng)態(tài)鏈接庫,so動(dòng)態(tài)鏈接庫是不需要在做apk打包時(shí)一系列壓縮處理的袁串。
META-INF 簽名文件夾概而,里面存放三個(gè)文件,有兩個(gè)是對(duì)資源文件做的SHA1 hash處理囱修,一個(gè)是簽名和公鑰證書赎瑰。
res 資源文件夾,里面還會(huì)分animator,anim,color,drawable,layout,menu和raw這幾個(gè)文件夾破镰。
AndroidManifest.xml AndroidManifest.xml 是每個(gè)android程序中必須的文件餐曼。它位于整個(gè)項(xiàng)目的根目錄,描述了package中暴露的組件(activities, services, 等等)鲜漩,他們各自的實(shí)現(xiàn)類源譬,各種能被處理的數(shù)據(jù)和啟動(dòng)位置。 除了能聲明程序中的Activities, ContentProviders, Services, 和Intent Receivers,還能指定permissions和instrumentation(安全控制和測(cè)試)孕似。這個(gè)文件是很重要的踩娘,里面有我們的Android四大組件和申請(qǐng)的權(quán)限。
classes.dex Android平臺(tái)上的可執(zhí)行文件喉祭,Android虛擬機(jī)Dalvik支持的字節(jié)碼文件格式Google在新發(fā)布的Android平臺(tái)上使用了自己的Dalvik虛擬機(jī)來定義养渴, 這種虛擬機(jī)執(zhí)行的并非Java字節(jié)碼, 而是另一種字節(jié)碼: dex格式的字節(jié)碼臂拓。在編譯Java代碼之后,通過Android平臺(tái)上的工具可以將Java字節(jié)碼轉(zhuǎn)換成Dex字節(jié)碼习寸。雖然Google稱Dalvik是為了移動(dòng)設(shè)備定做的胶惰,但是業(yè)界很多人認(rèn)為這是為了規(guī)避向sun申請(qǐng)Javalicense。這個(gè)DalvikVM針對(duì)手機(jī)程式/CPU做過最佳化霞溪,可以同時(shí)執(zhí)行許多VM而不會(huì)占用太多Resource孵滞。classes.dex也是由java的class文件重新編排而來中捆,我們也可以通過反編譯工具把dex文件轉(zhuǎn)換成class文件。如果做了拆包那么會(huì)有classes1.dex坊饶,classes2.dex ...多個(gè)classes.dex文件泄伪。
resources.arsc 這個(gè)文件記錄了所有的應(yīng)用程序資源目錄的信息,包括每一個(gè)資源名稱匿级、類型蟋滴、值、ID以及所配置的維度信息痘绎。我們可以將這個(gè)resources.arsc文件想象成是一個(gè)資源索引表津函,這個(gè)資源索引表在給定資源ID和設(shè)備配置信息的情況下,能夠在應(yīng)用程序的資源目錄中快速地找到最匹配的資源孤页。
打包工具
apk打包的7個(gè)步驟
1尔苦、aapt打包資源文件,生成R.java文件:
使用aapt來打包res資源文件行施,生成R.java允坚、resources.arsc和res文件,R.java文件是所有res資源的id列表,R.java是我們?cè)诰帉懘a的時(shí)候會(huì)用到的鲜侥,我們經(jīng)常R.drawable.icon之類的來引用工程中的資源文件轻猖。
resources.arsc也是清單文件,但是resources.arsc跟R.java區(qū)別是非常大的皿渗,R.java里面只是id值列表,而且里面的id值不重復(fù)轻腺。但是我們drawable-hdpi乐疆、drawable-xdpi或者drawable-xxdpi這些不同分辨率的文件夾存放的圖片的名稱和id是一樣的,在運(yùn)行的時(shí)候是怎么根據(jù)設(shè)備的分辨率來選擇對(duì)應(yīng)分辨率的圖片的呢贬养?這就要靠我們的resources.arsc文件了挤土,resources.arsc里面會(huì)對(duì)所有的資源id進(jìn)行組裝,在apk運(yùn)行時(shí)獲取資源的時(shí)候會(huì)根據(jù)設(shè)備的情況獲得不同的資源误算。
resources.arsc文件的作用就是通過一樣的ID仰美,根據(jù)不同的配置索引到最佳的資源顯示在UI中。
R.java是我們?cè)趯懘a時(shí)候引用res資源的id表儿礼,resources.arsc是程序在運(yùn)行時(shí)候的用到的資源表咖杂。R.java是程序員讀的,resources.arsc是機(jī)器讀的蚊夫!
appt在打包資源文件之前會(huì)檢測(cè)AndroidManifest.xml的合法性诉字,對(duì)res目錄下的資源子目錄進(jìn)行處理,處理的內(nèi)容包括資源文件名的合法性,這就是有時(shí)候?yàn)槭裁次覀兊馁Y源命名有問題的時(shí)候Android Studio會(huì)直接報(bào)錯(cuò)無法編譯壤圃!另外xml文件內(nèi)容都會(huì)被編譯成 二進(jìn)制的陵霉,這也是我們無法直接打開apk解壓后其中的xml文件。
2伍绳、處理aidl文件踊挠,生成相應(yīng)的java文件:
AIDL (Android Interface Definition Language), Android接口定義語言冲杀,Android提供的IPC (Inter Process Communication效床,進(jìn)程間通信)的一種獨(dú)特實(shí)現(xiàn)。這個(gè)階段處理.aidl文件漠趁,生成對(duì)應(yīng)的Java接口文件扁凛。
3、編譯工程源代碼闯传,生成相應(yīng)的class文件:
通過Java Compiler編譯R.java谨朝、Java接口文件、Java源文件甥绿,生成.class文件字币。如果有配置混淆的話,會(huì)編譯成混淆的class文件共缕,方便源代碼被偷看洗出。
4、轉(zhuǎn)換所有的class文件图谷,生成class.dex文件:
Android系統(tǒng)的Dalvik虛擬機(jī)的可執(zhí)行文件為DEX格式翩活,程序運(yùn)行所需的class.dex就是在這一步生成的,使用到的工具為dx便贵,它位于android-sdk\platform-tools目錄下菠镇,dx工具主要的工作是將java字節(jié)碼轉(zhuǎn)換為Dalvik字節(jié)碼、壓縮常量池承璃、消除冗余信息等利耍。
5、打包生成apk文件:
將classes.dex盔粹、resources.arsc隘梨、res文件夾(res/raw資源被原裝不動(dòng)地打包進(jìn)APK之外,其它的資源都會(huì)被編譯或者處理)舷嗡、Other Resources(assets文件夾)轴猎、AndroidManifest.xml打包成apk文件。
友情提示:
res/raw和assets的相同點(diǎn):兩者目錄下的文件在打包后會(huì)原封不動(dòng)的保存在apk包中进萄,不會(huì)被編譯成二進(jìn)制捻脖。
res/raw和assets的不同點(diǎn):
- res/raw中的文件會(huì)被映射到R.java文件中烦秩,訪問的時(shí)候直接使用資源ID即R.id.filename;assets文件夾下的文件不會(huì)被映射到R.java中郎仆,訪問的時(shí)候需要AssetManager類。
- res/raw不可以有目錄結(jié)構(gòu)兜蠕,而assets則可以有目錄結(jié)構(gòu)扰肌,也就是assets目錄下可以再建立文件夾
6、對(duì)apk文件進(jìn)行簽名:
對(duì)apk進(jìn)行簽名熊杨,可以進(jìn)行Debug和Release 簽名曙旭。Debug簽名是Android Studio默認(rèn)的,Release 簽名是需要我們自己配置的晶府。
7桂躏、對(duì)簽名后的apk文件進(jìn)行對(duì)對(duì)齊處理:
release mode 下使用 aipalign進(jìn)行align,即對(duì)簽名后的apk進(jìn)行對(duì)齊處理川陆。
Zipalign是一個(gè)android平臺(tái)上整理APK文件的工具剂习,它對(duì)apk中未壓縮的數(shù)據(jù)進(jìn)行4字節(jié)對(duì)齊,對(duì)齊后就可以使用mmap函數(shù)讀取文件较沪,可以像讀取內(nèi)存一樣對(duì)普通文件進(jìn)行操作鳞绕。如果沒有4字節(jié)對(duì)齊,就必須顯式的讀取尸曼,這樣比較緩慢并且會(huì)耗費(fèi)額外的內(nèi)存们何。
在 Android SDK 中包含一個(gè)名為 “zipalign” 的工具,它能夠?qū)Υ虬蟮?app 進(jìn)行優(yōu)化控轿。 其位于 SDK 的 build-tools 目錄下, 例如: D:\Develop\Android\sdk\build-tools\23.0.2\zipalign.exe
三. APK安裝流程
Apk安裝的四種方式:
1.系統(tǒng)應(yīng)用安裝:沒有安裝界面冤竹,在開機(jī)時(shí)自動(dòng)完成。
2.網(wǎng)絡(luò)下載應(yīng)用安裝: 沒有安裝界面茬射,在應(yīng)用市場(chǎng)完成鹦蠕。
3.ADB命令安裝: 沒有安裝界面,通過命令直接安裝躲株。
4.外部設(shè)備安裝: 有安裝界面片部,通過SD卡等外部設(shè)備安裝,由packageInstaller處理安裝邏輯霜定。
APK安裝涉及到的幾個(gè)常用目錄:
1.system/app : 系統(tǒng)自帶的應(yīng)用程序档悠,獲得root權(quán)限才能刪除。
2.data/app : 用戶程序安裝目錄望浩,安裝時(shí)會(huì)把a(bǔ)pk文件復(fù)制到此目錄下辖所。
3.data/data : 存放應(yīng)用程序的數(shù)據(jù)。
4.data/dalvik-cache : 將apk中的dex文件安裝到該目錄下(dex文件是dalvik虛擬機(jī)的可執(zhí)行文件磨德,大小約為原始apk的四分之一)缘回。
APK安裝的預(yù)備知識(shí)點(diǎn):
(1)PackageManagerService是由SystemServer啟動(dòng)吆视,PMS負(fù)責(zé)應(yīng)用的安裝、卸載酥宴、權(quán)限檢查等工作啦吧;
(2)在/system/app和/data/app目錄下的apk文件,PMS在啟動(dòng)過程中拙寡,都會(huì)掃描安裝授滓;
(3)每次開機(jī)時(shí),PMS都會(huì)在構(gòu)造函數(shù)中對(duì)指定目錄下的apk進(jìn)行掃描肆糕,沒有安裝的apk就會(huì)觸發(fā)安裝般堆;
apk安裝步驟
1、復(fù)制APK到/data/app目錄下诚啃,解壓并掃描安裝包淮摔。
2、資源管理器解析APK里的資源文件始赎。
3和橙、解析AndroidManifest文件,將apk的權(quán)限造垛、應(yīng)用包名胃碾、apk的安裝位置、版本筋搏、userID等重要信息保存在/data/system/packages.xml文件中仆百。并在/data/data/目錄下創(chuàng)建對(duì)應(yīng)的應(yīng)用數(shù)據(jù)目錄。
4奔脐、然后對(duì)dex文件進(jìn)行優(yōu)化俄周,并保存在data/dalvik-cache目錄下。
5髓迎、將AndroidManifest文件解析出的四大組件信息注冊(cè)到PackageManagerService中峦朗。
6、安裝完成后排龄,發(fā)送廣播波势。
四. App(Activity)啟動(dòng)流程
加粗非斜體為啟動(dòng)新Activity流程
- 啟動(dòng)者Activity的 startActivity() -> startActivityForResult()。
- ActivityThread中 mInstrumentation 調(diào)用 execStartActivity()橄维,將啟動(dòng)Activity的請(qǐng)求以Binder的方式發(fā)送給AMS尺铣。
- 如果是新啟動(dòng)APP,立即顯示一個(gè)空白的window争舞。
- AMS接收到啟動(dòng)請(qǐng)求后凛忿,交付ActivityStarter處理Intent和Flag等信息,然后再交給ActivityStackSupervisior/ActivityStack 處理Activity進(jìn)棧相關(guān)流程竞川。
- AMS以Socket方式請(qǐng)求Zygote進(jìn)程fork出一個(gè)新的APP進(jìn)程店溢。
- 在新進(jìn)程里創(chuàng)建ActivityThread對(duì)象叁熔,也就是應(yīng)用的主線程,在主線程里開啟Looper消息循環(huán)床牧,開始處理創(chuàng)建Activity荣回。
- 如果未創(chuàng)建,創(chuàng)建Application對(duì)象戈咳。(在ActivityThread的 main() 的 attach() 里)
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
......
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
Looper.loop();
}
- AMS處理完畢后回調(diào)ActivityThread中的ApplicationThread(Binder)的scheduleLaunchActivity()驹马,此方法只是通過 H(Handler)發(fā)送一個(gè)消息給ActivityThread。
- ActivityThread -> handleMessage() -> performLaunchActivity()除秀,其中調(diào)用 mInstrumentation 的 newActivity(),里面通過ClassLoader用反射加載出Activity的實(shí)例算利。
- 回調(diào)Activity的 onCreate() 方法册踩。
- 加載并繪制View。(onResume()后)
重要術(shù)語
1.ActivityManagerServices效拭,簡稱AMS暂吉,服務(wù)端對(duì)象,負(fù)責(zé)系統(tǒng)中所有Activity的生命周期缎患。
2.ActivityThread慕的,App的真正入口。當(dāng)開啟App之后挤渔,調(diào)用main()開始運(yùn)行肮街,開啟消息循環(huán)隊(duì)列,這就是傳說的UI線程或者叫主線程判导。與ActivityManagerService一起完成Activity的管理工作嫉父。
3.ApplicationThread,用來實(shí)現(xiàn)ActivityManagerServie與ActivityThread之間的交互眼刃。在ActivityManagerSevice需要管理相關(guān)Application中的Activity的生命周期時(shí)绕辖,通過ApplicationThread的代理對(duì)象與ActivityThread通信。
4.ApplicationThreadProxy擂红,是ApplicationThread在服務(wù)器端的代理仪际,負(fù)責(zé)和客戶端的ApplicationThread通信。AMS就是通過該代理與ActivityThread進(jìn)行通信的昵骤。
5.Instrumentation树碱,每一個(gè)應(yīng)用程序只有一個(gè)Instrumetation對(duì)象,每個(gè)Activity內(nèi)都有一個(gè)對(duì)該對(duì)象的引用变秦,Instrumentation可以理解為應(yīng)用進(jìn)程的管家赴恨,ActivityThread要?jiǎng)?chuàng)建或暫停某個(gè)Activity時(shí),都需要通過Instrumentation來進(jìn)行具體的操作伴栓。
6.ActivityStack伦连,Activity在AMS的棧管理雨饺,用來記錄經(jīng)啟動(dòng)的Activity的先后關(guān)系,狀態(tài)信息等惑淳。通過ActivtyStack決定是否需要啟動(dòng)新的進(jìn)程额港。
7.ActivityRecord,ActivityStack的管理對(duì)象歧焦,每個(gè)Acivity在AMS對(duì)應(yīng)一個(gè)ActivityRecord移斩,來記錄Activity狀態(tài)以及其他的管理信息。其實(shí)就是服務(wù)器端的Activit對(duì)象的映像绢馍。
8.TaskRecord向瓷,AMS抽象出來的一個(gè)“任務(wù)”的概念,是記錄ActivityRecord的棧舰涌,一個(gè)“Task”包含若干個(gè)ActivityRecord猖任。AMS用TaskRecord確保Activity啟動(dòng)和退出的順序。如果你清楚Activity的4種launchMode瓷耙,那么對(duì)這概念應(yīng)該不陌生朱躺。
Activity啟動(dòng)圖示
點(diǎn)擊應(yīng)用圖標(biāo)后會(huì)去啟動(dòng)應(yīng)用的Launcher Activity,如果Launcer Activity所在的進(jìn)程沒有創(chuàng)建搁痛,還會(huì)創(chuàng)建新進(jìn)程长搀,整體的流程就是一個(gè)Activity的啟動(dòng)流程。
五. View加載和繪制流程
1. Activity的 attach() 中創(chuàng)建 PhoneWindow(Window的具體實(shí)現(xiàn))鸡典。其中的 DecorView 為所有View的root view源请,是個(gè)包含title和content的FrameLayout。
2. setContentView() 中將布局賦給 DecorView 的 content (android.R.id.content)彻况,但此時(shí)并沒有真正將view顯示在window上巢钓。
3. 真正顯示是在ActivityThread的 handleResumeActivity() 中,performResumeActivity()(也就是onResume())之后疗垛。
4. handleResumeActivity()中症汹,從PhoneWindow取出decorView,通過WindowManager 的 addView() 將其加入Window上顯示贷腕。
5. WindowManager 可簡單當(dāng)作是WMS在應(yīng)用端的遠(yuǎn)程代理對(duì)象背镇。
實(shí)際上它是個(gè)抽象類,具體實(shí)現(xiàn)是 WindowManagerImpl泽裳,而 WindowManagerImpl 又是委托給 WindowManagerGlobal(單例)來遠(yuǎn)程與WMS交互瞒斩。
6. WindowManagerGlobal功能有:
- 獲取WMS的遠(yuǎn)程代理對(duì)象sWindowManagerService
- 獲取WMS的IWindowSession對(duì)象
- 創(chuàng)建ViewRootImpl對(duì)象
- 通過ViewRootImpl對(duì)象來addView(), removeView(), updateViewLayout()
所以最終是由 ViewRootImpl 來完成的。
ViewRootImpl 的 setView()
ViewRootImpl.setView() -> requestLayout() -> scheduleTraversals() -> doTraversal() -> performTraversals() -> performMeasure()涮总、performLayout()胸囱、performDraw()