性能優(yōu)化——App啟動(dòng)原理詳解(啟動(dòng)時(shí)間分析檢測(cè))

在Android系統(tǒng)中诬烹,有兩種操作會(huì)引發(fā)Activity的啟動(dòng):

??第一種:用戶點(diǎn)擊應(yīng)用程序圖標(biāo)時(shí)邪意,Launcher會(huì)為我們啟動(dòng)應(yīng)用程序的主Activity遵班;

??第二種:應(yīng)用程序的默認(rèn)Activity啟動(dòng)起來(lái)后,它又可以在內(nèi)部通過(guò)調(diào)用startActvity接口啟動(dòng)新的Activity谒所;

依此類推洗搂,每一個(gè)Activity都可以在內(nèi)部啟動(dòng)新的Activity消返。通過(guò)這種連鎖反應(yīng),按需啟動(dòng)Activity耘拇,從而完成應(yīng)用程序的功能撵颊。

本文主要講點(diǎn)擊應(yīng)用圖標(biāo),啟動(dòng)應(yīng)用程序的過(guò)程惫叛。

在手機(jī)屏幕中點(diǎn)擊應(yīng)用程序圖標(biāo)的情景就會(huì)引發(fā)Android應(yīng)用程序中的默認(rèn)Activity的啟動(dòng)倡勇,從而把應(yīng)用程序啟動(dòng)起來(lái)。這種啟動(dòng)方式的特點(diǎn):會(huì)啟動(dòng)一個(gè)新的進(jìn)程來(lái)加載相應(yīng)的Activity挣棕。

這里译隘,我們來(lái)研究下Android應(yīng)用程序的啟動(dòng)過(guò)程亲桥,即App的啟動(dòng)流程洛心。我們這里就不說(shuō)lancher2包中的Launcher了,好像已經(jīng)過(guò)時(shí)了题篷,我們直接查看lancher3包中的Launcher词身。

1、從手機(jī)屏幕點(diǎn)擊應(yīng)用圖標(biāo)開(kāi)始

我們來(lái)看下點(diǎn)擊應(yīng)用圖標(biāo)會(huì)發(fā)生什么事?

public final class Launcher extends Activity
        implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
                   View.OnTouchListener {

通過(guò)分析源碼我們可以知道,我們得Launcher就是一個(gè)Activity番枚,而且還是先了幾個(gè)點(diǎn)擊事件的接口法严,我們?nèi)タ匆幌翷auncher里面的onClick方法。


   /**
     *
     * @param v 表示點(diǎn)擊的應(yīng)用程序的圖標(biāo)
     */
    public void onClick(View v) {
        // Make sure that rogue clicks don't get through while allapps is launching, or after the
        // view has detached (it's possible for this to happen if the view is removed mid touch).
        if (v.getWindowToken() == null) {
            return;
        }

        if (!mWorkspace.isFinishedSwitchingState()) {
            return;
        }

        if (v instanceof Workspace) {
            if (mWorkspace.isInOverviewMode()) {
                showWorkspace(true);
            }
            return;
        }

        if (v instanceof CellLayout) {
            if (mWorkspace.isInOverviewMode()) {
                showWorkspace(mWorkspace.indexOfChild(v), true);
            }
        }

        Object tag = v.getTag();      //獲取圖標(biāo)的應(yīng)用標(biāo)識(shí)
        if (tag instanceof ShortcutInfo) {
            onClickAppShortcut(v);
        } else if (tag instanceof FolderInfo) {
            if (v instanceof FolderIcon) {
                onClickFolderIcon(v);
            }
        } else if (v == mAllAppsButton) {
            onClickAllAppsButton(v);
        } else if (tag instanceof AppInfo) {    //說(shuō)明是應(yīng)用程序
            startAppShortcutOrInfoActivity(v);
        } else if (tag instanceof LauncherAppWidgetInfo) {
            if (v instanceof PendingAppWidgetHostView) {
                onClickPendingWidget((PendingAppWidgetHostView) v);
            }
        }
    }

當(dāng)點(diǎn)擊Launcher上面的應(yīng)用圖標(biāo)的時(shí)候葫笼,就會(huì)觸發(fā)onClick方法的執(zhí)行深啤,然后根據(jù)傳入?yún)?shù)(View v)的v.getTag()方法得到被點(diǎn)擊應(yīng)用圖標(biāo)的tag,然后判斷tag的類型路星,我們從代碼邏輯上可以看出AppInfo是我們的應(yīng)用程序的類型溯街。所以直接調(diào)用了Launcher的startAppShortcutOrInfoActivity(v)方法。

2洋丐、然后我們看Launcher的startAppShortcutOrInfoActivity(v)方法

  @Thunk void startAppShortcutOrInfoActivity(View v) {
        Object tag = v.getTag();
        final ShortcutInfo shortcut;
        final Intent intent;
        if (tag instanceof ShortcutInfo) {
            shortcut = (ShortcutInfo) tag;
            intent = shortcut.intent;
            int[] pos = new int[2];
            v.getLocationOnScreen(pos);
            intent.setSourceBounds(new Rect(pos[0], pos[1],
                    pos[0] + v.getWidth(), pos[1] + v.getHeight()));

        } else if (tag instanceof AppInfo) {
            shortcut = null;
            intent = ((AppInfo) tag).intent;    //獲取v中的意圖呈昔,有了意圖我們就可以啟動(dòng)Activity了
        } else {
            throw new IllegalArgumentException("Input must be a Shortcut or AppInfo");
        }

        boolean success = startActivitySafely(v, intent, tag);   //這里就是啟動(dòng)入口
        mStats.recordLaunch(v, intent, shortcut);

        if (success && v instanceof BubbleTextView) {
            mWaitingForResume = (BubbleTextView) v;
            mWaitingForResume.setStayPressed(true);
        }
    }

從上面的代碼我們可以看出,launcher3和launcher2中的啟動(dòng)有一點(diǎn)不一樣友绝,就是launcher3中有了AppInfo這個(gè)類堤尾,launcher2中是沒(méi)有的,這也更方便了我們的程序啟動(dòng)迁客。最后還是同樣調(diào)用了Launcher中的startActivitySafely(v, intent, tag);方法郭宝。

3辞槐、然后我們看Launcher的startActivitySafely(v, intent, tag)方法

public boolean startActivitySafely(View v, Intent intent, Object tag) {
        boolean success = false;
        if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
            Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
            return false;
        }
        try {
            success = startActivity(v, intent, tag);    //調(diào)用Launcher的 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;
    }

3、然后我們看Launcher的 startActivity(v, intent, tag);

private boolean startActivity(View v, Intent intent, Object tag) {

        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  //并且傳入?yún)?shù)intent粘室,對(duì)Intent添加flag催蝗,F(xiàn)LAG_ACTIVITY_NEW_TASK
        ...........
             代碼較多省略了許多            

        startActivity(intent, optsBundle); //最后就調(diào)用了Activity的startActivity(Intent intent, @Nullable Bundle)方法 options) 
        ...........
        return false;
    }

這里的intent包含的信息為:action = "android.intent.action.Main",category="android.intent.category.LAUNCHER", cmp="shy.luo.activity/.MainActivity"育特,表示它要啟動(dòng)的Activity為shy.luo.activity.MainActivity丙号。

Intent.FLAG_ACTIVITY_NEW_TASK表示要在一個(gè)新的Task中啟動(dòng)這個(gè)Activity,注意缰冤,Task是Android系統(tǒng)中的概念犬缨,它不同于進(jìn)程Process的概念。

簡(jiǎn)單地說(shuō)棉浸,一個(gè)Task是一系列Activity的集合怀薛,這個(gè)集合是以堆棧的形式來(lái)組織的,遵循后進(jìn)先出的原則迷郑。

稍微擴(kuò)展一下:
(1)我們知道枝恋,一個(gè)應(yīng)用程序可以有多個(gè)Activity,每個(gè)Activity是同級(jí)別的嗡害。那么在啟動(dòng)程序時(shí)焚碌,最先啟動(dòng)哪個(gè)Activity呢?
(2)有些程序可能需要顯示在程 序列表里霸妹,有些不需要十电。怎么定義呢?

android.intent.action.MAIN決定應(yīng)用程序最先啟動(dòng)的Activity 叹螟;
android.intent.category.LAUNCHER決定應(yīng)用程序是否顯示在程序列表里鹃骂。

<intent-filter>
     <action android:name="android.intent.action.MAIN" />
     <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

Main和LAUNCHER同時(shí)設(shè)定才有意義,如果有多個(gè)同級(jí)的Activity都有過(guò)濾器罢绽,則只有最前面的Activity的 <action android:name="android.intent.action.MAIN" /> 有 效畏线,啟動(dòng)該程序時(shí),執(zhí)行的是該Activity良价。且在程序列表中有多個(gè)圖標(biāo)寝殴,這些Activity都在程序列表中顯示,該Application有多個(gè)入 口棚壁,執(zhí)行不同的Activity,但是整個(gè)程序的主入口(整個(gè)程序最先運(yùn)行的那個(gè)activity)只有最先定義的那個(gè)Activity杯矩。

如果一個(gè)應(yīng)用沒(méi)有Launcher則該apk仍能安裝到設(shè)備上,但是在主程序圖中看不到袖外。如果給那個(gè)Activity定了Launcher史隆,且同時(shí)設(shè)定了Main,則這個(gè)Activity就可出現(xiàn)在程序圖中;如果沒(méi)有Main曼验,則不知啟動(dòng)哪Activity泌射,故也不會(huì)有圖標(biāo)出現(xiàn)粘姜。

4、然后我們看Activity中的startActivity(intent, bundle)

    @Override
    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }
    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);  
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);  //這個(gè)方法其實(shí)也是調(diào)用了上面的startActivityForResult(intent, -1, null);  
        }
    }

從源碼可以看出Activity.startActivity方法又調(diào)用了Activity.startActivityForResult方法熔酷。

5孤紧、Activity中的startActivityForResult(Intent intent, int requestCode,Bundle options)

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(    //然后就走到了Instrumentation中的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 {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

mInstrumentation是Activity類的成員變量,它的類型是Intrumentation拒秘,它用來(lái)監(jiān)控應(yīng)用程序和系統(tǒng)的交互号显。

mMainThread也是Activity類的成員變量,它的類型是ActivityThread躺酒,它代表的是應(yīng)用程序的主線程押蚤。這里通過(guò)mMainThread.getApplicationThread獲得它里面的ApplicationThread成員變量,它是一個(gè)Binder對(duì)象羹应,ActivityManagerService會(huì)使用它來(lái)和ActivityThread來(lái)進(jìn)行進(jìn)程間通信揽碘,這里我們需注意的是,這里的mMainThread代表的是Launcher應(yīng)用程序運(yùn)行的進(jìn)程园匹。

mToken也是Activity類的成員變量雳刺,它是一個(gè)Binder對(duì)象的遠(yuǎn)程接口。

6裸违、Instrumentation.execStartActivity() 里面的參數(shù)有點(diǎn)多

 {@hide}
public ActivityResult execStartActivity(    //返回的是一個(gè)ActivityResult
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            int result = ActivityManagerNative.getDefault()     //啟動(dòng)Activity
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

從上面的代碼可以看出掖桦,啟動(dòng)Activity真正的實(shí)現(xiàn)由ActivityManagerNative.getDefault().startActivity方法執(zhí)行。

這里的ActivityManagerNative.getDefault() 它返回的是一個(gè)ActivityManagerService的一個(gè)代理類ActivityManagerProxy累颂。

此時(shí)啟動(dòng)Activity這一操作交給了ActivityManagerNative.getDefault()的startActivity()方法.ActivityManagerNative是一個(gè)抽象類,繼承了Binder,同時(shí)它又實(shí)現(xiàn)了IActivityManager接口,其實(shí)現(xiàn)類是ActivityManagerService(AMS).

ActivityManagerNative.getDefault()方法返回IActivityManager類型對(duì)象,其實(shí)現(xiàn)類是ActivityManagerProxy,其構(gòu)造函數(shù)接受一個(gè)IBinder類型,其實(shí)就是ActivityManagerService對(duì)象,此時(shí)你應(yīng)該發(fā)現(xiàn)ActivityManagerNative,IActivityManager以及ActivityManagerProxy三者之間的聯(lián)系如下:

代理模式圖

通過(guò)上圖,我們看到這三者就是一個(gè)典型的代理模式:ActivityManagerProxy就是ActivityManagerService的遠(yuǎn)程代理,那么此時(shí)ActivityManagerNative的作用也就很明顯:返回AMS的遠(yuǎn)程代理對(duì)象,這樣Launcher應(yīng)用就能和AMS服務(wù)通信了.

7. ActivityManagerService的代理類 ActivityManagerProxy.startActivity()

ActivityManagerProxy是ActivityManagerNative中的一個(gè)內(nèi)部類滞详。

public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

由于ActivityManagerProxy是一個(gè)代理類凛俱,上面是通過(guò)IPC的Binder聯(lián)系到ActivityManagerService紊馏,最后會(huì)調(diào)用ActivityManagerService的startActivity方法。

我們用一張圖來(lái)簡(jiǎn)單的描述上述整個(gè)流程:

啟動(dòng)流程調(diào)用示意圖

8. ActivityManagerService.startActivity()和startActivityAsUser()

    @Override
    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());
      //調(diào)用了ActivityManagerService的startActivityAsUser()
    }
    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {

        enforceNotIsolatedCaller("startActivity");
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.

        //這里的mActivityStarter的類型是ActivityStarter蒲犬。
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null);
    }

9. ActivityStarter.startActivityMayWait()和ActivityStackSupervisor.resolveActivity()

final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
            Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask) {
  
        //省略了很多代碼 
       .................................    
        // 調(diào)用ActivityStackSupervisor.resolveActivity()
        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
        .................................

            final ActivityRecord[] outRecord = new ActivityRecord[1];
            int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask);

          
      .................................
            return res;
        }
    }
ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags,
            ProfilerInfo profilerInfo) {
        final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null;
        if (aInfo != null) 
            intent.setComponent(new ComponentName(
                    aInfo.applicationInfo.packageName, aInfo.name));
            if (!aInfo.processName.equals("system")) {
                if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
                    mService.setDebugApp(aInfo.processName, true, false);
                }
                if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {
                    mService.setNativeDebuggingAppLocked(aInfo.applicationInfo, aInfo.processName);
                }
                if ((startFlags & ActivityManager.START_FLAG_TRACK_ALLOCATION) != 0) {
                    mService.setTrackAllocationApp(aInfo.applicationInfo, aInfo.processName);
                }
                if (profilerInfo != null) {
                    mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
                }
            }
        }
        return aInfo;
    }

ActivityStackSupervisor的resolveActivity方法主要是獲得對(duì)參數(shù)intent的內(nèi)容進(jìn)行解析朱监,得到MainActivity的相關(guān)信息,保存在aInfo變量中原叮。解析之后赫编,得到的aInfo.applicationInfo.packageName的值為應(yīng)用的包名,aInfo.name的值為MainActivity的完整名稱奋隶,被定為

<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

的Activity擂送,這是在這個(gè)實(shí)例的配置文件AndroidManifest.xml里面配置的。然后又調(diào)用了ActivityStarter的startActivityLocked方法唯欣。

10. ActivityStarter.startActivityLocked()

 final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType, ActivityInfo aInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode,
            int callingPid, int callingUid, String callingPackage,
            int realCallingPid, int realCallingUid, int startFlags, Bundle options,
            boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
            ActivityContainer container, TaskRecord inTask) {

        int err = ActivityManager.START_SUCCESS;

        ProcessRecord callerApp = null;
        if (caller != null) {
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } else {
               .........................
            }
        }

       ...........................................

        ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
            sourceRecord = isInAnyStackLocked(resultTo);
            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                    "Will send result to " + resultTo + " " + sourceRecord);
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }

        final int launchFlags = intent.getFlags();

        if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
            // Transfer the result target from the source activity to the new
            // one being started, including any failures.
            if (requestCode >= 0) {
                ActivityOptions.abort(options);
                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
            ..................................
        }
        }

        if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
           .................
        }

        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
           ................
        }

        if (err == ActivityManager.START_SUCCESS
             .................
        }

       ...........................................


        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, voiceSession != null, this, container, options);

        ....................................

        doPendingActivityLaunchesLocked(false);

        ....................................

從傳進(jìn)來(lái)的參數(shù)caller得到調(diào)用者的進(jìn)程信息嘹吨,并保存在callerApp變量中,這里就是Launcher應(yīng)用程序的進(jìn)程信息了境氢。 前面說(shuō)過(guò)蟀拷,參數(shù)resultTo是Launcher這個(gè)Activity里面的一個(gè)Binder對(duì)象碰纬,通過(guò)它可以獲得Launcher這個(gè)Activity的相關(guān)信息,保存在sourceRecord變量中问芬。再接下來(lái)悦析,創(chuàng)建即將要啟動(dòng)的Activity的相關(guān)信息,并保存在r變量中:

ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, voiceSession != null, this, container, options);

然后調(diào)用 ActivityStarter. doPendingActivityLaunchesLocked(false);方法此衅。

11. ActivityStarter.doPendingActivityLaunchesLocked(false)

final void doPendingActivityLaunchesLocked(boolean doResume) {
        while (!mPendingActivityLaunches.isEmpty()) {
            final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
            final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
            try {
                final int result = startActivityUnchecked(
                        pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null, null);

                postStartActivityUncheckedProcessing(
                        pal.r, result, mSupervisor.mFocusedStack.mStackId, mSourceRecord,
                        mTargetStack);
            } catch (Exception e) {
                Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
                pal.sendErrorResult(e.getMessage());
            }
        }
    }

12. ActivityStarter.startActivityUnchecked()

這個(gè)方法主要是創(chuàng)建Acitivity棧强戴,根據(jù)Activity的啟動(dòng)模式,由于是點(diǎn)擊圖標(biāo)進(jìn)來(lái)的挡鞍,一開(kāi)始也設(shè)置了標(biāo)志位Intent.FLAG_ACTIVITY_NEW_TASK酌泰,所以會(huì)新創(chuàng)建一個(gè)Activity棧。如果之前已經(jīng)有棧匕累,且不是singleinstance陵刹,就不會(huì)再創(chuàng)建新的棧,會(huì)將待啟動(dòng)的Activity添加到原來(lái)的棧中欢嘿。最后將會(huì)調(diào)到ActivityStack的resumeTopActivityUncheckedLocked()中衰琐。

13祭示、ActivityStack.resumeTopActivityUncheckedLocked()

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mStackSupervisor.inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
                mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
                mService.updateSleepIfNeededLocked();
            }
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
        return result;
    }

14蛋勺、ActivityStack.resumeTopActivityInnerLocked()

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {

      ---------------------------
    省略多余的代碼,太長(zhǎng)了

       mStackSupervisor.startSpecificActivityLocked(next, true, true);

      ---------------------------

}

(1)這個(gè)方法還會(huì)調(diào)用通過(guò)ActivityManagerService通過(guò)Binder進(jìn)程間通信機(jī)制通知Launcher進(jìn)入Paused狀態(tài)付枫;如果是通過(guò)其他Activity啟動(dòng)的掐隐。會(huì)將其他Activity進(jìn)入Paused狀態(tài)狗热。由于這里是Launcher發(fā)起的startActivity,所以Launcher進(jìn)入Paused狀態(tài)虑省。

(2)調(diào)用了ActivityStackSupervisor.startSpecificActivityLocked方法匿刮。

15、ActivityStackSupervisor.startSpecificActivityLocked()

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.task.stack.setLaunchTime(r);

         //該應(yīng)用的進(jìn)程已經(jīng)存在
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {

                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }

        }

        //該應(yīng)用的進(jìn)程尚未創(chuàng)建,調(diào)用AMS的startProcessLocked()
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

注意探颈,這里由于是第一次啟動(dòng)應(yīng)用程序的Activity熟丸,取回來(lái)的app為null。在Activity應(yīng)用程序中的AndroidManifest.xml配置文件中伪节,我們沒(méi)有指定Application標(biāo)簽的process屬性光羞,系統(tǒng)就會(huì)默認(rèn)使用package的名稱。

每一個(gè)應(yīng)用程序都有自己的uid怀大,因此纱兑,這里uid + process的組合就可以為每一個(gè)應(yīng)用程序創(chuàng)建一個(gè)ProcessRecord。所以下面if (app != null && app.thread != null)條件不成立化借,那么條件里面realStartActivityLocked 方法就不會(huì)執(zhí)行潜慎,而是執(zhí)行ActivityManagerService.startProcessLocked函數(shù)進(jìn)行下一步操作。

15、ActivityManagerService.startProcessLocked()

 final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
            boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
            String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
       
        .............................
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
           ...................

        String hostingNameStr = hostingName != null
                ? hostingName.flattenToShortString() : null;

        if (app == null) {
            checkTime(startTime, "startProcess: creating new process record");
        //  創(chuàng)建一個(gè)新的ProcessRecord
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);

            if (app == null) {
                Slog.w(TAG, "Failed making new process record for "
                        + processName + "/" + info.uid + " isolated=" + isolated);
                return null;
            }
            app.crashHandler = crashHandler;
            checkTime(startTime, "startProcess: done creating new process record");
        } else {
            ............................
        }

       ...............................

        startProcessLocked(
                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
        
    ........

        return (app.pid != 0) ? app : null;
    }

首先調(diào)用getProcessRecordLocked勘纯,但是返回的app為null局服,所以下面這一句就會(huì)執(zhí)行。

              app = newProcessRecordLocked(info, processName, isolated, isolatedUid);

newProcessRecordLocked方法會(huì)調(diào)用addProcessNameLocked方法驳遵,addProcessNameLocked方法中會(huì)執(zhí)行mProcessNames.put(proc.processName, proc.uid, proc);這時(shí)候mProcessNames這個(gè)全局變量就有數(shù)據(jù)了淫奔,再調(diào)用getProcessRecordLocked,返回的就不是null了堤结。

接著唆迁,ActivityManagerService.startProcessLocked方法會(huì)執(zhí)行另一個(gè)無(wú)返回值的startProcessLocked方法。

 private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        
        .............................

                try {
                    checkTime(startTime, "startProcess: getting gids from package manager");
                    final IPackageManager pm = AppGlobals.getPackageManager();
                    permGids = pm.getPackageGids(app.info.packageName, app.userId);
                    MountServiceInternal mountServiceInternal = LocalServices.getService(
                            MountServiceInternal.class);
                    mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
                            app.info.packageName);
                } catch (RemoteException e) {
                    throw e.rethrowAsRuntimeException();
                }

        .....................................

          //記住這里新進(jìn)程導(dǎo)入的是android.app.ActivityThread類
          if (entryPoint == null)   entryPoint = "android.app.ActivityThread";

                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName);
                checkTime(startTime, "startProcess: asking zygote to start proc");

          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);

        .......................

這里主要是調(diào)用Process.start接口來(lái)創(chuàng)建一個(gè)新的進(jìn)程竞穷,新的進(jìn)程會(huì)導(dǎo)入android.app.ActivityThread類唐责,并且執(zhí)行它的main函數(shù),這就是為什么我們前面說(shuō)每一個(gè)應(yīng)用程序都有一個(gè)ActivityThread實(shí)例來(lái)對(duì)應(yīng)的原因.

到現(xiàn)在我們同樣用一張圖來(lái)描述這過(guò)程:

image.png

16瘾带、走進(jìn)Zygote 調(diào)用Process.start接口來(lái)創(chuàng)建一個(gè)新的進(jìn)程

    /* 
     * {@hide}
     */
    public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }

start方法又調(diào)用了startViaZygote方法鼠哥,該方法會(huì)通過(guò)zygote機(jī)制開(kāi)啟一個(gè)新的進(jìn)程。由于我們導(dǎo)入的類名是android.app.ActivityThread看政,開(kāi)啟一個(gè)ActivityThread進(jìn)程朴恳,這也是為什么一個(gè)應(yīng)用程序只有一個(gè)ActivityThread,然后會(huì)執(zhí)行他的main方法允蚣。

17于颖、執(zhí)行ActivityThread.main()函數(shù)和ActivityThread.attach(false)函數(shù)

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());  //在libcore中設(shè)置事件日志記錄的報(bào)告程序

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        //確保可信證書(shū)在正確的位置查找CA證書(shū)
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");
        
        //將當(dāng)前線程初始化為L(zhǎng)ooper嚷兔,將其標(biāo)記為應(yīng)用程序的主Loopper對(duì)象森渐,應(yīng)用程序的主線程是由Androi環(huán)境創(chuàng)建的,因此您永遠(yuǎn)不需要自己調(diào)用此函數(shù)冒晰。

        Looper.prepareMainLooper();    

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

我們?cè)谶@個(gè)方法里創(chuàng)建ActivityThread同衣,并且構(gòu)建主線程的消息循環(huán)系統(tǒng)。

private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            // Watch for getting close to heap limit.
            BinderInternal.addGcWatcher(new Runnable() {
                @Override public void run() {
                    if (!mSomeActivitiesChanged) {
                        return;
                    }
                    Runtime runtime = Runtime.getRuntime();
                    long dalvikMax = runtime.maxMemory();
                    long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                    if (dalvikUsed > ((3*dalvikMax)/4)) {
                        if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                                + " total=" + (runtime.totalMemory()/1024)
                                + " used=" + (dalvikUsed/1024));
                        mSomeActivitiesChanged = false;
                        try {
                            mgr.releaseSomeActivities(mAppThread);
                        } catch (RemoteException e) {
                            throw e.rethrowFromSystemServer();
                        }
                    }
                }
            });
        } else {
            // Don't set application object here -- if the system crashes,
            // we can't display an alert, we just want to die die die.
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }

        // add dropbox logging to libcore
        DropBox.setReporter(new DropBoxReporter());

        ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
            @Override
            public void onConfigurationChanged(Configuration newConfig) {
                synchronized (mResourcesManager) {
                    // We need to apply this change to the resources
                    // immediately, because upon returning the view
                    // hierarchy will be informed about it.
                    if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
                        updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                                mResourcesManager.getConfiguration().getLocales());

                        // This actually changed the resources!  Tell
                        // everyone about it.
                        if (mPendingConfiguration == null ||
                                mPendingConfiguration.isOtherSeqNewer(newConfig)) {
                            mPendingConfiguration = newConfig;

                            sendMessage(H.CONFIGURATION_CHANGED, newConfig);
                        }
                    }
                }
            }
            @Override
            public void onLowMemory() {
            }
            @Override
            public void onTrimMemory(int level) {
            }
        });
    }

ActivityThread的內(nèi)部類ApplicationThread是一個(gè)Binder翩剪,獲得系統(tǒng)的ActivityManagerService乳怎, 調(diào)用它的attachApplication(mAppThread)并把ApplicationThread的對(duì)象mAppThread(是一個(gè)binder對(duì)象)傳給ActivityManagerService,AMS拿到了這個(gè)Binder對(duì)象后做了3件事。

18前弯、ActivityManagerService.attachApplication()和ActivityManagerService.attachApplicationLocked()

    @Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }

private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        ProcessRecord app;
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                app = mPidsSelfLocked.get(pid);
            }
        } else {
            app = null;
        }

        ................................
        final String processName = app.processName;
        try {
            AppDeathRecipient adr = new AppDeathRecipient(
                    app, pid, thread);
            thread.asBinder().linkToDeath(adr, 0);
            app.deathRecipient = adr;
        } catch (RemoteException e) {
            app.resetPackageList(mProcessStats);
            startProcessLocked(app, "link fail", processName);
            return false;
        }

        EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);

        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;

        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
        
            ..............

        boolean badApp = false;
        boolean didSomething = false;

        // See if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) {    //在這里有調(diào)用了ActivityStackSupervisor.attachApplicationLocked()
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }

        ..............................

        return true;
    }

19、ActivityStackSupervisor.attachApplicationLocked(app)

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        final String processName = app.processName;
        boolean didSomething = false;
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (!isFocusedStack(stack)) {
                    continue;
                }
                ActivityRecord hr = stack.topRunningActivityLocked();
                if (hr != null) {
                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                            && processName.equals(hr.processName)) {
                        try {
                            if (realStartActivityLocked(hr, app, true, true)) {
                                didSomething = true;
                            }
                        } catch (RemoteException e) {
                            Slog.w(TAG, "Exception in new application when starting activity "
                                  + hr.intent.getComponent().flattenToShortString(), e);
                            throw e;
                        }
                    }
                }
            }
        }
        if (!didSomething) {
            ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
        }
        return didSomething;
    }

調(diào)用ActivityStackSupervisor.realStartActivityLocked執(zhí)行真正的Activity啟動(dòng)操作秫逝。這里要啟動(dòng)的Activity通過(guò)調(diào)用ActivityStackSupervisor.topRunningActivityLocked(null)從堆棧頂端取回來(lái)恕出,這時(shí)候在堆棧頂端的Activity就是MainActivity了。

20违帆、ActivityStackSupervisor.topRunningActivityLocked()

 final boolean realStartActivityLocked(ActivityRecord r,
            ProcessRecord app, boolean andResume, boolean checkConfig)
            throws RemoteException {

        
            .....................
            app.forceProcessStateUpTo(mService.mTopProcessState);
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

            ..........................

        return true;
    }

app.thread是一個(gè)代理對(duì)象,代理的就是ApplicationThread浙巫,ApplicationThread是ActivityThread的一個(gè)內(nèi)部類.所以邏輯轉(zhuǎn)向了ApplicationThread的scheduleLaunchActivity方法。

20、ApplicationThreadProxy.scheduleLaunchActivity

@Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;
            r.persistentState = persistentState;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;

            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profilerInfo = profilerInfo;

            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);    //發(fā)送啟動(dòng)acitvity的消息
        }

函數(shù)首先創(chuàng)建一個(gè)ActivityClientRecord實(shí)例的畴,并且初始化它的成員變量渊抄,然后發(fā)送一個(gè)啟動(dòng)Activity的消息交給Handler處理,這個(gè)Handler有著一個(gè)很簡(jiǎn)潔的名字:H丧裁,然后看一下H對(duì)消息的處理护桦,H定義ActivityThrad類中。

21.在ActivityThread類中的內(nèi)部類H(是一個(gè)Handler)中接收消息

public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } 

                ----------------------------------

可以看出這個(gè)消息的處理交給了ActivityThread的handleLaunchActivity方法來(lái)處理煎娇。

22.ActivityThread.handleLaunchActivity()

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }

        handleConfigurationChanged(null, null);

        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);

        // Initialize before creating the activity
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

            if (!r.activity.mFinished && r.startsNotResumed) {

                performPauseActivityIfNeeded(r, reason);

                if (r.isPreHoneycomb()) {
                    r.state = oldState;
                }
            
        } else {
            // If there was an error, for any reason, tell the activity manager to stop us.
            try {
                ActivityManagerNative.getDefault()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }

從上面的源碼可以看出二庵,performLaunchActivity最終完成了Activity對(duì)象的創(chuàng)建和啟動(dòng)過(guò)程,并且Activity通過(guò)handleResumeActivity方法來(lái)調(diào)用被啟動(dòng)Activity的onResume這一生命周期方法缓呛。而onCreate這個(gè)這個(gè)生命周期方法在performLaunchActivity方法中被回調(diào)催享。

23、ActivityThread.performLaunchActivity

performLaunchActivity()主要做了以下幾個(gè)事:

(1)從ActivityClientRecord中獲取待啟動(dòng)的Activity的組件信息哟绊。

        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }

        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

(2)通過(guò)Instrumenttation的newActivity方法使用類加載器創(chuàng)建Activity對(duì)象

       Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

(3)通過(guò)LoadeApk的makeApplication方法來(lái)嘗試創(chuàng)建Application對(duì)象

 Application app = r.packageInfo.makeApplication(false, mInstrumentation);
 public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }

        Application app = null;

        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                initializeJavaContextClassLoader();
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            if (!mActivityThread.mInstrumentation.onException(app, e)) {
                throw new RuntimeException(
                    "Unable to instantiate application " + appClass
                    + ": " + e.toString(), e);
            }
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!instrumentation.onException(app, e)) {
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        }

        // Rewrite the R 'constants' for all library apks.
        SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
                .getAssignedPackageIdentifiers();
        final int N = packageIdentifiers.size();
        for (int i = 0; i < N; i++) {
            final int id = packageIdentifiers.keyAt(i);
            if (id == 0x01 || id == 0x7f) {
                continue;
            }

            rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
        }

        return app;
    }

(4)創(chuàng)建ContextImpl對(duì)象并通過(guò)Activity的attach方法來(lái)完成一些重要數(shù)據(jù)的初始化

Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                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);

ContextImpl是一個(gè)很重要的數(shù)據(jù)結(jié)構(gòu)因妙,它是Context的具體實(shí)現(xiàn),Context中的大部分邏輯都是由ContextImpl來(lái)完成的票髓。ContextImpl是通過(guò)Activity的attach方法來(lái)和Activity建立連接的兰迫,處理之外,在attach方法中Activity還會(huì)完成Window的創(chuàng)建并建立自己和Window的關(guān)聯(lián)炬称,這樣當(dāng)Window接受到外部輸入事件后就可以將時(shí)間傳遞給Activity汁果。

(5)調(diào)用Activity的onCreate

if (!r.activity.mFinished) {
                    activity.mCalled = false;
                    if (r.isPersistable()) {  //如果是重新啟動(dòng)
                        mInstrumentation.callActivityOnPostCreate(activity, r.state,r.persistentState);  
                    } else {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                    }
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onPostCreate()");
                    }
                }

最后回調(diào)Activity的onCreate方法。這也意味著應(yīng)用已經(jīng)啟動(dòng)起來(lái)了玲躯。

到現(xiàn)在,我們已經(jīng)完全走完應(yīng)用冷啟動(dòng)的流程,上面的過(guò)程看起來(lái)繁瑣,但是結(jié)合時(shí)序圖來(lái)看應(yīng)該是比較清晰的.拋開(kāi)細(xì)節(jié)不看,那么上述的整個(gè)流程可以用下圖概括:


image.png

最后為了方便系統(tǒng)理解整個(gè)流程,附上一張相對(duì)完整的時(shí)序圖:

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末据德,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子跷车,更是在濱河造成了極大的恐慌棘利,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件朽缴,死亡現(xiàn)場(chǎng)離奇詭異善玫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)密强,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門茅郎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人或渤,你說(shuō)我怎么就攤上這事系冗。” “怎么了薪鹦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵掌敬,是天一觀的道長(zhǎng)惯豆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)奔害,這世上最難降的妖魔是什么楷兽? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮华临,結(jié)果婚禮上芯杀,老公的妹妹穿的比我還像新娘。我一直安慰自己银舱,他們只是感情好瘪匿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著寻馏,像睡著了一般棋弥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诚欠,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天顽染,我揣著相機(jī)與錄音,去河邊找鬼轰绵。 笑死粉寞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的左腔。 我是一名探鬼主播唧垦,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼液样!你這毒婦竟也來(lái)了振亮?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鞭莽,失蹤者是張志新(化名)和其女友劉穎坊秸,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體澎怒,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡褒搔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喷面。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片星瘾。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖乖酬,靈堂內(nèi)的尸體忽然破棺而出死相,到底是詐尸還是另有隱情,我是刑警寧澤咬像,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響县昂,放射性物質(zhì)發(fā)生泄漏肮柜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一倒彰、第九天 我趴在偏房一處隱蔽的房頂上張望审洞。 院中可真熱鬧,春花似錦待讳、人聲如沸芒澜。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)痴晦。三九已至,卻和暖如春琳彩,著一層夾襖步出監(jiān)牢的瞬間誊酌,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工露乏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碧浊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓瘟仿,卻偏偏與公主長(zhǎng)得像箱锐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子劳较,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容