Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android源碼分析之Activity啟動過程

android源碼分析之Activity啟動過程

編輯:關於Android編程

Activity最為android開發者最熟悉的組件,由ActivityManagerService服務進行調度管理,本文基於其對Activity的啟動過程進行分析,同時也將分析AMS對Activity的調度管理。


1、 Activity的啟動模式

啟動模式實際上就是為了控制Activity與Task之間的關系,目前共有一下四種模式:standard、singleTop、singleTask以及singleInstance,默認的模式為standard模式。
注意:建議一般的開發者不要輕易使用後兩種模式,因為不同的模式,其出棧的順序不同,可能會導致用戶按下返回鍵時,會有不一樣的用戶體驗,對於啟動模式的分析。這篇文章使用圖文並用的方式,很好的分析了Activity各種模式的區別,本文不再分析啟動模式。


2、Activity的啟動時機

Activity作為android非常重要的組件,那麼我們會在哪些時機啟動它呢?
通常有如下幾種情形:
1. android AM命令
android系統為開發者提供了adb工具,而在adb的基礎上執行adb shell就可以從PC上對手機側執行shell命令。如啟動浏覽器:am start -n com.android.browser/com.android.browser.BrowserActivity。
2. 啟動AMS服務時
在啟動AMS服務時,在最後調用AMS的systemReady的最後階段會啟動Home界面,此時就會啟動一個Activity。
3. 調用startActivity()和startActivityForResult()方法時
這是我們最常用也最熟悉的啟動Activity的方式。


3、AM命令行啟動Activity的過程分析

在adb中可以使用AM命令,同時在應用程序中,也可以通過AM命令來啟動指定的Activity,AM是一個腳本命令,它還可以啟動Service,發送廣播等。

3.1 Am 框架層調用流程分析

adb執行Am命令後,最終會執行Am.java的main方法,其代碼如下:

//Am.java
public static void main(String[] args){
    (new Am()).run(args);
}

它調用的是抽象父類BaseCommand類的run方法:

//BaseCommand.java
public void run(String[] args){
    if(args.length<1){
        //顯示命令使用說明
        onShowUsage(System.out);
        return;
    }
    mArgs = args;
    mNextArg = 0;
    mCurArgData = null;
    try{
        onRun();
    }catch(...){...}
}

跟其他命令腳本類似,如果參數為空,顯示使用說明,否則調用onRun()方法,它是一個抽象方法,在Am.java中有實現:

//Am.java
@Override
public void onRun() throws Exception{
    //獲取AMS
    mAm = ActivityManagerNative.getDefault();
    ...
    String op = nextArgRequired();
    if(op.equals("start")){
        //啟動Activity
        runStart();
    }else if(op.equals("startService")){
        //啟動服務
        runStartService();  
    }else if(op.equals("force-stop")){
        //強制停止
        runForceStop();
    }else if(op.equals("kill")){
        //殺死進程
        runKill();  
    }else if{
        ...
    }else{
        ...
    }
}

命令參數不同,其執行的操作不同,就本節來說,其參數為start,所以將會執行runStart()方法來啟動Activity:

//Am.java
private void runStart() throws Exception{
    Intent intent = makeIntent(UserHandle.USER_CURRENT);
    ...
    do{
        //獲取包信息
        ...
        //設置intent的標志位FLAG_ACTIVITY_NEW_TASK,即將啟動一個新任務
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        ParcelFileDescriptor fd = null;
        ProfilerInfo profilerInfo = null;
        if(mProfileFile != null){//處理-P選項,統計性能
            try{
                fd = openForSystemServer(new File(mProfileFile),ParcelFileDescriptior.MODE_CREATE|
                    ParcelFileDescriptor.MODE_TRUNCATE|ParcelFileDescriptor.MODE_READ_WRITE);
            }catch(...){...}
            profilerInfo = new ProfilerInfo(mProfileFile,fd,mSamplingInterval,mAutoStop);
        }
        ...
        int res;
        ...
        if(mWaitOption){//控制是否等待啟動結果,如果有-W選項,則該值為true
            result = mAm.startActivityAndWait(null,null,intent,mimeType,null,null,0,mStartFlags,
                profilerInfo,null,mUserId);
            res = result.result;
        }else{
            res = mAm.startActivityAsUser(null,null,intent,mimeType,null,null,0,mStartFlags,
                profilerInfo,null,mUserId);
        }
        //處理一些返回結果
        ...
    }while(mRepeat > 1);
}

startActivityAsUser()最後也是調用AMS的startActivityAndWait()方法,所以Am命令框架層的調用結束,其調用時序如下:
Am框架層調用流程


3.2 AMS啟動Activity流程分析

Am命令將啟動Activity的工作交給了AMS來進行,首先看startActivityAndWait()方法,它直接調用StackSupervisor類的startActivityMayWait()方法,其代碼如下:

//StackSupervisor.java
final int startActivityMayWait(...){
    ...
    //為了不改變用戶的intent
    intent = new Intent(intent);
    //收集目標intent的信息,在resolveActivity方法中與PKMS交互獲得
    ActivityInfo aInfo = resolveActivity(intent,resolvedType,startFlags,profilerInfo,userId);
    ActivityContainer container = (ActivityContainer)iContainer;
    synchronized(mService){
        ...
        final ActivityStack stack;
        //取得需要啟動的ActivityStack棧
        if(container == null || container.mStack.isOnHomeDisplay()){
            stack = mFocusedStack;
        }else{
            stack = container.mStack;
        }
        ...
        if(aInfo!=null&&(aInfo.applicationInfo.privateFlags&
            ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)!=0){
            //Androidmanifest.xml中的Application標簽可以聲明一個cantSaveState屬性,若設置,其將不享受系統提
            //供的狀態保存/恢復功能。主要是為了保證用戶體驗的連續性
            ...
        }
        //啟動Activity
        int res = startActivityLocked(caller,intent,resolvedType,aInfo,voiceSession,
            voiceInteractor,resultTo,resultWho,requestCode,callingPid,callingUid,callingPackage,
            realCallingPid,realCallingUid,startFlags,options,ignoreTargetSecurity,
            componentSpecified,null,container,inTask);
        ...
        //如果配置Configration發生變化,則調用AMS的updateConfigurationLocked進行處理
        if(stack.mConfigWillChange){
            mService.enforceCallingPermission(...);
            mConfigWillChange = false;
            mService.updateConfigurationLocked(config,null,false);
        }
        if(outResult != null){
            outResult.result = res;
            if(res == IActivityManager.START_SUCCESS){
                //將結果放入mWaitingActivityLaunced中保存
                mWaitingActivityLaunched.add(outResult);
                do{
                    try{
                        //等待啟動結果
                        mService.wait();
                    }
                }while(!outResult.timeout&&outResult.who == null);
            }else if{
                ...
            }
            ...
        }
        return res;
    }
}

首先通過PKMS查找匹配的ActivityInfo,然後獲取調用者的pid,uid等信息,由於本文的caller為空,得到的是Am所在進程的pid和uid。接著調用startActivityLocked()方法啟動Activity,最後再調用mService.wait()方法來等待啟動結果,並對返回值進行一些處理,此處的等待主要是Am參數中有一個-W選項,若無此選項,則不會有這個等待,最後再將啟動結果res返回。
繼續分析startActivityLocked()方法:

//StackSupervisor.java
final int startActivityLocked(...){
    int err = ActivityManager.START_SUCCESS;
    ProcessRecord callerApp = null;
    if (caller != null) {//如果caller不為空,從AMS中找到它所屬的ProcessRecord即進程,本文此處為null
        callerApp = mService.getRecordForAppLocked(caller);
        if (callerApp != null) {
            callingPid = callerApp.pid;
            callingUid = callerApp.info.uid;
        } else {
            err = ActivityManager.START_PERMISSION_DENIED;
        }
    }
    ...
    //sourceRecord用於描述啟動目標Activity的那個Activity
    ActivityRecord sourceRecord = null;
    //resultRecord用於描述接收啟動結果的Activity,即onActivityResult將被調用以通知啟動結果
    ActivityRecord resultRecord = null;
    ...
    //獲取Intent設置的啟動標志
    final int launchFlags = intent.getFlags();
    //此部分與LaunchMode類似,它用於控制Activity啟動結果的通知
    if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
        ...
    }
    ...
    //檢查權限
    final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid, callingUid);
    ...
    //可為AMS設置IActivityController類型的監聽者,AMS有任何動靜都將回調該監聽者
    if (mService.mController != null) {
        try {
            Intent watchIntent = intent.cloneFilter();
            //交給回調對象處理,由它判斷能否繼續後面的行程
            abort |= !mService.mController.activityStarting(watchIntent,
                        aInfo.applicationInfo.packageName);
        } catch (RemoteException e) {
            mService.mController = null;
        }
    }
    if (abort) {//通知resultRecord
        if (resultRecord != null) {
            resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
                Activity.RESULT_CANCELED, null);
    }   
        ActivityOptions.abort(options);
        return ActivityManager.START_SUCCESS;
    }
    //創建一個ActivityRecord對象
    ActivityRecord r = new ActivityRecord(mService,this,callerApp,callingUid,...);
    ...
    final ActivityStack stack = mFocusedStack;
    if (voiceSession == null && (stack.mResumedActivity == null
        || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
        //判斷是否有權限切換Application
        if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,realCallingPid, 
            realCallingUid, "Activity start")) {
            PendingActivityLaunch pal =new PendingActivityLaunch(r, sourceRecord,startFlags,
                stack);
            //將Pending的請求保存到AMS的mPendingActivityLaunches變量中
            mPendingActivityLaunches.add(pal);
            ActivityOptions.abort(options);
            return ActivityManager.START_SWITCHES_CANCELED;
        }
    }
    if (mService.mDidAppSwitch) {
        mService.mAppSwitchesAllowedTime = 0;
    } else {
        mService.mDidAppSwitch = true;
    }
    //啟動處於Pending狀態的Activity
    doPendingActivityLaunchesLocked(false);
    //調用此函數繼續啟動Activity
    err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,startFlags, 
        true, options, inTask);
    //做一些結果處理
    ...
    return err;
}

此段代碼的主要工作就是處理sourceRecord和resultRecord,然後再處理app switch屬性,如果當前禁止app switch,則將本次啟動保存起來,等允許app switch時再處理,最後再調用startActivityUncheckedLocked()方法處理本次Activity啟動請求:

//StackSupervisor.java
final int startActivityUncheckedLocked(...) {
    final Intent intent = r.intent;
    final int callingUid = r.launchedFromUid;
    ...
    //獲取啟動標志
    int launchFlags = intent.getFlags();
    if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&(launchSingleInstance 
        || launchSingleTask)) {
        //如果Intent和AndroidManifest.xml的啟動模式有沖突,以AndroidManifest.xml為准
        launchFlags &=~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
    } else {
         ...
    }
    ...
    if (sourceRecord != null) {//如果請求的發起者為空,則需要創建一個新的Task
        if (sourceRecord.finishing) {
            if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
                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;
    }




}

未完待續

4、startActivity方法啟動Activity的過程分析

本節將對我們熟悉的調用startActivity的啟動方式進行分析,同樣基於的源碼版本是android 6.0,這種情況下,應用進程已經存在,不需要進行應用進程的創建啟動(區別於AMS啟動Home桌面等啟動新應用的方式),首先看startActivity()代碼:

@Override
public void startActivity(Intent intent,@Nullable Bundle options){
    if(options != null){
        startActivityForResult(intent,-1,options);
    }else{
        startActivityForResult(intent,-1);
    }
}

由代碼可知,startActivity()最終只是對startActivityForResult()方法進行簡單調用,所以只需對startActivityForResult()繼續分析:

public void startActivityForResult(Intent intent,int requestCode,@Nullable Bundle options){
    if(mParent == null){
        //執行Activity啟動,並返回啟動結果
        Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this,
            mMainThread.getApplicationThread(),mToken,this,intent,requestCode,options);
        if(ar != null){
            //向主線程發送啟動結果
            mMainThread.sendActivityResult(mToken,mEmbeddedID,requestCode,ar.getResultCode(),
                ar.getResultData());
        }
        if(requestCode > 0){
            //啟動成功
            mStartedActivity = true;
        }
        cancelInputsAndStartExitTransition(options);
    }else{
        //如果mParent不為空,此時最後還是會調用Instrumentation的execStartActivity()方法
        if(options != null){
            mParent.startActivityFromChild(this,intent,requestCode,options);
        }else{
            mParent.startActivityFromChild(this,intent,requestCode);
        }
    }
}

最後還是會調用Instrumentation的execStartActivity()方法來啟動Activity,並將啟動的結果返回給該應用的主線程,繼續分析execStartActivity()方法:

public ActivityResult execStartActivity(Context who,IBinder contextThread,IBinder token,String 
                            target,Intent intent,int requestCode,Bundle options){
    //獲取通信存根類,它派發消息給ActivityThread主線程,而主線程的mH的handler會進行相應處理
    IApplicationThread whoThread = (IApplicationThread)contextThread;
    ...
    try{
        intent.migrateExtraStreanToClipData();
        intent.prepareToLeaveProcess();
        //調用AMS的startActivity()方法,即進入AMS的調度管理
        int result = ActivityManagerNative.getDefault().startActivity(whoThread,
            who.getBasePackageName(),intent,intent.resolveTypeIfNeeded(
                who.getContentResolver()),token,target,requestCode,0,null,options); 
        //檢查啟動結果
        checkStartActivityResult(result,intent);
    }catch(RemoteException e){
        throw new RuntimeException("Failure from system",e);
    }
    return null;
}

首先獲得IApplicationThread對象,它用於與主線程進行通信,ActivityManagerNative.getDefault()獲取的是AMS對象,所以此處將啟動任務交給了AMS進行調度管理。startActivity方法會調用startActivityAsUser()方法:

@Override
public final int startActivityAsUser(...){
    userId = handleIncomingUser(Binder.getCallingPid(),Binder.getCallingUid(),userId,false,
        ALLOW_FULL_ONLY,"startActivity",null);
    return mStackSupervisor.startActivityMayWait(caller,-1,callingPackage,intent,resolvedType,
        null,null,resultTo,resultWho,requestCode,startFlags,profierInfo,null,null,options,false,
        userId,null,null);
}

至此,它的分析同第3節中的過程一致,此處不再做分析,只是本節的啟動不需要啟動進程,所以它的執行分支不一致。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved