真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

App的啟動(dòng)流程是什么

本篇內(nèi)容介紹了“App的啟動(dòng)流程是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

我們提供的服務(wù)有:網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、萬寧ssl等。為上千多家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的萬寧網(wǎng)站制作公司

前言

首先,new一個(gè)女兒,

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

解答小小面試官

女兒,你可以把手表里面想象成一個(gè)幼兒園,里面有一個(gè)老師,一個(gè)班長,一個(gè)班干部,以及一大堆小朋友。

  • 一個(gè)老師:Z老師(Zygote進(jìn)程)

  • 一個(gè)班長:小A(ActivityManagerService)

  • 一個(gè)班干部:小L(Launcher桌面應(yīng)用)

  • 一大堆小朋友:所有應(yīng)用,包括音樂小朋友,聊天小朋友,日歷小朋友等等。 

應(yīng)用啟動(dòng)過程就像一個(gè)小朋友被叫醒一樣,開機(jī)之后呢,Z老師會(huì)依次叫醒班長和班干部(SystemServer#ActivityManagerService,Launcher),小L醒了之后就會(huì)去了解手表里有哪些小朋友,長什么樣(icon,name),家庭信息(包名,androidmanifest)等等,然后一個(gè)個(gè)把小朋友的照片(icon)貼到自己的身上。比如有音樂小朋友,聊天小朋友,日歷小朋友,其實(shí)也就是你手表上這個(gè)桌面啦。

這時(shí)候你要點(diǎn)開一個(gè)音樂小朋友呢(startActivity),小L就會(huì)通知班長小A(Binder),小A知道了之后,讓小L自己休息下(Paused),然后就去找Z老師了。Z老師就負(fù)責(zé)叫音樂小朋友起床了(fork進(jìn)程,啟動(dòng)ActivityThread),音樂小朋友起來后就又找小A帶她去洗臉?biāo)⒀?/code>(啟動(dòng)ApplicationThread,Activity),都弄完了就可以進(jìn)行各種表演了,唱歌啊,跳舞啊

十五年后

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

過了十五年,女兒已經(jīng)21歲了,正在學(xué)習(xí)Android,考慮要不要女從父業(yè)。

這天,她一臉疑惑的來找我:“爸,這個(gè)app啟動(dòng)到底是怎么個(gè)流程啊,我看了好久還是不大明白,要不你再跟我詳細(xì)講一遍吧?” “好嘞,別擔(dān)心,我這次詳細(xì)跟你說說”

解答Android程序媛

還記得我小時(shí)候跟你說過的故事嗎,Android系統(tǒng)就像一個(gè)幼兒園,有一個(gè)大朋友叫Launcher,身上會(huì)貼很多其他小朋友的名片。這個(gè)Launcher就是我們的桌面了,它通過PackageManagerService獲知了系統(tǒng)里所有應(yīng)用的信息,并展示了出來,當(dāng)然它本身也是一個(gè)應(yīng)用。

通過點(diǎn)擊一個(gè)應(yīng)用圖標(biāo),也就是觸發(fā)了點(diǎn)擊事件,最后會(huì)執(zhí)行到startActivity方法。這里也就和啟動(dòng)Activity步驟重合上了。

那么這個(gè)startActivity干了啥?是怎么通過重重關(guān)卡喚醒這個(gè)應(yīng)用的?

首先,介紹下系統(tǒng)中那些重要的成員,他們?cè)赼pp啟動(dòng)流程中都擔(dān)任了重要的角色. 

系統(tǒng)成員介紹

  • init進(jìn)程,Android系統(tǒng)啟動(dòng)后,Zygote并不是第一個(gè)進(jìn)程,而是linux的根進(jìn)程init進(jìn)程,然后init進(jìn)程才會(huì)啟動(dòng)Zygote進(jìn)程。
  • Zygote進(jìn)程,所有android進(jìn)程的父進(jìn)程,當(dāng)然也包括SystemServer進(jìn)程
  • SystemServer進(jìn)程,正如名字一樣,系統(tǒng)服務(wù)進(jìn)程,負(fù)責(zé)系統(tǒng)中大大小小的事物,為此也是啟動(dòng)了三員大將(ActivityManagerService,PackageManagerService,WindowManagerService)以及binder線程池。
  • ActivityManagerService,主要負(fù)責(zé)系統(tǒng)中四大組件的啟動(dòng)、切換、調(diào)度及應(yīng)用進(jìn)程的管理和調(diào)度等工作,對(duì)于一些進(jìn)程的啟動(dòng),都會(huì)通過Binder通信機(jī)制傳遞給AMS,再處理給Zygote。
  • PackageManagerService,主要負(fù)責(zé)應(yīng)用包的一些操作,比如安裝,卸載,解析AndroidManifest.xml,掃描文件信息等等。
  • WindowManagerService,主要負(fù)責(zé)窗口相關(guān)的一些服務(wù),比如窗口的啟動(dòng),添加,刪除等。
  • Launcher,桌面應(yīng)用,也是屬于應(yīng)用,也有自己的Activity,一開機(jī)就會(huì)默認(rèn)啟動(dòng),通過設(shè)置Intent.CATEGORY_HOME的Category隱式啟動(dòng)。

搞清楚這些成員,就跟隨我一起看看怎么過五關(guān)斬六將,最終啟動(dòng)了一個(gè)App。 

第一關(guān):跨進(jìn)程通信,告訴系統(tǒng)我的需求

首先,要告訴系統(tǒng),我Launcher要啟動(dòng)一個(gè)應(yīng)用了,調(diào)用Activity.startActivityForResult方法,最終會(huì)轉(zhuǎn)到mInstrumentation.execStartActivity方法。由于Launcher自己處在一個(gè)單獨(dú)的進(jìn)程,所以它需要跨進(jìn)程告訴系統(tǒng)服務(wù)我要啟動(dòng)App的需求。找到要通知的Service,名叫ActivityTaskManagerService,然后使用AIDL,通過Binder與他進(jìn)行通信。

這里的簡單說下ActivityTaskManagerService(簡稱ATMS)。原來這些通信工作都是屬于ActivityManagerService,現(xiàn)在分了一部分工作給到ATMS,主要包括四大組件的調(diào)度工作。也是由SystemServer進(jìn)程直接啟動(dòng)的,相關(guān)源碼可見ActivityManagerService.Lifecycle.startService方法,感興趣朋友可以自己看看。

接著說跨進(jìn)程通信,相關(guān)代碼如下:

    //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 IActivityTaskManagerSingleton =
            new Singleton() {
                @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我們都很熟悉,平時(shí)啟動(dòng)Activity都會(huì)使用,啟動(dòng)應(yīng)用也是從這個(gè)方法開始的,也會(huì)同樣帶上intent信息,表示要啟動(dòng)的是哪個(gè)Activity。

另外要注意的一點(diǎn)是,startActivity之后有個(gè)checkStartActivityResult方法,這個(gè)方法是用作檢查啟動(dòng)Activity的結(jié)果。當(dāng)啟動(dòng)Activity失敗的時(shí)候,就會(huì)通過這個(gè)方法拋出異常,比如有我們常見的問題:未在AndroidManifest.xml注冊(cè)。

   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");
            //...
        }
    }
  

第二關(guān):通知Launcher可以休息了

ATMS收到要啟動(dòng)的消息后,就會(huì)通知上一個(gè)應(yīng)用,也就是Launcher可以休息會(huì)了,進(jìn)入Paused狀態(tài)。

    //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()) {
            //應(yīng)用已經(jīng)啟動(dòng)
            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 {
            //冷啟動(dòng)流程
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }        
    }
 

這里有兩個(gè)類沒有見過:

  • ActivityStack,是Activity的棧管理,相當(dāng)于我們平時(shí)項(xiàng)目里面自己寫的Activity管理類,用于管理Activity的狀態(tài)啊,如棧出棧順序等等。
  • ActivityRecord,代表具體的某一個(gè)Activity,存放了該Activity的各種信息。

startPausingLocked方法就是讓上一個(gè)應(yīng)用,這里也就是Launcher進(jìn)入Paused狀態(tài)。然后就會(huì)判斷應(yīng)用是否啟動(dòng),如果已經(jīng)啟動(dòng)了,就會(huì)走ResumeActivityItem的方法,看這個(gè)名字,結(jié)合應(yīng)用已經(jīng)啟動(dòng)的前提,是不是已經(jīng)猜到了它是干嗎的?沒錯(cuò),這個(gè)就是用來控制Activity的onResume生命周期方法的,不僅是onResume還有onStart方法,具體可見ActivityThread的handleResumeActivity方法源碼。

如果應(yīng)用沒啟動(dòng)就會(huì)接著走到startSpecificActivityLocked方法,接著看。 

第三關(guān):是否已啟動(dòng)進(jìn)程,否則創(chuàng)建進(jìn)程

Launcher進(jìn)入Paused之后,ActivityTaskManagerService就會(huì)判斷要打開的這個(gè)應(yīng)用進(jìn)程是否已經(jīng)啟動(dòng),如果已經(jīng)啟動(dòng),則直接啟動(dòng)Activity即可,這也就是應(yīng)用內(nèi)的啟動(dòng)Activity流程。如果進(jìn)程沒有啟動(dòng),則需要?jiǎng)?chuàng)建進(jìn)程。

這里有兩個(gè)問題:

  • 怎么判斷應(yīng)用進(jìn)程是否存在呢?如果一個(gè)應(yīng)用已經(jīng)啟動(dòng)了,會(huì)在ATMS里面保存一個(gè)     WindowProcessController信息,這個(gè)信息包括processName和uid,uid則是應(yīng)用程序的id,可以通過applicationInfo.uid獲取。processName則是進(jìn)程名,一般為程序包名。所以判斷是否存在應(yīng)用進(jìn)程,則是根據(jù)processName和uid去判斷是否有對(duì)應(yīng)的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()) {
            //應(yīng)用進(jìn)程存在
            try {
                realStartActivityLocked(r, wpc, andResume, checkConfig);
                return;
            } 
        }
    }

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

    boolean hasThread() {
        return mThread != null;
    }
 
  • 還有個(gè)問題就是怎么創(chuàng)建進(jìn)程?還記得Z老師嗎?對(duì),就是Zygote進(jìn)程。之前說了他是所有進(jìn)程的父進(jìn)程,所以就要通知     Zygote去fork一個(gè)新的進(jìn)程,服務(wù)于這個(gè)應(yīng)用。
    //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");
            }
        }
    }
 

可以看到,這里其實(shí)是通過socket和Zygote進(jìn)行通信,BufferedWriter用于讀取和接收消息。這里將要新建進(jìn)程的消息傳遞給Zygote,由Zygote進(jìn)行fork進(jìn)程,并返回新進(jìn)程的pid。

可能又會(huì)有人問了?fork是啥?為啥這里又變成socket進(jìn)行IPC通信,而不是Bindler了?

  • 首先,     fork()是一個(gè)方法,是類Unix操作系統(tǒng)上創(chuàng)建進(jìn)程的主要方法。用于創(chuàng)建子進(jìn)程(等同于當(dāng)前進(jìn)程的副本)。
  • 那為什么fork的時(shí)候不用Binder而用socket了呢?主要是因?yàn)閒ork     不允許存在多線程,Binder通訊偏偏就是多線程。

問題總是在不斷產(chǎn)生,總有好奇的朋友會(huì)接著問,為什么fork不允許存在多線程?

  • 防止死鎖。其實(shí)你想想,多線程+多進(jìn)程,聽起就不咋靠譜是不。假設(shè)多線程里面線程A對(duì)某個(gè)鎖     lock,另外一個(gè)線程B調(diào)用fork創(chuàng)建了子進(jìn)程,但是子進(jìn)程卻沒有了線程A,但是鎖本身卻被     fork了出來,那么這個(gè)鎖沒人可以打開了。一旦子進(jìn)程中另外的線程又對(duì)這個(gè)鎖進(jìn)行     lock,就死鎖了。 

第四關(guān):ActivityThread閃亮登場(chǎng)

剛才說到由Zygote進(jìn)行fork進(jìn)程,并返回新進(jìn)程的pid。其實(shí)這過程中也實(shí)例化ActivityThread對(duì)象。一起看看是怎么實(shí)現(xiàn)的:

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

原來是反射!通過反射調(diào)用了ActivityThread 的 main 方法。ActivityThread大家應(yīng)該都很熟悉了,代表了Android的主線程,而main方法也是app的主入口。這不對(duì)上了!新建進(jìn)程的時(shí)候就調(diào)用了,可不是主入口嘛。來看看這個(gè)主入口。

    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方法主要?jiǎng)?chuàng)建了ActivityThread,創(chuàng)建了主線程的Looper對(duì)象,并開始loop循環(huán)。除了這些,還要告訴AMS,我醒啦,進(jìn)程創(chuàng)建好了!也就是上述代碼中的attach方法,最后會(huì)轉(zhuǎn)到AMSattachApplicationLocked方法,一起看看這個(gè)方法干了啥:

    //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方法,主要用來啟動(dòng)Application。
  • makeActive方法,設(shè)定WindowProcessController里面的線程,也就是上文中說過判斷進(jìn)程是否存在所用到的。
  • attachApplication方法,啟動(dòng)根Activity。

第五關(guān):創(chuàng)建Application

接著上面看,按照我們所熟知的,應(yīng)用啟動(dòng)后,應(yīng)該就是啟動(dòng)Applicaiton,啟動(dòng)Activity??纯词遣皇窃趺椿厥拢?/p>

    //ActivityThread#ApplicationThread
    public final void bindApplication(String processName, ApplicationInfo appInfo,
                List 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;
                }
            }
    
 

可以看到這里有個(gè)H,H是主線程的一個(gè)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);
                }
            }
        }
            //...
    }
 

這里信息量就多了,一點(diǎn)點(diǎn)的看:

  • 首先,創(chuàng)建了     Instrumentation,也就是上文一開始startActivity的第一步。每個(gè)應(yīng)用程序都有一個(gè)     Instrumentation,用于管理這個(gè)進(jìn)程,比如要?jiǎng)?chuàng)建Activity的時(shí)候,首先就會(huì)執(zhí)行到這個(gè)類里面。
  • makeApplication方法,創(chuàng)建了Application,終于到這一步了。最終會(huì)走到newApplication方法,執(zhí)行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方法又是何時(shí)調(diào)用的呢?馬上來了:

    instrumentation.callApplicationOnCreate(app);

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

也就是創(chuàng)建Application->attach->onCreate調(diào)用順序。

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

installContentProviders

這里就是啟動(dòng)Provider的相關(guān)代碼了,具體邏輯就不分析了。 

第六關(guān):啟動(dòng)Activity

說完bindApplication,該說說后續(xù)了,上文第五關(guān)說到,bindApplication方法之后執(zhí)行的是attachApplication方法,最終會(huì)執(zhí)行到ActivityThread的handleLaunchActivity方法:

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

首先,初始化了WindowManagerGlobal,這是個(gè)啥呢?沒錯(cuò),就是WindowManagerService了,也為后續(xù)窗口顯示等作了準(zhǔn)備。

繼續(xù)看performLaunchActivity:

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

        try {
            if (activity != null) {
                //完成activity的一些重要數(shù)據(jù)的初始化
                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;
                }

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

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

        return activity;
    }
 

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

首先,創(chuàng)建了ContextImpl對(duì)象,ContextImpl可能有的朋友不知道是啥,ContextImpl繼承自Context,其實(shí)就是我們平時(shí)用的上下文。有的同學(xué)可能表示,這不對(duì)啊,獲取上下文明明獲取的是Context對(duì)象。來一起跟隨源碼看看。

    //Activity.java
    Context mBase;

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

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

這里可以看到,我們平時(shí)用的上下文就是這個(gè)mBase,那么找到這個(gè)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嗎?太巧了,所以這個(gè)ContextImpl就是我們平時(shí)所用的上下文。

順便看看attach還干了啥?新建了PhoneWindow,建立自己和Window的關(guān)聯(lián),并設(shè)置了setSoftInputMode等等。

ContextImpl創(chuàng)建完之后,會(huì)通過類加載器創(chuàng)建Activity的對(duì)象,然后設(shè)置好activity的主題,最后調(diào)用了activity的onCreate方法。 

“App的啟動(dòng)流程是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!


分享名稱:App的啟動(dòng)流程是什么
地址分享:http://weahome.cn/article/gdddsj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部