本文整理和引用他人的筆記,旨在個(gè)人復(fù)習(xí)使用。
創(chuàng)新互聯(lián)建站是專(zhuān)業(yè)的向陽(yáng)網(wǎng)站建設(shè)公司,向陽(yáng)接單;提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專(zhuān)業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行向陽(yáng)網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專(zhuān)業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專(zhuān)業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
參考鏈接:
;depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight
默認(rèn)情況下,一個(gè)app只會(huì)運(yùn)行在一個(gè)進(jìn)程中,進(jìn)程名為app的包名。
1. 分散內(nèi)存的占用
Android系統(tǒng)對(duì)每個(gè)應(yīng)用進(jìn)程的內(nèi)存占用是有限制的,占用內(nèi)存越大的進(jìn)程,被系統(tǒng)殺死的可能性就越大。使用多進(jìn)程可以減少主進(jìn)程占用的內(nèi)存,避免OOM問(wèn)題,降低被系統(tǒng)殺死的概率。
2. 實(shí)現(xiàn)多模塊
一個(gè)成熟的應(yīng)用一定是多模塊化的。項(xiàng)目解耦,模塊化,意味著開(kāi)辟新的進(jìn)程,有獨(dú)立的JVM,帶來(lái)數(shù)據(jù)解耦。模塊之間互不干預(yù),團(tuán)隊(duì)并行開(kāi)發(fā),同時(shí)責(zé)任分工也很明確。
3. 降低程序奔潰率
子進(jìn)程崩潰不會(huì)影響主進(jìn)程的運(yùn)行,能降低程序的崩潰率。
4. 實(shí)現(xiàn)一些特殊功能
比如可以實(shí)現(xiàn)推送進(jìn)程,使得主進(jìn)程退出后,能離線完成消息推送服務(wù)。還可以實(shí)現(xiàn)守護(hù)進(jìn)程,來(lái)喚醒主進(jìn)程達(dá)到?;钅康摹_€可以實(shí)現(xiàn)監(jiān)控進(jìn)程專(zhuān)門(mén)負(fù)責(zé)上報(bào)bug,進(jìn)而提升用戶(hù)體驗(yàn)。
android:process 屬性的值以冒號(hào)開(kāi)頭的就是 私有進(jìn)程 ,否則就是 公有進(jìn)程 。當(dāng)然命名還需要符合規(guī)范,不能以數(shù)字開(kāi)頭等等。
1. 前臺(tái)進(jìn)程
2. 可見(jiàn)進(jìn)程
3. 服務(wù)進(jìn)程
4. 后臺(tái)進(jìn)程
5. 空進(jìn)程
Android 會(huì)將進(jìn)程評(píng)定為它可能達(dá)到的最高級(jí)別。另外服務(wù)于另一進(jìn)程的進(jìn)程其級(jí)別永遠(yuǎn)不會(huì)低于其所服務(wù)的進(jìn)程。
創(chuàng)建新的進(jìn)程時(shí)會(huì)創(chuàng)建新的Application對(duì)象,而我們通常在Application的onCreate方法中只是完成一些全局的初始化操作,不需要多次執(zhí)行。
解決思路:獲取當(dāng)前進(jìn)程名,判斷是否為主進(jìn)程,只有主進(jìn)程的時(shí)候才執(zhí)行初始化操作
獲取當(dāng)前進(jìn)程名的兩種方法:
Application中判斷是否是主進(jìn)程(方法1例子):
Serializable 和 Parcelable是數(shù)據(jù)序列化的兩種方式,Android中只有進(jìn)行序列化過(guò)后的對(duì)象才能通過(guò)intent和Binder傳遞。
通常序列化后的對(duì)象完成傳輸后,通過(guò)反序列化獲得的是一個(gè)新對(duì)象,而不是原來(lái)的對(duì)象。
Serializable是java接口,位于java.io的路徑下。Serializable的原理就是把Java對(duì)象序列化為二進(jìn)制文件后進(jìn)行傳遞。Serializable使用起來(lái)非常簡(jiǎn)單,只需直接實(shí)現(xiàn)該接口就可以了。
Parcelable是Google為了解決Serializable效率低下的問(wèn)題,為Android特意設(shè)計(jì)的一個(gè)接口。Parcelable的原理是將一個(gè)對(duì)象完全分解,分解成可以傳輸?shù)臄?shù)據(jù)類(lèi)型(如基本數(shù)據(jù)類(lèi)型)再進(jìn)行傳遞。
通常需要存到本地磁盤(pán)的數(shù)據(jù)就使用Serializable,其他情況就使用效率更高的Parcelable。
IPC 即 Inter-Process Communication (進(jìn)程間通信)。Android 基于 Linux,而 Linux 出于安全考慮,不同進(jìn)程間不能之間操作對(duì)方的數(shù)據(jù),這叫做“進(jìn)程隔離”。
每個(gè)進(jìn)程的虛擬內(nèi)存空間(進(jìn)程空間)又被分為了 用戶(hù)空間和內(nèi)核空間 , 進(jìn)程只能訪問(wèn)自身用戶(hù)空間,只有操作系統(tǒng)能訪問(wèn)內(nèi)核空間。
由于進(jìn)程只能訪問(wèn)自身用戶(hù)空間,因此在傳統(tǒng)的IPC中,發(fā)送進(jìn)程需要通過(guò)copy_from_user(系統(tǒng)調(diào)用)將數(shù)據(jù)從自身用戶(hù)空間拷貝到內(nèi)核空間,再由接受進(jìn)程通過(guò)copy_to_user從內(nèi)核空間復(fù)拷貝到自身用戶(hù)空間,共需要拷貝2次,效率十分低下。Android采用的是Binder作為IPC的機(jī)制,只需復(fù)制一次。
Binder翻譯過(guò)來(lái)是粘合劑,是進(jìn)程之間的粘合劑。
Binder IPC通信的底層原理是 通過(guò)內(nèi)存映射(mmap),將接收進(jìn)程的用戶(hù)空間映射到內(nèi)核空間 ,有了這個(gè)映射關(guān)系,接收進(jìn)程就能通過(guò)用戶(hù)空間的地址獲得內(nèi)核空間的數(shù)據(jù),這樣只需發(fā)送進(jìn)程將數(shù)據(jù)拷貝到內(nèi)核空間就可完成通訊。
一次完整的Binder IPC通信:
從IPC的角度看,Binder是一種跨進(jìn)程通信機(jī)制(一種模型),Binder 是基于 C/S 架構(gòu)的,這個(gè)通信機(jī)制中主要涉及四個(gè)角色:Client、Server、ServiceManager和Binder驅(qū)動(dòng)。
Client、Server、ServiceManager都是運(yùn)行在用戶(hù)空間的進(jìn)程,他們通過(guò)系統(tǒng)調(diào)用(open、mmap 和 ioctl)來(lái)訪問(wèn)設(shè)備文件/dev/binder,從而實(shí)現(xiàn)與Binder驅(qū)動(dòng)的交互。Binder驅(qū)動(dòng)提供進(jìn)程間通信的能力(負(fù)責(zé)完成一些底層操作,比如開(kāi)辟數(shù)據(jù)接受緩存區(qū)等),是Client、Server和ServiceManager之間的橋梁。
Client、Server就是需要進(jìn)行通信兩個(gè)的進(jìn)程,通信流程:
細(xì)心的你一定發(fā)現(xiàn)了,注冊(cè)服務(wù)和獲得服務(wù)本身就是和ServiceManager進(jìn)行跨進(jìn)程通信。其實(shí)和ServiceManager的通信的過(guò)程也是獲取Binder對(duì)象(早已創(chuàng)建在Binder驅(qū)動(dòng)中,攜帶了注冊(cè)和查詢(xún)服務(wù)等接口方法)來(lái)使用,所有需要和ServiceManager通信的進(jìn)程,只需通過(guò)0號(hào)引用,就可以獲得這個(gè)Binder對(duì)象了。
AIDL內(nèi)部原理就是基于Binder的,可以借此來(lái)分析Binder的使用。
AIDL是接口定義語(yǔ)言,簡(jiǎn)短的幾句話就能定義好一個(gè)復(fù)雜的、內(nèi)部有一定功能的java接口。
先看看ICallBack.aidl文件,這里定義了一個(gè)接口,表示了服務(wù)端提供的功能。
被定義出來(lái)的java接口繼承了IInterface接口,并且內(nèi)部提供了一個(gè)Stub抽象類(lèi)給服務(wù)端(相當(dāng)于封裝了一下,服務(wù)端只需繼承這個(gè)類(lèi),然后完成功能的里面具體的實(shí)現(xiàn))。
參考:
(以下是添加了回調(diào)的最終實(shí)現(xiàn),可以看參考鏈接一步一步來(lái))
為需要使用的類(lèi),創(chuàng)建aidl文件。
系統(tǒng)會(huì)自動(dòng)在main文件下生成aidl文件夾,并在該文件夾下創(chuàng)建相應(yīng)目錄。
在java相同路徑下創(chuàng)建Student類(lèi),這里不能使用@Parcelize注解,否則會(huì)報(bào)錯(cuò)
創(chuàng)建IStudentService.aidl,定義了一個(gè)接口,該接口定義了服務(wù)端提供的功能。創(chuàng)建完后rebuild一下項(xiàng)目 (每次創(chuàng)建和修改定義接口文件都要rebuild一下)
創(chuàng)建在服務(wù)端的StudentService
可以看見(jiàn)有回調(diào),說(shuō)明客戶(hù)端也提供了接口給服務(wù)端來(lái)回調(diào)(雙向通信,此時(shí)客戶(hù)端的變成了服務(wù)端),即ICallBack.aidl
客戶(hù)端是通過(guò)Binder驅(qū)動(dòng)返回的Binder調(diào)用StudentService里的具體實(shí)現(xiàn)方法
AIDL使用注意:
Messenger可以在不同進(jìn)程中傳遞 Message 對(duì)象,在Message中放入我們需要傳遞的數(shù)據(jù),就可以輕松地實(shí)現(xiàn)數(shù)據(jù)的進(jìn)程間傳遞了。Messenger 是一種輕量級(jí)的 IPC 方案,是對(duì)AIDL的封裝,底層實(shí)現(xiàn)是 AIDL。
使用詳見(jiàn):
[img]mmap是Linux中常用的系統(tǒng)調(diào)用API,用途廣泛,Android中也有不少地方用到,比如匿名共享內(nèi)存,Binder機(jī)制等。本文簡(jiǎn)單記錄下Android中mmap調(diào)用流程及原理。mmap函數(shù)原型如下:
幾個(gè)重要參數(shù)
返回值是void *類(lèi)型,分配成功后,被映射成虛擬內(nèi)存地址。
mmap屬于系統(tǒng)調(diào)用,用戶(hù)控件間接通過(guò)swi指令觸發(fā)軟中斷,進(jìn)入內(nèi)核態(tài)(各種環(huán)境的切換),進(jìn)入內(nèi)核態(tài)之后,便可以調(diào)用內(nèi)核函數(shù)進(jìn)行處理。 mmap-mmap64-__mmap2-sys_mmap2- sys_mmap_pgoff -do_mmap_pgoff
而 __NR_mmap在系統(tǒng)函數(shù)調(diào)用表中對(duì)應(yīng)的減值如下:
通過(guò)系統(tǒng)調(diào)用,執(zhí)行swi軟中斷,進(jìn)入內(nèi)核態(tài),最終映射到call.S中的內(nèi)核函數(shù):sys_mmap2
進(jìn)而調(diào)用do_mmap_pgoff:
get_unmapped_area用于為用戶(hù)空間找一塊內(nèi)存區(qū)域,
current-mm-get_unmapped_area一般被賦值為arch_get_unmapped_area_topdown,
先找到合適的虛擬內(nèi)存(用戶(hù)空間),幾經(jīng)周轉(zhuǎn)后,調(diào)用相應(yīng)文件或者設(shè)備驅(qū)動(dòng)中的mmap函數(shù),完成該設(shè)備文件的mmap,至于如何處理處理虛擬空間,要看每個(gè)文件的自己的操作了。
這里有個(gè)很關(guān)鍵的結(jié)構(gòu)體
它是文件驅(qū)動(dòng)操作的入口,在open的時(shí)候,完成file_operations的綁定,open流程跟mmap類(lèi)似
先通過(guò)get_unused_fd_flags獲取個(gè)未使用的fd,再通過(guò)do_file_open完成file結(jié)構(gòu)體的創(chuàng)建及初始化,最后通過(guò)fd_install完成fd與file的綁定。
重點(diǎn)看下path_openat:
拿Binder設(shè)備文件為例子,在注冊(cè)該設(shè)備驅(qū)動(dòng)的時(shí)候,對(duì)應(yīng)的file_operations已經(jīng)注冊(cè)好了,
open的時(shí)候,只需要根根inode節(jié)點(diǎn),獲取到file_operations既可,并且,在open成功后,要回調(diào)file_operations中的open函數(shù)
open后,就可以利用fd找到file,之后利用file中的file_operations *f_op調(diào)用相應(yīng)驅(qū)動(dòng)函數(shù),接著看mmap。
Binder機(jī)制中mmap的最大特點(diǎn)是一次拷貝即可完成進(jìn)程間通信 。Android應(yīng)用在進(jìn)程啟動(dòng)之初會(huì)創(chuàng)建一個(gè)單例的ProcessState對(duì)象,其構(gòu)造函數(shù)執(zhí)行時(shí)會(huì)同時(shí)完成binder mmap,為進(jìn)程分配一塊內(nèi)存,專(zhuān)門(mén)用于Binder通信,如下。
第一個(gè)參數(shù)是分配地址,為0意味著讓系統(tǒng)自動(dòng)分配,流程跟之前分子類(lèi)似,先在用戶(hù)空間找到一塊合適的虛擬內(nèi)存,之后,在內(nèi)核空間也找到一塊合適的虛擬內(nèi)存,修改兩個(gè)控件的頁(yè)表,使得兩者映射到同一塊物力內(nèi)存。
Linux的內(nèi)存分用戶(hù)空間跟內(nèi)核空間,同時(shí)頁(yè)表有也分兩類(lèi),用戶(hù)空間頁(yè)表跟內(nèi)核空間頁(yè)表,每個(gè)進(jìn)程有一個(gè)用戶(hù)空間頁(yè)表,但是系統(tǒng)只有一個(gè)內(nèi)核空間頁(yè)表。而B(niǎo)inder mmap的關(guān)鍵是:也更新用戶(hù)空間對(duì)應(yīng)的頁(yè)表的同時(shí)也同步映射內(nèi)核頁(yè)表,讓兩個(gè)頁(yè)表都指向同一塊地址,這樣一來(lái),數(shù)據(jù)只需要從A進(jìn)程的用戶(hù)空間,直接拷貝拷貝到B所對(duì)應(yīng)的內(nèi)核空間,而B(niǎo)多對(duì)應(yīng)的內(nèi)核空間在B進(jìn)程的用戶(hù)空間也有相應(yīng)的映射,這樣就無(wú)需從內(nèi)核拷貝到用戶(hù)空間了。
binder_update_page_range完成了內(nèi)存分配、頁(yè)表修改等關(guān)鍵操作:
可以看到,binder一次拷貝的關(guān)鍵是,完成內(nèi)存的時(shí)候,同時(shí)完成了內(nèi)核空間跟用戶(hù)空間的映射,也就是說(shuō),同一份物理內(nèi)存,既可以在用戶(hù)空間,用虛擬地址訪問(wèn),也可以在內(nèi)核空間用虛擬地址訪問(wèn)。
普通文件的訪問(wèn)方式有兩種:第一種是通過(guò)read/write系統(tǒng)調(diào)訪問(wèn),先在用戶(hù)空間分配一段buffer,然后,進(jìn)入內(nèi)核,將內(nèi)容從磁盤(pán)讀取到內(nèi)核緩沖,最后,拷貝到用戶(hù)進(jìn)程空間,至少牽扯到兩次數(shù)據(jù)拷貝;同時(shí),多個(gè)進(jìn)程同時(shí)訪問(wèn)一個(gè)文件,每個(gè)進(jìn)程都有一個(gè)副本,存在資源浪費(fèi)的問(wèn)題。
另一種是通過(guò)mmap來(lái)訪問(wèn)文件,mmap()將文件直接映射到用戶(hù)空間,文件在mmap的時(shí)候,內(nèi)存并未真正分配,只有在第一次讀取/寫(xiě)入的時(shí)候才會(huì)觸發(fā),這個(gè)時(shí)候,會(huì)引發(fā)缺頁(yè)中斷,在處理缺頁(yè)中斷的時(shí)候,完成內(nèi)存也分配,同時(shí)也完成文件數(shù)據(jù)的拷貝。并且,修改用戶(hù)空間對(duì)應(yīng)的頁(yè)表,完成到物理內(nèi)存到用戶(hù)空間的映射,這種方式只存在一次數(shù)據(jù)拷貝,效率更高。同時(shí)多進(jìn)程間通過(guò)mmap共享文件數(shù)據(jù)的時(shí)候,僅需要一塊物理內(nèi)存就夠了。
安卓系統(tǒng)調(diào)用disksgio是采用的是LRU算法,通過(guò)LRU算法對(duì)緩存進(jìn)行管理,以最近最少使用作為管理的依據(jù),刪除最近最少使用的數(shù)據(jù),保留最近最常用的數(shù)據(jù)。