startActivity()流程分析

startActivity() 流程分析 (SDK源碼為28)

當我們從手機桌面點擊應用圖標時,這時候就會打開我們的應用程序弊仪,在這個過程中發(fā)生了什么事情灌曙,整個流程是怎么樣的?我們知道在Android中一個App就相當于一個進程缠俺,點擊應用icon時就相當于從一個進程跳轉(zhuǎn)到了另一進程。在這里就涉及到了跨進程通訊贷岸,Android系統(tǒng)中是通過Binder來實現(xiàn)進程通訊的壹士,是由ActivityThread的內(nèi)部類ApplicationThread來完成的,這里主要涉及到了三個階段:

  • 第一階段:ActivityA 通過Binder通訊告訴 ActivityManagerService要啟動ActivityB

  • 第二階段:ActivityManagerService收到啟動ActivityB的消息后偿警,會做一些列的判斷和準備工作躏救,比如構(gòu)造Intent,應用棧的處理,應用進程的創(chuàng)建等工作盒使,然后把任務交給ActivityB所在的進程

  • 第三階段:ActivityB所在進程收到任務消息后崩掘,會創(chuàng)建Activity并調(diào)用其生命周期方法

針對Android系統(tǒng)來說,手機桌面也是頁面少办,應用icon是這個頁面展示的數(shù)據(jù)苞慢;手機桌面是通過Launcher類來實現(xiàn)的,Launcher繼承自Activity凡泣,手機廠商自定義桌面都是通過實現(xiàn)Launcher來實現(xiàn)的枉疼,我們首先來看它的onClick方法,這里面記錄了我們點擊應用icon后的操作邏輯:

public void onClick(View v) {
    Object tag = v.getTag();
    
    if (tag instanceof ShortcutInfo) { //點擊應用icon
        final Intent intent = ((ShortcutInfo) tag).intent;
        boolean success = startActivitySafely(v, intent, tag);
    } else if (tag instanceof FolderInfo) {//點擊文件夾鞋拟,主要是應用分類
        if (v instanceof FolderIcon) {
            FolderIcon fi = (FolderIcon) v;
            handleFolderClick(fi);
        }
    } else if (v == mAllAppsButton) {//點擊顯示所有應用icon
        if (isAllAppsVisible()) {
            showWorkspace(true);
        } else {
            onClickAllAppsButton(v);
        }
    }
}

這里我們主要關(guān)注點擊應用icon的邏輯處理骂维,因為后面兩種點擊邏輯處理最終都會調(diào)用點擊應用icon的梳理邏輯,接下來我們進入startActivitySafely()方法

boolean startActivitySafely(View v, Intent intent, Object tag) {
    boolean success = false;
    try {
        success = startActivity(v, intent, tag);
    } catch (ActivityNotFoundException e) {
        Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
        Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
    }
    return success;
}

這個方法主要對startActivity()進行了一層包裝贺纲,進行異常處理航闺,然后進入startActivity()

boolean startActivity(View v, Intent intent, Object tag) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //在新的任務棧中啟動
                    
    try {
        UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
        LauncherApps launcherApps = (LauncherApps)
                this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
        
        if (user == null || user.equals(android.os.Process.myUserHandle())) {
            startActivity(intent, opts.toBundle()); //調(diào)用Activity的startActivity()
        } else {
            launcherApps.startMainActivity(intent.getComponent(), user,
                                           intent.getSourceBounds(),
                                           opts.toBundle());
        }
        
        return true;
    } catch (SecurityException e) {
        Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
    }
    return false;
}

這里主要分了兩步走,我們首先看Activity#startActivity()

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

Activity#startActivity()重寫了父類ContextWrapper的startActivity()猴誊,然后調(diào)用了startActivityForResult(),傳入-1的作用是不需要返回結(jié)果

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {
    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());
    }
}

以上代碼我只摘抄了主要部分潦刃,方便理解,在startActivityForResult中調(diào)用了Instrumentation#execStartActivity(),這個Instrumentation是用來監(jiān)控應用程序和系統(tǒng)交互的懈叹,mMainThread.getApplicationThread()是一個IBinder接口乖杠,用于實現(xiàn)進程間通訊的。

public ActivityResult execStartActivity(Context who, IBinder contextThread ...) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    
    try {
        int result = ActivityTaskManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
}

可以發(fā)現(xiàn)澄成,在這里獲取了ActivityAIApplicationThread胧洒,然后通過ActivityTaskManager獲取了ActivityManagerService,并調(diào)用了其startActivity墨状,這一步實現(xiàn)了ActivityAActivityManagerService的過渡卫漫,啟動ActivityB的任務就交由AMS來實現(xiàn)。

接下來我們來看Server端啟動Activity的流程肾砂,首先我們進入AMS#startActivity()

public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}
public final int startActivityAsUser() {
    return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
            .setCaller(caller)
            .setCallingPackage(callingPackage)
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setMayWait(userId)
            .execute();
}

在這里我們獲取了一個ActivityStarter列赎,然后采用Builder模式設(shè)置了一些參數(shù),最后調(diào)用了execute镐确;看名字這個ActivityStarter是專門用來啟動Activity的包吝,接下來我們進入這個類,查看execute做了什么處理

int execute() {
    if (mRequest.mayWait) {
        return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
                mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
                mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
                mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
                mRequest.inTask, mRequest.reason,
                mRequest.allowPendingRemoteAnimationRegistryLookup);
    } else {
        return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
                mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
                mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
                mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
                mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
                mRequest.outActivity, mRequest.inTask, mRequest.reason,
                mRequest.allowPendingRemoteAnimationRegistryLookup);
    }
}

startActivityMayWaitstartActivity中主要做了解析Intent源葫,創(chuàng)建ActivityRecord诗越,創(chuàng)建TaskRecord等工作;最終這兩個方法都會調(diào)用ActivityStarter#startActivityUnchecked()

private int startActivityUnchecked() {
    //啟動Flag計算
    computeLaunchingTaskFlags();
    
    //處理Task和Activity的進站操作
    mTargetStack.startActivityLocked();
    
    //處理棧頂Activity
    mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);
}
boolean resumeFocusedStackTopActivityLocked() {

    if (targetStack != null && isFocusedStack(targetStack)) {
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }
    
    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
    if (r == null || !r.isState(RESUMED)) {
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
    } else if (r.isState(RESUMED)) {
        mFocusedStack.executeAppTransition(targetOptions);
    }
    
    return false;
}

上面幾個判斷最終都會調(diào)用ActivityStack#resumeTopActivityUncheckedLocked

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
    boolean result = false;
    result = resumeTopActivityInnerLocked(prev, options);
    
    return result;
}

ActivityStack#resumeTopActivityInnerLocked()中會經(jīng)過一些列的判斷臼氨,最后調(diào)用ActivityStackSupervisor#startSpecificActivityLocked()方法

void startSpecificActivityLocked(ActivityRecord r,boolean andResume, boolean checkConfig) {
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);
    
    if (app != null && app.thread != null) {
        realStartActivityLocked(r, app, andResume, checkConfig);
        return;
    }
    
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

在這里會判斷ActivityB所在的應用進程是否存在,如果進程不存在芭届,會先去創(chuàng)建進程储矩,最后會調(diào)用realStartActivityLocked感耙,我們再進入ActivityStackSupervisor#realStartActivityLocked(),查看做了什么邏輯

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
    
    // Create activity launch transaction. 創(chuàng)建transaction
    final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,r.appToken);
    
    //添加Callback回調(diào)接口持隧,稍后會執(zhí)行
    clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
        System.identityHashCode(r), 
        r.info,
        mergedConfiguration.getGlobalConfiguration(),
        mergedConfiguration.getOverrideConfiguration(), 
        r.compat,
        r.launchedFromPackage, 
        task.voiceInteractor, 
        app.repProcState, 
        r.icicle,
        r.persistentState, 
        results, 
        newIntents, 
        mService.isNextTransitionForward(),
        profilerInfo));
    
    // Schedule transaction.  執(zhí)行transaction
    mService.getLifecycleManager().scheduleTransaction(clientTransaction);
}

可以看到最后獲取了ClientLifecycleManager即硼,然后執(zhí)行了scheduleTransaction(),然后進入這個方法

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule();
}

在這里Transaction的client屡拨,這個client是IApplicationThread類型只酥,這個類是用于進程間通訊的,有可能這里會使用client來和AMS通信呀狼,后面會不會使用它裂允,我們向下分析就知道了,最后這個方法執(zhí)行了transaction.schedule()

public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this);
}

果然這里使用利用client實現(xiàn)了ActivityB所在的進程和AMS所在進程進行通訊哥艇,調(diào)用了ActivityB所在進程的IApplicationThread的scheduleTransaction()绝编,這里Activity啟動任務實現(xiàn)了從AMS到ActivityB所在進程的交接

這下startActivity任務來到第三階段,AMS通過Binder通信貌踏,把啟動ActivityB的任務交由ActivityB所在進程處理十饥,ActivityB所在進程的ApplicationThreadscheduleTransaction()方法被調(diào)用

@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    ActivityThread.this.scheduleTransaction(transaction);
}

在ActivityThread方法中會找不到scheduleTransaction,因為調(diào)用的是其父類ClientTransactionHandler#scheduleTransaction()

void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

在這個方法中祖乳,先調(diào)用了preExecute()做了一些預處理工作逗堵,然后向ActivityThread所在線程的Handler發(fā)送了一條消息EXECUTE_TRANSACTION;這個時候直接查看這個名為H的Handler的handleMessage()做了什么處理邏輯

public void handleMessage(Message msg) {
    case EXECUTE_TRANSACTION:
        final ClientTransaction transaction = (ClientTransaction) msg.obj;
        mTransactionExecutor.execute(transaction);
        if (isSystem()) {
            transaction.recycle();
        }
        break;
}

Handler在收到這條消息后眷昆,調(diào)用TransactionExecutor#execute()

public void execute(ClientTransaction transaction) {
    executeCallbacks(transaction);
    executeLifecycleState(transaction);
}
public void executeCallbacks(ClientTransaction transaction) {
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
    final int size = callbacks.size();
    
    for (int i = 0; i < size; ++i) {
        final ClientTransactionItem item = callbacks.get(i);
        item.execute(mTransactionHandler, token, mPendingActions);
        item.postExecute(mTransactionHandler, token, mPendingActions);
    }
}

這里會獲取到transaction的所有Callback對象蜒秤,然后依次執(zhí)行它們的execute方法,那么這些Callback是什么時候添加的呢隙赁?還記得我們創(chuàng)建Transaction的時候么垦藏,創(chuàng)建Transaction對象時,我們往里面添加了Callback對象LaunchActivityItem伞访,這里我們只需要查看LaunchActivityItem的execute做了什么處理就行 (LaunchActivityItem是繼承自ClientTransactionItem)

public void execute(ClientTransactionHandler client ...) {
    ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
            mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
            mPendingResults, mPendingNewIntents, mIsForward,
            mProfilerInfo, client);
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}

這里調(diào)用了ClientTransactionHandler#handleLaunchActivity掂骏,其實就是調(diào)用的ActivityThread的handleLaunchActivity(),因為ActivityThread是ClientTransactionHandler的實現(xiàn)類

public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
    WindowManagerGlobal.initialize();
    final Activity a = performLaunchActivity(r, customIntent);
}

首先創(chuàng)建WindowManagerService厚掷,進行Window初始化相關(guān)操作弟灼;然后再調(diào)用performLaunchActivity()處理Activity的創(chuàng)建邏輯

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //第一步:創(chuàng)建Activity的Context
    ContextImpl appContext = createBaseContextForActivity(r);

    //第二步:創(chuàng)建Activity實例
    Activity activity = null;
    java.lang.ClassLoader cl = appContext.getClassLoader();
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    
    //第三步:獲取當前進程的application實例
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    //LoadedApk的makeApplication
    app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
    
    //第三步:執(zhí)行Activity的attach方法
    //創(chuàng)建PhoneWindow,設(shè)置mWindow#setCallback()冒黑,設(shè)置mWindowManager田绑,設(shè)置mApplication
    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, window, r.configCallback);
    
    //第四步:調(diào)用Activity的onCreate()
    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
}

到此從ActivityA到ActivityB的啟動流程已經(jīng)完成,ActivityB成功啟動抡爹,并調(diào)用了其onCreate()掩驱,如還需要分析后續(xù)流程,就應該是View的繪制流程了

到最后,我們對這個流程做一個總結(jié):

  • 第一步:無論是從桌面點擊應用圖標啟動Activity還是從ActivityA跳轉(zhuǎn)到ActivityB欧穴,其本質(zhì)都是從ActivityA跳轉(zhuǎn)到ActivityB民逼,通過調(diào)用startActivity方法,通過Binder機制把啟動Activity的任務交由AMS涮帘,由Instrumentation調(diào)用AMS#startActivity()
  • 第二步:AMS的startActivity()收到任務拼苍,經(jīng)過ActivityStarter,ActivityStack调缨,ActivityStackSupervisor的一系列處理疮鲫,最終由AMS調(diào)用目標Activity所在進程的ApplicationThread的scheduleTransaction()
  • 第三步:在ActivityThread的ApplicationThread收到scheduleTransaction()任務后,經(jīng)過ActivityThread的一系列處理后調(diào)用handleLaunchActivity弦叶,進行Activity的創(chuàng)建等一系列工作俊犯,最后調(diào)用onCreate(),完成Activity的啟動
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市湾蔓,隨后出現(xiàn)的幾起案子瘫析,更是在濱河造成了極大的恐慌,老刑警劉巖默责,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贬循,死亡現(xiàn)場離奇詭異,居然都是意外死亡桃序,警方通過查閱死者的電腦和手機杖虾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來媒熊,“玉大人奇适,你說我怎么就攤上這事÷ⅲ” “怎么了嚷往?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長柠衅。 經(jīng)常有香客問我皮仁,道長,這世上最難降的妖魔是什么菲宴? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任贷祈,我火速辦了婚禮,結(jié)果婚禮上喝峦,老公的妹妹穿的比我還像新娘势誊。我一直安慰自己,他們只是感情好谣蠢,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布粟耻。 她就那樣靜靜地躺著查近,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挤忙。 梳的紋絲不亂的頭發(fā)上嗦嗡,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音饭玲,去河邊找鬼。 笑死叁执,一個胖子當著我的面吹牛茄厘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谈宛,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼次哈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吆录?” 一聲冷哼從身側(cè)響起窑滞,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恢筝,沒想到半個月后哀卫,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡撬槽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年此改,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侄柔。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡共啃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出暂题,到底是詐尸還是另有隱情移剪,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布薪者,位于F島的核電站纵苛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏啸胧。R本人自食惡果不足惜赶站,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望纺念。 院中可真熱鬧贝椿,春花似錦、人聲如沸陷谱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至渣窜,卻和暖如春铺根,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乔宿。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工位迂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人详瑞。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓掂林,卻偏偏與公主長得像,于是被迫代替她去往敵國和親坝橡。 傳聞我的和親對象是個殘疾皇子泻帮,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344