學(xué)習(xí)筆記1-深入理解Android內(nèi)核設(shè)計(jì)思想

4.1 計(jì)算機(jī)體系結(jié)構(gòu)(Computer Architecture)

4.1.1 馮·諾依曼結(jié)構(gòu)

兩個(gè)深遠(yuǎn)影響的觀點(diǎn):

  • 采用二進(jìn)制,拋棄十進(jìn)制

  • 程序存儲(chǔ)(stored-program)

馮·諾依曼結(jié)構(gòu).png

4.1.2 哈佛結(jié)構(gòu)

對(duì)馮諾依曼結(jié)構(gòu)的改進(jìn)與完善,區(qū)別在指令與數(shù)據(jù)并不保存在同一個(gè)存儲(chǔ)器。

這意味著:

  • 指令與數(shù)據(jù)可以有不同的的數(shù)據(jù)寬度;

  • 執(zhí)行速度更快。

哈佛結(jié)構(gòu).png

計(jì)算機(jī)結(jié)構(gòu)的基本元素:

  • 中央處理器(CPU)

  • 內(nèi)存儲(chǔ)器

  • I/O設(shè)備

4.2 什么是操作系統(tǒng)

定義:

計(jì)算機(jī)操作系統(tǒng)是負(fù)責(zé)管理系統(tǒng)硬件,并為上層應(yīng)用提供穩(wěn)定編程接口和人機(jī)交互界面的軟件集合。

最核心的工作:硬件管理與抽象。

肩負(fù)兩大重任:

  • 面向下層:管理硬件(CPU、內(nèi)存、Flash、各種IO設(shè)備)

  • 面向上層:一方面,為用戶提供可用的人機(jī)交互界面;另一方面,負(fù)責(zé)為第三方程序的研發(fā)提供便捷、可靠、高效的API。

操作系統(tǒng)的難點(diǎn):進(jìn)程和內(nèi)存管理、硬件驅(qū)動(dòng)的支持等,這正是Linux的長(zhǎng)處所在。

4.3 進(jìn)程間通信的經(jīng)典實(shí)現(xiàn)

進(jìn)程間的通信(Inter-process communication,IPC)是指運(yùn)行在不同進(jìn)程(不論是否在同一臺(tái)機(jī)器)中的若干線程間的數(shù)據(jù)交換。

實(shí)現(xiàn)方式:消息傳遞、管道、文件共享、操作系統(tǒng)提供的公共信息機(jī)制等等。

4.3.1 共享內(nèi)存(Shared Memory)

一種常用的IPC機(jī)制,優(yōu)勢(shì):共享內(nèi)存區(qū)域,減少數(shù)據(jù)的復(fù)制操作,速度快。

實(shí)現(xiàn)步驟:

  • 創(chuàng)建內(nèi)存共享區(qū)

  • 映射內(nèi)存共享區(qū)

  • 訪問內(nèi)存共享區(qū)

  • 進(jìn)程間通信

  • 撤銷內(nèi)存映射區(qū)

  • 刪除內(nèi)存共享區(qū)

4.3.2 管道(Pipe)

一種常見的IPC方式

  • 分立管道的兩邊,進(jìn)行數(shù)據(jù)的傳輸通信

  • 管道是單向的

  • 一根管道同時(shí)具有“讀取”端(read end)和“寫入”端(write end)

  • 管道有容量限制

4.3.3 UNIX Domain Socket(UDS)

專門針對(duì)單機(jī)內(nèi)的進(jìn)程間通信,有時(shí)稱為IPC Socket。

Network Socket是以TCP/IP協(xié)議棧為基礎(chǔ),UDS因?yàn)槭潜镜貎?nèi)的“安全可靠操作”,實(shí)現(xiàn)機(jī)制上并不依賴于這些協(xié)議。

典型流程:

UNIX Domain Socket的通信流程.png

UDS的基本流程與傳統(tǒng)Socket一致,只是在參數(shù)上有區(qū)分:

  • 服務(wù)器端監(jiān)聽I(yíng)PC請(qǐng)求;

  • 客戶端發(fā)起IPC申請(qǐng);

  • 雙方成功建立起IPC連接;

  • 客戶端向服務(wù)端發(fā)送數(shù)據(jù),證明IPC通信是有效的

4.3.4 Remote Procedure Calls(RPC)

涉及的通信雙方通常運(yùn)行于兩臺(tái)不同的機(jī)器中。

RPC通信圖釋.png

4.4 同步機(jī)制的經(jīng)典實(shí)現(xiàn)

同步:如果多個(gè)進(jìn)程間存在時(shí)序關(guān)系,需要協(xié)同工作以完成一項(xiàng)任務(wù)

互斥:如果多個(gè)進(jìn)程并不滿足協(xié)同的條件,而只是因?yàn)楣蚕砭哂信潘缘馁Y源時(shí)所產(chǎn)生的關(guān)系。

4.4.1 信號(hào)量(Semaphore)

涉及的元素:信號(hào)量(S)、PV原語操作(有時(shí)稱wait()、signal())。

S:共享資源的可用數(shù)量

P: 減少S的計(jì)數(shù)(進(jìn)入共享區(qū)的操作)

V:增加S的計(jì)數(shù)(退出共享區(qū)的操作)

PV操作圖.png

4.4.2 Mutex

是Mutual Exclusion的縮寫,即互斥體

4.4.3 管程(Monitor)

一種控制更為簡(jiǎn)單的同步手段。

可以被多個(gè)進(jìn)程/線程安全訪問的對(duì)象(object)或模塊(module)。

具備安全性、互斥性、共享性。

4.4.4 Linux Futex

核心優(yōu)勢(shì)是Fast。

4.4.5 同步范例

生產(chǎn)者與消費(fèi)者問題:

兩個(gè)進(jìn)程共享一塊大小為N的緩沖區(qū),其中一個(gè)進(jìn)程負(fù)責(zé)填充數(shù)據(jù)(生產(chǎn)者),另一個(gè)進(jìn)程負(fù)責(zé)讀取數(shù)據(jù)(消費(fèi)者)。

問題的核心有兩點(diǎn):

  • 當(dāng)緩沖區(qū)滿時(shí),禁止生產(chǎn)者繼續(xù)添加數(shù)據(jù),直到消費(fèi)者讀取了部分?jǐn)?shù)據(jù);

  • 當(dāng)緩沖區(qū)空時(shí),消費(fèi)者應(yīng)等待對(duì)方繼續(xù)生產(chǎn)后再執(zhí)行操作。

解決方式:信用量,用到3個(gè)Semaphore,功能如下:

  • S_emptyCount: 用于生產(chǎn)者獲取可用的的緩沖空間大小,初始N

  • S_fillCount: 用于消費(fèi)者獲取可用的數(shù)據(jù)大小,初始為0

  • S_mutex: 用于操作緩沖區(qū),初始為1

生產(chǎn)者的執(zhí)行步驟:

  • 循環(huán)開始;

  • Produce_item;

  • P(S_emptyCount)

  • P(S_mutex)

  • Put_item_to_buffer

  • V(S_mutex)

  • V(S_fillCount)

  • 繼續(xù)循環(huán)

消費(fèi)者的執(zhí)行步驟:

  • 循環(huán)開始

  • P(S_fillCount)

  • P(S_mutex)

  • Read_item_from_buffer

  • V(S_mutex)

  • V(S_emptyCount)

  • Consume

  • 繼續(xù)循環(huán)

4.5 Android中的同步機(jī)制

4.5.1 進(jìn)程間同步 - Mutex

頭文件:frameworks/native/include/utils/Mutex.h

既可以處理進(jìn)程內(nèi)同步、又可以解決進(jìn)程間同步。

4.5.2 條件判斷 - Condition

頭文件:frameworks/native/include/utils/Condition.h

核心思想:判斷“條件是否已經(jīng)滿足”,如果滿足則馬上返回,繼續(xù)執(zhí)行未完成的動(dòng)作,否則就進(jìn)行休眠等待,直到條件滿足時(shí)有人喚醒它。

4.5.3 “柵欄、障礙” - Barrier

頭文件:frameworks/native/services/surfaceflinger/Barrier.h

Barrier是填充了“具體條件”的Condition,專門為SurfaceFlinger而設(shè)計(jì)。

通常被用于對(duì)某線程是否初始化完成進(jìn)行判斷,這種場(chǎng)景具有不可逆性。

4.5.4 加解鎖的自動(dòng)化操作 - Autolock

在Mutex類內(nèi)部的嵌套類Autolock,實(shí)現(xiàn)加、解鎖的自動(dòng)化操作。

當(dāng)Auto構(gòu)造時(shí),會(huì)主動(dòng)調(diào)用內(nèi)部成員變量mLock的lock()方法獲取一個(gè)鎖。

而析構(gòu)時(shí)正好相反,調(diào)用它的unlock()方法釋放鎖。

4.5.5 讀寫鎖 - ReaderWriterMutex

基礎(chǔ)仍是mutex,特點(diǎn)是 允許有多個(gè)對(duì)象共享Read鎖,但同時(shí)卻只能有唯一一個(gè)對(duì)象擁有Write鎖。

4.6 操作系統(tǒng)內(nèi)存管理基礎(chǔ)

內(nèi)存管理是操作系統(tǒng)的重點(diǎn)和難點(diǎn)

內(nèi)存管理重點(diǎn)理解幾個(gè)核心:虛擬內(nèi)存、內(nèi)存分配與回收、內(nèi)存保存。

4.6.1 虛擬內(nèi)存(Virtual Memory)

虛擬內(nèi)存:為大體積程序的運(yùn)行提供了可能。

基本思想:

  • 將外存儲(chǔ)器的部分空間作為內(nèi)存的擴(kuò)展

  • 當(dāng)內(nèi)存資源不足時(shí),系統(tǒng)將按照一定算法自動(dòng)挑選優(yōu)先級(jí)低的數(shù)據(jù)塊,并把它們存儲(chǔ)到硬盤中。

  • 后續(xù)如果需要用到硬盤中的這些數(shù)據(jù)塊,系統(tǒng)將產(chǎn)生“缺頁”指令,然后把它們交換回內(nèi)存中。

  • 這些操作是由操作系統(tǒng)內(nèi)部?jī)?nèi)核自動(dòng)完成,對(duì)上層應(yīng)用“完全透明”。

涉及3種不同的地址空間:

1、邏輯地址

是程序編譯后所產(chǎn)生的地址,Segment Selector(段選擇子, 16bit) + Offset (偏移值,32bit)

2、線性地址

是邏輯地址經(jīng)過分段機(jī)制轉(zhuǎn)換后形成的

3、物理地址

是指機(jī)器真實(shí)的物理內(nèi)存所能表示的地址空間范圍,64KB內(nèi)存的物理地址范圍是 0x0000 - 0xFFFF

地址空間的轉(zhuǎn)換過程簡(jiǎn)圖.png

4.6.2 內(nèi)存保護(hù)(Memory Protection)

4.6.3 內(nèi)存分配與回收

分Native層(C/C++)、Java層

4.6.4 進(jìn)程間通信 - mmap

IPC方式: 通過映射同一塊物理內(nèi)存來共享內(nèi)存,減少數(shù)據(jù)復(fù)制次數(shù),提高效率。

mmap可以將某個(gè)設(shè)備或者文件映射到應(yīng)用進(jìn)程的內(nèi)存空間中,這樣訪問這塊內(nèi)存就相當(dāng)于對(duì)設(shè)備/文件進(jìn)行讀寫,而不需要通過read()、write()。

4.6.5 寫時(shí)拷貝技術(shù)(Copy on Write)

基本思想:多個(gè)對(duì)象在起始時(shí)共享某些資源(如代碼段、數(shù)據(jù)段),直到某個(gè)對(duì)象需要修改該資源才擁有自己的一份拷貝。

4.7 Android中的Low Memory Killer

Linux底層內(nèi)核的內(nèi)存監(jiān)控機(jī)制:OOMKiller,核心思想:按照優(yōu)先級(jí)順序,從低到高逐步殺掉進(jìn)程,回收內(nèi)存。

優(yōu)先級(jí)的設(shè)定策略需綜合以下幾個(gè)因素:

  • 進(jìn)程消耗的內(nèi)存

  • 進(jìn)程占用的CPU時(shí)間

  • oom_adj(OOM權(quán)重)

Android擴(kuò)展出自己的內(nèi)存監(jiān)控體系,Linux的“內(nèi)存殺手”要等到系統(tǒng)資源“瀕臨絕境”的情況下才產(chǎn)生效果,而Android則實(shí)現(xiàn)了“不同梯級(jí)”的Killer(Low Memory Killer(LMK))。

LMK的源碼在內(nèi)核工程的driver/staging/android/Lowmemorykiller.c中。

4.8 Android匿名共享內(nèi)存(Anonymous Shared Memory)

Anonymous Shared Memory(簡(jiǎn)稱Ashmem)是Android特有的內(nèi)存共享機(jī)制,可以將制定的物理內(nèi)存分別映射到各個(gè)進(jìn)程自己的虛擬地址空間中,從而便捷地實(shí)現(xiàn)進(jìn)程間的內(nèi)存共享。

應(yīng)用實(shí)例:基于ashmem設(shè)備來實(shí)現(xiàn)跨進(jìn)程內(nèi)存共享,如MemoryDealer。

匿名共享內(nèi)存涉及設(shè)備驅(qū)動(dòng)、Binder原理等一系列技術(shù),比較難理解,等學(xué)習(xí)相關(guān)基礎(chǔ)知識(shí),再來攻克。

4.9 JNI

JNI(Java Native Interface)是一種允許運(yùn)行于JVM的Java程序去調(diào)用(反向亦然)本地代碼的編程框架。

有3種情況需要用到JNI:

  • 應(yīng)用程序需要一些平臺(tái)相關(guān)的feature的支持,而Java無法滿足

  • 兼容以前的用其他語言書寫的代碼庫

  • 應(yīng)用程序的某些關(guān)鍵操作對(duì)運(yùn)行速度要求較高。

JNI涉及以下兩方面:

  • Java Code -> Native Code

  • Native Code -> Java Code

4.9.1 Java函數(shù)的本地實(shí)現(xiàn)

創(chuàng)建一個(gè)可供Java代碼調(diào)用的本地函數(shù)步驟:

  • 將需要本地實(shí)現(xiàn)的Java方法加上native聲明;

  • 使用javac命令編譯Java類

  • 使用javah生成.h頭文件

  • 在本地代碼中實(shí)現(xiàn)native方法

  • 編譯上述的本地方法,生成動(dòng)態(tài)鏈接庫

  • 在Java類中加載這一動(dòng)態(tài)鏈接庫

  • Java代碼中其他地方可以正常調(diào)用這個(gè)native方法

4.9.2 本地代碼訪問JVM

上節(jié)內(nèi)容的“逆向”操作,本地層(C/C++)訪問JVM空間(Java)。

4.10 Java中的反射機(jī)制

4.11 學(xué)習(xí)Android系統(tǒng)的兩條線索

主線:操作系統(tǒng)的體系結(jié)構(gòu)、硬件組成

輔線:在主線的基礎(chǔ)上,以Android系統(tǒng)的5層框架為輔,逐一解析各層框架中的重要元素,或拾級(jí)而上,或深入淺出,直到問題的最根源處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容