android N进程启动流程(二)(上一个activity的暂停、进程启动、绑定进程与创建application)

android N进程启动流程(二)(上一个activity的暂停、进程启动、绑定进程与创建application)

第二部分将分为:上一个activity的暂停、进程启动、绑定进程与创建application

5. 上一个activity的暂停

上一个activity的暂停
图5.1 上一个activity的暂停

接着章节3.6的startActivityUnchecked中会调用最后有调用resumeFocusedStackTopActivityLocked,我们接下去从这里开始讲解。

5.1 resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java)

resumeFocusedStackTopActivityLocked恢复当前focus的堆栈stack中的顶端活动对象top activity

1) 上面章节3.6中setTaskFromReuseOrCreateNewTask->computeStackFocus->mSupervisor.getStack已经创建了mTargetStack,并将其添加到ActivityDisplay的mStack中去。
2) 章节3.6中moveToFront的insertTaskAtTop中也设置了需要启动的应用如test2.com.myapplication成为堆栈顶端Top的进程
3) 章节4.2中setFocusStackUnchecked也设置了mTargetStack为test2

    //上面章节3.6中setTaskFromReuseOrCreateNewTask已经创建了mTargetStack,
    //章节3.6中moveToFront的insertTaskAtTop中也设置了需要启动的应用如test2.com.myapplication
    //成为堆栈顶端Top的进程
    boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if (targetStack != null && isFocusedStack(targetStack)) {
            //targetStack不为null,而且isFocusedStack也是test2,故此处是会进来的
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        //...
    }

5.2 resumeTopActivityUncheckedLocked(ActivityStack.java)

resumeFocusedStackTopActivityLocked恢复当前focus堆栈stack中的顶端活动对象
1) 此处的stack this对象是test2上一章节5.1中说的mTargetStack
2) 此时是第一次看到resumeTopActivityInnerLocked,故是第一次进入,传递的prev是test2.com.myapplication我们先看第一次进入该函数的处理逻辑(第二次的请忽略先)
3) 此处逻辑依次是resumeTopActivityUncheckedLocked->resumeTopActivityInnerLocked->pauseBackStacks
4) 第一次进入由于在pauseBackStacks返回有需要pause的应用,故pausing==true,pauseBackStacks做完不久就直接返回了

    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        //....
        result = resumeTopActivityInnerLocked(prev, options);
        //....
    }

    //第一次进来的时候prev是test2.com.myapplication(所以会先pause上一个应用如com.android.launcher);
    //第二次进来是prev是com.android.launcher,此时launcher已经pause了,
    //会进入下一个应用的resume流程(如test2.com.myapplication)
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        //...
        //第一次进来topRunningActivityLocked是test2,第二次进来也是test2,
        //此处是在moveActivityStackToFront中已经设置过了
        final ActivityRecord next = topRunningActivityLocked();

        //...
        //此处allPausedActivitiesComplete是true,不会进入这里,
        //说明之前已经没有需要pause的应用(第一次进来mPausingActivity还没有设置过==null)
        //或者pause完成(第二次进来)
        if (!mStackSupervisor.allPausedActivitiesComplete()) {
            …
            return false;
        }

        //...
        //是否有设置标志位在pausing的时候resume,默认没有设置都是false
        final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;

        //此处判断是否有需要pasue的进程(是所有stack而不仅仅是当前stack),
        //第一次进来会pause launcher(launcher的堆栈中有mResumedActivity,
        //但是章节4.2已经将焦点切换到test2)故反馈pausing==true,第二次直接返回pausing==false
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
        //mResumedActivity一直都是null(由于当前mTargetStack是新new出来的给进程test2使用),
        //只有在test2 resume之后才会设置,如在minimalResumeActivityLocked之后设置,故不会走下面的逻辑
        if (mResumedActivity != null) {
            //...
        }

        //第一次走的pausing是true(代表有需要暂停的应用,如launcher),第二次pausing是false
        if (pausing) {
            //...
            //第一次进来到这里就结束了
            return true;
        //此处一般都是不走的mResumedActivity == null,第二次pausing是false,
        //但是还是有activity继续resume(allResumedActivitiesComplete返回false)
        } else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                mStackSupervisor.allResumedActivitiesComplete()) {
            ...
            return true;
        }

        //第二次时会进来这里prev != next,此处next代表test2.com.myapplication,
        //prev代表com.android.launcher
        if (prev != null && prev != next) {
            if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                    && next != null && !next.nowVisible) {
                //等待prev的界面launcher隐藏,此处在mStackSupervisor的
                //processStoppingActivitiesLocked时才会remove
                mStackSupervisor.mWaitingVisibleActivities.add(prev);
            } else {
            //...
        }
        //...
        //第二次进来时prev == com.android.launcher
        if (prev != null) {
            //launcher是没有finishing的,不进入这里
            if (prev.finishing) {
                //...
            //准备resume test2.com.myapplication时prev代表com.android.launcher,会进来这里
            } else {
                //prev.task不等于next.task,mLaunchTaskBehind是false,
                //WMS中传输类型是TRANSIT_TASK_OPEN
                mWindowManager.prepareAppTransition(prev.task == next.task
                        ? TRANSIT_ACTIVITY_OPEN
                        : next.mLaunchTaskBehind
                                ? TRANSIT_TASK_OPEN_BEHIND
                                : TRANSIT_TASK_OPEN, false);
            }
        } else {
            //...
        }
        //...
        //此处next(test2.com.myapplication)进程都还没有起来,不会进入这里
        if (next.app != null && next.app.thread != null) {
            //...
        //next(test2.com.myapplication)进入的是else
        } else {
            //第一次启动hasBeenLaunched肯定是false,所以会进入此处
            if (!next.hasBeenLaunched) {
                next.hasBeenLaunched = true;
            } else {
                ...
            }
            //这里才是真正启动test2进程的地方
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }
        //...
    }

5.3 pauseBackStacks(ActivityStackSupervisor.java)

pauseBackStacks遍历ActivityDisplay显示设备中的所有栈,当循环到luancher的时候,由于launcher已经不是focus的stack栈,但是它的mResumedActivity仍然存在,代表这个activity需要进行pause暂停的操作。

    boolean pauseBackStacks(boolean userLeaving, boolean resuming, boolean dontWait) {
        //...
        //遍历stacks当前显示设备的所有堆栈
        final ActivityStack stack = stacks.get(stackNdx);
        //stack是launcher,isFocusedStack是false,mResumedActivity是launcher不等于null
        if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
            //launcher的stack进行pause的操作,注意resuming是true,dontWait是false,
            //userLeaving是true,在章节3.6 startActivityUnchecked->setInitialState中设置
            someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
                    dontWait);
        //...
    }

5.4 startPausingLocked(ActivityStack.java)

1) startPausingLocked这个函数是启动应用暂停pause(如此处的是上一个应用launcher),设置当前状态为pausing
2) 进入ActivityThread处理暂停任务之前会在eventlog中输出am_pause_activity的信息,表示将要开始该应用的暂停了
3) 不过最重要的函数还是ActivityThread的schedulePauseActivity,该函数会处理pause任务

    //userLeaving==true, uiSleeping==false, resuming==true, dontWait==false
    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
            boolean dontWait) {
        //第一次进来mPausingActivity是null,应用没有暂停就没有所谓的mPausingActivity
        if (mPausingActivity != null) {
            //...
        }

        //mResumedActivity是当前resume的activity,此处是launcher
        ActivityRecord prev = mResumedActivity;

        //注意此处pause之后将设置mResumedActivity==null,代表没有该Stack没有resume的activity了
        mResumedActivity = null;
        //launcher设置为正在pause的进程
        mPausingActivity = prev;
        //设置上一个暂停的应用
        mLastPausedActivity = prev;
        //标定该进程在PAUSING状态
        prev.state = ActivityState.PAUSING;

        //此处next是test2,章节4.2的insertTaskAtTop已经设置过
        final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();

        //pause应用会触发cpu状态更新,可以使用adb shell dumpsys cpuinfo查询
        mService.updateCpuStats();

        //prev是launcher,里面的app和thread都是已经创建的,所有此处会进入
        if (prev.app != null && prev.app.thread != null) {
            try {
                //event log中的am_pause_activity,代表应用的pause开始
                EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                        prev.userId, System.identityHashCode(prev),
                        prev.shortComponentName);
                //cpu前后台切换,用于耗电统计
                mService.updateUsageStats(prev, false);
                //ActivityThread里面的方法是handle(异步),此处才是activity的真正的pause执行的地方
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, dontWait);
            //...

        //mPausingActivity就是launcher,所以会进来此处。
        if (mPausingActivity != null) {
            //uiSleeping==false
            if (!uiSleeping) {
                //应用的pause的时候,会暂停接收输入事件,此时系统触摸了不反馈给上层
                prev.pauseKeyDispatchingLocked();
            }

            //dontWait==false,章节5.2中设置dontWaitForPause
            if (dontWait) {
                //只有当dontWait是true的时候才会走这里,就是不等待pause完成
                completePauseLocked(false);
                return false;
            } else {
                //launcher的最后onpause会走到这里来
                Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
                msg.obj = prev;
                prev.pauseTime = SystemClock.uptimeMillis();
                //设置pause的超时时间为500ms
                mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
                //返回ture,代表有响应的activity正在pausing,
                //故在章节5.2 resumeTopActivityInnerLocked运行完该函数后不久就返回了
                return true;
            }

        } else {
        //...
    }

ps:上面也看到了pause的时候会限制输入事件,如果应用一直重启又挂掉又重启,此时如果不停调用pause/finish的话会限制输入事件的分发pauseKeyDispatchingLocked,当然这种情况只是极端情况,一般不会出现

5.5 schedulePauseActivity(ActivityThread.java)

1) schedulePauseActivity这个是通过handler(一直想吐槽这个hander也类名也太简洁了的点吧,一个”H”就搞定)在UI主线程里面做的事情
2) 主要流程是schedulePauseActivity->PAUSE_ACTIVITY->handlePauseActivity->performPauseActivity->performPauseActivityIfNeeded
3) 我们主要关注performPauseActivityIfNeeded当前activity暂停(这部分本章节讲解)、activityPaused通知AMS上一个activity暂停完成(这部分下一章里讲解)。

    //ActivityThread给外部提供的接口,pause暂停是通过应用的主线程进行处理
    public final void schedulePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) {
        int seq = getLifecycleSeq();
        //...
        //finished等于false,走的是PAUSE_ACTIVITY,userLeaving==true,dontReport==dontWait==false
        sendMessage(
                finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                token,
                (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
                configChanges,
                seq);
    }

    //handler传递,调用的是handlePauseActivity
    case PAUSE_ACTIVITY: {
        //...
        //进入pause的处理
        handlePauseActivity((IBinder) args.arg1, false,
                (args.argi1 & USER_LEAVING) != 0, args.argi2,
                (args.argi1 & DONT_REPORT) != 0, args.argi3);
        //...
    } break;

    //finished是false,userLeaving==true,dontReport==false
    private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport, int seq) {
        ActivityClientRecord r = mActivities.get(token);
        ...
        if (r != null) {
            //userLeaving一般都是true
            if (userLeaving) {
                //会进入此处,会调用activity.performUserLeaving,当离开用户可视的时候会调用
                performUserLeavingActivity(r);
            }

            //...
            //此处是pause上一个应用launcher,isPreHoneycomb是android3.0之前用的,此处是false
            performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");

            //dontReport一般没有设置都是false,故一般都是进入此处的
            if (!dontReport) {
                try {
                    //通知AMS上一个应用完成pause了,这里接下去就会resume下一个应用(先启动进程),
                    //下一章会讲到
                    ActivityManagerNative.getDefault().activityPaused(token);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }
            mSomeActivitiesChanged = true;
        }
    }


    final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
            boolean saveState, String reason) {

        //saveState是false,不跑这里
        if (!r.activity.mFinished && saveState) {
            callCallActivityOnSaveInstanceState(r);
        }

        //这里才是pause activity的地方
        performPauseActivityIfNeeded(r, reason);

        // 将当前pause的应用的OnActivityPausedListener暂停监听去除
        ArrayList<OnActivityPausedListener> listeners;
        synchronized (mOnPauseListeners) {
            listeners = mOnPauseListeners.remove(r.activity);
        }
        //...
        for (int i = 0; i < size; i++) {
            //此处是调用注册了该activity thread的监听onPaused的回调,
            //如NfcAdapter.java中的ActivityThread.currentActivityThread()
            //.registerOnActivityPausedListener(activity,mForegroundDispatchListener);
            listeners.get(i).onPaused(r.activity);
        }
        //...
    }

5.6 performPauseActivityIfNeeded(ActivityThread.java)

1) 通过代理类Instrumentation调用callActivityOnPause,其调用的是activity的performPause(分别会调用mFragments.dispatchPause、activity的onPause,application的ActivityLifecycleCallback生命周期回调方法onActivityPaused)
2) OnPause调用完成后会在event log中写入am_on_paused_called,代表activity的OnPause已经完成(如果你使用onpause有问题,可以从am_pause_activity到am_on_paused_called之间所花费的时间做初步判断)
3) 注意OnPause完成之后paused会赋值为true,代表当前是暂停状态

    private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
        if (r.paused) {
            //如果之前paused==true了就直接返回,activitythread创建设置成false,
            //oncreate将设置成ture,onresume将设置成false
            //上一个activity的上一个状态是onresume,正在pause,故此处是paused==false
            return;
        }

        try {
            //这里解释一下mCalled,这个值是用来判断是否有调用activity生命周期的函数
            r.activity.mCalled = false;

            //这就就是具体调用activity的performPause的地方
            //(包括mFragments.dispatchPause、activity的onPause,
            //application的ActivityLifecycleCallback生命周期回调方法onActivityPaused),
            //运行完之后mCalled会设置成true
            mInstrumentation.callActivityOnPause(r.activity);

            //写event log,am_on_paused_called,说明pause已经调用
            EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
                    r.activity.getComponentName().getClassName(), reason);
            //...
        //运行了之后设置标致位paused==true
        r.paused = true;
    }

到目前为止基本上把上一个activity的OnPause流程讲解完了。

6. 进程启动(一)am_proc_start

讲了一大堆,是不是发现我们需要启动的进程test2怎么还没到呢,流程有点长,目前android的默认架构就是这样,大家耐心的继续看下去,我们这一章节就开始讲到进程启动(这部分应该很多文章都有提到,了解的同学可以不必细看)。

其实这些流程只是学习作用,对我们了解android架构有一定帮助,解决问题(仅针对那些代码不规范自己改出来的问题)时有帮助,不过这些都不是关注的重点,我们关注的是如何优化整个流程,如果没有明确这个目的,对我们来说是没有很大提升的。路漫漫其修远,我们先把流程梳理清楚,一步步来…

进程启动(一)
图6.1 进程启动(一)

6.1 activityPaused(ActivityManagerService.java)

在章节5.5中的ActivityManagerNative.getDefault().activityPaused(token),这个函数的意思是告诉AMS,上一个应用已经完成OnPause了,接下去的工作可以继续下去。

    public final void activityPaused(IBinder token) {
        //...
        //调用的是ActivityStack的activityPausedLocked,第二个参数timeout==false
        stack.activityPausedLocked(token, false);
        //...
    }

其中token是上一个应用的Ibinder对象,我们认为是launcher就行了

6.2 activityPausedLocked(ActivityStack.java)

1) 通知launcher自身Stack栈中的activityPausedLocked,当前已经完成pause暂停操作了,可以将之前章节5.4中说的PAUSE_TIMEOUT_MSG超时去掉。
2) mPausingActivity也是在章节5.4开始暂停的时候设置的,如果发现真正暂停的应用和完成暂停的应用是一个,代表暂停完成,调用completePauseLocked,并传递resumeNext==true,代表需要resume下一个应用

    //AMS调用的timeout==false
    final void activityPausedLocked(IBinder token, boolean timeout) {
        //代表该task仍在堆栈中,此时launcher是launcher的paused
        final ActivityRecord r = isInStackLocked(token);
        if (r != null) {
            //pause已经完成,不需要PAUSE_TIMEOUT_MSG了
            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            //之前在startPausingLocked的时候设置了当前pause的应用,
            //这个时候AMS返回代表pause成功,会进入这里
            if (mPausingActivity == r) {
                //pause成功,传递的参数是resumeNext==true,代表需要resume下一个应用
                completePauseLocked(true);
                return;
            } else {
            ...
    }

6.3 completePauseLocked(true)

1) mWaitingVisibleActivities这里代表的是需要隐藏的可视界面,到目前为止我们没有设置过,这个是在第二次进入章节5.2 resumeTopActivityInnerLocked的时候才会设置。(准备resume恢复下一个应用test2,上一个应用launcher就会放入等待隐藏的列表mWaitingVisibleActivities中)
2) 非睡眠或者关机状态的时候会进入下一个activity的resume操作resumeFocusedStackTopActivityLocked
3) 最后ensureActivitiesVisibleLocked(ActivityStackSupervisor.java/ActivityStack.java)会更新界面相关操作,属于WMS范畴,本文不过多涉及
{

    //启动进程后会更新界面,此处仅仅把流程列出来,由于这篇文章本身太长了,不想在额外增加内容
    ensureActivitiesVisibleLocked
        ->ensureActivityConfigurationLocked
        ->makeVisibleAndRestartIfNeeded->startSpecificActivityLocked()
        ->screenshotActivitiesLocked
        ->makeInvisible->addToStopping->scheduleIdleLocked

}

    private void completePauseLocked(boolean resumeNext) {
        //prev,mPausingActivity是launcher
        ActivityRecord prev = mPausingActivity;
        //prev是不等于null的会进来这里
        if (prev != null) {
            //state在startPausingLocked时设置了ActivityState.PAUSING,
            //所以一般情况wasStopping都是false
            final boolean wasStopping = prev.state == ActivityState.STOPPING;

            //重新设置标志位是ActivityState.PAUSED,这个是已经暂停的状态
            prev.state = ActivityState.PAUSED;

            //一般情况launcher启动应用,prev.finishing==false,故不会进入这里面
            if (prev.finishing) {
                //...
            //prev.app是launcher
            } else if (prev.app != null) {
                //pause com.android.launcher时,此处会进来,prev就是com.android.launcher,
                //wasStopping==false,visible==true

               //第一次进来时mWaitingVisibleActivities还没有prev(resumeTopActivityInnerLocked
               //第二次运行是才会设置),故不会进来这个
                if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
                    //...
                }

                //这个是在pause之后重新启动,一般都是false
                if (prev.deferRelaunchUntilPaused) {
                    //...
                //wasStopping==false,也不走这里
                } else if (wasStopping) {
                    //...
                //由于visible==true,也不是在睡眠状态,这里也不会进来
                } else if ((!prev.visible && !hasVisibleBehindActivity())
                        || mService.isSleepingOrShuttingDownLocked()) {
                    //...
                }
            } else {
                //这里实在app在onpause过程中died掉才会进入,正常不会运行
                prev = null;
            }

            if (prev != null) {
                //如果界面是冻屏的话,由于界面不再可见,将移除冻屏状态
                prev.stopFreezingScreenLocked(true /*force*/);
            }
            //mPausingActivity设置为null,此时pause已经全部完成
            mPausingActivity = null;
        }

        //上面都是AMS进来的activityPausedLocked,resumeNext == true
        if (resumeNext) {
            //之前的moveActivityStackToFront中有设置过focus stack为test2
            final ActivityStack topStack = mStackSupervisor.getFocusedStack();

            //非睡眠或者关机会进入这里
            if (!mService.isSleepingOrShuttingDownLocked()) {
                //一般进入这里,会resume 下一个应用(next),
                //同步的,执行了Process.start之后才会继续往下跑
                mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
            } else {
            ...
        }

        if (prev != null) {
            //重新恢复接收输入事件
            prev.resumeKeyDispatchingLocked();

            //如果是在使用电池
            if (prev.app != null && prev.cpuTimeAtResume > 0
                    && mService.mBatteryStatsService.isOnBattery()) {
                //cpuTimeAtResume是在activity resume的时候设置的,
                //代表从resume到pause的时间,将作为前台运行时间
                long diff = mService.mProcessCpuTracker.getCpuTimeForPid(prev.app.pid)
                        - prev.cpuTimeAtResume;
                //...
                //addForegroundTimeLocked这个是电量估算的时候用的,判断该activity前台运行的时常
                if (ps != null) {
                    ps.addForegroundTimeLocked(diff);
                //...
            }
            //当前已经是onpause暂停了,清空进入resume的时间
            prev.cpuTimeAtResume = 0;
        }

        //有界面可视的时候mAppVisibilitiesChangedSinceLastPause==true(setVisible时设置),
        //所以这里会进来
        if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause) {
            //...
            //launcher已经pause,设置mAppVisibilitiesChangedSinceLastPause==false
            mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
        }

        //最后是更新显示界面,这里是第一次调用ensureActivitiesVisibleLocked,
        //遍历所有stack的ensureActivitiesVisibleLocked
        mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    }

6.4 resumeFocusedStackTopActivityLocked/startSpecificActivityLocked(ActivityStackSupervisor.java)

resumeFocusedStackTopActivityLocked在章节5.1-5.2已经看过,此处传递的targetStack是test2,pre是launcher,resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java) -> resumeTopActivityUncheckedLocked(ActivityStack.java) -> resumeTopActivityInnerLocked -> startSpecificActivityLocked(ActivityStackSupervisor.java),启动的是next==test2

这里就不翻回去讲了,接下去讲startSpecificActivityLocked(ActivityStackSupervisor.java)这个启动应用的函数(注意此处是第一次进入,章节6.3提到的那一次是第二次进入,是在之后)

    //r==test2,andResume==true,checkConfig==true
    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        //...
        //当进程都未启动时不走这里,thread肯定是null,热启动相关逻辑本次不讨论
        if (app != null && app.thread != null) {
            ...
        }
        //AMS中去启动进程
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

6.5 startProcessLocked(ActivityManagerService.java)

重要看到startProcessLocked启动进程相关名字,这个是AMS的启动进程的api。
先关注第一次进入的逻辑:
1) 新建一个进程对象的实例new ProcessRecord,该对象可以代表一个进程
2) 判断应用是32位还是64位的,用于虚拟机参数配置
3) Process.start进程启动
4) event log写入am_proc_start,代表进程已经启动,这句话出来的时候应用进程已经创建

    //9个参数(r.processName==test2, r.info.applicationInfo, true, 0, 
    //"activity", r.intent.getComponent(), false, false, true)
    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        //注意此处entryPoint==null
        return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
                hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
                null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
                null /* crashHandler */);
    }

    //14个参数,新建ProcessRecord
    final ProcessRecord startProcessLocked(String processName, ...) {
        long startTime = SystemClock.elapsedRealtime();
        ProcessRecord app;
        //isolated(孤立应用)是false,knownToBeDead是true
        if (!isolated) {
            //第一次进来app肯定是null
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            //...

            //设置了后台运行,桌面启动应用一般都不会走这里
            if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
                ...
            } else {
                //重新计算崩溃次数(crash大于等于2次服务将不会再启动)
                mAppErrors.resetProcessCrashTimeLocked(info);
                //...
            }
        }

        //这个是用来设置启动进程时cpu的策略,可以加快app启动速度
        //默认没有用到,需要设置USE_SCHED_BOOST才会生效
        nativeMigrateToBoost();

        //3s钟后会关闭启动进程的cpu策略,同样此处默认没有用到
        mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);

        //第一次进入时没有启动过app/thread是null,pid是没有的.
        //第二次进来时此处app是有了,pid也生成了,但是thread还没有

        //第一次没启动不走这里,第二次会进来
        if (app != null && app.pid > 0) {
            //knownToBeDead是true,第二次进来app.thread还是null,故会进来,
            //第二次是从章节6.3中ensureActivitiesVisibleLocked调用过来的
            if ((!knownToBeDead && !app.killed) || app.thread == null) {
                //第二次进程已经创建了,直接返回
                //...
                return app;
            }
            //...
        }

        //...
        //第一次走这里,app是null
        if (app == null) {
            //这个是google的,用于调试卡顿的,不过除了特别有问题一般情况不会出现问题,
            //50ms去掉系统或许更快,如果是给用户的稳定版本可以考虑把这段调试代码删除
            checkTime(startTime, "startProcess: creating new process record");

            //此处是new ProcessRecord
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
            //...
            //新建ProcessRecord完成,该监控操作(newProcessRecordLocked)完成
            checkTime(startTime, "startProcess: done creating new process record");
        }

        //监控进程启动的时常是否超时
        checkTime(startTime, "startProcess: stepping in to startProcess");
        //这里才是真正的启动进程的地方
        startProcessLocked(
                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
        checkTime(startTime, "startProcess: done starting proc!");

        //如果有pid产生代表进程创建完成
        return (app.pid != 0) ? app : null;
    }

    //真正启动进程的地方
    private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        //...
        if (app.pid > 0 && app.pid != MY_PID) {//第一次启动app.pid == -1,不走这里
            ...
        }

        //...
        updateCpuStats();//启动进程也会更新CPU状态

        try {
            try {
                //用于检测是否可以启动,如:是否安装,是否正在冻屏等
                AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
            }

            //isolated初始值是false
            if (!app.isolated) {
                //...
                //返回应用用户组的gid,如果是uid不一样,同一个应用该值也会不一样
                permGids = pm.getPackageGids(app.info.packageName,
                        MATCH_DEBUG_TRIAGED_MISSING, app.userId);

                MountServiceInternal mountServiceInternal = LocalServices.getService(
                        MountServiceInternal.class);

                //获取应用读写外部存储的权限
                //如果是孤立应用(uid是99000-99999)将返回MOUNT_EXTERNAL_NONE;
                //能读返回MOUNT_EXTERNAL_READ,能写返回MOUNT_EXTERNAL_WRITE
                mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
                        app.info.packageName);
                //...
            }

            //...
            //android:multiArch="true"代表所有架构都支持,一般都不设置,
            //一般应用库文件需要判断是否32位还算64位,判断方法使用
            //com_android_internal_content_NativeLibraryHelper.cpp的findSupportedAbi
            //requiredAbi就是为了兼容32位&64位系统设计的
            String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
            if (requiredAbi == null) {
                //此处如果应用没有设置实在32位还是64位运行的化,
                //默认使用属性值ro.product.cpu.abilist的第一个值arm64-v8a(64bit),
                //armeabi-v7a(32bit),armeabi(32bit)
                requiredAbi = Build.SUPPORTED_ABIS[0];
            }

            String instructionSet = null;
            if (app.info.primaryCpuAbi != null) {
                //通过应用的库文件获取虚拟机要使用那种参数
                instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
            }


            //上面传递的entryPoint==null,isActivityProcess==true
            boolean isActivityProcess = (entryPoint == null);

            //将ActivityThread作为应用默认的入口函数entryPoint
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";

            //此处才是调用Process.start启动进程的地方
            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);//此处才是调用Process.start启动进程的地方

            //此处就是event log中am_proc_start
            EventLog.writeEvent(EventLogTags.AM_PROC_START,
                    UserHandle.getUserId(uid), startResult.pid, uid,
                    app.processName, hostingType,
                    hostingNameStr != null ? hostingNameStr : "");


            //设置进程的pid
            app.setPid(startResult.pid);

            //一般usingWrapper==false
            app.usingWrapper = startResult.usingWrapper;

            //代表正在运行
            app.removed = false;
            app.killed = false;

            //代表没有给AMS杀死
            app.killedByAm = false;

            synchronized (mPidsSelfLocked) {
                //process start之后就会有pid了,此处是test2.com.myapplication的pid会生成
                //会将该pid放入AMS的pid列表中
                this.mPidsSelfLocked.put(startResult.pid, app);

                if (isActivityProcess) {//isActivityProcess==true
                    //10s没有启动将不再启动,该app,Process.start虚拟机进程创建是同步的,
                    //但是attachApplicationLocked是异步的,在attachApplication的时候
                    //会remove这个超时PROC_START_TIMEOUT_MSG
                    mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                            ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
                ...
    }

7. 进程启动(二)Process.start

Process.start这个是新建进程通用的系统方法,代码位置:
frameworks/base/core/java/android/os/Process.java。
接下去从这个开始,这里面大家熟悉的内容可能更多。

进程启动(二)
图7.1 进程启动(二)

7.1 Process.start(Process.java)

我们注意传递的参数processClass是android.app.ActivityThread,niceName是processName,debugFlags一般都是等于0,mountExternal代表是否可读写外部存储,targetSdkVersion是这个应用的targetSdkVersion,seInfo是签名相关(默认是”default”),abi是这个应用要运行的cpu架构(32还是64位),instructionSet是指的是arm或者arm64,appDataDir一般指的是/data这个目录,zygoteArgs==null。

后面这些参数都会有用到,对于理解流程有很大的帮助。

    //processClass是android.app.ActivityThread,niceName是processName,
    //debugFlags一般都是等于0,mountExternal代表是否可读写外部存储,
    //targetSdkVersion是这个应用的targetSdkVersion,seInfo是签名相关(默认是”default”),
    //abi是这个应用要运行的cpu架构(32还是64位),instructionSet是指的是arm或者arm64,
    //appDataDir一般指的是/data这个目录,zygoteArgs==null
    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);
        //...
    }

7.2 startViaZygote-> zygoteSendArgsAndGetResult

1) startViaZygote通将参数全部转化成Zygote的数组String
2) openZygoteSocketIfNeeded/zygoteSocket.connect创建Socket链接,并获取输入输出流对象
3) zygoteSendArgsAndGetResult通过Socket与底层交互,传递相应的事件内容,并获取返回的结果

    private static ProcessStartResult startViaZygote(final String processClass,
        //...
        ArrayList<String> argsForZygote = new ArrayList<String>();
        //...添加虚拟机参数
        //最后添加的是ActivityThread应用的入口类
        argsForZygote.add(processClass);

        //extraArgs==null,所以后面没有参数了
        if (extraArgs != null) {
            for (String arg : extraArgs) {
                argsForZygote.add(arg);
            }
        }

        //注意openZygoteSocketIfNeeded是connect Socket,
        //zygoteSendArgsAndGetResult是向Socket传递参数
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    }

    private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                //ZYGOTE_SOCKET的名字是"zygote",连接socket
                primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
            //...
    }

    public static ZygoteState connect(String socketAddress) throws IOException {
        //...
        try {
            //这里是connect的地方,会通知相应的链接对象
            zygoteSocket.connect(new LocalSocketAddress(socketAddress,
                    LocalSocketAddress.Namespace.RESERVED));

            //输入流,是用来读东西的,例如设备有数据输出,然后我们读取
            zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());

            //输出流是用来写东西的,例如写东西然后输出到什么位置
            zygoteWriter = new BufferedWriter(new OutputStreamWriter(
                    zygoteSocket.getOutputStream()), 256);
        //...
    }

    private static ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            //...
           //第一个先写的是参数大小
            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                //传递设置参数
                writer.write(arg);
                writer.newLine();
            }

            //清空输出流,并写入,运行完成之后代表写入成功,此时Socket会接受到相应消息
            writer.flush();

            //...
            //读取返回的pid数据
            result.pid = inputStream.readInt();
            //读取返回的usingWrapper数据
            result.usingWrapper = inputStream.readBoolean();
            ...
    }

7.3 ZygoteInit.main(ZygoteInit.java)

1) 开机运行app_process进程(init.zygote*.rc->app_process)->app_main.main->ZygoteInit.main,Zygote受精卵进程是由init进程创建,如下通过ps可知:init进程是Zygote64受精卵进程的父进程,而system_server是通过zygote64受精卵进程创建的。(pid是该进程的id,ppid是其父进程的id)

USER      PID   PPID  VSIZE  RSS   WCHAN              PC  NAME
root      1     0     28524  1932  SyS_epoll_ 0000000000 S /init
root      428   1     1771768 22020 poll_sched 0000000000 S zygote64   //此处代表是64bit的
system    996   428   2086288 190084 SyS_epoll_ 0000000000 S system_server

2) 获取当前操作系统的32&64位架构abiList,这个在socket connect的时候用于
2) 注册zygote的LocalServerSocket对象(Socket的服务端,可以给别人connect)
3) 启动系统服务startSystemServer
4) 等待Socket消息的通知来执行相应的任务runSelectLoop
5) MethodAndArgsCaller的run方法

    //开机运行app_process进程(init.zygote*.rc->app_process)->app_main.main->ZygoteInit.main
    public static void main(String argv[]) {
        //...
        try {
            //Socket的名字是zygote
            String socketName = "zygote";
            String abiList = null; 
            for (int i = 1; i < argv.length; i++) {
                //第一次进来会设置startSystemServer==true
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    //读的是系统属性ro.product.cpu.abilist64或者ro.product.cpu.abilist32里面的值
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                //...

            //android的Socket名字:ANDROID_SOCKET_ + zygote
            registerZygoteSocket(socketName);

            //event log中会出现boot_progress_preload_start
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());

            //重新加载Cache,Classes,Resources,OpenGL,SharedLibraries,
            //TextResources,WebView,AndroidKeyStoreProvider
            preload();

            //event log中会出现boot_progress_preload_end
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            //...
            //做GC,清除一些软引用对象
            gcAndFinalize();
            //...

            //在初始化时unmount根目录"/storage"
            Zygote.nativeUnmountStorageOnInit();

            //允许zygote创建进程
            ZygoteHooks.stopZygoteNoThreadCreation();

            //如果需要启动系统服务则进入这里
            if (startSystemServer) {
                //启动系统服务system_server,先后调用fork顺序是init
                //->zygote64(64位系统)->system_server,如果是系统进程的话,
                //这里是永远不会返回的startSystemServer->handleSystemServerProcess
                //->RuntimeInit.zygoteInit->SystemServer.main/run->Looper.loop()
                //->(pollInner/epoll_wait)Looper.cpp,
                //这个除了Loop里面调用mQueue.quit是不会退出的
                startSystemServer(abiList, socketName); 
            }

            //会跑下来的是zygote进程,zygote进程会一直在此运行
            runSelectLoop(abiList);

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            //对于此处zygote frok的子进程会进入此处,抛出MethodAndArgsCaller异常,
            //会执行run方法,其实是反射调用ActivityThread.main,这个后面会讲到
            caller.run();
        //...
    }

ps: Zygote进程是用来fork各个子进程的,如system_server就是其创建的,其中zygote64是所有64位进程的父进程,zygote是所有32位进程的父进程。

7.4 runSelectLoop

runSelectLoop循环等待Socket的数据反馈,这里写的是Select的Loop,目前androidN使用的方法是Os.poll不再有1024个Socket的限制(androidL和之前的版本使用的是select方法),后续android版本升级的话可能使用epoll(目前上层的Looper、MessageQueue就是使用epoll)

1) 循环遍历等待Socket缓冲区有可读的数据
2) Socket.connect时会创建新的ZygoteConnection
3) ZygoteConnection执行runOnce
4) 创建子进程后,子进程退出循环,父进程继续等待下一个Socket数据

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        //...

        // sServerSocket是AMS Process.java中的ZYGOTE_SOCKET链接的对象, 用来创建进程
        //sServerSocket是LocalServerSocket,代表整个socket
        //fds是所有zygote Socket相关的文件描述符
        fds.add(sServerSocket.getFileDescriptor());

        //peers是ZygoteConnection对象,是zygote链接之后的对象
        peers.add(null);

        while (true) {
            //...
            //events代表等待的事件类型,POLLIN类型代表我们只关心缓冲区是否有数据可读
            pollFds[i].events = (short) POLLIN;

            //...
            try {
                //poll函数与select类似都是,可以监视多个描述符,-1代表永不超时,
                //轮询一遍之后等待,当设备驱动发生自身资源可读写后,会唤醒其等待队列上睡眠的进程
                Os.poll(pollFds, -1);
            }
            //...

            for (int i = pollFds.length - 1; i >= 0; --i) {
                //revents域是文件描述符的操作结果事件掩码,POLLIN代表有数据可读
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }

                //i==0是就是外部有创建socket的时候,如Socket.connect,
                //这个时候Os.poll中LocalServerSocket会有数据返回,
                //此时LocalServerSocket会accept并创建新的ZygoteConnection
                if (i == 0) {
                    //创建新的受精卵的Socket链接ZygoteConnection
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    //添加到ZygoteConnection数组peers
                    peers.add(newPeer);
                    //添加到zygote Socket相关的文件描述符数组中去
                    fds.add(newPeer.getFileDesciptor());

                //非第一次运行时,如果之前创建的Socket链接对象ZygoteConnection有数据可以读,
                //如OutputStream(zygoteWriter就是输出流)有写入,那么此处会有数据,
                //进入runOnce函数。
                } else {
                    //创建子进程会抛出MethodAndArgsCaller的异常,
                    //给ZygoteInit.main捕获,然后运行ActivityThread的main函数,
                    //子进程抛出异常后退出该循环,但是Zygote父进程还算会继续循环的
                    boolean done = peers.get(i).runOnce();

                    //创建子进程后,父进程也就是zygote进程才会进入这里
                    //...
                }
            }
        }
    }

runSelectLoop函数就是在监听Socket端是否有数据可以读,如果有数据来了,那么就是创建进程,这个Zygote进程主要作用就是创建进程(子进程的一些基本信息都不用再初始化,因为Zygote已经初始过了,相当于优化了启动进程的流程)。

7.5 runOnce(ZygoteConnection.java)

1) 读取相应的参数列表
2) 创建子进程forkAndSpecialize(Zygote.forkAndSpecialize -> com_android_internal_os_Zygote_nativeForkAndSpecialize/ForkAndSpecializeCommon/fork(com_android_internal_os_Zygote.cpp)),通过jni调用com_android_internal_os_Zygote_nativeForkAndSpecialize,最后调用的是fork函数,该函数用于创建进程,具体在这里不展开,具体可以参考之前的一篇文章Android上层如何调用一个底层函数的章节2.1.3 com_android_internal_os_Zygote.cpp本地函数里面有关于fork的讲解。最终子进程返回的是pid==0,父进程返回的是子进程的pid。
3) 处理父进程的内容handleParentProc,如返回给AMS章节6.5中startProcessLocked的Process.start,其值是Process.ProcessStartResult startResult,包含子进程pid
4) 处理子进程的内容handleChildProc,这个放在下一节讲解

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        ...
        try {
            //读取相应的参数列表
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        }
        //...
        //invokeWith==null,目前没有设置
        if (parsedArgs.invokeWith != null) {
            //...
        }

        //...
        int [] fdsToClose = { -1, -1 };
        FileDescriptor fd = mSocket.getFileDescriptor();
        if (fd != null) {
            //客户端的文件描述符
            fdsToClose[0] = fd.getInt$();
        }
        fd = ZygoteInit.getServerSocketFileDescriptor();
        if (fd != null) {
            //服务端的文件描述符
            fdsToClose[1] = fd.getInt$();
        }

        //调用native fork进程的地方
        //此处是fock进程(Zygote.forkAndSpecialize
        //->com_android_internal_os_Zygote_nativeForkAndSpecialize
        //->ForkAndSpecializeCommon/fork(com_android_internal_os_Zygote.cpp))
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
        //...
        try {
            //如果是子进程pid会等于0,父进程此处pid会返回子进程的pid
            if (pid == 0) {
                //...
                //处理子进程逻辑
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

                //子进程是永远不会到这个位置来的,因为之前已经抛出MethodAndArgsCaller异常
                return true;
            } else {
                //...
                //处理父进程逻辑
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        ...
    }

    private String[] readArgumentList()
            throws IOException {
        //...
        try {
            //读取第一个参数
            String s = mSocketReader.readLine();
            //第一个参数上面章节7.2 Process.java中zygoteSendArgsAndGetResult写的就是参数个数
            argc = Integer.parseInt(s);
        }
        //传递的参数最多是1024个,超过的话系统可能受到DOS攻击
        if (argc > MAX_ZYGOTE_ARGC) {
            throw new IOException("max arg count exceeded");
        }
        for (int i = 0; i < argc; i++) {
            //读出每一个参数返回result数组中去
            result[i] = mSocketReader.readLine();
            ...
    }

    private boolean handleParentProc(int pid,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
        if (pid > 0) {
            //如果返回的pid大于0,说明子进程创建成功,此时设置子进程的pid
            setChildPgid(pid);
        }

        //...
        try {
            //传递pid回去,最后写入章节7.2中zygoteSendArgsAndGetResult的result.pid
            mSocketOutStream.writeInt(pid);
            //传递是否wrapped进程,此处一般都是false
            mSocketOutStream.writeBoolean(usingWrapper);
        }
        //...
        return false;
    }

8. 绑定进程am_proc_bound

上一章节我们知道了Process.start用于创建进程,父进程会直接返回子进程的pid,那么接下去我们需要从子进程处理的内容开始分析,看看子进程是怎样关联到上层的application中去的,这里讲解第一步am_proc_bound

这里写图片描述
图8.1 绑定进程

8.1 handleChildProc(ZygoteConnection.java)

1) 关闭相应的子进程Socket链接
2) 设置进程的名字,这个时候通过ps就可以看到进程名字变成应用声明的进程(如果没有定义android:process那么默认该进程名字就是应用的包名)
3) RuntimeInit.zygoteInit子进程的初始化

    private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {
        //关闭自己的Socket
        closeSocket();
        //关闭ZygoteInit中服务端的Socket
        ZygoteInit.closeServerSocket();
        //...
        if (parsedArgs.niceName != null) {
            //自己设置自己的名字,此处设置进程名字为之前传进来的processName
            Process.setArgV0(parsedArgs.niceName);
        }

        //这里是不运行的
        if (parsedArgs.invokeWith != null) {
            //...
        //此处会进来
        } else {
            //运行初始化RuntimeInit中的进程(受精卵)初始化zygoteInit
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }

ps:Process.setArgV0会通过prctl(PR_SET_NAME…),裁剪后(process_name.c),只保留processName后面15个字符(kernel实际还会裁剪到最后一个字符,其实是14个字符),设置进程名字(内核标识进程的名字是task_struc->comm).
进程的名字在某些地方显示不是无限长的,如在systrace显示的进程名字就不超过15个字符。

8.2 zygoteInit(RuntimeInit.java)

1) log重定向redirectLogStreams
2) 通用设置初始化commonInit
3) 初始化zygote:nativeZygoteInit
4) 应用初始化applicationInit

    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        //重新定向log的输入地方,此处设置log输出到Android log中
        redirectLogStreams();

        //一些通用设置的初始化
        commonInit();

        //初始化zygote,这里AppRuntime继承的是AndroidRuntime,运行的是启动线程池startThreadPool
        nativeZygoteInit();

        //应用初始化,此处是接下来运行的地方
        applicationInit(targetSdkVersion, argv, classLoader);
    }

    private static final void commonInit() {
        //...
        //设置默认的异常捕获
        Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
        TimezoneGetter.setInstance(new TimezoneGetter() {
            @Override
            public String getId() {
                //设置时区id
                return SystemProperties.get("persist.sys.timezone");
            }
        });
        //设置时区
        TimeZone.setDefault(null);
        LogManager.getLogManager().reset();
        //Android log相关初始化
        new AndroidConfig();
        String userAgent = getDefaultUserAgent();
        //网络用户代理初始化
        System.setProperty("http.agent", userAgent);
        //网络Socket相关
        NetworkManagementSocketTagger.install();
        //...
        initialized = true;
    }

8.3 applicationInit

1) 设置虚拟机GC回收比例,正在使用的对象/堆栈大小 = 0.75
2) 设置虚拟机sdk的版本号
3) 获取相应的参数,如args.startClass就是在章节7.2 startViaZygote设置的processClass(ActivityThread)
4) 通过反射查找ActivityThread的main函数,并将其作为MethodAndArgsCaller异常的参数

    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        //设置退出时不调用onExit()函数
        nativeSetExitWithoutCleanup(true);

        //设置GC回收后的比例,正在使用的对象/堆栈大小 = 0.75,对应于dalvik.vm.heaptargetutilization
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        //设置sdk的版本号,这个是进程启动Process.start时就传递过来的
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

        //获取相应的参数,如args.startClass就是第一个非"--"开头的参数
        final Arguments args;
        try {
            args = new Arguments(argv);
        }

        //...
        //反射调用main函数,注意startClass是Process.start时传递进来的android.app.ActivityThread
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        //...
        //查找android.app.ActivityThread类
        cl = Class.forName(className, true, classLoader);

        //...
        //查找其中的main函数
        m = cl.getMethod("main", new Class[] { String[].class });

        //...
        //获取函数的调用属性
        int modifiers = m.getModifiers();

        //必须是静态而且是public的方法,否则抛出RuntimeException异常
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }

        //抛出MethodAndArgsCaller异常
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }

在章节7.3 ZygoteInit.main方法里面有捕获MethodAndArgsCaller异常,并调用MethodAndArgsCaller的run方法。

8.4 MethodAndArgsCaller.run()

反射调用ActivityThread的main静态函数

   public static class MethodAndArgsCaller extends Exception
            implements Runnable {
        //...
        public MethodAndArgsCaller(Method method, String[] args) {
            //mMethod是ActivityThread的main方法
            mMethod = method;
            //mArgs一般都是null
            mArgs = args;
        }
        public void run() {
            try {
                //调用方法method,传递的是args参数,传递第一个参数是类对象为null,代表静态函数
                mMethod.invoke(null, new Object[] { mArgs });
            //...

到这里进程已经启动完成,将进入应用相关流程

8.5 MethodAndArgsCaller.run()

1) 消息队列初始化Looper.prepareMainLooper
2) 新建ActivityThread并附着thread.attach
3) 进入消息队列的循环Looper.loop

    public static void main(String[] args) {
        //默认是没有用到SamplingProfilerIntegration的,
        //该类用于监听性能数据,包含进程名字、应用信息、线程启动与关闭,
        //还有默认persist.sys.profiler_ms毫秒dump一次该进程堆栈信息
        SamplingProfilerIntegration.start();

        //在严格模式或者调试的时候打开,默认不打卡
        CloseGuard.setEnabled(false);

        //初始化环境(这里主要是存储设备的环境,用user id初始化)
        Environment.initForCurrentUser();

        //主要是libcore中使用event log的方法,Reporter的report类似于EventLog.writeEvent
        EventLogger.setReporter(new EventLoggingReporter());

        //配置文件目录在/data/misc/user/1000
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());

        //设置认证相关的目录cacerts-added,cacerts-removed
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        //设置进程名字为<pre-initialized>,这个很快在handleBindApplication时就会给修改
        Process.setArgV0("<pre-initialized>");

        //消息队列初始化,主进程是不允许退出的,无法调用MessageQueue.quit退出
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        //新建一个ActivityThread并attach附着,这个跟接下去的attachApplication相关
        thread.attach(false);

        if (sMainThreadHandler == null) {
            //获取thread的handler,将其作为应用的主线程
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            //用户调试log,用于消息队列Message的事件分发log输出,
            //调试消息队列的时候可以打开
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        //Looper.loop()里面是个for (;;)死循环,只要Message不为null,会一直运行
        //Looper.loop() -> MessageQueue.next() 
        //-> nativePollOnce(android_os_MessageQueue.cpp) 
        //->(pollOnce/pollInner/epoll_wait) Looper.cpp,
        //这个Message==null情况只有调用MessageQueue.quit才会发生,
        //目前没有看到主动调用MessageQueue.quit,故这个消息队列循环是不会退出的
        Looper.loop();

        //如果进入到这里代表程序出错了,这里程序正常运行是不会进来的
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

在调用静态方法ActivityThread.main之后会新建一个ActivityThread对象,相当于该进程的主线程(UI线程),创建之后首先跑的就是ActivityThread的attach函数

8.6 attach

这里我们主要关注attachApplication,也就是AMS的应用附着即可

    private void attach(boolean system) {
        //...
        //是否system,应用启动肯定不是system,会进入此处
        if (!system) {
            //...

            //设置ddms中的进程名字为"<pre-initialized>",临时的
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId());

            //设置ApplicationObject为ActivityThread
            RuntimeInit.setApplicationObject(mAppThread.asBinder());

            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                //此处就是attachApplication
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }

            //Java允许在类中定义一个名为finalize()的方法。
            //它的工作原理是:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法。
            //并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存
            //BinderInternal里面实现的是Object finalize,
            //当资源释放的时候会调用finalize,然后会调用
            BinderInternal.addGcWatcher(new Runnable() {
                //ActivityThread对象没有再使用时会进行回收
                @Override public void run() {
                    if (!mSomeActivitiesChanged) {
                        return;
                    }
                    Runtime runtime = Runtime.getRuntime();

                    //这个是HeapGrowthLimit,正常应用虚拟机内存最大值dalvik.vm.heapgrowthlimit, 
                    //AndroidRuntime.cpp/runtime.cc/heap.cc
                    long dalvikMax = runtime.maxMemory();
                    long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();

                    //当前使用内存,如果最大内存的3/4将进行activity的释放操作
                    if (dalvikUsed > ((3*dalvikMax)/4)) {
                        //...
                        mSomeActivitiesChanged = false;
                        try {
                            //此处释放指的是activity的ondestroy,
                            //目前可以destroy的activity是处于onstop状态的activity
                            mgr.releaseSomeActivities(mAppThread);
                        //...
        //让DropBox在libcore可用
        DropBox.setReporter(new DropBoxReporter());

    }

8.7 attachApplication/attachApplicationLocked

1) 首先是ActivityManagerNative.java的attachApplication会传递ActivityThread和调用者的pid给到AMS的attachApplicationLocked
2) eventlog中设置服务绑定进程am_proc_bound,说明进程启动完成,而且该进程的主线程ActivityThread已经创建,并且通知到AMS中
3) ActivityThread的绑定应用bindApplication, 这个会在下面章节讲解
4) 由于我们这个例子是桌面启动应用,那么最后mStackSupervisor.attachApplicationLocked堆栈中的绑定应用会真正启动activity活动对象,这个会在下面章节讲解

    //ActivityManagerNative.java
    public final void attachApplication(IApplicationThread thread) {
        ...
            attachApplicationLocked(thread, callingPid);
        ...

    //ActivityManagerService.java
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        //...
        ProcessRecord app;
        //调用者非系统进程,且调用者的pid大于0
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                //在进程启动Process.start后就将pid添加进入mPidsSelfLocked了(父进程调用)
                //现在是子进程调用,这个时候已经添加
                app = mPidsSelfLocked.get(pid);
            //...

        //app.thread还没有设置过,下面makeActive将进行设置,会将app.thread设置成
        //IApplicationThread(在ActivityThread中),app.thread不为null了
        if (app.thread != null) {
            //...
        }

        //...
        try {
            AppDeathRecipient adr = new AppDeathRecipient(
                    app, pid, thread);
            //设置binder died掉之后的的回调地方是binderDied
            thread.asBinder().linkToDeath(adr, 0);
            //设置目前谁在监控死亡状态
            app.deathRecipient = adr;

        //...
        //eventlog中设置服务绑定am_proc_bound
        EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);

        //设置ProcessRecord的IApplicationThread(在ActivityThread中)
        app.makeActive(thread, mProcessStats);

        //默认设置一个adj
        app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
        //...

        //用户更新电量估算mBatteryStatsService的FOREGROUND时间
        updateProcessForegroundLocked(app, false, false);
        //...
        //判断是否解锁
        app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);

        //去除进程启动超时的msg PROC_START_TIMEOUT_MSG,
        //此处有ActivityThread回传,代表进程启动完成
        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

        //一般情况normalMode都是true
        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);

        //generateApplicationProvidersLocked是开始创建应用的ContentProvider对象
        List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
        //...
        //一般不会进入这里,这里是自动化测试的时候会进来
        if (app.instrumentationClass != null) {
            //...
        }
        //...

        //应用兼容性相关,该参数会传入AcitiviyThread中
        app.compat = compatibilityInfoForPackageLocked(appInfo);

        //一般profilerInfo==null
        ProfilerInfo profilerInfo = profileFile == null ? null
                : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);

        //回到AcitiviyThread中的bindApplication,processName==test2,
        //instrument相关都等于null,mBinderTransactionTrackingEnabled/
        //enableTrackAllocation/isRestrictedBackupMode默认等于false,
        //normalMode默认是true,persistent代表是否常驻内存,compat是兼容性相关,
        //isolated==false,getCommonServicesLocked是将PMS、WMS、ALARM相关服务传入,
        //mCoreSettingsObserver用于监听一些参数变化(长按超时,12/24小时显示时间变化,
        //调试界面属性),bindApplication是异步的
        thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode,
                mBinderTransactionTrackingEnabled, enableTrackAllocation,
                isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(mConfiguration), app.compat,
                getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked());

        //将进程添加进入mLruProcesses中
        //mLruProcesses保存的是正在运行应用的列表,第一个是最近使用的
        updateLruProcessLocked(app, false, null);

        //触发GC的时间重新计算
        app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();

        //...
        //一般normalMode都是true
        if (normalMode) {
            try {
                //如果是activity导致的进程启动,activity从这里开始启动
                //此处用于am_restart_activity,此处设置了didSomething = true
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            //...

        //一般badApp==false
        if (!badApp) {
            try {
                //如果之前该进程有需要启动的服务,此处开始启动服务
                //启动进程了之后才会去启动服务
                didSomething |= mServices.attachApplicationLocked(app, processName);
        //...
        if (!badApp && isPendingBroadcastProcessLocked(pid)) {
            try {
                //如果该进程之前有挂起的广播,现在可以开始发送了
                didSomething |= sendPendingBroadcastsLocked(app);
           // ...

到目前为止绑定进程的逻辑已经讲解完了,接下去我们仅需要关注thread.bindApplication和mStackSupervisor.attachApplicationLocked这2个函数

9 创建application

这一章节将会讲到application的实例化、application进程上下文context的创建、application的OnCreate

创建application
图9.1 创建application

9.1 bindApplication(ActivityThread.java)

我们关注的重点:
1) getPackageInfoNoCheck新建new LoadedApk,该类用于加载apk
2) makeApplication新建一个Application对象new newApplication(这里面会createAppContext创建application的进程上下文context)
3) callApplicationOnCreate调用Application的OnCreate

    private void handleBindApplication(AppBindData data) {
        //设置art实时编译更加敏感,更新art配置相关信息的计数count会乘10=((10000/500)/2),
        //会让art更容易更新配置(如做实时编译还是解释执行等)
        VMRuntime.registerSensitiveThread();

        //...
        //设置process的启动时间,这个主要是给上层调用的
        Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());

        //AMS传递进来的参数全部放在data上
        mBoundApplication = data;

        //进程启动时如果你没有设置固定方向或者手动改变方向,这个config就是AMS中的mConfiguration
        mConfiguration = new Configuration(data.config);
        mCompatConfiguration = new Configuration(data.config);

        mProfiler = new Profiler();
        //一般情况initProfilerInfo都是null,除了使用instrumentation(如自动化测试相关会使用到)
        if (data.initProfilerInfo != null) {
            ...
        }

        //此处会通过prctl(PR_SET_NAME...),裁剪后(process_name.c)
        //只保留processName后面15个字符(kernel实际还会裁剪到最后一个字符,其实是14个字符),
        //设置进程名字(内核标识进程的名字是task_struc->comm).
        Process.setArgV0(data.processName);

        //此处设置的是ddms调试使用的名字
        android.ddm.DdmHandleAppName.setAppName(data.processName,
                                                UserHandle.myUserId());

        //常驻内存的进程
        if (data.persistent) {
            //如果在不能使用GPU加速(如低内存设备
            //或者显示定义config_avoidGfxAccel为ture的情况都会进来)
            if (!ActivityManager.isHighEndGfx()) {
                //当前进程停止使用硬件渲染,这里的作用主要是为了减少运存RAM的消耗,
                //对于低内存手机,这个是有帮助的
                ThreadedRenderer.disable(false);
            }
        }

        //...
        //回复系统默认时区
        TimeZone.setDefault(null);
        //设置默认的语言
        LocaleList.setDefault(data.config.getLocales());

        //...
        //新建new LoadedApk,该类用于加载apk
        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);

        //...
        //可以通过config对分辨率进行设置,默认是没有设置的
        updateDefaultDensity();

        //设置是否24小时
        final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
        DateFormat.set24HourTimePref(is24Hr);

        //...
        //网络代理相关设置
        final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
        if (b != null) {
            final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
            try {
                final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
                Proxy.setHttpProxySystemProperty(proxyInfo);

        //...
        //新建一个appContext
        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);

        //...
        //应用一般是isIsolated == false,这里讲的不是系统进程,是普通app的进程的启动,故会进入此处
        if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) {
            //获取应用缓存目录,如("/data/user_de/0/com.android.settings/cache")
            final File cacheDir = appContext.getCacheDir();

            //...
            //获取应用代码缓存目录,"/data/user_de/0/com.android.settings/code_cache"
            //此处主要是存放的opengl和renderscript部分的缓存代码
            //类似于com.android.opengl.shaders_cache、com.android.renderscript.cache这样的数据
            final File codeCacheDir = deviceContext.getCodeCacheDir();
        }

        //...
        //ii非自动化测试一般都是null
        if (ii != null) {
            ...
        } else {
            //一般情况下走的是这里
            mInstrumentation = new Instrumentation();
        }

        //设置虚拟机堆栈最大能增长到的内存是多少,根据largeHeap属性判断是否大应用
        if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
            //如果是大应用的话,应用虚拟机内存可以增长到堆栈大小dalvik.vm.heapsize
            dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
        } else {
            //默认只能增长到dalvik.vm.heapgrowthlimit受限制的堆栈大小
            dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
        }

        // allowThreadDiskWrites在应用oncreate的时候允许写的操作,
        //返回的值是就得策略,此处仅用于临时修改
        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
        try {
            //restrictedBackupMode是flase,data.info是上面new的LoadedApk,
            //这里面的createAppContext和上面的createAppContext传递的参数是一样的
            //此处会新建一个Application对象new newApplication,此处是Application的实例化
            //此处传递的第二个参数instrumentation==null,故application不会在此处OnCreate
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);

            //保存当前的Application对象
            mInitialApplication = app;

            //一般没有限制备份模式,restrictedBackupMode == false
            if (!data.restrictedBackupMode) {
                //如果apk有provider就会进入这里(如静态注册的providers)
                if (!ArrayUtils.isEmpty(data.providers)) {
                    //初始化app中的所有provider
                    installContentProviders(app, data.providers);
                    //...
                }
            }
            try {
                //如果没有复写Instrumentation,一般此处没有做任何事情
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            //...
            try {
                //此处调用的就是Application的OnCreate方法,
                //activity的OnCreate后面会讲到,这里先调用的是Application的OnCreate
                mInstrumentation.callApplicationOnCreate(app);
            //...
    }

9.2 getPackageInfoNoCheck/getPackageInfo

getPackageInfoNoCheck/getPackageInfo返回的是LoadedApk,用于加载apk

    public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
            CompatibilityInfo compatInfo) {
        return getPackageInfo(ai, compatInfo, null, false, true, false);
    }

    //(ai, compatInfo, null, false, true, false);
    private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
            ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
            boolean registerPackage) {
        //...

        //此处apk是包含代码的,故是从mPackages取,第一次进来此处是null
        ref = mPackages.get(aInfo.packageName);
        LoadedApk packageInfo = ref != null ? ref.get() : null;

        //新建LoadedApk加载apk的类
        packageInfo =
            new LoadedApk(this, aInfo, compatInfo, baseLoader,
                    securityViolation, includeCode &&
                    (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);

        //...
        //将新建的LoadedApk放到mPackages中
        mPackages.put(aInfo.packageName,
                new WeakReference<LoadedApk>(packageInfo));
        //...
        return packageInfo;
    }

9.3 makeApplication(LoadedApk.java)

1) 创建Application的进程上下文
2) 调用代理Instrumentation新建Application
3) Application实例化、Application设置进程上下文context

    //LoadedApk.java
    //forceDefaultAppClass==false,instrumentation==null
    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        //...
        Application app = null;

        //如果应用没有重载Application类的话,直接使用默认的"android.app.Application"
        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            java.lang.ClassLoader cl = getClassLoader();
            //...
            //创建Application的进程上下文
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //调用代理Instrumentation新建Application
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        }
        //...
        return app;
    }

    //Instrumentation.java
    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }
    static public Application newApplication(Class<?> clazz, Context context)
            ... {
        //Application类的实例化,如类非静态变量等会在此处生成
        Application app = (Application)clazz.newInstance();
        //调用Application的attach附着,用于设置进程上下文context
        app.attach(context);
        return app;
    }

    //Application.java
    final void attach(Context context) {
        //设置base应用基本的进程上下文
        attachBaseContext(context);
        //设置类的加载器
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

现在有了Application这个对象,下面接着会进行Application的OnCreate

9.4 callApplicationOnCreate(Instrumentation.java)

callApplicationOnCreate这个函数通过代理调用Application的OnCreate

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

    //Application.java
    public void onCreate() {
    }

进程启动会先调用Application的OnCreate,这个也是算在应用启动生命周期内的。

目前Application创建了,Application的OnCreate也调用了,接下去就是Activity相关的逻辑。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值