天天看點

女兒拿着小天才電話手表問我App啟動流程

前言

首先,new一個女兒,

var mDdaughter = new 女兒("6歲",“漂亮可愛”,“健康乖巧”,“最喜歡玩小天才電話手表和她的爸爸”)
           

好了,女兒有了,有一天,女兒問我:

“爸爸爸爸,你說我玩的這個

小天才電話手表

怎麼這麼厲害,随便點一下這個小圖檔,這個應用就冒出來了,就可以聽兒歌了。好神奇啊。”

我心裡一驚:

小天才電話手表的系統就是

Android

,是以這不就是。。面試官常考的應用啟動流程嘛!

女兒也要來面試我了嗎!😭

好了,既然女兒問了,那就答吧。

但是,對付這個小小的0經驗面試官,我該咋說呢?

解答小小面試官

女兒,你可以把手表裡面想象成

一個幼稚園

,裡面有一個老師,一個班長,一個班幹部,以及一大堆小朋友。

  • 一個老師

    :Z老師(Zygote程序)
  • 一個班長

    :小A(ActivityManagerService)
  • 一個班幹部

    :小L(Launcher桌面應用)
  • 一大堆小朋友

    :所有應用,包括音樂小朋友,聊天小朋友,月曆小朋友等等。

應用啟動過程就像一個小朋友

被叫醒

一樣,開機之後呢,Z老師會依次叫醒

班長和班幹部

(SystemServer#ActivityManagerService,Launcher),小L醒了之後就會去了解手表裡有哪些小朋友,長什麼樣(icon,name),家庭資訊(包名,androidmanifest)等等,然後一個個把

小朋友的照片(icon)

貼到自己的身上。比如有音樂小朋友,聊天小朋友,月曆小朋友,其實也就是你手表上這個桌面啦。

這時候你要點開一個音樂小朋友呢(startActivity),小L就會通知班長

小A(Binder)

,小A知道了之後,讓小L自己休息下(Paused),然後就去找

Z老師

了。Z老師就負責叫音樂小朋友起床了(fork程序,啟動ActivityThread),音樂小朋友起來後就又找小A帶她去

洗臉刷牙

(啟動ApplicationThread,Activity),都弄完了就可以進行各種表演了,唱歌啊,跳舞啊。

不是很明白啊?我們一起聊個天你就懂了,假如我是

Launcher

女兒似懂非懂的給我點了一個贊👍,爸爸你真棒。

十五年後

mDdaughter.grow(15)
mDdaughter.study("Android")
           

過了十五年,女兒已經21歲了,正在學習

Android

,考慮要不要女從父業。

這天,她一臉疑惑的來找我:

“爸,這個app啟動到底是怎麼個流程啊,我看了好久還是不大明白,要不你再跟我詳細講一遍吧?”

“好嘞,别擔心,我這次詳細跟你說說”

解答Android程式媛

還記得我小時候跟你說過的故事嗎,

Android系統

就像一個幼稚園,有一個大朋友叫

Launcher

,身上會貼很多其他小朋友的名片。這個

Launcher

就是我們的桌面了,它通過

PackageManagerService

獲知了系統裡所有應用的資訊,并展示了出來,當然它本身也是一個應用。

通過點選一個應用圖示,也就是觸發了點選事件,最後會執行到

startActivity

方法。這裡也就和啟動

Activity

步驟重合上了。

那麼這個

startActivity

幹了啥?是怎麼通過重重關卡喚醒這個應用的?

首先,介紹下系統中那些重要的成員,他們在app啟動流程中都擔任了重要的角色.

系統成員介紹

  • init程序

    ,Android系統啟動後,Zygote并不是第一個程序,而是linux的根程序init程序,然後init程序才會啟動Zygote程序。
  • Zygote程序

    ,所有android程序的父程序,當然也包括SystemServer程序
  • SystemServer程序

    ,正如名字一樣,系統服務程序,負責系統中大大小小的事物,為此也是啟動了三員大将(ActivityManagerService,PackageManagerService,WindowManagerService)以及binder線程池。
  • ActivityManagerService

    ,主要負責系統中四大元件的啟動、切換、排程及應用程序的管理和排程等工作,對于一些程序的啟動,都會通過Binder通信機制傳遞給AMS,再處理給Zygote。
  • PackageManagerService

    ,主要負責應用包的一些操作,比如安裝,解除安裝,解析AndroidManifest.xml,掃描檔案資訊等等。
  • WindowManagerService

    ,主要負責視窗相關的一些服務,比如視窗的啟動,添加,删除等。
  • Launcher

    ,桌面應用,也是屬于應用,也有自己的Activity,一開機就會預設啟動,通過設定Intent.CATEGORY_HOME的Category隐式啟動。

搞清楚這些成員,就跟随我一起看看怎麼過五關斬六将,最終啟動了一個App。

第一關:跨程序通信,告訴系統我的需求

首先,要告訴系統,我

Launcher

要啟動一個應用了,調用

Activity.startActivityForResult

方法,最終會轉到

mInstrumentation.execStartActivity

方法。

由于Launcher自己處在一個單獨的程序,是以它需要跨程序告訴系統服務我要啟動App的需求。

找到要通知的Service,名叫

ActivityTaskManagerService

,然後使用AIDL,通過Binder與他進行通信。

這裡的簡單說下

ActivityTaskManagerService

(簡稱ATMS)。原來這些通信工作都是屬于ActivityManagerService,現在分了一部分工作給到ATMS,主要包括四大元件的排程工作。也是由SystemServer程序直接啟動的,相關源碼可見

ActivityManagerService.Lifecycle.startService

方法,感興趣朋友可以自己看看。

接着說跨程序通信,相關代碼如下:

//Instrumentation.java
    int result = ActivityTaskManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);


    //ActivityTaskManager.java            
    public static IActivityTaskManager getService() {
        return IActivityTaskManagerSingleton.get();
    }
    private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
            new Singleton<IActivityTaskManager>() {
                @Override
                protected IActivityTaskManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                    return IActivityTaskManager.Stub.asInterface(b);
                }
            };



    //ActivityTaskManagerService.java
    public class ActivityTaskManagerService extends IActivityTaskManager.Stub
    
    public static final class Lifecycle extends SystemService {
        private final ActivityTaskManagerService mService;

        public Lifecycle(Context context) {
            super(context);
            mService = new ActivityTaskManagerService(context);
        }

        @Override
        public void onStart() {
            publishBinderService(Context.ACTIVITY_TASK_SERVICE, mService);
            mService.start();
        }
    }        
           

startActivity

我們都很熟悉,平時啟動Activity都會使用,啟動應用也是從這個方法開始的,也會同樣帶上

intent

資訊,表示要啟動的是哪個Activity。

另外要注意的一點是,startActivity之後有個

checkStartActivityResult

方法,這個方法是用作檢查啟動Activity的結果。當啟動Activity失敗的時候,就會通過這個方法抛出異常,比如有我們常見的問題:未在AndroidManifest.xml注冊。

public static void checkStartActivityResult(int res, Object intent) {
        switch (res) {
            case ActivityManager.START_INTENT_NOT_RESOLVED:
            case ActivityManager.START_CLASS_NOT_FOUND:
                if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
                    throw new ActivityNotFoundException(
                            "Unable to find explicit activity class "
                            + ((Intent)intent).getComponent().toShortString()
                            + "; have you declared this activity in your AndroidManifest.xml?");
                throw new ActivityNotFoundException(
                        "No Activity found to handle " + intent);
            case ActivityManager.START_PERMISSION_DENIED:
                throw new SecurityException("Not allowed to start activity "
                        + intent);
            case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
                throw new AndroidRuntimeException(
                        "FORWARD_RESULT_FLAG used while also requesting a result");
            case ActivityManager.START_NOT_ACTIVITY:
                throw new IllegalArgumentException(
                        "PendingIntent is not an activity");
            //...
        }
    }
           

第二關:通知Launcher可以休息了

ATMS收到要啟動的消息後,就會通知上一個應用,也就是

Launcher

可以休息會了,進入Paused狀态。

//ActivityStack.java

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        //...
        ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
        //...
        boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
        if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, next, false);
        }
        //...

        if (next.attachedToProcess()) {
            //應用已經啟動
            try {
                //...
                transaction.setLifecycleStateRequest(
                        ResumeActivityItem.obtain(next.app.getReportedProcState(),
                                getDisplay().mDisplayContent.isNextTransitionForward()));
                mService.getLifecycleManager().scheduleTransaction(transaction);
                //...
            } catch (Exception e) {
                //...
                mStackSupervisor.startSpecificActivityLocked(next, true, false);
                return true;
            }
            //...
            // From this point on, if something goes wrong there is no way
            // to recover the activity.
            try {
                next.completeResumeLocked();
            } catch (Exception e) {
                // If any exception gets thrown, toss away this
                // activity and try the next one.
                Slog.w(TAG, "Exception thrown during resume of " + next, e);
                requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
                        "resume-exception", true);
                return true;
            }
        } else {
            //冷啟動流程
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }        
    }
           

這裡有兩個類沒有見過:

  • ActivityStack

    ,是Activity的棧管理,相當于我們平時項目裡面自己寫的Activity管理類,用于管理Activity的狀态啊,如棧出棧順序等等。
  • ActivityRecord

    ,代表具體的某一個Activity,存放了該Activity的各種資訊。

startPausingLocked

方法就是讓上一個應用,這裡也就是Launcher進入Paused狀态。

然後就會判斷應用是否啟動,如果已經啟動了,就會走

ResumeActivityItem

的方法,看這個名字,結合應用已經啟動的前提,是不是已經猜到了它是幹嗎的?沒錯,這個就是用來控制Activity的onResume生命周期方法的,不僅是onResume還有

onStart

方法,具體可見ActivityThread的

handleResumeActivity

方法源碼。

如果應用沒啟動就會接着走到

startSpecificActivityLocked

方法,接着看。

第三關:是否已啟動程序,否則建立程序

Launcher進入Paused之後,

ActivityTaskManagerService

就會判斷要打開的這個應用程序是否已經啟動,如果已經啟動,則直接啟動Activity即可,這也就是應用内的啟動Activity流程。如果程序沒有啟動,則需要建立程序。

這裡有兩個問題:

  • 怎麼判斷應用程序是否存在呢?如果一個應用已經啟動了,會在ATMS裡面儲存一個

    WindowProcessController

    資訊,這個資訊包括processName和uid,uid則是應用程式的id,可以通過applicationInfo.uid擷取。processName則是程序名,一般為程式包名。是以判斷是否存在應用程序,則是根據processName和uid去判斷是否有對應的WindowProcessController,并且

    WindowProcessController

    裡面的線程不為空。代碼如下:
//ActivityStackSupervisor.java
    void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);

        boolean knownToBeDead = false;
        if (wpc != null && wpc.hasThread()) {
            //應用程序存在
            try {
                realStartActivityLocked(r, wpc, andResume, checkConfig);
                return;
            } 
        }
    }

    //WindowProcessController.java
    IApplicationThread getThread() {
        return mThread;
    }

    boolean hasThread() {
        return mThread != null;
    }
           
  • 還有個問題就是怎麼建立程序?還記得Z老師嗎?對,就是Zygote程序。之前說了他是所有程序的父程序,是以就要通知

    Zygote

    去fork一個新的程序,服務于這個應用。
//ZygoteProcess.java
    private Process.ProcessStartResult attemptUsapSendArgsAndGetResult(
            ZygoteState zygoteState, String msgStr)
            throws ZygoteStartFailedEx, IOException {
        try (LocalSocket usapSessionSocket = zygoteState.getUsapSessionSocket()) {
            final BufferedWriter usapWriter =
                    new BufferedWriter(
                            new OutputStreamWriter(usapSessionSocket.getOutputStream()),
                            Zygote.SOCKET_BUFFER_SIZE);
            final DataInputStream usapReader =
                    new DataInputStream(usapSessionSocket.getInputStream());

            usapWriter.write(msgStr);
            usapWriter.flush();

            Process.ProcessStartResult result = new Process.ProcessStartResult();
            result.pid = usapReader.readInt();
            // USAPs can't be used to spawn processes that need wrappers.
            result.usingWrapper = false;

            if (result.pid >= 0) {
                return result;
            } else {
                throw new ZygoteStartFailedEx("USAP specialization failed");
            }
        }
    }
           

可以看到,這裡其實是通過

socket

和Zygote進行通信,

BufferedWriter

用于讀取和接收消息。這裡将要建立程序的消息傳遞給Zygote,由Zygote進行fork程序,并傳回新程序的pid。

可能又會有人問了?fork是啥?為啥這裡又變成

socket

進行IPC通信,而不是

Bindler

了?

  • 首先,

    fork()

    是一個方法,是類Unix作業系統上建立程序的主要方法。用于建立子程序(等同于目前程序的副本)。
  • 那為什麼fork的時候不用Binder而用socket了呢?主要是因為fork

    不允許存在多線程

    ,Binder通訊偏偏就是多線程。

問題總是在不斷産生,總有好奇的朋友會接着問,為什麼

fork

不允許存在多線程?

  • 防止死鎖。其實你想想,多線程+多程序,聽起就不咋靠譜是不。假設多線程裡面線程A對某個鎖

    lock

    ,另外一個線程B調用fork建立了子程序,但是子程序卻沒有了線程A,但是鎖本身卻被

    fork

    了出來,那麼這個鎖沒人可以打開了。一旦子程序中另外的線程又對這個鎖進行

    lock

    ,就死鎖了。

第四關:ActivityThread閃亮登場

剛才說到由

Zygote

進行fork程序,并傳回新程序的pid。其實這過程中也執行個體化

ActivityThread

對象。一起看看是怎麼實作的:

//RuntimeInit.java
   protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;

        try {
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }

        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException(
                    "Problem getting static main on " + className, ex);
        }
        //...
        return new MethodAndArgsCaller(m, argv);
    }
           

原來是反射!通過反射調用了

ActivityThread

的 main 方法。

ActivityThread

大家應該都很熟悉了,代表了Android的主線程,而main方法也是app的主入口。這不對上了!建立程序的時候就調用了,可不是主入口嘛。來看看這個主入口。

public static void main(String[] args) {
        //...
        Looper.prepareMainLooper();

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

        //...

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

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

           

main方法主要建立了

ActivityThread

,建立了主線程的Looper對象,并開始loop循環。除了這些,還要告訴AMS,我醒啦,程序建立好了!也就是上述代碼中的attach方法,最後會轉到

AMSattachApplicationLocked

方法,一起看看這個方法幹了啥:

//ActivitymanagerService.java
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
        //...
        ProcessRecord app;
        //...
        thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                        null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                        new Configuration(app.getWindowProcessController().getConfiguration()),
                        app.compat, getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, autofillOptions, contentCaptureOptions);
        //...
        app.makeActive(thread, mProcessStats);

        //...
        // See if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
                didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }
        //...        
    }

    //ProcessRecord.java
    public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
        //...
        thread = _thread;
        mWindowProcessController.setThread(thread);
    }
           

這裡主要做了三件事:

  • bindApplication方法

    ,主要用來啟動Application。
  • makeActive方法

    ,設定WindowProcessController裡面的線程,也就是上文中說過判斷程序是否存在所用到的。
  • attachApplication方法

    ,啟動根Activity。

第五關:建立Application

接着上面看,按照我們所熟知的,應用啟動後,應該就是啟動

Applicaiton

,啟動

Activity

。看看是不是怎麼回事:

//ActivityThread#ApplicationThread
    public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableBinderTracking, boolean trackAllocation,
                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                String buildSerial, AutofillOptions autofillOptions,
                ContentCaptureOptions contentCaptureOptions) {
            AppBindData data = new AppBindData();
            data.processName = processName;
            data.appInfo = appInfo;
            data.providers = providers;
            data.instrumentationName = instrumentationName;
            data.instrumentationArgs = instrumentationArgs;
            data.instrumentationWatcher = instrumentationWatcher;
            data.instrumentationUiAutomationConnection = instrumentationUiConnection;
            data.debugMode = debugMode;
            data.enableBinderTracking = enableBinderTracking;
            data.trackAllocation = trackAllocation;
            data.restrictedBackupMode = isRestrictedBackupMode;
            data.persistent = persistent;
            data.config = config;
            data.compatInfo = compatInfo;
            data.initProfilerInfo = profilerInfo;
            data.buildSerial = buildSerial;
            data.autofillOptions = autofillOptions;
            data.contentCaptureOptions = contentCaptureOptions;
            sendMessage(H.BIND_APPLICATION, data);
        }

        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                }
            }
    
           

可以看到這裡有個H,H是主線程的一個

Handler

類,用于處理需要主線程處理的各類消息,包括

BIND_SERVICE,LOW_MEMORY,DUMP_HEAP

等等。接着看handleBindApplication:

private void handleBindApplication(AppBindData data) {
        //...
        try {
            final ClassLoader cl = instrContext.getClassLoader();
            mInstrumentation = (Instrumentation)
                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
        }
        //...
        Application app;
        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
        final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
        try {
            // If the app is being launched for full backup or restore, bring it up in
            // a restricted environment with the base application class.
            app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;
            // don't bring up providers in restricted mode; they may depend on the
            // app's custom Application class
            if (!data.restrictedBackupMode) {
                if (!ArrayUtils.isEmpty(data.providers)) {
                    installContentProviders(app, data.providers);
                }
            }

            // Do this after providers, since instrumentation tests generally start their
            // test thread at this point, and we don't want that racing.
            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            //...
            try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!mInstrumentation.onException(app, e)) {
                    throw new RuntimeException(
                            "Unable to create application " + app.getClass().getName()
                                    + ": " + e.toString(), e);
                }
            }
        }
            //...
    }
           

這裡資訊量就多了,一點點的看:

  • 首先,建立了

    Instrumentation

    ,也就是上文一開始startActivity的第一步。每個應用程式都有一個

    Instrumentation

    ,用于管理這個程序,比如要建立Activity的時候,首先就會執行到這個類裡面。
  • makeApplication方法,建立了Application,終于到這一步了。最終會走到newApplication方法,執行Application的

    attach

public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
        app.attach(context);
        return app;
    }
           

attach方法有了,

onCreate

方法又是何時調用的呢?馬上來了:

instrumentation.callApplicationOnCreate(app);

    public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }
           

也就是建立Application->attach->onCreate調用順序。

等等,在onCreate之前還有一句重要的代碼:

installContentProviders
           

這裡就是啟動

Provider

的相關代碼了,具體邏輯就不分析了。

第六關:啟動Activity

說完bindApplication,該說說後續了,上文第五關說到,bindApplication方法之後執行的是

attachApplication

方法,最終會執行到ActivityThread的

handleLaunchActivity

方法:

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

首先,初始化了WindowManagerGlobal,這是個啥呢?

沒錯,就是

WindowManagerService

了,也為後續視窗顯示等作了準備。

繼續看performLaunchActivity:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //建立ContextImpl
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            //建立Activity
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
        }

        try {
            if (activity != null) {
                //完成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, window, r.configCallback,
                        r.assistToken);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }

                //設定activity的主題
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                //調用activity的onCreate方法
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
            }
        }

        return activity;
    }
           

哇,終于看到onCreate方法了。穩住,還是一步步看看這段代碼。

ContextImpl

對象,ContextImpl可能有的朋友不知道是啥,ContextImpl繼承自

Context

,其實就是我們平時用的上下文。有的同學可能表示,這不對啊,擷取上下文明明擷取的是Context對象。來一起跟随源碼看看。

//Activity.java
    Context mBase;

    @Override
    public Executor getMainExecutor() {
        return mBase.getMainExecutor();
    }

    @Override
    public Context getApplicationContext() {
        return mBase.getApplicationContext();
    }
           

這裡可以看到,我們平時用的上下文就是這個

mBase

,那麼找到這個mBase是啥就行了:

protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

    //一層層往上找

    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        
        attachBaseContext(context);

        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }

       
    }

           

這不就是,,,剛才一開始

performLaunchActivity

方法裡面的attach嗎?太巧了,是以這個ContextImpl就是我們平時所用的上下文。

順便看看attach還幹了啥?建立了

PhoneWindow

,建立自己和Window的關聯,并設定了

setSoftInputMode

等等。

ContextImpl

建立完之後,會通過類加載器建立Activity的對象,然後設定好activity的主題,最後調用了activity的

onCreate

總結

再一起捋一遍App的啟動流程:

  • Launcher

    被調用點選事件,轉到Instrumentation類的startActivity方法。
  • Instrumentation

    通過跨程序通信告訴AMS要啟動應用的需求。
  • AMS

    回報Launcher,讓Launcher進入Paused狀态
  • Launcher

    進入Paused狀态,AMS轉到ZygoteProcess類,并通過socket與Zygote通信,告知Zygote需要建立程序。
  • Zygote

    fork程序,并調用ActivityThread的main方法,也就是app的入口。
  • ActivityThread

    的main方法建立了ActivityThread執行個體,并建立了Looper執行個體,開始loop循環。
  • 同時

    ActivityThread

    也告知AMS,程序建立完畢,開始建立Application,Provider,并調用Applicaiton的attach,onCreate方法。
  • 最後就是建立上下文,通過類加載器加載Activity,調用Activity的

    onCreate

至此,應用啟動完畢。

當然,分析源碼的目的一直都不是為了學知識而學,而是了解了這些基礎,我們才能更好的解決問題。

學習了App的啟動流程,我們可以再思考下一些之前沒了解透的問題,比如

啟動優化

分析啟動過程,其實可以優化啟動速度的地方有三個地方:

  • Application的attach方法

    ,MultiDexApplication會在方法裡面會去執行MultiDex邏輯。是以這裡可以進行MultiDex優化,比如今日頭條方案就是單獨啟動一個程序的activity去加載MultiDex。
  • Application的onCreate方法

    ,大量三方庫的初始化都在這裡進行,是以我們可以開啟線程池,懶加載等等。把每個啟動任務進行區分,哪些可以子線程運作,哪些有先後順序。
  • Activity的onCreate方法

    ,同樣進行線程處理,懶加載。或者預建立Activity,提前類加載等等。

最後希望各位老鐵都能有一個乖巧可愛漂亮的

女兒/兒子

。😊

附件

fork使用多線程

今日頭條啟動優化

app啟動流程分析

我的公衆号:碼上積木,每天三問面試題,詳細剖析,助你成為offer收割機。

謝謝你的閱讀,如果你覺得寫的還行,就點個贊支援下吧!感謝!

你的一個👍,就是我分享的動力❤️。

下一篇: Linux man指令