Zygote的啟動過程
1.系統啟動init程式時會啟動Zygote程式(負責Android執行時程式和應用程式的啟動)
2.Zygote程式會首先啟動SystemServer程式,SystemServer程式會啟動系統的關鍵服務(PMS和AMS)
3.當啟動應用程式時,AMS通過socket向Zygote通知建立新的程式
Android應用程式安裝過程
- 系統啟動安裝過程
-
SystemServer程式啟動PackageManagerService服務例項,新增到ServiceManager(負責管理系統中的Binder物件)
-
PackageManagerService.main()掃描指定目錄的apk歸檔檔案
/system/framework
/system/app
/vendor/app
/data/app
/data/app-private
複製程式碼
- 對apk檔案解析AndroidManifest.xml各個標籤,得到的package、provider、service、receiver和activity等資訊儲存在PackageManagerService服務的記憶體中。
- 下載安裝過程 下載apk->拷貝到指定目錄->解析apk歸檔檔案的AndroidManifest.xml的應用程式的資訊到packageManagerServices中 #應用程式啟動流程
- Launcher通過Binder程式間通訊機制通知ActivityManagerService,它要啟動一個Activity;
- ActivityManagerService通過Binder程式間通訊機制通知Launcher進入Paused狀態;
- Launcher通過Binder程式間通訊機制通知ActivityManagerService,它已經準備就緒進入Paused狀態,於是ActivityManagerService就建立一個新的程式,用來啟動一個ActivityThread例項,即將要啟動的Activity就是在這個ActivityThread例項中執行;
- ActivityThread通過Binder程式間通訊機制將一個ApplicationThread型別的Binder物件傳遞給ActivityManagerService,以便以後ActivityManagerService能夠通過這個Binder物件和它進行通訊;
- AMS通知ActivityThread物件中呼叫bindApplication()方法. 送到訊息佇列中, 最終通過handleBindApplication()方法處理該訊息. 然後呼叫makeApplication()方法來載入Application的classes到記憶體中,然後通知AMS。
- ActivityManagerService通過Binder程式間通訊機制通知ActivityThread,可以真正執行Activity的啟動。
Launcher啟動過程
- SystemServer程式啟動ActivityManagerService服務例項,新增到ServiceManager(負責管理系統中的Binder物件)
- ActivityManagerService向PackageManagerService查詢Category型別為HOME的Activity,通過 ActivityStack.startActivityLocked將Launcher啟動起來
- Launcher在onCreate()中,通過這個PackageManagerService.queryIntentActivities介面來取回所有Action型別為Intent.ACTION_MAIN,並且Category型別為Intent.CATEGORY_LAUNCHER的Activity。顯示這些到頁面上。
Activity啟動流程
- AMS建立新程式,建立ActivityThread例項,將ApplicationThread的Binder物件傳遞給AMS並且開始了訊息迴圈。
- 從新程式呼叫到ActivityManagerService程式中,獲取要在新程式啟動的服務的相關資訊;
- 從ActivityManagerService程式又回到新程式中,最終將服務啟動起來。
3.1. performLaunchActivity()初始化Activity
3.1.1 classLoader載入Activity類,mInstrumentation.newActivity例項化Activity
3.1.2 makeApplication如果程式中沒有就重新建立
3.1.3 Activity.attach()將上下文資訊設定到Activity中 包括window建立
3.1.4 mInstrumentation.callActivityOnCreate->onCreate()
呼叫setContentView為decorView設定頁面內容
3.1.5 Instrumentation.callActivityOnStart->onStart()
初始化應用資料準備
3.2 handleResumeActivity啟用Activity
3.2.1 mInstrumentation.callActivityOnResume->onResume()
做準備顯示到互動的處理
3.2.2 wm.addView新增window的decorView開始繪製顯示頁面互動
Service啟動流程
service將計算型的邏輯單獨放在一個程式內執行提高使用者體驗。
start流程
- AMS建立新程式(會判斷ProcessRecord不存在才去建立),建立ActivityThread例項,將ApplicationThread的Binder物件傳遞給AMS並且開始了訊息迴圈。
- 從新程式呼叫到ActivityManagerService程式中,獲取要在新程式啟動的服務的相關資訊;
- 從ActivityManagerService程式又回到新程式中,最終將服務啟動起來。
3.1 handleCreateService()初始化Service
3.1.1 通過ClassLoader載入service類,然後的newInstance例項化Service
3.1.2 makeApplication如果程式中沒有就重新建立
3.1.3 service.attach() 上下文資訊設定到service中
3.1.4service.onCreate()
回撥 - 然後還會回新程式ApplicationThread.scheduleServiceArgs在主執行緒中回撥
onStartCommand
bind流程
- MainActivity呼叫bindService函式通知ActivityManagerService,它要啟動CounterService這個服務,ActivityManagerService於是在MainActivity所在的程式內部把CounterService啟動起來,並且呼叫它的
onCreate
函式; - ActivityManagerService把CounterService啟動起來後,繼續呼叫CounterService的
onBind
函式,要求CounterService返回一個Binder物件給它; - ActivityManagerService從CounterService處得到這個Binder物件後,就把它傳給MainActivity,即把這個Binder物件作為引數傳遞給MainActivity內部定義的ServiceConnection物件的onServiceConnected函式;
- MainActivity內部定義的ServiceConnection物件的onServiceConnected函式在得到這個Binder物件後,就通過它的getService成同函式獲得CounterService介面。
PhoneWindow流程
- 在Activity的attach中建立PhoneWindow並完成相關設定
1.1 呼叫PolicyManager.makeNewWindow建立PhoneWindow,
1.2 設定window的Calback將IO輸入事件分發給Activity(softMode設定)
1.3 設定windowManager,mAppToken為ActivityManagerService側ActivityRecord(Binder物件),mAppName為Activity元件名稱 - 在onCreate中的setContentView(rId)完成window的檢視內容的設定
2.1 installDecor()根據Theme和Feature完成window的頂級檢視mDecor以及找到mContentParent
2.2 通過mLayoutInflater.inflate(layoutResID, mContentParent)設定到mContentParent中 - 在handleResumeActivity()中wm.addView()將window的內容繪製出來
3.1 WindowManagerImpl.addView將decorView、viewRoot、LayoutParamas分別新增到mViews[i]、mRoots[i]和mParams[I]中
3.2 viewRootImpl.setView()完成相關成員的配置工作和繪製
3.2.1 將decorView設定到mAttachInfo.mRootView上
3.2.2 panelParentView不為空表示window是子視窗,需要儲存ApplicationWindowToken到mAttachInfo中
3.2.3 呼叫requestLayout()執行view樹的繪製流程
View繪製流程
- viewRootImpl的requestLayout()和invalidateChildInParent()最終都呼叫performTraversals()開始執行測量、佈局、繪製
- mView.measure測量所有view的寬高
這裡就比按照流程敘述了,按照我自己的通俗的理解來講
前言:view測量時有限制MeasureSpec。自己的申請(layout_)告訴父親,父親根據自己的情況計算家裡的情況給出的錢(空間)的使用限制。Mode:家裡的情況,Size:到手錢 自己當爸爸了 viewGroup(詳情getChildMeasureSpec)
家裡的情況 Mode,拿到手上有 size大小的錢
1.不管家裡任何情況,只要兒子申請花調固定的數字childDimension>=0,超過限制也給,
兒子的Mode=EXACTLY,Size=childDimension
2.其他的話看家裡情況
都用掉 EXACTLY:
兒子申請都給我吧 MATCH_PARENT:目標明確,給。兒子的Mode=EXACTLY,Size=size
兒子申請我自己算 WRAP_CONTENT:兒子的Model=AT_MOST,Size=size
家裡手頭緊不能超過 AT_MOST:
不管兒子申請 MATCH_PARENT 還是 WRAP_CONTENT:告訴子孫們手頭緊Mode=AT_MOST,Size=size
不知道啥情況,但是手動有錢 UNSPECIFIED:
不管兒子申請 MATCH_PARENT 還是 WRAP_CONTENT:告訴子孫們家裡不知道啥情況Mode=UNSPECIFIED,Size=size
複製程式碼
自己絕育了View,祖宗傳下來過日子之法 (詳情resolveSize)
看家裡情況
要你都用掉 EXACTLY:
都用光
家裡手頭緊不能超過 AT_MOST:
自己用多少算多少吧,不超過就行
不知道啥情況,但是手動有錢 UNSPECIFIED:
沒限制,自己用多少算多少
複製程式碼
- mView.layout 遞迴View樹 根據viewGroup的layout規則設定所有子View的位置
3.1 ViewGroup必須重寫onLayout,根據排列規則以及measure測量的寬高呼叫child.layout對子View進行設定
3.2 View的layout中呼叫setFrame完成對mLeft、mTop、mRight和mBottom賦值
總結:所有的View都得靠父佈局通過自己的margin等相對規則確定位置 - mView.draw 遞迴View樹繪製所有view到canvas上
4.1 draw()控制整體繪製流程,可被重寫
4.2 drawBackground()繪製背景,不可被重寫
4.3 ondraw()繪製主體,可被重寫
4.4 dispatchDraw() 主要給ViewGroup重寫分配給子View繪製,可重寫
4.5 繪製滾動條和前景 在6.0合併到onDrawForeground(),可被重寫
ps:其實還有一個draw被ViewGroup通過drawChild呼叫,這個draw拿到的canvas是完整的父View的canvas,應用view動畫的矩陣之後在整個canvas裡裁剪對應view位置和大小的一塊canvas交給處理view自身繪製流程的draw方法
應用事件分發流程
通過View樹傳遞觸控事件,一旦有View消費掉事件就不會繼續向下傳遞,如果沒有消費掉就會往上拋交給父View處理。down事件被View消費之後,後面連續的事件都會交給它處理。
- Activity事件分發
- phoneWindow將事件回撥Activity的dispatchTouchEvent()分發事件
- 如果Event是ACTION_DOWN的情況下會接著觸發onUserInteraction方法。
- 分發給mContentParent的子View處理事件
- 若子view攔截了事件(返回true)則Activity.onTouchEvent方法就不會執行。
- ViewGroup事件分發
- dispatchTouchEvent 分發處理事件
- 通過disallowIntercept先判斷子View是否不讓ViewGroup攔截事件
- onInterceptTouchEvent()判斷當前ViewGroup是否需要攔截該事件
- 不攔截就直接dispatchTransformedTouchEvent()分發給子View處理,如果子View沒有處理就繼續交給自己邏輯
- 攔截就交給自己處理,交給super.dispatchTochEvent()處理
- View事件分發
- dispatchTouchEvent 分發處理事件
- 如果view可用則呼叫mOnTouchListener(可消費調觸控事件)
- 在onTochEvent中處理事件
3.1 如果view是disable且是cliable 則直接消費調事件
3.2 如果是enable且discliable直接返回 不消費事件
3.3 如果是enable且cliable則處理消費事件邏輯,如up事件就會觸發clickListner
總結:view要消費調Down事件才會接受到後續事件,而事件達到view時可以被責任鏈裡的ViewGroup攔截掉,一旦攔截掉後續的任何一個事件對View來說就不完整了,所以為了保證view可以獲取所有事件,可以宣告不讓他們攔截自己的事件。自己也不要在onTouchListner裡隨便攔截會影響onTouchEvent的正常處理的。如果沒有view處理就會向上繼續傳播處理
部分學習自老羅的部落格