启动Activity的流程(Launcher中点击图标启动)
啟動(dòng)Activity一般有多種方式,常見的有三種:
在Launcher桌面點(diǎn)擊app圖標(biāo)
調(diào)用startActivity啟動(dòng)一個(gè)Activity
命令am start啟動(dòng)
這三種方式在服務(wù)端的處理方式基本相同,客戶端的請(qǐng)求方式也差別不大,理解其中之一就可以類推到其他方式。本文結(jié)合案例分析在Launcher桌面點(diǎn)擊app圖標(biāo)啟動(dòng)應(yīng)用的方式,再簡(jiǎn)要給出其他兩種方式的區(qū)別。
案例
應(yīng)用名稱為TestLaunchApp,包含A和B兩個(gè)Activity,A為入口類,點(diǎn)擊按鈕跳轉(zhuǎn)到B
A.java| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | packagecom.example.startapptest; import?android.app.Activity; import?android.content.Intent; import?android.os.Bundle; import?android.util.Log; import?android.view.View; publicclassAextendsActivity{ privatefinalstaticStringTAG="StartAppTest"; @Override protectedvoidonCreate(Bundle?savedInstanceState){ super.onCreate(savedInstanceState); Log.i(TAG,"A"+"--------------onCreate()"); setContentView(R.layout.a_layout); } @Override protectedvoidonResume(){ // TODO Auto-generated method stub Log.i(TAG,"A"+"--------------onResume()"); super.onResume(); } @Override protectedvoidonPause(){ // TODO Auto-generated method stub Log.i(TAG,"A"+"--------------onPause()"); super.onPause(); } publicvoidfuncA(View?view){ startActivity(newIntent("com.feeyan.www.b_activity")); } @Override publicvoidonBackPressed(){ // TODO Auto-generated method stub finish(); super.onBackPressed(); } } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | packagecom.example.startapptest; import?android.app.Activity; import?android.content.Intent; import?android.os.Bundle; import?android.util.Log; import?android.view.View; publicclassBextendsActivity{ privatefinalstaticStringTAG="StartAppTest"; @Override protectedvoidonCreate(Bundle?savedInstanceState){ super.onCreate(savedInstanceState); Log.i(TAG,"B"+"--------------onCreate()"); setContentView(R.layout.b_layout); } @Override protectedvoidonResume(){ Log.i(TAG,"B"+"--------------onResume()"); super.onResume(); } @Override protectedvoidonPause(){ // TODO Auto-generated method stub Log.i(TAG,"B"+"--------------onPause()"); super.onPause(); } publicvoidfuncB(View?view){ startActivity(newIntent("com.feeyan.www.a_activity")); finish(); } } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?xml?version="1.0"encoding="utf-8"?> <RelativeLayout?xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <Button android:id="@+id/button_a_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="50dp" android:onClick="funcA" android:text="@string/button_a_text" android:textSize="20sp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="154dp" android:text="@string/page_a_text" android:textSize="30sp"/> </RelativeLayout> |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?xml?version="1.0"encoding="utf-8"?> <RelativeLayout?xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <Button android:id="@+id/button_b_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="50dp" android:onClick="funcB" android:text="@string/button_b_text" android:textSize="20sp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/button_b_id" android:layout_centerHorizontal="true" android:layout_marginBottom="140dp" android:text="@string/page_b_text" android:textSize="30sp"/> </RelativeLayout> |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <?xml?version="1.0"encoding="utf-8"?> <manifest?xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.startapptest" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="17" android:targetSdkVersion="21"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".A" android:label="@string/app_name"> <intent-filter> <action?android:name="android.intent.action.MAIN"/> <category?android:name="android.intent.category.LAUNCHER"/> </intent-filter> <intent-filter> <action?android:name="com.feeyan.www.a_activity"> </action> <category?android:name="android.intent.category.DEFAULT"> </category> </intent-filter> </activity> <activity android:name=".B" android:label="@string/app_name"> <intent-filter> <action?android:name="com.feeyan.www.b_activity"> </action> <category?android:name="android.intent.category.DEFAULT"> </category> </intent-filter> </activity> </application> </manifest> |
當(dāng)點(diǎn)擊A中的按鈕時(shí),跳轉(zhuǎn)到B,先暫停A,A從前臺(tái)轉(zhuǎn)入到后臺(tái),開始執(zhí)行B的onCreate、onResume方法,B被調(diào)入到棧頂,B現(xiàn)在可見,日志為:
| 1 2 3 4 5 | I/StartAppTest(26256):A--------------onCreate() I/StartAppTest(26256):A--------------onResume() I/StartAppTest(26256):A--------------onPause() I/StartAppTest(26256):B--------------onCreate() I/StartAppTest(26256):B--------------onResume() |
啟動(dòng)一個(gè)Activity的標(biāo)志是開始執(zhí)行生命周期onCreate方法,轉(zhuǎn)入到后臺(tái)的標(biāo)志是onPause方法,正在運(yùn)行、可見的標(biāo)志是onResume方法,本文將從源碼著手,分析啟動(dòng)activity的過程。
1. 在Launcher桌面點(diǎn)擊app圖標(biāo)啟動(dòng)入口Activity
本文基于android5.1.1源碼,在Launcher主頁(yè)面當(dāng)點(diǎn)擊圖表時(shí),調(diào)用過程為:
onClick—->……—->startActivitySafely—->startActivity(v, intent, tag)—->startActivity(intent, optsBundle);
源碼:packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
intent設(shè)置了FLAG_ACTIVITY_NEW_TASK標(biāo)志,表示開啟一個(gè)新任務(wù),在新任務(wù)中啟動(dòng)activity,本案例沒有特殊的動(dòng)畫設(shè)置,optsBundle為null。
framework層客戶端
過程1 ? ?frameworks\base\core\java\android\app\Activity.java
startActivity所屬的對(duì)象是this,表示當(dāng)前啟動(dòng)類Launcher對(duì)象,下一步執(zhí)行到Activity的startActivity方法,過程為:
startActivity(Intent intent, @Nullable Bundle options)
—-> startActivityForResult(intent, -1)
—-> startActivityForResult(intent, requestCode, null)
注:由于源碼較長(zhǎng),本文不貼上全部源碼,只給出方法名稱、部分代碼以及源碼路徑
action為字符串“com.feeyan.www.b_activity”,requestCode等于-1,如果>=0, B被啟動(dòng)后會(huì)返回到A中,且A中的onActivityResult()方法會(huì)被調(diào)用。即便是調(diào)用startActivity,還是會(huì)調(diào)到 startActivityForResult,只不過此時(shí)requestCode是-1了。
mParent:如果不為空,表示當(dāng)前Activity有子類,本案例沒有子類,為空,進(jìn)程執(zhí)行到:
| 1 2 3 4 | Instrumentation.ActivityResult?ar= mInstrumentation.execStartActivity( this,mMainThread.getApplicationThread(),mToken,this, intent,requestCode,options); |
要搞懂源碼,最關(guān)鍵的就是弄清楚參數(shù)的具體含義,源碼中參數(shù)有時(shí)候多達(dá)十幾個(gè),如果不清楚參數(shù)的來龍去脈,無從分析。
this:當(dāng)前進(jìn)程還是在Launcher所在的進(jìn)程,this就是Launcher類的一個(gè)對(duì)象。
mMainThread.getApplicationThread():返回一個(gè)ApplicationThread對(duì)象類型,也是一個(gè)IBinder對(duì)象類型,,mMainThread是ActivityThread的一個(gè)對(duì)象,代表當(dāng)前Launcher主線程對(duì)象
mToken:也是一個(gè)IBinder對(duì)象類型
requestCode仍為-1,options為null
過程2 ? ?frameworks\base\core\java\android\app\Instrumentation.java
| 1 2 3 4 5 | publicActivityResult?execStartActivity( Context?who,IBinder?contextThread,IBinder?token,Activity?target, Intent?intent,intrequestCode,Bundle?options){ ...... } |
this對(duì)象傳給execStartActivity,該函數(shù)的第一個(gè)形參who是Context類型,第4個(gè)形參target是Activity類型,其實(shí)際類型都是Launcher對(duì)象,只是名字起的不一樣,這就是一種共識(shí),代表著某種含義,讀者看到名字就能猜得著其用意。
| 1 | IApplicationThread?whoThread=(IApplicationThread)contextThread; |
contextThread既是IBinder對(duì)象,也是IApplicationThread對(duì)象,此處向上轉(zhuǎn)型為IApplicationThread對(duì)象,
| 1 2 3 4 5 | intresult=ActivityManagerNative.getDefault() .startActivity(whoThread,who.getBasePackageName(),intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token,target!=null?target.mEmbeddedID:null, requestCode,0,null,options); |
ActivityManagerNative實(shí)現(xiàn)了IActivityManager接口,調(diào)用getDefault方法最終返回ActivityManagerService的代理類ActivityManagerProxy的一個(gè)對(duì)象,于是,startActivity便轉(zhuǎn)入到ActivityManagerProxy對(duì)象中開始執(zhí)行。
過程3 ? ?frameworks\base\core\java\android\app\ActivityManagerNative.java
| 1 2 3 4 5 | publicintstartActivity(IApplicationThread?caller,StringcallingPackage,Intent?intent, StringresolvedType,IBinder?resultTo,StringresultWho,intrequestCode, intstartFlags,ProfilerInfo?profilerInfo,Bundle?options)throwsRemoteException{ ...... } |
分析參數(shù)時(shí),結(jié)合實(shí)際參數(shù)來看,否則單獨(dú)看形參不能確定具體含義。
caller:前面?zhèn)鬟^來的值,代表ApplicationThread對(duì)象
callingPackage:由who.getBasePackageName()的值傳遞而來,who是Context對(duì)象,getBasePackageName()的實(shí)現(xiàn)在ContextImple中,返回當(dāng)前啟動(dòng)類的包名,就是Launcher的包名
resolvedType:解析當(dāng)前發(fā)送的Intent的MIME數(shù)據(jù)類型,本案例沒有為intent設(shè)置type、data屬性,因此,intent.resolveTypeIfNeeded(who.getContentResolver())返回null
resultTo:Ibinder對(duì)象,具體含義后面繼續(xù)看
resultWho:由target != null ? target.mEmbeddedID : null得來,target是activity對(duì)象即啟動(dòng)類Launcher對(duì)象,不為空,該語句返回mEmbeddedID,一個(gè)id號(hào),這個(gè)值必須要從Launcher這個(gè)apk啟動(dòng)中獲得,在Launcher啟動(dòng)后,代表Launcher啟動(dòng)類的對(duì)象是一個(gè)ActivityClientRecord對(duì)象,該對(duì)象所屬的類路徑為:
frameworks\base\core\java\android\app\ActivityThread.java
該對(duì)象的scheduleLaunchActivity方法中,有一句:
ActivityClientRecord r = new ActivityClientRecord();
在ActivityClientRecord的構(gòu)造方法中會(huì)把embeddedID初始化為null,因此mEmbeddedID為空
startFlags:整型值,已經(jīng)初始化為0,具體作用后面分析
profilerInfo:為null,具體作用后面分析
這些參數(shù)都會(huì)被打包到持久化類Parcel的對(duì)象data中,把data作為transact的參數(shù)進(jìn)行跨進(jìn)程傳遞:
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
該方法通過binder通信機(jī)制會(huì)傳遞到ActivityManagerNative的onTransact方法,在onTransact方法中,根據(jù)發(fā)送命令START_ACTIVITY_TRANSACTION找到case處理語句,把data中的數(shù)據(jù)取出來賦給相應(yīng)的變量,繼續(xù)調(diào)用:
| 1 2 | intresult=startActivity(app,callingPackage,intent,resolvedType, resultTo,resultWho,requestCode,startFlags,profilerInfo,options); |
startActivity最終會(huì)調(diào)用到服務(wù)端ActivityManagerService中。此時(shí),進(jìn)程也從啟動(dòng)類Launcher所在的進(jìn)程切換到了服務(wù)端進(jìn)程。從ActivityManagerNative.getDefault().startActivity一直到ActivityManagerService的startActivity方法,主要由binder通信實(shí)現(xiàn),該過程相當(dāng)復(fù)雜,但binder通信不屬于本文重點(diǎn),而且binder機(jī)制貫穿于整個(gè)Android系統(tǒng)、內(nèi)核、驅(qū)動(dòng)部分,本文如再遇到binder通信機(jī)制,直接給出最終被調(diào)用的類及方法。
在進(jìn)入到服務(wù)端之前,看看客戶端到底做了哪些工作?
主要是獲得了一些必要的參數(shù):IApplicationThread對(duì)象、啟動(dòng)類包名、Intent的MIME數(shù)據(jù)類型、IApplicationToken.Stub類型對(duì)象resultTo等,除了這些,沒有其他特殊的操作了,其實(shí)最關(guān)鍵的操作還是在服務(wù)端進(jìn)行的,這就是為何本文一開始提到無論哪種啟動(dòng)方式,客戶端都是大同小異。
framework層服務(wù)端
過程4 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
startActivity—->startActivityAsUser—->mStackSupervisor.startActivityMayWait
| 1 2 3 | mStackSupervisor.startActivityMayWait(caller,-1,callingPackage,intent, resolvedType,null,null,resultTo,resultWho,requestCode,startFlags, profilerInfo,null,null,options,userId,null,null); |
這幾步?jīng)]有太多的操作,獲得了一個(gè)用戶id,用來作一些檢測(cè)
過程5 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
| 1 2 3 4 5 6 7 8 | finalintstartActivityMayWait(IApplicationThread?caller,intcallingUid, StringcallingPackage,Intent?intent,StringresolvedType, IVoiceInteractionSession?voiceSession,IVoiceInteractor?voiceInteractor, IBinder?resultTo,StringresultWho,intrequestCode,intstartFlags, ProfilerInfo?profilerInfo,WaitResult?outResult,Configuration?config, Bundle?options,intuserId,IActivityContainer?iContainer,TaskRecord?inTask){ ...... } |
先看多了哪些參數(shù):
voiceSession:IVoiceInteractionSession對(duì)象類型,被初始化null。IVoiceInteractionSession本是一個(gè)aidl遠(yuǎn)程接口,定義了任務(wù)棧啟動(dòng)taskStarted、任務(wù)棧結(jié)束taskFinished等方法
voiceInteractor:IVoiceInteractor對(duì)象類型,被初始化為null。IVoiceInteractor也是一個(gè)aidl遠(yuǎn)程接口
outResult:WaitResult對(duì)象類型,被初始化為null。WaitResult是IActivityManager的內(nèi)部類,實(shí)現(xiàn)了Parcelable接口,主要用來保存啟動(dòng)Activity后返回的結(jié)果信息
config:Configuration對(duì)象類型,被初始化為null。Configuration描述了所有設(shè)備相關(guān)的配置信息,比如,本地語言、屏幕大小、屏幕方向、輸入法模式,可以通過Resources的getConfiguration獲得改對(duì)象
iContainer:IActivityContainer對(duì)象類型,被初始化為null。IActivityContainer也是一個(gè)aidl遠(yuǎn)程接口
inTask:TaskRecord對(duì)象類型,被初始化為null。TaskRecord很重要,會(huì)經(jīng)常用到此類,描述一個(gè)任務(wù)棧,每個(gè)任務(wù)棧可以包含多個(gè)Activity對(duì)象,每個(gè)TaskRecord對(duì)象都有一個(gè)當(dāng)前棧ActivityStack的引用,每個(gè)棧可以對(duì)應(yīng)多個(gè)TaskRecord對(duì)象
除了這些多余的參數(shù),其他參數(shù)都是從客戶端傳遞而來。
| 1 | booleancomponentSpecified=intent.getComponent()!=null; |
getComponent方法返回一個(gè)ComponentName對(duì)象,該對(duì)象表示通過intent要啟動(dòng)的組件類,本案例就對(duì)應(yīng)A這個(gè)Activity,ComponentName對(duì)象一般用包名和類名標(biāo)識(shí)一個(gè)組件,因此,componentSpecified為true
| 1 | intent=newIntent(intent); |
根據(jù)客戶端傳遞過來的Intent對(duì)象重新構(gòu)建一個(gè)Intent對(duì)象,這樣做是不要破壞客戶端傳遞來的Intent對(duì)象
| 1 2 3 4 5 6 7 | ActivityInfo?aInfo=resolveActivity(intent,resolvedType,startFlags, profilerInfo,userId); ActivityInfo?resolveActivity(Intent?intent,StringresolvedType,intstartFlags, ProfilerInfo?profilerInfo,intuserId){ ...... } |
resolveActivity方法開始解析Intent對(duì)象,返回intent對(duì)應(yīng)的目標(biāo)Activity類的ActivityInfo對(duì)象,ActivityInfo類專門用來描述AndroidManifest.xml中Activity、Receiver組件信息的,本案例返回的就是A這個(gè)類對(duì)應(yīng)的信息,ActivityInfo的成員變量name就是類名稱,packageName就是包名稱,對(duì)應(yīng)本案例分別為com.example.startapptest.A和com.example.startapptest
| 1 2 3 4 5 6 7 8 | if(callingUid>=0){ callingPid=-1; }elseif(caller==null){ callingPid=realCallingPid; callingUid=realCallingUid; }else{ callingPid=callingUid=-1; } |
callingUid傳過來時(shí)為-1,call又不為空,進(jìn)程執(zhí)行else字句callingPid = callingUid = -1;
| 1 2 3 4 5 6 7 8 | ActivityContainer?container=(ActivityContainer)iContainer; finalActivityStack?stack; if(container==null||container.mStack.isOnHomeDisplay()){ stack=getFocusedStack(); }else{ stack=container.mStack; } |
iContainer為空,那么container也為空,調(diào)用getFocusedStack獲得當(dāng)前正在前臺(tái)的棧,也就是Launcher所在的棧。
| 1 2 3 4 | if(aInfo!=null&& (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE)!=0){ ...... } |
aInfo雖然不為空,但aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE卻為0,因?yàn)闆]有設(shè)置這種屬性,因此跳過該if語句,開始執(zhí)行:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | intres=startActivityLocked(caller,intent,resolvedType,aInfo, voiceSession,voiceInteractor,resultTo,resultWho, requestCode,callingPid,callingUid,callingPackage, realCallingPid,realCallingUid,startFlags,options, componentSpecified,null,container,inTask); finalintstartActivityLocked(IApplicationThread?caller, Intent?intent,StringresolvedType,ActivityInfo?aInfo, IVoiceInteractionSession?voiceSession,IVoiceInteractor?voiceInteractor, IBinder?resultTo,StringresultWho,intrequestCode, intcallingPid,intcallingUid,StringcallingPackage, intrealCallingPid,intrealCallingUid,intstartFlags,Bundle?options, booleancomponentSpecified,ActivityRecord[]outActivity,ActivityContainer?container, TaskRecord?inTask){ ...... } |
callingPid:int型變量,看字面意思與pid相關(guān),具體含義后面再看
callingUid:int型變量,看字面意思與uid相關(guān),具體含義后面再看
realCallingPid:啟動(dòng)類所在進(jìn)程的pid,本案例是Launcher
realCallingUid:啟動(dòng)類所在進(jìn)程的uid,本案例是Launcher
componentSpecified:為true,表明intent對(duì)應(yīng)的目標(biāo)Activity類存在
outActivity:ActivityRecord數(shù)組名稱,初始化為null,ActivityRecord是一個(gè)動(dòng)態(tài)生成的對(duì)象,代表Activity在歷史棧中的記錄,ActivityRecord包含了Activity所有信息。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | ProcessRecord?callerApp=null; if(caller!=null){ callerApp=mService.getRecordForAppLocked(caller); if(callerApp!=null){ callingPid=callerApp.pid; callingUid=callerApp.info.uid; }else{ Slog.w(TAG,"Unable to find app for caller "+caller +" (pid="+callingPid+") when starting: " +intent.toString()); err=ActivityManager.START_PERMISSION_DENIED; } } |
mService是ActivityManagerService對(duì)象,通過getRecordForAppLocked方法獲得啟動(dòng)類所在進(jìn)程的進(jìn)程記錄對(duì)象ProcessRecord。參數(shù)caller是IApplicationThread對(duì)象,前文提到過,實(shí)際是ApplicationThread對(duì)象,代表Launcher類的主線程,caller在ActivityManagerService和ActivityThread兩個(gè)進(jìn)程之間完成通信,現(xiàn)在終于明白了,為何在startActivity時(shí)會(huì)帶著這樣一個(gè)參數(shù):服務(wù)端通過該參數(shù)獲得客戶端進(jìn)程信息,該參數(shù)起到橋梁作用。
callerApp不為空,分別獲得啟動(dòng)類進(jìn)程的pid和uid保存到callingPid、callingUid中,這個(gè)callingPid和之前的realCallingPid獲得的值一樣,都是Launcher進(jìn)程pid
| 1 2 3 4 5 6 7 8 9 10 11 12 | ActivityRecord?sourceRecord=null; ActivityRecord?resultRecord=null; if(resultTo!=null){ sourceRecord=isInAnyStackLocked(resultTo); if(DEBUG_RESULTS)Slog.v( TAG,"Will send result to "+resultTo+" "+sourceRecord); if(sourceRecord!=null){ if(requestCode>=0&&!sourceRecord.finishing){ resultRecord=sourceRecord; } } } |
定義了兩個(gè)ActivityRecord變量sourceRecord、resultRecord,用來對(duì)應(yīng)啟動(dòng)類和目標(biāo)類。上文提到,resultTo屬于IBinder對(duì)象,屬于啟動(dòng)方的對(duì)象。isInAnyStackLocked方法根據(jù)啟動(dòng)類的標(biāo)記resultTo對(duì)象在列表?xiàng)V姓页鰧?duì)應(yīng)的棧,再在棧頂找到Activity記錄保存到sourceRecord中。
| 1 | finalintlaunchFlags=intent.getFlags(); |
上文提到,intent一開始在客戶端就被設(shè)置了FLAG_ACTIVITY_NEW_TASK標(biāo)志,getFlags方法便取出該標(biāo)志,保存到launchFlags變量中。
| 1 2 3 | ActivityRecordr=newActivityRecord(mService,callerApp,callingUid,callingPackage, intent,resolvedType,aInfo,mService.mConfiguration,resultRecord,resultWho, requestCode,componentSpecified,this,container,options); |
創(chuàng)建一個(gè)ActivityRecord對(duì)象,這個(gè)ActivityRecord對(duì)象具體有什么作用?看看參數(shù)具體含義
前4個(gè)參數(shù)代表了啟動(dòng)類Launcher,第5~7參數(shù)(Intent,resolvedType, aInfo)代表了目標(biāo)類
mService.mConfiguration表示系統(tǒng)配置,resultRecord代表目標(biāo)類,resultWho代表啟動(dòng)類的一個(gè)id號(hào),為空
componentSpecified為true
this:代表當(dāng)前ActivityStackSupervisor對(duì)象
從參數(shù)來看,該類既包含啟動(dòng)類的屬性,又包含目標(biāo)類屬性,推測(cè)該類應(yīng)該用來表達(dá)目標(biāo)類,后面可以證明。
startActivityLocked方法的作用:獲得啟動(dòng)類進(jìn)程信息、pid、uid,創(chuàng)建ActivityRecord類對(duì)象sourceRecord保存啟動(dòng)類信息,創(chuàng)建ActivityRecord對(duì)象r,暫時(shí)推測(cè)代表目標(biāo)類,具體含義后面分析。進(jìn)程繼續(xù)調(diào)用:
| 1 2 | err=startActivityUncheckedLocked(r,sourceRecord,voiceSession,voiceInteractor, startFlags,true,options,inTask); |
開始調(diào)用下一步操作,第一個(gè)參數(shù)就是剛才創(chuàng)建的ActivityRecord對(duì)象;第二個(gè)參數(shù)是啟動(dòng)類對(duì)象,不為空;
| 1 2 3 4 5 | finalintstartActivityUncheckedLocked(ActivityRecordr,ActivityRecord?sourceRecord, IVoiceInteractionSession?voiceSession,IVoiceInteractor?voiceInteractor,intstartFlags, booleandoResume,Bundle?options,TaskRecord?inTask){ ...... } |
| 1 2 | finalIntent?intent=r.intent; finalintcallingUid=r.launchedFromUid; |
r.intent就是傳遞而來的intent對(duì)象,r.launchedFromUid就是啟動(dòng)類Launcher的uid
| 1 2 3 | finalbooleanlaunchSingleTop=r.launchMode==ActivityInfo.LAUNCH_SINGLE_TOP; finalbooleanlaunchSingleInstance=r.launchMode==ActivityInfo.LAUNCH_SINGLE_INSTANCE; finalbooleanlaunchSingleTask=r.launchMode==ActivityInfo.LAUNCH_SINGLE_TASK; |
這三個(gè)變量代表目標(biāo)類的啟動(dòng)模式,本案例就是A的啟動(dòng)模式,沒有任何設(shè)置,默認(rèn)為Standard模式,因而這三個(gè)變量都是false
| 1 | mUserLeaving=(launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION)==0; |
FLAG_ACTIVITY_NO_USER_ACTION:當(dāng)啟動(dòng)目標(biāo)Activity時(shí)Intent設(shè)置了此標(biāo)志,前臺(tái)正在行的Activity在暫停之前(執(zhí)行onPaused方法)不會(huì)回調(diào)onUserLeaveHint方法。NO_USER_ACTION表示非用戶操作,如果設(shè)置了此標(biāo)志,表示非用戶行為時(shí)不會(huì)回調(diào)onUserLeaveHint。比如,鬧鐘響了、來電話了,這屬于非用戶操作,如果設(shè)置了此標(biāo)志,就不會(huì)回調(diào)onUserLeaveHint,相反,如果是用戶操作行為比如按下HOME按鍵,返回鍵等,就會(huì)回調(diào)onUserLeaveHint。本案例中發(fā)送給A的Intent沒有設(shè)置該標(biāo)志,mUserLeaving為true,表明不是非用戶操作行為。
| 1 2 | ActivityRecord?notTop= (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)!=0?r:null; |
Intent沒有設(shè)置FLAG_ACTIVITY_PREVIOUS_IS_TOP,notTop為空
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | if(sourceRecord!=null){ if(sourceRecord.finishing){ // If the source is finishing, we can't further count it as our source. ?This // is because the task it is associated with may now be empty and on its way out, // so we don't want to blindly throw it in to that task. ?Instead we will take // the NEW_TASK flow and try to find a task for it. But save the task information // so it can be used when creating the new task. if((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK)==0){ Slog.w(TAG,"startActivity called from finishing "+sourceRecord +"; forcing "+"Intent.FLAG_ACTIVITY_NEW_TASK for: "+intent); launchFlags|=Intent.FLAG_ACTIVITY_NEW_TASK; newTaskInfo=sourceRecord.info; newTaskIntent=sourceRecord.task.intent; } sourceRecord=null; sourceStack=null; }else{ sourceStack=sourceRecord.task.stack; } }else{ sourceStack=null; } |
sourceRecord不為空,變量finishing為空,因?yàn)榇藭r(shí)啟動(dòng)類Launcher還在前臺(tái),沒有進(jìn)入到銷毀列表中,進(jìn)程執(zhí)行else語句,得到啟動(dòng)類所在的棧對(duì)象并保存到sourceStack中。
| 1 2 3 4 5 6 7 8 9 | if(((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK)!=0&& (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK)==0) ||launchSingleInstance||launchSingleTask){ // If bring to front is requested, and no result is requested and we have not // been given an explicit task to launch in to, and // we can find a task that was started with this same // component, then instead of launching bring that one to the front. if(inTask==null&&r.resultTo==null){ ...... |
Intent沒有設(shè)置FLAG_ACTIVITY_MULTIPLE_TASK,resultTo和startActivityLocked參數(shù)中resultTo不是一個(gè)意思,前者是在startActivityLocked函數(shù)中創(chuàng)建的ActivityRecord對(duì)象resultRecord,代表目標(biāo)類一方,被初始化為空,而后者代表啟動(dòng)類一方,不能混淆。
| 1 2 3 4 | ActivityRecord?intentActivity=!launchSingleInstance? findTaskLocked(r):findActivityLocked(intent,r.info); if(intentActivity!=null){ ...... |
啟動(dòng)A時(shí)沒有設(shè)置啟動(dòng)模式,采用是默認(rèn)的標(biāo)準(zhǔn)模式,因此launchSingleInstance為false,調(diào)用findTaskLocked(r)在當(dāng)前棧頂中查詢是否有目標(biāo)類,如果有,就返回該類,否則,返回空。因?yàn)槭状螁?dòng)A,因此棧中肯定沒有A,返回空保存到intentActivity變量中,這樣的話,if語句不成立。如果棧中有實(shí)例,再次啟動(dòng)時(shí)就會(huì)執(zhí)行這段代碼。
| 1 2 3 4 5 6 7 8 9 | if(r.packageName!=null){ ActivityStack?topStack=getFocusedStack(); ActivityRecord?top=topStack.topRunningNonDelayedActivityLocked(notTop); if(top!=null&&r.resultTo==null){ if(top.realActivity.equals(r.realActivity)&&top.userId==r.userId){ ...... }else{ ...... } |
目標(biāo)類包名肯定不為空,執(zhí)行if條件,getFocusedStack返回當(dāng)前棧,topRunningNonDelayedActivityLocked返回當(dāng)前ActivityRecord對(duì)象保存到top中,肯定不為空;top.realActivity表示啟動(dòng)類,r.realActivity表示目標(biāo)類,本案例前者是Launcher,后者是A,兩者肯定不相等,因此if語句不成立,跳過此段。如果成立的話,就會(huì)在當(dāng)前棧中找到已存在的實(shí)例繼續(xù)使用。
既然當(dāng)前棧中沒有已存在實(shí)例,那么只能新創(chuàng)建一個(gè)任務(wù)棧,繼續(xù)看:
| 1 2 3 4 5 6 7 8 | booleannewTask=false; booleankeepCurTransition=false; TaskRecord?taskToAffiliate=launchTaskBehind&&sourceRecord!=null? sourceRecord.task:null; // Should this be considered a new task? if(r.resultTo==null&&inTask==null&&!addingToTask &&(launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK)!=0){ ...... |
此if語句成立,launchTaskBehind為空,那么taskToAffiliate也為空
| 1 2 | newTask=true; targetStack=adjustStackFocus(r,newTask); |
newTask代表新建一個(gè)任務(wù)的標(biāo)志,設(shè)為true;adjustStackFocus獲得一個(gè)ActivityStack保存到targetStack變量作為目標(biāo)類的棧;
| 1 2 3 4 5 6 7 8 9 | if(reuseTask==null){ r.setTask(targetStack.createTaskRecord(getNextTaskId(), newTaskInfo!=null?newTaskInfo:r.info, newTaskIntent!=null?newTaskIntent:intent, voiceSession,voiceInteractor,!launchTaskBehind/* toTop */), taskToAffiliate); if(DEBUG_TASKS)Slog.v(TAG,"Starting new activity "+r+" in new task "+ r.task); } |
createTaskRecord創(chuàng)建TaskRecord對(duì)象并放到棧頂,然后再放到目標(biāo)類ActivityRecord的task變量中
| 1 2 3 4 5 6 | targetStack.mLastPausedActivity=null; targetStack.startActivityLocked(r,newTask,doResume,keepCurTransition,options); if(!launchTaskBehind){ // Don't set focus on an activity that's going to the back. mService.setFocusedActivityLocked(r,"startedActivity"); } |
調(diào)用startActivityLocked進(jìn)行下一步操作
startActivityUncheckedLocked函數(shù)非常復(fù)雜,最關(guān)鍵的就是查詢是否有已存在的TaskRcord作為目標(biāo)類的任務(wù)棧,如果棧中有就復(fù)用,否則就創(chuàng)建一個(gè)新的TaskRcord對(duì)象作為目標(biāo)類的任務(wù)棧。該函數(shù)涉及到了FLAG標(biāo)志,啟動(dòng)模式的判斷等,其目的就是找到一個(gè)合適的任務(wù)棧,為何要找到這個(gè)棧,就是因?yàn)锳ctivity在執(zhí)行時(shí)以棧這個(gè)數(shù)據(jù)結(jié)構(gòu)來管理。
過程6 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
| 1 2 | finalvoidstartActivityLocked(ActivityRecordr,booleannewTask, booleandoResume,booleankeepCurTransition,Bundle?options) |
第一個(gè)參數(shù)對(duì)應(yīng)目標(biāo)類對(duì)象記錄,newTask為true,表示新建了一個(gè)任務(wù)棧,doResume為true,keepCurTransition為false。
| 1 2 | TaskRecord?rTask=r.task; finalinttaskId=rTask.taskId; |
r.task就是在startActivityUncheckedLocked中創(chuàng)建的目標(biāo)類的RaskRecord對(duì)象,取出來保存到rRask變量中
| 1 2 3 4 5 6 7 | if(!r.mLaunchTaskBehind&&(taskForIdLocked(taskId)==null||newTask)){ // Last activity in task had been removed or ActivityManagerService is reusing task. // Insert or replace. // Might not even be in. insertTaskAtTop(rTask); mWindowManager.moveTaskToTop(taskId); } |
mLaunchTaskBehind在上文得知為空,taskForIdLocked在歷史棧中查詢是否含有id號(hào)為目標(biāo)類所在的棧id,如果有,表明目標(biāo)類之前已經(jīng)被創(chuàng)建過,現(xiàn)在開始復(fù)用該對(duì)象,屬于非首次啟動(dòng),否則為首次啟動(dòng)對(duì)象,本案例首次啟動(dòng)A,因此,此函數(shù)返回null;newTask傳遞過來為true,if語句成立,調(diào)用insertTaskAtTop函數(shù)把新創(chuàng)建的TaskRecord對(duì)象插入到列表mTaskHistory的尾部,也就是插入到歷史棧頂;
| 1 2 3 | if(doResume){ mStackSupervisor.resumeTopActivitiesLocked(this,r,options); } |
過程7 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
| 1 2 | booleanresumeTopActivitiesLocked(ActivityStack?targetStack,ActivityRecord?target, Bundle?targetOptions) |
this對(duì)象表示當(dāng)前對(duì)象ActivityStack,此ActivityStack是新建的對(duì)象,不是Launcher所在的ActivityStack,是在startActivityUncheckedLocked中的adjustStackFocus方法獲得的,目的就是把新創(chuàng)建的任務(wù)插入到該ActivityStack對(duì)象中,這個(gè)對(duì)象就代表了目標(biāo)類所屬的棧
第二個(gè)參數(shù)r就表示目標(biāo)類對(duì)象記錄,第三個(gè)參數(shù)依然為null
| 1 2 3 | if(isFrontStack(targetStack)){ result=targetStack.resumeTopActivityLocked(target,targetOptions); } |
isFrontStack判斷新獲得的ActivityStack對(duì)象位于棧頂,判斷為真,執(zhí)行if語句,調(diào)用resumeTopActivityLocked(target, targetOptions)
過程8 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
| 1 2 3 | finalbooleanresumeTopActivityLocked(ActivityRecord?prev,Bundle?options){ ...... } |
第一個(gè)參數(shù)prev表示目標(biāo)類ActivityRecord對(duì)象,第二個(gè)傳遞過來為空
| 1 2 3 4 5 6 7 8 | try{ // Protect against recursion. mStackSupervisor.inResumeTopActivity=true; ...... result=resumeTopActivityInnerLocked(prev,options); }finally{ mStackSupervisor.inResumeTopActivity=false; } |
繼續(xù)調(diào)用resumeTopActivityInnerLocked方法,再調(diào)用resumeTopActivityInnerLocked
| 1 2 3 | finalbooleanresumeTopActivityInnerLocked(ActivityRecord?prev,Bundle?options){ ...... } |
| 1 2 3 4 5 6 7 | // Find the first activity that is not finishing. finalActivityRecord?next=topRunningActivityLocked(null); // Remember how we'll process this pause/resume situation, and ensure // that the state is reset however we wind up proceeding. finalbooleanuserLeaving=mStackSupervisor.mUserLeaving; mStackSupervisor.mUserLeaving=false; |
topRunningActivityLocked方法找到棧頂?shù)腁ctivityRecord對(duì)象,此處對(duì)應(yīng)著A
mStackSupervisor.mUserLeaving的值在過程5中被設(shè)置為true,此處取出來賦值給userLeaving,表明是用戶操作行為(按下返回鍵,HOME按鍵等);無論是true還是false,此處還是再?gòu)?fù)位一下,重新設(shè)置為false
| 1 2 3 4 5 | booleandontWaitForPause=(next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING)!=0; booleanpausing=mStackSupervisor.pauseBackStacks(userLeaving,true,dontWaitForPause); if(mResumedActivity!=null){ pausing|=startPausingLocked(userLeaving,false,true,dontWaitForPause);?? ? ? } |
目標(biāo)類A沒有設(shè)置FLAG_RESUME_WHILE_PAUSING標(biāo)志,dontWaitForPause為false
pauseBackStacks函數(shù)返回false賦給pausing變量,mResumedActivity表示當(dāng)前正在前臺(tái)運(yùn)行的Activity,就是Launcher,不為空,進(jìn)程調(diào)用startPausingLocked繼續(xù)執(zhí)行
| 1 2 3 4 5 6 | pausing|=startPausingLocked(userLeaving,false,true,dontWaitForPause); finalbooleanstartPausingLocked(booleanuserLeaving,booleanuiSleeping,booleanresuming, booleandontWait){ ...... } |
startPausingLocked開始暫停當(dāng)前Activity,如果成功,返回true,否則false
4個(gè)參數(shù)分別為false,false,true,false
| 1 2 3 4 | ActivityRecord?prev=mResumedActivity; mResumedActivity=null; mPausingActivity=prev; mLastPausedActivity=prev; |
mResumedActivity代表Launcher,先賦值給prev再置空;prev賦值給mPausingActivity,表明即將要暫停的Activity是Launcher,mLastPausedActivity也賦值為prev,表示剛剛暫停的Activity是哪個(gè)
| 1 2 3 4 5 6 | if(prev.app!=null&&prev.app.thread!=null){ ...... prev.app.thread.schedulePauseActivity(prev.appToken,prev.finishing, userLeaving,prev.configChangeFlags,dontWait); ...... } |
prev.app表示Launcher進(jìn)程信息,不為空;prev.app.thread是一個(gè)IApplicationThread對(duì)象,對(duì)應(yīng)Launcher也不為空,進(jìn)程繼續(xù)調(diào)用schedulePauseActivity方法,此處是一個(gè)Binder進(jìn)程間通信,下一步調(diào)用到ApplicationThread對(duì)象的schedulePauseActivity方法中,ApplicationThread是ActivityThread內(nèi)部類
過程9 ? ?frameworks\base\core\java\android\app\ActivityThread.java
| 1 2 3 4 5 6 7 8 | publicfinalvoidschedulePauseActivity(IBinder?token,booleanfinished, booleanuserLeaving,intconfigChanges,booleandontReport){ sendMessage( finished?H.PAUSE_ACTIVITY_FINISHING:H.PAUSE_ACTIVITY, token, (userLeaving?1:0)|(dontReport?2:0), configChanges); } |
finished傳遞過來為false,因?yàn)長(zhǎng)auncher此時(shí)還沒有執(zhí)行生命周期方法onPause()、onDestory(),因此沒有進(jìn)入finishing狀態(tài),那么,sendMessage的第一個(gè)參數(shù)值為H.PAUSE_ACTIVITY
sendMessage把消息發(fā)送到隊(duì)列中等待執(zhí)行,執(zhí)行方法是Handler的handleMessage方法,通過命令PAUSE_ACTIVITY可以得到執(zhí)行程序:
| 1 2 3 4 5 6 7 | casePAUSE_ACTIVITY: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"activityPause"); handlePauseActivity((IBinder)msg.obj,false,(msg.arg1&1)!=0,msg.arg2, (msg.arg1&2)!=0); maybeSnapshot(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; |
繼續(xù)調(diào)用handlePauseActivity方法
| 1 2 3 4 | privatevoidhandlePauseActivity(IBinder?token,booleanfinished, booleanuserLeaving,intconfigChanges,booleandontReport){ ...... } |
finished為false,userLeaving傳遞過來為true,configChanges為0,dontReport為false
| 1 | ActivityClientRecordr=mActivities.get(token); |
token對(duì)應(yīng)啟動(dòng)類Launcher,此處獲得Launcher的ActivityRecord對(duì)象
| 1 2 3 | if(userLeaving){ performUserLeavingActivity(r); } |
調(diào)用performUserLeavingActivity方法,performUserLeavingActivity的最終調(diào)用過程為:
performUserLeavingActivity—->
mInstrumentation.callActivityOnUserLeaving(r.activity) —->
activity.performUserLeaving() —->
onUserInteraction()
onUserLeaveHint()
意味著,如果是用戶操作的主動(dòng)行為,比如返回按鍵,遙控器上下左右按鍵,HOME按鍵燈,會(huì)調(diào)用Activity的
onUserInteraction和onUserLeaveHint方法,如果是按鍵,觸摸、軌跡球被分發(fā)到Activity時(shí),onUserInteraction會(huì)被回調(diào);onUserLeaveHint的作用是當(dāng)Activity即將進(jìn)入到后臺(tái)前被回調(diào),起到提示作用
performUserLeavingActivity執(zhí)行完后,進(jìn)程繼續(xù)調(diào)用
| 1 2 3 4 5 6 7 8 | performPauseActivity(token,finished,r.isPreHoneycomb()); finalBundle?performPauseActivity(ActivityClientRecordr,booleanfinished, booleansaveState){ ..... mInstrumentation.callActivityOnPause(r.activity); r.paused=true; } |
performPauseActivity方法中繼續(xù)調(diào)用callActivityOnPause方法,參數(shù)r.activity代表啟動(dòng)類Launcher
過程9.1 ? ?frameworks\base\core\java\android\app\Instrumentation.java
| 1 2 3 | publicvoidcallActivityOnPause(Activity?activity){ activity.performPause(); } |
過程9.1.1 ? ?frameworks\base\core\java\android\app\Activity.java
| 1 2 3 4 5 6 7 8 9 | finalvoidperformPause(){ mDoReportFullyDrawn=false; mFragments.dispatchPause(); mCalled=false; onPause(); mResumed=false; ...... mResumed=false; } |
最終調(diào)用到Activity的performPause方法,再調(diào)用生命周期方法onPause()意味著啟動(dòng)類處于暫停狀態(tài)了,這一步執(zhí)行完后返回到performPauseActivity中,執(zhí)行r.paused = true把啟動(dòng)類的ActivityClientRecord的paused置為true,表示啟動(dòng)類此時(shí)已經(jīng)處于暫停狀態(tài)了。再返回到handlePauseActivity中,繼續(xù)執(zhí)行performPauseActivity后面的語句
| 1 | ActivityManagerNative.getDefault().activityPaused(token); |
這一步通過Binder進(jìn)程間通信機(jī)制進(jìn)入到ActivityManagerService的activityPaused方法中
過程9.2 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
| 1 2 3 4 5 | publicfinalvoidactivityPaused(IBinder?token){ ...... stack.activityPausedLocked(token,false); ..... } |
過程10 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
| 1 2 3 | finalvoidactivityPausedLocked(IBinder?token,booleantimeout){ ...... } |
mPausingActivity表示啟動(dòng)類Launcher,r是Launcher的ActivityRecord對(duì)象,if條件為真,進(jìn)程繼續(xù)調(diào)用completePauseLocked(true)方法
| 1 2 3 | privatevoidcompletePauseLocked(booleanresumeNext){ ...... } |
既然啟動(dòng)類都已經(jīng)暫停了,那下一步工作是不是就是把目標(biāo)類啟動(dòng)起來呢?如果是的話,應(yīng)該會(huì)執(zhí)行生命周期onResume方法,這只是猜測(cè),具體詳細(xì)看方法的執(zhí)行過程
參數(shù)resumeNext傳遞過來為true
prev.finishing屬性為false,這個(gè)屬性一直沒有設(shè)置
mPausingActivity = null;
如果啟動(dòng)類已經(jīng)stop,就把mPausingActivity設(shè)為null
進(jìn)程繼續(xù)執(zhí)行到:
| 1 2 3 4 | finalActivityStack?topStack=mStackSupervisor.getFocusedStack(); if(!mService.isSleepingOrShuttingDown()){ mStackSupervisor.resumeTopActivitiesLocked(topStack,prev,null); } |
當(dāng)前系統(tǒng)處于非睡眠和關(guān)機(jī)狀態(tài),if條件為真,進(jìn)程開始調(diào)用resumeTopActivitiesLocked方法
過程11 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
| 1 2 3 4 | booleanresumeTopActivitiesLocked(ActivityStack?targetStack,ActivityRecord?target, Bundle?targetOptions){ ...... } |
要清楚方法具體做了什么,一定要先弄清楚參數(shù)的含義
形參targetStack的實(shí)參是topStack,通過mStackSupervisor.getFocusedStack獲得,即當(dāng)前獲得焦點(diǎn)的棧,此處,啟動(dòng)類已經(jīng)暫停,那么當(dāng)前棧就是目標(biāo)類所在的棧,prev是啟動(dòng)類
又調(diào)用了resumeTopActivityLocked方法
| 1 2 3 | if(isFrontStack(targetStack)){ result=targetStack.resumeTopActivityLocked(target,targetOptions); } |
過程12 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
| 1 2 3 | finalbooleanresumeTopActivityLocked(ActivityRecord?prev,Bundle?options){ ...... } |
繼續(xù)調(diào)用resumeTopActivityInnerLocked方法
| 1 2 3 | finalbooleanresumeTopActivityInnerLocked(ActivityRecord?prev,Bundle?options){ ...... } |
再次進(jìn)入到此方法時(shí),mResumedActivity為空,因?yàn)檫@是在過程8中startPausingLocked方法內(nèi)設(shè)置的,表明啟動(dòng)類Launcher已經(jīng)不在是當(dāng)前運(yùn)行的Activity,因此
| 1 2 3 4 | if(mResumedActivity!=null){ if(DEBUG_STATES)Slog.d(TAG,"resumeTopActivityLocked: Pausing "+mResumedActivity); pausing|=startPausingLocked(userLeaving,false,true,dontWaitForPause); } |
這個(gè)語句就不再成立,進(jìn)程跳過此句繼續(xù)執(zhí)行
| 1 2 3 4 5 6 7 8 9 | if(next.app!=null&&next.app.thread!=null){ ...... mStackSupervisor.startSpecificActivityLocked(next,true,false); ...... }else{ ...... mStackSupervisor.startSpecificActivityLocked(next,true,false); ...... } |
next就是目標(biāo)類A,此時(shí)A的一些棧等信息已經(jīng)構(gòu)建,但是A得進(jìn)程還沒有創(chuàng)建,正常情況下,啟動(dòng)一個(gè)新的應(yīng)用程序一般會(huì)創(chuàng)建一個(gè)新的進(jìn)程,應(yīng)用程序在此進(jìn)程中執(zhí)行,特殊情況下可以通過AndroidManifest中process屬性執(zhí)行指定應(yīng)用程序在某個(gè)進(jìn)程中執(zhí)行,本文沒有設(shè)置process屬性,默認(rèn)為啟動(dòng)一個(gè)新的進(jìn)程,本文后面會(huì)分析到。由此可知,A還沒有進(jìn)程信息,if語句不成立,進(jìn)程轉(zhuǎn)到else語句執(zhí)行
過程13 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
| 1 2 3 4 | voidstartSpecificActivityLocked(ActivityRecordr, booleanandResume,booleancheckConfig){ ...... } |
| 1 2 3 4 5 6 7 8 9 | ProcessRecord?app=mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid,true); if(app!=null&&app.thread!=null){ ...... realStartActivityLocked(r,app,andResume,checkConfig); ...... } mService.startProcessLocked(r.processName,r.info.applicationInfo,true,0, "activity",r.intent.getComponent(),false,false,true); |
此時(shí)A進(jìn)程還沒有創(chuàng)建,所以app為空,跳過if語句,開始調(diào)用startProcessLocked方法
假如A的應(yīng)用程序已經(jīng)啟動(dòng),然后在A中啟動(dòng)B,B是A應(yīng)用程序的一個(gè)Activity,那么此時(shí)進(jìn)程已經(jīng)創(chuàng)建,app就不會(huì)為空,進(jìn)程會(huì)調(diào)用realStartActivityLocked方法
過程14 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
| 1 2 3 4 5 6 7 8 9 | finalProcessRecord?startProcessLocked(StringprocessName, ApplicationInfo?info,booleanknownToBeDead,intintentFlags, StringhostingType,ComponentName?hostingName,booleanallowWhileBooting, booleanisolated,booleankeepIfLarge){ returnstartProcessLocked(processName,info,knownToBeDead,intentFlags,hostingType, hostingName,allowWhileBooting,isolated,0/* isolatedUid */,keepIfLarge, null/* ABI override */,null/* entryPoint */,null/* entryPointArgs */, null/* crashHandler */); } |
| 1 2 3 4 5 6 7 8 9 | finalProcessRecord?startProcessLocked(StringprocessName,ApplicationInfo?info, booleanknownToBeDead,intintentFlags,StringhostingType,ComponentName?hostingName, booleanallowWhileBooting,booleanisolated,intisolatedUid,booleankeepIfLarge, StringabiOverride,StringentryPoint,String[]entryPointArgs,Runnable?crashHandler){ ...... } |
該方法中會(huì)為A創(chuàng)建ProcessRecord信息,然后繼續(xù)調(diào)用
| 1 2 | startProcessLocked( app,hostingType,hostingNameStr,abiOverride,entryPoint,entryPointArgs); |
| 1 2 3 4 5 6 7 8 9 | privatefinalvoidstartProcessLocked(ProcessRecord?app,StringhostingType, StringhostingNameStr,StringabiOverride,StringentryPoint,String[]entryPointArgs){ ...... Process.ProcessStartResult?startResult=Process.start(entryPoint, app.processName,uid,uid,gids,debugFlags,mountExternal, app.info.targetSdkVersion,app.info.seinfo,requiredAbi,instructionSet, app.info.dataDir,entryPointArgs); ...... } |
此方法中會(huì)調(diào)用進(jìn)程的start方法創(chuàng)建一個(gè)新的進(jìn)程,具體是通過zygote進(jìn)程的來fork一個(gè)新的進(jìn)程,成為子進(jìn)程,子進(jìn)程共享父進(jìn)程資源,幾乎和父進(jìn)程一樣。當(dāng)子進(jìn)程創(chuàng)建好后,系統(tǒng)會(huì)分配一個(gè)進(jìn)程號(hào)PID給新進(jìn)程并返回,否則拋出異常
| 1 2 3 4 5 6 7 8 9 10 11 12 | publicstaticfinalProcessStartResult?start(finalStringprocessClass, finalStringniceName, intuid,intgid,int[]gids, intdebugFlags,intmountExternal, inttargetSdkVersion, StringseInfo, Stringabi, StringinstructionSet, StringappDataDir, String[]zygoteArgs){ ...... } |
第一個(gè)參數(shù)processClass為新創(chuàng)建的進(jìn)程的入口類即android.app.ActivityThread.java
niceName:新創(chuàng)建的進(jìn)程的進(jìn)程名字,用ps命令可以查看到該名字,一般情況下,應(yīng)用程序的進(jìn)程名就是包名
如果進(jìn)程創(chuàng)建成功,待方法start執(zhí)行完后,系統(tǒng)就會(huì)轉(zhuǎn)到ActivityThread.java的main方法入口開始執(zhí)行,注意這個(gè)流程,和我們通常看到的方法調(diào)用方法是不一樣的。
過程15 ? ?frameworks\base\core\java\android\app\ActivityThread.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | publicstaticvoidmain(String[]args){ ...... Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread?thread=newActivityThread(); thread.attach(false); if(sMainThreadHandler==null){ sMainThreadHandler=thread.getHandler(); } if(false){ Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG,"ActivityThread")); } Looper.loop(); thrownewRuntimeException("Main thread loop unexpectedly exited"); } |
prepareMainLooper方法創(chuàng)建了looper對(duì)象和MessageQueue消息隊(duì)列;創(chuàng)建了并初始化ActivityThread對(duì)象,同時(shí)也創(chuàng)建并初始化了ApplicationThread對(duì)象mAppThread
| 1 2 3 4 5 6 | thread.attach(false); privatevoidattach(booleansystem){ ...... finalIActivityManager?mgr=ActivityManagerNative.getDefault(); mgr.attachApplication(mAppThread); } |
獲得ActivityManagerProxy對(duì)象,調(diào)用該對(duì)象的attachApplication方法,通過binder通信,最終調(diào)用到ActivityManagerService的attachApplication方法
過程16 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
| 1 2 3 4 5 | publicfinalvoidattachApplication(IApplicationThread?thread){ synchronized(this){ ...... } } |
| 1 2 3 4 | privatefinalbooleanattachApplicationLocked(IApplicationThread?thread, intpid){ ...... } |
先通過pid獲得ProcessRecord對(duì)象,該對(duì)象上一步創(chuàng)建過,不為空
| 1 2 3 4 5 6 7 8 9 | app.makeActive(thread,mProcessStats); app.curAdj=app.setAdj=-100; app.curSchedGroup=app.setSchedGroup=Process.THREAD_GROUP_DEFAULT; app.forcingToForeground=null; updateProcessForegroundLocked(app,false,false); app.hasShownUi=false; app.debugging=false; app.cached=false; app.killedByAm=false; |
初始化該P(yáng)rocessRecord對(duì)象
| 1 2 3 4 5 6 7 8 9 10 11 | // See if the top visible activity is waiting to run in this process... if(normalMode){ try{ if(mStackSupervisor.attachApplicationLocked(app)){ didSomething=true; } }catch(Exceptione){ Slog.wtf(TAG,"Exception thrown launching activities in "+app,e); badApp=true; } } |
這段話就是真正開始啟動(dòng)目標(biāo)Activity了,本案例就是A
注:在這段話后面分別有:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // Find any services that should be running in this process... if(!badApp){ try{ Slog.i("zhulf","---------------------601"); didSomething|=mServices.attachApplicationLocked(app,processName); }catch(Exceptione){ Slog.wtf(TAG,"Exception thrown starting services in "+app,e); badApp=true; } } // Check if a next-broadcast receiver is in this process... if(!badApp&&isPendingBroadcastProcessLocked(pid)){ try{ didSomething|=sendPendingBroadcastsLocked(app); }catch(Exceptione){ // If the app died trying to launch the receiver we declare it 'bad' Slog.wtf(TAG,"Exception thrown dispatching broadcasts in "+app,e); badApp=true; } } |
用來啟動(dòng)Service、發(fā)送廣播,此處作為一個(gè)備注,如果要分析啟動(dòng)Service、廣播,研究這兩段語句,本文只研究啟動(dòng)Activity,因此,詳細(xì)看attachApplicationLocked方法
過程17 ? ?frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
| 1 2 3 | booleanattachApplicationLocked(ProcessRecord?app)throwsRemoteException{ ...... } |
| 1 2 3 | if(realStartActivityLocked(hr,app,true,true)){ didSomething=true; } |
| 1 2 3 4 5 | finalbooleanrealStartActivityLocked(ActivityRecordr, ProcessRecord?app,booleanandResume,booleancheckConfig) throwsRemoteException{ ...... } |
hr就是目標(biāo)類ActivityRecord對(duì)象,app是進(jìn)程名字
| 1 2 | mService.updateLruProcessLocked(app,true,null); mService.updateOomAdjLocked(); |
調(diào)整進(jìn)程LRU算法;參與管理進(jìn)程
| 1 2 3 4 5 | app.thread.scheduleLaunchActivity(newIntent(r.intent),r.appToken, System.identityHashCode(r),r.info,newConfiguration(mService.mConfiguration), r.compat,r.launchedFromPackage,r.task.voiceInteractor,app.repProcState, r.icicle,r.persistentState,results,newIntents,!andResume, mService.isNextTransitionForward(),profilerInfo); |
app.thrad是IApplicationThread對(duì)象,此處就是ApplicationThreadProxy對(duì)象接口,這里也是Binder通信過程,調(diào)用ApplicationThreadProxy的scheduleLaunchActivity方法,通過binder通信轉(zhuǎn)到ApplicationThread對(duì)象的scheduleLaunchActivity方法,該方法在ActivityThread對(duì)象中
過程18 ? ?frameworks\base\core\java\android\app\ActivityThread.java
| 1 2 3 4 5 6 7 8 | publicfinalvoidscheduleLaunchActivity(Intent?intent,IBinder?token,intident, ActivityInfo?info,Configuration?curConfig,CompatibilityInfo?compatInfo, Stringreferrer,IVoiceInteractor?voiceInteractor,intprocState,Bundle?state, PersistableBundle?persistentState,List<ResultInfo>pendingResults, List<ReferrerIntent>pendingNewIntents,booleannotResumed,booleanisForward, ProfilerInfo?profilerInfo){ .... } |
該方法創(chuàng)建了目標(biāo)類對(duì)應(yīng)的ActivityClientRecord對(duì)象,而后初始化該對(duì)象,作為sendMessage參數(shù)發(fā)送到消息隊(duì)列待處理
| 1 2 3 4 5 6 | caseLAUNCH_ACTIVITY:{ finalActivityClientRecordr=(ActivityClientRecord)msg.obj; r.packageInfo=getPackageInfoNoCheck( r.activityInfo.applicationInfo,r.compatInfo); handleLaunchActivity(r,null); } |
| 1 2 3 | privatevoidhandleLaunchActivity(ActivityClientRecordr,Intent?customIntent){ ...... } |
該方法分為兩個(gè)部分,先調(diào)用performLaunchActivity,再調(diào)用handleResumeActivity,最后還有finishActivity
先看performLaunchActivity
| 1 2 3 | privateActivity?performLaunchActivity(ActivityClientRecordr,Intent?customIntent){ ...... } |
| 1 | ActivityInfo?aInfo=r.activityInfo; |
從目標(biāo)類ActivityClientRecord對(duì)象中取出ActivityInfo對(duì)象,ActivityInfo對(duì)象包含了Activity、receiver對(duì)象信息
| 1 | ComponentName?component=r.intent.getComponent(); |
再根據(jù)Intent獲得組件對(duì)象component,組件包含了啟動(dòng)類名稱和包名稱
| 1 2 3 | java.lang.ClassLoader?cl=r.packageInfo.getClassLoader(); activity=mInstrumentation.newActivity( cl,component.getClassName(),r.intent); |
通過Java反射機(jī)制找到目標(biāo)類文件,再創(chuàng)建目標(biāo)類的一個(gè)對(duì)象賦值給activity。從此處可知,原來Android中Activity對(duì)象是在啟動(dòng)時(shí)創(chuàng)建的,系統(tǒng)已經(jīng)幫助程序員寫好了new Activity對(duì)象的動(dòng)作,無需程序員自行new對(duì)象,這解決了一開始學(xué)習(xí)android時(shí)總是搞不清楚Activity對(duì)象是從什么時(shí)候創(chuàng)建的的困惑,因此,Android并不關(guān)注組件的創(chuàng)建過程,而把關(guān)注點(diǎn)落在了組件的生命周期上。
| 1 | Application?app=r.packageInfo.makeApplication(false,mInstrumentation); |
makeApplication方法也是利用反射機(jī)制找到應(yīng)用程序Application類并創(chuàng)建一個(gè)對(duì)象,并調(diào)用Application對(duì)象的onCreate方法,這就是為什么應(yīng)用一啟動(dòng)后,Application的onCreate比Activity的onCreate先執(zhí)行的原因!
| 1 2 3 4 5 | Context?appContext=createBaseContextForActivity(r,activity); activity.attach(appContext,this,getInstrumentation(),r.token, r.ident,app,r.intent,r.activityInfo,title,r.parent, r.embeddedID,r.lastNonConfigurationInstances,config, r.referrer,r.voiceInteractor); |
createBaseContextForActivity方法中會(huì)調(diào)用createActivityContext創(chuàng)建ContextImpl對(duì)象,ContextImpl實(shí)現(xiàn)了Context,也就同時(shí)創(chuàng)建了上下文管理者Context對(duì)象,這也解決了為什么在寫程序時(shí)總是能夠獲得Context對(duì)象的原因
attach方法把Context對(duì)象、Instrumentation對(duì)象等和Activity關(guān)聯(lián)起來
| 1 | mInstrumentation.callActivityOnCreate(activity,r.state); |
通過Instrumentation對(duì)象的callActivityOnCreate方法進(jìn)入到Instrumentation對(duì)象中,Instrumentation對(duì)象就是監(jiān)控所有用戶和系統(tǒng)之間的交互操作,比如onCreate、onResume等
過程19 ? ?frameworks\base\core\java\android\app\Instrumentation.java
| 1 2 3 4 5 | publicvoidcallActivityOnCreate(Activity?activity,Bundle?icicle){ prePerformCreate(activity); activity.performCreate(icicle); postPerformCreate(activity); } |
繼續(xù)調(diào)用performCreate方法
過程20 ? ?frameworks\base\core\java\android\app\Activity.java
| 1 2 3 4 5 | finalvoidperformCreate(Bundle?icicle){ onCreate(icicle); mActivityTransitionState.readState(icicle); performCreateCommon(); } |
最終調(diào)用Activity的onCreate方法開始生命周期
再返回到handleLaunchActivity中,進(jìn)程繼續(xù)執(zhí)行到handleResumeActivity方法
| 1 2 3 4 | ActivityClientRecordr=performResumeActivity(token,clearHide); r.activity.performResume(); mInstrumentation.callActivityOnResume(this); activity.onResume(); |
這四步寫在一個(gè)代碼段,可以看到最終調(diào)用了Activity的onResume方法,目標(biāo)類A啟動(dòng)起來了并成為可見狀態(tài)
到此處為止,在Launcher中啟動(dòng)Activity的過程就分析完了。
整個(gè)過程相當(dāng)復(fù)雜,涉及到很多動(dòng)態(tài)對(duì)象,進(jìn)程間通信,棧的管理等,可以不必要理解每句代碼,但是清楚整個(gè)流程做了哪些核心的動(dòng)作是有必要的:
1. ?過程5
resolveActivity方法中調(diào)用了包管理器PackageManager的resolveIntent方法解析啟動(dòng)目標(biāo)類的Intent對(duì)象,獲得解析后的對(duì)象ActivityInfo,為何要獲得這個(gè)對(duì)象,這個(gè)對(duì)象有有什么作用?
在AndroidManifest.xml中Activity和receiver標(biāo)簽包含了很多屬性,比如主題、啟動(dòng)模式、屏幕方向,輸入法設(shè)置,進(jìn)程名稱等,ActivityInfo就是對(duì)應(yīng)目標(biāo)類Activity的一個(gè)動(dòng)態(tài)對(duì)象,該對(duì)象包含了這些屬性信息。該對(duì)象的作用用來構(gòu)建目標(biāo)類對(duì)應(yīng)的ActivityRecord對(duì)象,該對(duì)象也是一個(gè)動(dòng)態(tài)對(duì)象,是歷史棧中的一條記錄,在內(nèi)存中對(duì)應(yīng)目標(biāo)類。
這樣就明白一個(gè)問題:啟動(dòng)activity時(shí)有顯示和隱式,對(duì)于隱式方式,只需要在目標(biāo)類中intetn-filter中增加一個(gè)action,然后啟動(dòng)類通過這個(gè)action即可啟動(dòng)目標(biāo)類,這是如何做到的?實(shí)際上是通過包管理器PackageManager解析intent,查找到匹配的action對(duì)應(yīng)的目標(biāo)類的。
2. 過程8
startPausingLocked方法是進(jìn)入到暫停啟動(dòng)類過程的標(biāo)志,逐步調(diào)用prev.app.thread.schedulePauseActivity,然后又binder通信進(jìn)入到ApplicationThread對(duì)象的schedulePauseActivity方法,在此方法中,發(fā)送消息給啟動(dòng)類Launcher主線程ActivityThread,ActivityThread利用handler循環(huán)處理消息,調(diào)用handlePauseActivity方法處理,最終調(diào)用到Activity的生命周期方法onPause暫停啟動(dòng)類
3. ?過程14
Process對(duì)象的start方法開啟了一個(gè)新的進(jìn)程作為目標(biāo)類的主線程,由此,目標(biāo)類開始從ActivityThread的main方法開支執(zhí)行,然后由
mgr.attachApplication(mAppThread);
語句通過binder通信進(jìn)入到ActivityManagerService中,并傳遞了ApplicationThread對(duì)象,該對(duì)象傳入到ActivityManagerService中后構(gòu)建目標(biāo)類進(jìn)程信息,然后ActivityManagerService負(fù)責(zé)啟動(dòng)目標(biāo)類,最終通過該對(duì)象又通過Binder通信返回到ApplicationThread對(duì)象中,然后ApplicationThread對(duì)象又發(fā)送消息給目標(biāo)類主線程ActivityThread對(duì)象,該對(duì)象循環(huán)處理來自ActivityManagerService的消息,進(jìn)而調(diào)用Activity的生命周期方法onCreate、onResume。其中,IApplicationThread遠(yuǎn)程接口對(duì)象起著非常關(guān)鍵作用,他在主線程對(duì)象ActivityThread與Activity管理器ActivityManagerService對(duì)象之間起著通信橋梁作用。
ActivityManagerService是Activity Manager(注意,分開大寫,代表Framework層的核心模塊,該模塊包含了ActivityManagerService、ActivityStack、Binder接口等)的核心部分,負(fù)責(zé)啟動(dòng)Activity、Service、發(fā)送Broadcast Receiver、啟動(dòng)ContentProvider;調(diào)整進(jìn)程調(diào)度算法,管理任務(wù)棧、檢查權(quán)限等一些列核心功能。
2. 調(diào)用startActivity啟動(dòng)一個(gè)Activity
在應(yīng)用程序內(nèi)啟動(dòng)Activity,和應(yīng)用程序外啟動(dòng)最根本的不同在于不會(huì)新創(chuàng)建進(jìn)程,也就是說,過程13中,不會(huì)執(zhí)行startProcessLocked方法,而執(zhí)行realStartActivityLocked方法,過程13~過程16可以省略不看,此時(shí)在同一個(gè)進(jìn)程中;除此之外,就是棧的獲取不一樣,用startActivity方法啟動(dòng)可能不會(huì)新建棧,直接使用已有的棧,而Launcher啟動(dòng)時(shí)一般會(huì)新建棧。
3. 命令am start啟動(dòng)
這種方法適合調(diào)試時(shí)使用,在串口中直接采用
am start -n xxx/.yyy
即可啟動(dòng)應(yīng)用程序,包名是xxx,入口類名是yyy
am 這個(gè)可執(zhí)行程序?qū)?yīng)的源碼目錄位置:
| 1 | framework\base\cmds\am\src\com\android\commands\am\Am.java |
當(dāng)執(zhí)行這條命令時(shí),先從main方法開始執(zhí)行
| 1 2 3 | publicstaticvoidmain(String[]args){ (newAm()).run(args); } |
Am繼承了BaseCommand類,run方法在BaseCommand中定義,在run方法中又調(diào)用了onRun()方法,系統(tǒng)運(yùn)行時(shí)具體類型是Am,這樣就調(diào)到了Am的onRun方法。onRun中先執(zhí)行:
| 1 | mAm=ActivityManagerNative.getDefault(); |
獲得ActivityManagerService的代理類ActivityManagerProxy的一個(gè)對(duì)象
| 1 2 3 4 | Stringop=nextArgRequired(); if(op.equals("start")){ runStart(); } |
判斷參數(shù)是否有start這個(gè)字符串,如果有,就調(diào)用runStart方法,本文啟動(dòng)Activity當(dāng)然含有start參數(shù)
在runStart方法中,會(huì)執(zhí)行這一句
| 1 2 | res=mAm.startActivityAsUser(null,null,intent,mimeType, null,null,0,mStartFlags,profilerInfo,null,mUserId); |
這一步會(huì)繼續(xù)調(diào)用ActivityStackSupervisor的startActivityMayWait方法,與上文的“過程4”一樣,后面的步驟基本上差不多。
不管哪種方式啟動(dòng),在服務(wù)端的操作基本上相同,區(qū)別就在于是否復(fù)用當(dāng)前棧還是新創(chuàng)建一個(gè)棧,是否新建一個(gè)進(jìn)程作為目標(biāo)類的進(jìn)程等;在客戶端,區(qū)別在于啟動(dòng)Activity的方式不同,第三種命令啟動(dòng)方式缺少了startActivity部分。
http://blogread.cn/it/article/8026?
總結(jié)
以上是生活随笔為你收集整理的启动Activity的流程(Launcher中点击图标启动)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS 苹果官方Demo合集
- 下一篇: 一些开源的项目 收藏