更新:
2016-10-29:更新handlebindapplication部分。
我這個版本的原則是,有話則長,無話則短.
以下分析基于6.0.1_r10版本。
先看一張大圖:
我們暫時忽略input處理的過程,以桌面的onclick事件被觸發為起點。
這部分根據launcher的不同而大同小異。
路徑:frameworks/base/services/core/java/com/android/server/am/activitymanagerservice.java
桌面調用framework,最後會調到ams的startactivity方法.
現在是多使用者時代了,startactivity現在唯一做的事兒,就是通過userhandle.getcallinguserid()去擷取目前的user id,然後調用startactivityasuser方法。
這個方法如其名,還真是隻處理跟user相關的工作,調用handleincominguser。
之後,調用activitystacksupervisor來去處理跟activity狀态相關真正邏輯。
路徑:frameworks/base/services/core/java/com/android/server/am/activitystacksupervisor.java
先解釋一下為什麼叫maywait,因為調用startactivity是可能要等待結果的startactivityforresult,那就要挂起調用者。
首先,startactivitymaywait要讀取一些資訊。從4.4開始,這部分邏輯寫到resolveactivity方法中,它會調用packagemanagerservice的resolveintent方法。這個方法會先調用queryintentactivities方法出查詢相關的清單,然後再調用choosebestactivity方法去選擇。為了不影響主線,這些支線内容後面再講。
主線往下走,進入startactivitylocked。locked意思是調用者需要保證加鎖保護,不能重複調用,在startactivitymaywait中,是采用mservice對象,也就是構造activitystacksupervisor時傳進來的activitymanagerservice的對象。
調用成功了之後,如果需要wait,就讓mservice.wait()去等待吧。新activity還在征途上。
前面先做一系列檢查的工作,比如權限,比如intent防火牆檢查。
準備做好之後,就new一個activityrecord,用于存儲activity的各種狀态和曆史資訊。
然後,通過getfocusedstack方法擷取目前擷取焦點的activitystack。activitystacksupervisor中的mfocusedstack中儲存了目前的前台activitystack。
下面就準備切換新程序了,先判斷一下是否可以切換,如果處于通話中界面等無法馬上切換的情況。通過activitymanagerservice的checkappswitchallowedlocked方法來做檢查,如果目前不允許做程序切換,就先存到pendingactivitylaunch的清單中,等待以後有機會再調用。
如果允許做切換,那麼先檢查一下目前是否有以前的等待任務,如果有就先執行它們,調用dopendingactivitylauncheslocked方法去執行這個循環。
如果以上都完成了,就調用startactivityuncheckedlocked。
通過一系列分析,找到了該執行的目标activitystack,然後調用該activitystack的startactivitylocked方法針對該任務做具體的操作。
路徑:frameworks/base/services/core/java/com/android/server/am/activitystack.java
如果需要的話,這一步中會調用到wms的setappstartingwindow,開始準備新應用的啟動視窗。
這其中,有重要一步是調用windowmanagerservice的addapptoken方法去将資訊共步給wms,為下一步的顯示做準備。
最後,調用activitystacksupervisor的resumetopactivitieslocked方法,将顯示的activities都resume一下。
先擷取目前焦點顯示的activitystack,調其resumetopactivitylocked。完成後,周遊所有能顯示的activity的stack。
調用resumetopactivityinnerlocked
這是第一次進入這個方法,這次我們是走pause桌面這一支,下一次我們就走到最後的startspecificactivitylocked那一支。
調用startpausinglocked去pause。
ams開始發起pause桌面的操作
如果不是從桌面啟動的話,就要去為上一個應用抓個用于顯示在近期任務裡的圖。
prev.updatethumbnaillocked(screenshotactivities(prev), null);
處理完成之後,通知桌面應用去執行onpause。
prev.app.thread.schedulepauseactivity(prev.apptoken, prev.finishing,userleaving, prev.configchangeflags, dontwait);
這個thread就是ipc的applicationthreadnative對象。
路徑:frameworks/base/core/java/android/app/applicationthreadnative.java
ams要通過ipc來通知給桌面,于是通過proxy來發送ipc操作.
路徑:frameworks/base/core/java/android/app/activitythread.java
通過ipc,運作桌面應用的activitythread的schedulepauseactivity。此處activitythread會将這個請求放入隊列中,等待運作。
在這段期間,wms也沒閑着,類似于之前我們在startactivitylocked時做的addwindow之類的操作一直在幹活。
終于從隊列中輪到出場了,開始執行桌面的onpause吧。
不過先别急,執行onpause之前,先執行performuserleavingactivity,最後會調到activity的performuserleaving。
這個方法做兩步:
這些都做完了,調用performpauseactivity。
首先判斷一下狀态,如果已經pause了,那就需要先resume之。當然,如果pause了之後正在finishing中,就算了,不是的話,抛個runtimeexception,問問調用者不先resume是為哪般。
沒有異常的話,先調用callcallactivityonsaveinstancestate,這個會通過instrumentation的callactivityonsaveinstancestate去調用activity的performsaveinstancestate, 然後會調到activity的onsaveinstancestate。還會将對話框的資訊做儲存操作。
儲存完狀态之後,再調用instrumentation的callactivityonpause。然後調用activity的performpause。
activity在onpause之前,先通知各個fragment去onpause,再調用activity的onpause.
performpauseactivity結束後,回到launchpauseactivity,下面通知ams,調ipc來做activitypaused。
路徑:frameworks/base/core/java/android/app/activitymanagernative.java
桌面的onpause執行完了,通過ipc通知ams,可以啟動新應用了。
路徑:services/core/java/com/android/server/am/activitymanagerservice.java
ams收到activitypaused的消息,然後找到對應的activitystack的activitypausedlocked。
然後調用completepausedlocked。
到此,桌面的onpause正式告一段落。
結束之後,再次調用前面我們已經遇到過的activitystacksupervisor的resumetopactivitieslocked,前一次我們走了一半就調pause過程去了,這次我們将走到最後。
還跟上次一樣,調相應的activitystack的resumetopactivitylocked。
這個方法隻是一個十幾行的wrapper,除了設了個flag和處理鎖屏之外,直接調用resumetopactivityinnerlocked方法。
這個大方法走到最後,執行activitystacksupervisor的startspecificactivitylocked。
(注:這個方法是5.0之後分出來的,4.4上還在resumetopactivitylocked裡面)
從這裡,又從activitystacksupervisor調回activitymanagerservice,調用startprocesslocked。
通過調用android.os.process的start去啟動新程序。
路徑:frameworks/base/ core/java/android/os/process.java
其實就是startviazygote的一個簡單封裝。
路徑:frameworks/base/core/java/android/os/process.java
主要是處理參數,然後調用zygotesendargsandgetresult去通過socket通信去通知zygote。
通過socket通知zygote程序去fork新程序。接收方是zygoteconnection。
路徑:frameworks/base/core/java/com/android/internal/os/zygoteconnection.java
從socket中讀取指令并執行。
這個可以往下再分為4步:
readargumentlist
apply security policies
preforkandspecialize
路徑:/frameworks/base/core/java/com/android/internal/os/zygote.java
這步分為三個子步驟:
prefork
nativeforkandspecialize
postforkcommon
路徑:/libcore/dalvik/src/main/java/dalvik/system/ zygotehooks.java
這步離開了frameworks/base,進入了libcore。這裡面要注意,不能調用android的api,打個log什麼的都要注意。
daemons.stop()
停掉gc,停掉finalizer等,fork程序時不需要這些
waituntilallthreadsstopped()
確定fork之前隻有一個線程在運作
nativeprefork()
給虛拟機一個機會去在fork之前做點處理
路徑:/frameworks/base/core/jni/com_android_internal_os_zygote.cpp
這是我們第一次進入c++層。真正做事的函數是forkandspecializecommon。
真正開始fork新程序
setsigchldhandler
fork and detach(新程序從這一步開始誕生)
child process setup
這一步是值得大書特書的一步,因為從這一步開始,更具體地說是從fork and detach開始,新應用的程序終于fork出來了。從此zygote老程序的事情我們不再關心,我們來看新程序号就好了。
child process setup之後,有一個重要的函數會被執行到,這就是zygotehooks_nativepostforkchild。
在這個函數中,我們熟悉的aoc版本号的log會輸出出來。
這個函數的aoc版本路徑在:/aliyunos/aoc/vm/native/dalvik_system_zygotehooks.cc中。
對應的art版本在:/art/runtime/native/dalvik_system_zygotehooks.cc中。
路徑:/libcore/dalvik/src/main/java/dalvik/system/zygotehooks.java
隻幹一件事,把prefork裡面stop的monitor們重新打開。這一步要注意,原來的zygote裡面的不要去管了,隻看新程序的就好。
路徑:frameworks/base/core/java/com/android/internal/os/runtimeinit.java
初始化完成,通過反射來調用activitythread的main方法
路徑:frameworks/base/ core/java/android/app/activitythread.java
執行activitythread的main方法,新的應用正式上路
路徑:frameworks/base/
新的activity建好了,要通知ams,走ipc。
路徑: frameworks/base/services/core/java/com/android/server/am/activitymanagerservice.java
ams收到attach的通知,一切準備就緒。
路徑:frameworks/base/ services/core/java/com/android/server/am/activitymanagerservice.java
其它部分都是線性的,這部分我們不得不分成兩個部分各表一支了。這兩部分分别走ipc,最後在activitythread的隊列中彙合。
首先是bindapplication。
ipc調用
主要包括兩部分的操作,雖然這個方法不叫做schedulexxx,但是實際上兩步的操作都是放到隊列中。
到這一步的時候,其實我們隻是啟動了一個空程序而己,跟實際的apk還一點關系也沒有。
首先,如果services不為空的話,先初始化一下services cache。
servicemanager.initservicecache(services);
然後,schedule第一個任務,setcoresettings(coresettings);
這個最終會走到handlesetcoresettings。
下面,pm才出場去讀真正的package的資訊。讀好之後,再去将bind_application消息放到隊列裡去,這時候可能正在執行setcoresettings。
真正啟動activity之前,還得做一些準備工作。比如install provider就是在這時候做的。
我們都知道,在activity之外,對于每個應用,還對應一個application類。這個application就是在loadapk的makeapplication方法時構造的。
下面調用classloader,并且生成applicationcontext.
下面将通過intrumentation的newapplication方法去真正建立application
通過反射構造對象,然後調用application的attach方法。
attach再調用attachbasecontext。
50 @override
51 protected void attachbasecontext(context newbase) {
52 super.attachbasecontext(newbase);
53 }
65 protected void attachbasecontext(context base) {
66 if (mbase != null) {
67 throw new illegalstateexception("base context already set");
68 }
69 mbase = base;
70 }
586 if (instrumentation != null) {
587 try {
588 instrumentation.callapplicationoncreate(app);
589 } catch (exception e) {
590 if (!instrumentation.onexception(app, e)) {
591 throw new runtimeexception(
592 "unable to create application " + app.getclass().getname()
593 + ": " + e.tostring(), e);
594 }
595 }
596 }
598 // rewrite the r 'constants' for all library apks.
599 sparsearray packageidentifiers = getassets(mactivitythread)
600 .getassignedpackageidentifiers();
601 final int n = packageidentifiers.size();
602 for (int i = 0; i < n; i++) {
603 final int id = packageidentifiers.keyat(i);
604 if (id == 0x01 || id == 0x7f) {
605 continue;
606 }
607
608 rewritervalues(getclassloader(), packageidentifiers.valueat(i), id);
609 }
610
611 return app;
612 }
mwindowsession = windowmanagerglobal.getwindowsession();
if (mwindowmap.containskey(client.asbinder())) {
}
win = new windowstate(this, session, client, token,attachedwindow, appop0, seq, attrs, viewvisibility, displaycontent);
getrunqueue().executeactions(mattachinfo.mhandler);
windowsizemaychange |= measurehierarchy(host, lp, res,desiredwindowwidth, desiredwindowheight);
winanimator.applyenteranimationlocked();
surfacecontrol surfacecontrol = winanimator.createsurfacelocked();
void drawframetask::postandwait() {
automutex _lock(mlock);
mrenderthread->queue(this);
msignal.wait(mlock);