Android Framework內部啓動流程

App啓動過程導圖

  1. 點擊桌面App圖標,Launcher進程採用Binder IPC向system_server進程發起startActivity請求
  2. system_server進程接收到請求後,向zygote進程發送創建進程的請求
  3. Zygote進程fork出新的子進程,即App進程
  4. App進程,通過Binder IPC向sytem_server進程發起attachApplication請求
  5. system_server進程在收到請求後,進行一系列準備工作後,再通過binder IPC向App進程發送scheduleLaunchActivity請求
  6. App進程的binder線程(ApplicationThread)在收到請求後,通過handler向主線程發送LAUNCH_ACTIVITY消息
  7. 主線程在收到Message後,通過發射機制創建目標Activity,並回調Activity.onCreate()等方法
  8. App便正式啓動,開始進入Activity生命週期,執行完onCreate/onStart/onResume方法,UI渲染結束後便可以看到App的主界面

 

Android開機流程導圖

BootLoader引導

當按開機鍵的時候,引導芯片開始從固化在ROM的預設代碼開始執行,然後加載引導程序到RAM
BootLoader,又稱爲引導程序。它是在操作系統運行之前運行的一段程序
BootLoader負責初始化軟件運行所需要的最小硬件環境,最後加載內核到內存

 

啓動Kernel

這個入口的函數是start_kernel函數
start_kernel函數執行到最後調用了reset_init函數進行後續的初始化
start_kernel最終啓動用戶空間的init程序

 

啓動Android

當初始化內核之後,init進程負責解析init.rc配置文件, 就會啓動一個相當重要的祖先進程,也就是init進程,在Linux中所有的進程都是由init進程直接或間接fork出來的

* /system/bin/app_process_Zygote服務啓動的進程名
* --start-system-server 表明Zygote啓動完成後,需要啓動System_Server進程
* socket zygote stream 666在Zygote啓動時,創建一個權限爲666的socket。此socket用來請求zygote創建新進程
* socket的fd保存在名稱爲"ANDROID_SOCKET_zygote"的環境變量中

init進程負責創建系統中最關鍵的幾個核心daemon(守護)進程,尤其是zygote和System_Server進程

1. zygote進程 android啓動的第一個Dalvik 虛擬機,它將負責啓動Java世界的進程
2. zygote虛擬機啓動子進程system_server,同時也可以看出zygote中定義了一個Socket,綁定666端口,用於接收ActivityManagerService啓動應用程序的請求
3. System_Server進程  Binder通信的基礎,它還提供了property service(屬性服務),類似於windows系統的註冊表服務
4. 系統裏面重要的服務都是在這個進程裏面開啓的,例如AMS, WindowsManager, PackageManagerService等等都是由這個System_Server fork出來的
5. 在System_Server進程開啓的時候,就會初始化ActivityManagerService 。同時,會加載本地系統的服務庫,調用createSystemContext()創建系統上下文,創建ActivityThread及開啓各種服務等等
6. system_server中開啓了核心系統服務,並將系統服務添加到ServiceManager中,然後系統進入SystemReady狀態

 

啓動Home Activity

  1. 在systemReady狀態,ActivityManagerService會與zygote的Socket通信,請求啓動Home
  2. zygote收到AMS的連接請求後,執行runSelectLoopMode處理請求
  3. zygote處理請求會通過forkAndSpecialize啓動新的應用進程,並最終啓動Home
概況
1. 系統加電,執行bootloader。Bootloader負責初始化軟件運行的最小硬件環境,最後加載內核到內存
2. 內核加載到內存後,進入內核引導階段,在內核引導的最後,調用start_kernel進入內核啓動階段。start_kernel最終啓動用戶空間的init程序
3. init負責解析init.rc配置文件,開啓系統守護進程。2個最重要的守護進程是zygote進程和serverManager進程。zygote是android啓動的第一個Dalvik虛擬機,ServiceManager服務是Binder通信的基礎
4. zygote虛擬機啓動子進程system_server,在system_server中啓動了核心系統服務,並將系統服務添加到ServiceManager中,然後系統進入SystemReady狀態
5. 在SystemReady狀態,ActivityManagerService與zygote中的socket通信,通過zygote啓動home應用,進入系統界面

* 從步驟3開始, init啓動後,上層的實現
1. init啓動的核心Daemon服務包括Android的第一個Dalvik虛擬機Zygote
2. zygote定義一個socket,用於接受ActivityManangerService啓動應用的請求
3. zygote通過fork系統調用創建system_server進程
4. 在system_server進程中,將會啓動系統核心服務以及其他服務
5. 系統服務啓動後會註冊到ServiceManager中,用於Binder通信
6. ActivityManagerService進入systemReady狀態
7. 在systemReady狀態,ActivityManangerService會與zygote的Socket通信,請求啓動Home
8. zygote收到AMS的連接請求後,執行runSelectLoopMode處理請求
9. zygote處理請求會通過forkAndSpecialize啓動新的應用進程,並最終啓動Home

 

Handler機制與底層實現原理

概念:

Message - Message代表一個行爲what或者一串動作Runnable, 每一個消息在加入消息隊列時,都有明確的目標Handler
ThreadLocal - 線程本地存儲區(Thread Local Storage,簡稱爲TLS),每個線程都有自己的私有的本地存儲區域,不同線程之間彼此不能訪問對方的TLS區域。ThreadLocal的作用是提供線程內的局部變量TLS,這種變量在線程的生命週期內起作用,每一個線程有他自己所屬的值(線程隔離)
MessageQueue (C層與Java層都有實現) - 以隊列的形式對外提供插入和刪除的工作, 其內部結構是以雙向鏈表的形式存儲消息的
Looper (C層與Java層都有實現) - Looper是循環的意思,它負責從消息隊列中循環的取出消息然後把消息交給Handler處理
Handler - 消息的真正處理者, 具備獲取消息、發送消息、處理消息、移除消息等功能

普通的線程是沒有looper的,如果需要looper對象,那麼必須要先調用Looper.prepare方法,而且一個線程只能有一個looper
Handler是如何完成跨線程通信的

* Android中採用的是Linux中的管道通信
* 關於管道,簡單來說,管道就是一個文件
* 在管道的兩端,分別是兩個打開文件文件描述符,這兩個打開文件描述符都是對應同一個文件,其中一個是用來讀的,別一個是用來寫的
* 消息隊列創建時,會調用JNI函數,初始化NativeMessageQueue對象。NativeMessageQueue則會初始化Looper對象
* Looper的作用就是,當Java層的消息隊列中沒有消息時,就使Android應用程序主線程進入等待狀態,而當Java層的消息隊列中來了新的消息後,就喚醒Android應用程序的主線程來處理這個消息

 

整個消息機制流程

Handler通過sendMessage()發送Message到MessageQueue隊列
Looper通過loop(),不斷提取出達到觸發條件的Message,並將Message交給target來處理
經過dispatchMessage()後,交回給Handler的handleMessage()來進行相應地處理
將Message加入MessageQueue時,處往管道寫入字符,可以會喚醒loop線程;如果MessageQueue中沒有Message,並處於Idle狀態,則會執行IdelHandler接口中的方法,往往用於做一些清理性地工作

 

ContentProvider原理

Android繪製原理

Activity的window組成,Activity內部有個Window成員,它的實例爲PhoneWindow,PhoneWindow有個內部類是DecorView,這個DecorView就是存放佈局文件的,裏面有TitleActionBar和我們setContentView傳入進去的layout佈局文件

  1. Window類時一個抽象類,提供繪製窗口的API
  2. PhoneWindow是繼承Window的一個具體的類,該類內部包含了一個DecorView對象,該DectorView對象是所有應用窗口(Activity界面)的根View
  3. DecorView繼承FrameLayout,裏面id=content的就是我們傳入的佈局視圖
  4. ContentView必須是一個ViewGroup
  5. ViewGroup 開始遞歸執行以下邏輯進行繪製
+ measure, 遞歸測量view的大小。有3種測量模式
    - MeasureSpec.EXACTLY表示確定大小
    - MeasureSpec.AT_MOST表示最大大小
    - MeasureSpec.UNSPECIFIED不確定
+ layout,遞歸佈局view的位置
+ draw,遞歸繪製view
    - ViewRootImpl中的代碼會創建一個Canvas對象,然後調用View的draw()方法來執行具體的繪製

 

AsyncTask源碼分析

Binder機制及底層實現

進程空間分配

  1. 進程間,用戶空間的數據不可共享,所以用戶空間 = 不可共享空間
  2. 進程間,內核空間的數據可共享,所以內核空間 = 可共享空間
  3. 進程內用戶與內核進行交互稱爲系統調用

Binder跨進程通信(IPC)的原理

  1. 先通過進程間的內核空間進行數據交互
  2. 再通過進程內的用戶空間&內核空間進行數據交互,從而實現進程間的用戶空間的數據交互
  3. 而Binder,就是充當連接兩個進程(內核空間)的通道

使用步驟:
註冊服務

* Server進程向Binder驅動發起服務註冊請求
* Binder驅動將註冊請求轉發給ServiceManager進程
* ServiceManager進程添加該服務
* 此時ServiceManager進程擁有該服務信息

獲取服務

* Client向Binder驅動發起獲取服務的請求,傳遞要獲取的服務名稱(service name)
* Binder驅動將該請求轉發給ServiceManager進程
* ServiceManager查找到Client需要的Server對應的服務信息
* 通過Binder驅動將上述服務信息返回給Client進程
* 此時client進程與server進程已經建立了連接

使用服務

* Client進程將參數數據發到Server進程
    1. client 進程將需要的傳送的數據放到client進程的共享內存;(當前線程被掛起)
    2. Binder驅動從client的共享內存中讀取數據,並根據ServiceManager進程裏面的Server信息找到對應的Server進程
    3. Binder驅動將數據copy到Server進程的共享內存裏,並通知Server進程解包
* Server進程根據Client進程要求,調用目標方法
    1. 接到Binder驅動通知後,Server進程從線程池中取出線程,進行數據解包和調用目標方法
    2. 將最終方法結果寫到自己的共享內存
* Server進程將目標方法的結果,返回給Client進程
    1. Binder驅動程序將Server進程的共享內存裏面的數據(方法執行結果) copy 到client進程的共享內存
    2. 通知client進程獲得返回結果(此時client進程之前被掛起的線程被重新喚醒)

Client進程、Server進程 & Service Manager 進程之間的交互 都必須通過Binder驅動(使用 open 和 ioctl文件操作函數),而非直接交互
Client進程、Server進程 & Service Manager進程屬於進程空間的用戶空間,不可進行進程間交互
Binder驅動 屬於 進程空間的 內核空間,可進行進程間 & 進程內交互

Binder驅動 & Service Manager進程 屬於 Android基礎架構(即系統已經實現好了);而Client 進程 和 Server 進程 屬於Android應用層(需要開發者自己實現)

ActivityThread工作原理

Window 、WMS的工作原理

ThreadLocal原理,實現及如何保證Local屬性

每個Thread維護一個ThreadLocalMap映射表,這個映射表的key是ThreadLocal實例本身,value是真正需要存儲的Object

 

Android線程有沒有上限

android本身就是linux系統 所以查看命令和linux一樣

 

Android內存限制

dalvik.vm.heapstartsize 表示 初始內存大小是8m
dalvik.vm.heapgrowthlimit 表示標準內存大小是96m 一般應用都是這麼大
dalvik.vm.heapsize 表示 在manifest配置文件中application標籤下配置 android:largeHeap="true"時的內存大小

 

Android apk大小限制

apk安裝包大小理論上沒有限制。但是各個應用商店爲了有大小限制google play 要求小於50M , 擴展包可以擴展到2g
壓測: 800M的apk是沒問題的只是安裝的時間比較長。1.6G的apk包則把手機弄死機

 

線程池有沒有上限

ThreadPoolExecutor構造函數的maximumPoolSize決定

 

AndroidToast原理分析

Art和Dalvik對比

ART 的機制與 Dalvik 不同。在Dalvik下,應用每次運行的時候,字節碼都需要通過即時編譯器(just in time ,JIT)轉換爲機器碼,這會拖慢應用的運行效率,而在ART 環境中,應用在第一次安裝的時候,字節碼就會預先編譯成機器碼,使其成爲真正的本地應用。這個過程叫做預編譯(AOT,Ahead-Of-Time)。這樣的話,應用的啓動(首次)和執行都會變得更加快速。

 

BlockCanaryEx原理

即整個應用的主線程,只有這一個looper,不管有多少handler,最後都會回到這裏

public static void loop() {
    ...

    for (;;) {
        ...

        // This must be in a local variable, in case a UI event sets the logger
        Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        msg.target.dispatchMessage(msg);

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        ...
    }
}

設置Printer對象,判斷是否超過預期時間,notifyLog

 

Android GC探究

虛擬機原理,如何自己設計一個虛擬機(內存管理,類加載,雙親委派)

對於Activity 的 onCreate 等生命週期的函數爲什麼不會因爲 Looper.loop()裏的死循環卡死而永無機會執行

View 的繪製到底是怎樣完成的,它又爲什麼不會因爲 Looper.loop()裏的死循環卡死而永無機會刷新

子線程真的不能刷新UI

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章