Android源码探究:Activity启动流程完全解析

概述

本文主要内容是从源码角度进行Activity启动流程的分析。由于整个启动的过程非常长并且代码非常多,同时受限于笔者的水平,所以本文不会细致到解释每一行的代码的具体作用,只能抽取处关键部分的代码就主体流程进行分析,如有错误之处,希望批评指出。

行文脉络

由于本文会非常长,为了方便读者的理解,首先给出笔者的行文脉络。本文主要沿着:在应用程序1的Activity A内打开另一个应用程序2的Activity B,这一思路进行写作。流程概括如下:
①Activity A发起一个启动Activity B的请求(对应主流程分析1~2)
②AMS为启动Activity B做准备 (对应主流程分析3~4)
③暂停Activity A(对应主流程分析5~7)
④应用程序1通知AMS完成了暂停操作,AMS处理该消息(对应主流程分析8)
⑤AMS启动一个新的进程,即应用程序2(对应主流程分析9~11)
⑥在新进程内完成Activity B的创建、启动操作(对应主流程分析12~13)

时序图

下面先给出与代码分析相一致的时序图,通过该时序图能更好地理解Activity的启动流程,读者可以结合该时序图与下面的代码分析一起看。
时序图

主流程分析

1、Activity#startActivityForResult()方法:
无论从Launcher或者Activity打开一个新的Activity,都会调用startActivity()方法,而这些重载方法最终都会调用startActivityForResult方法,代码如下:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
        @Nullable Bundle options) {
    if (mParent == null) {
        options = transferSpringboardActivityOptions(options);

        //把启动一个Activity的行为交给Instrumentation处理
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        if (requestCode >= 0) {
            mStartedActivity = true;
        }

    } //省略部分代码..
}

2、Instrumentation#execStartActivity()方法:
在该方法内,主要是通过ActivityManagerService来启动一个Activity,而该ActivityManagerService是运行在一个独立的进程空间的,它负责整个Android系统内的所有Activity的创建过程。因此,当前APP进程需要与ActivityManagerService进程进行跨进程通信,这就需要借助Binder机制了。

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    //省略部分代码,只看关键部分..
    //IApplicationThread有点特殊,它是IBinder对象,用于跨进程通信
    IApplicationThread whoThread = (IApplicationThread) contextThread;

    //ActivityMonitor主要配合InstrumentationTest一起使用,用于统计
    //相匹配的Activity启动次数,与APP测试有关,这里省略不谈
    if (mActivityMonitors != null) {
        //....
    }

    try {
        //获取ActivityManagerService代理对象,调用startActivity()方法,
        //这里实际上通过Binder跨进程调用了ActivityManagerService的方法
        int result = ActivityManager.getService()  //2-1代码
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

2-1、我们看看ActivityManager#getService()代码做了什么工作:

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                //如果进程不同,则获取一个IActivityManager代理对象
                final IActivityManager am = IActivityManager.Stub.asInterface(b);   
                return am;
            }
        };

显然,这是一个典型的AIDL使用过程。IActivityManager实际上是一个AIDL文件,编译器会帮我们把AIDL文件解析成一个Java文件,也即是IActivityManager.java,通过AIDL的方式我们能方便地实现Binder通信。而Binder通信的内部调用过程,这里不展开来说,我们只关注大体的逻辑即可。上面的IActivityManager.Stub是在编译器生成的一个内部类,而它的asInterface()方法则是根据当前进程是否与IBinder处于同一进程,如果是,则直接返回IActivityManager的实例,否则会返回一个IActivityManager.Stub.Proxy的代理对象。由于我们的App与AMS肯定不是同一进程,所以这里获得的是AMS的远程代理。(可以参考设计模式中的代理模式)

回到代码2-1往下看,在获取了IActivityManager的实例后(实际上是代理对象),会调用它的startActivity(params..)方法,在这个过程中,进行了基于Binder跨进程通信,把一系列的params参数传递给AMS,此时AMS的startActivity(params…)被调用了,我们往下看它的代码。


3、ActivityManagerService#startActivity()
需要注意的是,AMS的代码在/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 目录下,这是frameworks层的源码,在sdk下是看不到的,所以我们需要下载Android的源码或者在网上查看。(笔者这里通过Android Frameworks源码来查看的,有兴趣的可以自行前往查看)。

当代码运行到这里的时候,我们可以知道以下两个信息:
①从架构的层面来看,已经从应用层来到了frameworks层。
②从进程的层面来看,当前进程已经是AMS所在的进程。

好了,我们继续来分析源码AMS的startActivity()方法的源码:

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}


public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
        boolean validateIncomingUser) {
    enforceNotIsolatedCaller("startActivity");

    userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
            Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

    return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
                                                //ActivityStarter内部有一个Request,封装了请求的具体信息
            .setCaller(caller)                  //设置Caller为IApplicationThread对象,这个实际上是代理对象
            .setCallingPackage(callingPackage)  //设置包名
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setMayWait(userId)
            .execute();

}

可以看到,方法的参数已经包含了一系列启动Activity所需要的参数,而在最后又调用了ActivityStartController的方法来获取一个ActivityStarter,并把所有的参数封装到了ActivityStarter.Request内,最后调用ActivityStarter#execute()方法来启动一个Activity的创建过程。

3-1、ActivityStartController#obtainStarter()
我们直接从源码的注释来看看ActivityStartController有什么作用:

/**
 * Controller for delegating activity launches.
 *
 * This class' main objective is to take external activity start requests and prepare them into
 * a series of discrete activity launches that can be handled by an {@link ActivityStarter}. It is
 * also responsible for handling logic that happens around an activity launch, but doesn't
 * necessarily influence the activity start. Examples include power hint management, processing
 * through the pending activity list, and recording home activity launches.
 */
public class ActivityStartController {
     //...

    /**
     * @return A starter to configure and execute starting an activity. It is valid until after
     * {@link ActivityStarter#execute} is invoked. At that point, the starter should be
     * considered invalid and no longer modified or used.
     */
    ActivityStarter obtainStarter(Intent intent, String reason) {
        return mFactory.obtain().setIntent(intent).setReason(reason);
    }
}

从源码注释可以知道,它一个是委派Activity启动的控制器,它管理着一系列的Activity的启动行为,并且承担着Activity启动过程的电量提示管理、Home的启动记录等的工作。但它实际上并不涉及Activity启动的具体逻辑,它把启动的逻辑交给了ActivityStarter来处理了。

3-2、ActivityStarter代码分析

/**
 * Controller for interpreting how and then launching an activity.
 *
 * This class collects all the logic for determining how an intent and flags should be turned into
 * an activity and associated task and stack.
 */
class ActivityStarter {

    //ActivityStartController通过该Factory来获取一个Starter
    static class DefaultFactory implements Factory {

        //对象池内只有3个活跃对象,也即是ActivityStarter被设计成可循环利用的
        private final int MAX_STARTER_COUNT = 3;        

        private SynchronizedPool<ActivityStarter> mStarterPool =
                new SynchronizedPool<>(MAX_STARTER_COUNT);

        //省略部分代码...

        @Override
        public ActivityStarter obtain() {
            ActivityStarter starter = mStarterPool.acquire();

            if (starter == null) {
                starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
            }

            return starter;
        }

        @Override
        public void recycle(ActivityStarter starter) {
            starter.reset(true /* clearRequest*/);
            mStarterPool.release(starter);
        }
    }

    //Request类封装了启动Activity所需要的一切参数
    private static class Request {
        //省略...
    }

    /**
     * Starts an activity based on the request parameters provided earlier.
     * @return The starter result.
     */
    int execute() {
        try {
            if (mRequest.mayWait) {
                return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                        mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
                        mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                        mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
                        mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
                        mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
                        mRequest.inTask, mRequest.reason,
                        mRequest.allowPendingRemoteAnimationRegistryLookup);
            }else { 
                //... 
            }
        } finally {
            onExecutionComplete();      //最后,会调用ActivityStartController的对应方法,进行Starter的释放回收
        }
    }

    //省略...
}

ActivityStarter是具体的Activity启动器,它的内部类Request封装了启动Activity的一系列信息,而ActivityStarter被设计成了一个对象池的形式,是可以复用的,因为Android系统可能会频繁地启动Activity,所以启动器设计出复用的形式可以减少开销。当execute()被调用的时候,该启动器便开始执行启动一个Activity的具体流程,即调用startActivityMayWait(params)方法。

我们顺着代码继续往下看,即ActivityStarter#startActivityMayWait()

    private int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult,
            Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
            int userId, TaskRecord inTask, String reason,
            boolean allowPendingRemoteAnimationRegistryLookup) {
        
        //由于代码很长,这里做了很多删减,只关注主体部分..

        // Collect information about the target of the Intent.
        //这里里面调用了PackageManagerService的方法来解析Intent.
        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,0 /* matchFlags */,
            computeResolveFilterUid(callingUid, realCallingUid, mRequest.filterCallingUid));
        //接着将Intent的信息解析为ActivityInfo
        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);

        synchronized (mService) {
            final ActivityStack stack = mSupervisor.mFocusedStack;
            stack.mConfigWillChange = globalConfig != null
                    && mService.getGlobalConfiguration().diff(globalConfig) != 0;

            final long origId = Binder.clearCallingIdentity(); //设置callingPid和callingUid为当前进程标识

            final ActivityRecord[] outRecord = new ActivityRecord[1];
            //进一步调用startActivity(params..)方法,24个参数的重载方法
            int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
                    ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
                    allowPendingRemoteAnimationRegistryLookup);

            Binder.restoreCallingIdentity(origId);     //设置callingPid和callingUid为跨进程调用该方法的进程标识 


            if (outResult != null) {
                outResult.result = res;

                final ActivityRecord r = outRecord[0];

                //根据res来判断Activity的启动状态来做进一步处理
                switch(res) {
                    //Activity正常启动
                    case START_SUCCESS: {
                        mSupervisor.mWaitingActivityLaunched.add(outResult);
                        do {
                            try {
                                mService.wait();
                            } catch (InterruptedException e) {
                            }
                        } while (outResult.result != START_TASK_TO_FRONT
                                && !outResult.timeout && outResult.who == null);
                        if (outResult.result == START_TASK_TO_FRONT) {
                            res = START_TASK_TO_FRONT;
                        }
                        break;
                    }
                    //Activity并不是真正的启动,因为该Intent对应的Activity已在栈顶
                    case START_DELIVERED_TO_TOP: {
                        //省略..

                        break;
                    }
                    //Activity并不是真正的启动,而是把已有的Activity带到了前台
                    case START_TASK_TO_FRONT: {
                        //省略...

                        break;
                    }
                }
            }
            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
            return res;
        }
    }


    /**
     * 经过一系列startActivity()重载方法的调用,最后会调用该方法
     */
    private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
                ActivityRecord[] outActivity) {
        int result = START_CANCELED;
        try {
            mService.mWindowManager.deferSurfaceLayout();   //通知WindowManager暂停布局

            //进一步调用startActivityUnchecked(params..)方法
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        } finally {
            //如果Activity没有启动成功,那么关闭它,否则可能会出现问题
            final ActivityStack stack = mStartActivity.getStack();
            if (!ActivityManager.isStartResultSuccessful(result) && stack != null) {
                stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,
                        null /* intentResultData */, "startActivity", true /* oomAdj */);
            }
            mService.mWindowManager.continueSurfaceLayout();    //通知WindowManager继续布局
        }
        //Activity启动后还有一些工作要处理
        postStartActivityProcessing(r, result, mTargetStack);

        return result;
    }

    /**
     * 该方法处理了Intent的各种flags以及Activity的启动模式
     */
    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
        //初始化信息
        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                voiceInteractor);
        //计算LaunchingTaskFlags,对flag进行合法性处理
        computeLaunchingTaskFlags();
        //如果Task已经结束了,要做出处理,然后获得一个新的Task
        computeSourceStack();

        mIntent.setFlags(mLaunchFlags);

        ActivityRecord reusedActivity = getReusableIntentActivity();    //获取当前Task的Activity

        //...

        //如果Task内已有Activity,结合即将启动Activity的launch mode做出处理
        if (reusedActivity != null) {
            //省略具体处理过程暂不作分析,这里与Activity的启动模式有关
            //..
        }

        //如果Activity的包名不存在,则启动失败
        if (mStartActivity.packageName == null) {
            //省略..

            return START_CLASS_NOT_FOUND;
        }

        //如果即将启动的Activity与栈顶的Activity相同,那么判断是否需要继续启动
        final ActivityStack topStack = mSupervisor.mFocusedStack;
        final ActivityRecord topFocused = topStack.getTopActivity();
        final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
        final boolean dontStart = top != null && mStartActivity.resultTo == null
                && top.realActivity.equals(mStartActivity.realActivity)
                && top.userId == mStartActivity.userId
                && top.app != null && top.app.thread != null
                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
        if (dontStart) {
            //省略...

            return START_DELIVERED_TO_TOP;  //这里的返回值表示栈顶就是需要启动的Activity
        }

        //...

        //权限认证
        mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
                mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
        mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
                mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));
        
        //...

        //代码3-3,见下面分析
        mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
                mOptions);

        //mDoResume为true,从函数参数传递进来的
        if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
                mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                //告诉WindowManager该Activity要做转场动作了
                mService.mWindowManager.executeAppTransition();
            } else {
                
                //代码4-1:第一次启动时,会在这里进行Activity的启动
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        } else if (mStartActivity != null) {
            mSupervisor.mRecentTasks.add(mStartActivity.getTask());
        }

        return START_SUCCESS;
    }

从函数调用栈来看:startActivityMayWait(params..) -> startActivity(params.. ) -> startActivityUnchecked(params..)其中省略了若干个重载方法,这是已经是很深层次的调用栈了,代码也难以理解,因此我们很难对每行代码进行详细的分析也没有这个必要,我们要善于利用奥卡姆剃刀,抽出主干部分进行分析即可,我们的关注点在理解Activity的启动过程及其有关的类的作用,而在此过程有关的Activity launchMode和Flag等可以不做分析。

上面的代码揭示了,一个Activity如果要启动,要结合任务栈Task和Activity的启动模式来进行综合的处理,比如新建一个栈又或者栈内复用等模式的处理。我们来关注上面标注出来的代码3-3,看看它内部做了什么工作。

3-3、ActivityStack#startActivityLocked(params…)

void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
        boolean newTask, boolean keepCurTransition, ActivityOptions options) {
    TaskRecord rTask = r.getTask();
    final int taskId = rTask.taskId;

    //这里把Activity添加到Stack的顶部
    if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
            // Last activity in task had been removed or ActivityManagerService is reusing task.
            // Insert or replace.
            // Might not even be in.
            insertTaskAtTop(rTask, r);
        }

    TaskRecord task = null;
    if (!newTask) {
        //如果该Task是已存在的,那么要找到这个Task
        //下面的标志位用来表示找到的Task是否是前台Task
        boolean startIt = true;
        //mTaskHistory最后的元素就是最前面的Task
        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
            task = mTaskHistory.get(taskNdx);
            if (task.getTopActivity() == null) {
                // All activities in task are finishing.
                continue;
            }
            if (task == rTask) {
                //要创建的Activity所在的Task不在前台
                if (!startIt) {
                    if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
                             + task, new RuntimeException("here").fillInStackTrace());
                    r.createWindowContainer();
                    ActivityOptions.abort(options);
                    return;
                }
                break;
            } else if (task.numFullscreen > 0) {
                startIt = false;
            }
        }
    }
    final TaskRecord activityTask = r.getTask();
    task = activityTask;

    if (!isHomeOrRecentsStack() || numActivities() > 0) {
        
        //如果Activity被设置为没有进场动画效果
        if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
            mWindowManager.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
            mStackSupervisor.mNoAnimActivities.add(r);
        } else {
            //Activity有动画效果
            int transit = TRANSIT_ACTIVITY_OPEN;
            
            //省略...

            //通知WindowManager来准备转场效果
            mWindowManager.prepareAppTransition(transit, keepCurTransition);
            mStackSupervisor.mNoAnimActivities.remove(r);
        }
        
        //如果Activity启动时,它的Task不在前台,确保该Activity是可见的
        if (r.mLaunchTaskBehind) {
            r.setVisibility(true);
            ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
        }

    } 
}

从上面代码的逻辑可以看出,主要是涉及了窗口的处理,即WindowManager,比如该Activity有没有进场动画的标志位等。因为启动一个Activity时,是WindowManager和ActivityManager协同工作的,所以这里主要逻辑是通过通知窗口管理者来进行Window Container的创建。当然,具体逻辑还是很复杂的,这里就不再深究了,让我们回到上一个方法,开始阅读4-1的代码。


4-1、ActivityStackSupervisor#resumeFocusedStackTopActivityLocked(params…)
创建一个Activity,并不只是创建一个可视化的视图而已,它背后任务栈的这一重要的操作,因此打开一个Activity的流程很复杂,其函数的调用栈很深,目前我们来到了ActivityStackSupervisor的地盘,我们来看看这个方法:

boolean resumeFocusedStackTopActivityLocked(
        ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {

    //省略..

    //如果当前Stack位于前台
    if (targetStack != null && isFocusedStack(targetStack)) {
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }

    //若Stack不在前台
    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
    if (r == null || !r.isState(RESUMED)) {
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
    } else if (r.isState(RESUMED)) {
        // Kick off any lingering app transitions form the MoveTaskToFront operation.
        mFocusedStack.executeAppTransition(targetOptions);
    }


    return false;
}

逻辑还是很简单,ActivityStackSupervisor又把打开Activity的任务交给了一个具体的ActivityStack,因为在之前的代码中我们把一个即将启动的Activity放到了这个Stack里面,现在我们就要对它进行启动工作,我们继续往下来看它的代码。

4-2、ActivityStack#resumeTopActivityUncheckedLocked(params…)

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
    //如果当前正在重新启动一个Activity,那么跳过
    if (mStackSupervisor.inResumeTopActivity) {
        return false;
    }

    boolean result = false;
    try {
        mStackSupervisor.inResumeTopActivity = true;
        result = resumeTopActivityInnerLocked(prev, options);

        //...
        }
    } finally {
        mStackSupervisor.inResumeTopActivity = false;
    }

    return result;
}

进一步调用了resumeTopActivityInnerLocked(params..),我们来继续看这个方法。

4-3、ActivityStack#resumeTopActivityInnerLocked(params…)

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    //下面省略了大量代码,仅保留主要逻辑

    //从当前栈顶取出正在启动的Activity
    final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);

    //...

    // mResumedActivity是当前正在运行的Activity,即处于Resumed状态的,
    //而next是我们放到了栈顶正在启动的Activity,注意二者的区别。
    //如果二者相等,那么不做任何改变
    if (mResumedActivity == next && next.isState(RESUMED)
            && mStackSupervisor.allResumedActivitiesComplete()) {
        //...
        return false;
    }

    //如果屏幕关闭了,没有Activity需要启动,并且栈顶的Activity已经暂停,不做改变
    if (shouldSleepOrShutDownActivities()
            && mLastPausedActivity == next
            && mStackSupervisor.allPausedActivitiesComplete()) {
        //...
        return false;
    }

    //...

    //确保该Activity的状态是正确的,从等待停止队列移除等
    mStackSupervisor.mStoppingActivities.remove(next);
    mStackSupervisor.mGoingToSleepActivities.remove(next);
    next.sleeping = false;
    mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(next);

    //当前有Activity正在执行pause操作,return
    if (!mStackSupervisor.allPausedActivitiesComplete()) {
        //...
        return false;
    }

    //暂停后备堆栈中的所有Activity
    boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
    if (mResumedActivity != null) {
        //代码5-1、暂停当前处于Resumed状态的Activity
        pausing |= startPausingLocked(userLeaving, false, next, false);
    }
        
    //与WindowManager交互,确定Activity的启动动画
    boolean anim = true;
    if (prev != null) {
        if (prev.finishing) {
            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                    "Prepare close transition: prev=" + prev);
            if (mStackSupervisor.mNoAnimActivities.contains(prev)) {
                anim = false;
                mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
            } else {
                mWindowManager.prepareAppTransition(prev.getTask() == next.getTask()
                        ? TRANSIT_ACTIVITY_CLOSE
                        : TRANSIT_TASK_CLOSE, false);
            }
            prev.setVisibility(false);
        }
    } else {
        //...
    }
    mStackSupervisor.mNoAnimActivities.clear();

    ActivityStack lastStack = mStackSupervisor.getLastStack();
    if (next.app != null && next.app.thread != null) {
        //...

    } else {
        //代码8-4
        //该方法实际上是真正启动一个Activity的地方,但这里的调用不会生效
        //因为,该方法的内部会进行一次判断:是否有Activity处于未暂停的状态
        //上面我们跨进程进行了Activity的暂停,在Activity未全部暂停之前,该方法都不会真正被调用。
        //这里的调用应该是适用于这种情况:别的Activity全部处于暂停状态,能直接启动新的Activity了
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }
    return true;
}

从上面代码的逻辑来看,主要是先执行5-1的代码,暂停当前处于Resumed状态的Activity,然后在最后真正地去启动当前栈顶就绪的Activity。下面,我们就先来查看怎么处理暂停Activity的逻辑,接着再看怎么处理启动Activity的逻辑。


5-1、ActivityStack#startPausingLocked(params…)

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
        ActivityRecord resuming, boolean pauseImmediately) {
    //省略部分代码...
    ActivityRecord prev = mResumedActivity;

    if (prev == null) {
        if (resuming == null) {
            Slog.wtf(TAG, "Trying to pause when nothing is resumed");
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
        }
        return false;
    }

    if (prev == resuming) {
        Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed");
        return false;
    }

    if (prev.app != null && prev.app.thread != null) {
        try {
            //代码5-2、调用LifecycleManager#scheduleTransaction方法...
            mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken,
                    PauseActivityItem.obtain(prev.finishing, userLeaving,
                            prev.configChangeFlags, pauseImmediately));
        } 
    } 

}

通过mService#getLifecycleManager()获得了LifecycleManager,这里的mService就是AMS,而LifecycleManager实际上是类ClientLifecycleManager,它的代码位于/frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java

5-2、ClientLifecycleManager#scheduleTransaction(params…)

/**
 * Schedule a single lifecycle request or callback to client activity.
 * @param client Target client.
 * @param activityToken Target activity token.
 * @param stateRequest A request to move target activity to a desired lifecycle state.
 * @throws RemoteException
 *
 * @see ClientTransactionItem
 */
void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken,
        @NonNull ActivityLifecycleItem stateRequest) throws RemoteException {
    final ClientTransaction clientTransaction = transactionWithState(client, activityToken,
            stateRequest);
    scheduleTransaction(clientTransaction);
}

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule();
    if (!(client instanceof Binder)) {
        // If client is not an instance of Binder - it's a remote call and at this point it is
        // safe to recycle the object. All objects used for local calls will be recycled after
        // the transaction is executed on client in ActivityThread.
        transaction.recycle();
    }
}

上面的逻辑很清晰,先获得了一个ClientTransaction对象,然后再调用它的schedule()方法,最后进行了ClientTransaction对象的回收。ClientTransaction封装了一系列的请求信息,即我们的暂停Activity的所有信息都封装到了它的内部,同时它实现了Parcelable接口,表示可序列化的,这说明它肯定是用于跨进程传输的对象,我们往下看代码。

5-3、ClientTransaction#schedule()
代码文件在/frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java

    /**
     * Schedule the transaction after it was initialized. It will be send to client and all its
     * individual parts will be applied in the following sequence:
     * 1. The client calls {@link #preExecute(ClientTransactionHandler)}, which triggers all work
     *    that needs to be done before actually scheduling the transaction for callbacks and
     *    lifecycle state request.
     * 2. The transaction message is scheduled.
     * 3. The client calls {@link TransactionExecutor#execute(ClientTransaction)}, which executes
     *    all callbacks and necessary lifecycle transitions.
     */
    public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this);
    }

从方法的注释我们可以知道:
①一次请求会先调用ClientTransaction#preExecute(ClientTransactionHandler)
②然后执行这个请求
③接着调用TransactionExecutor#execute(ClientTransaction)

方法里面进行了mClient#scheduleTransaction这一调用,这里的mClient其实就是IApplicationThread,它实际上是一个代理对象,继承了IBinder,表示我们的APP,主要用于跨进程通信。这里实际上是一次跨进程调用,此时,从AMS所在的进程切换到了我们的应用进程。


6-1、IApplicationThread#scheduleTransaction(transaction)
IApplicationThread是ActivityThread的一个内部类,我们从那里寻找它的方法scheduleTransaction(transaction)

public final class ActivityThread extends ClientTransactionHandler {
    //...

    private class ApplicationThread extends IApplicationThread.Stub {
        @Override
        public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
            ActivityThread.this.scheduleTransaction(transaction);
        }

        //...
    }
}

可以看到,在该方法的内部进一步调用了ActivityThread#scheduleTransaction()方法,实际上这里交给了ActivityThread的父类ClientTransactionHandler来处理了。需要注意的是:这里传递过来的ClientTransaction是跨进程通信过程中反序列化生成的对象。

6-2、ClientTransactionHandler#scheduleTransaction(transaction)

public abstract class ClientTransactionHandler {

    // Schedule phase related logic and handlers.

    /** Prepare and schedule transaction for execution. */
    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);  //代码6-3
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);  //代码6-4
    }
    //...
}

6-3、ClientTransaction#preExecute(ClientTransactionHandler)
前面5-3有提到过会先调用preExecute方法,这里得到了印证。我们来看ClientTransactionpreExecute方法。

    public void preExecute(android.app.ClientTransactionHandler clientTransactionHandler) {
        if (mActivityCallbacks != null) {
            final int size = mActivityCallbacks.size();
            for (int i = 0; i < size; ++i) {
                mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken);
            }
        }
        if (mLifecycleStateRequest != null) {
            mLifecycleStateRequest.preExecute(clientTransactionHandler, mActivityToken);
        }
    }

这里主要是进行各种回调的调用,就不继续展开说了。

6-4、ActivityThread#sendMessage(params…)
继续执行代码6-4,这里调用了sendMessage方法,在ClientTransactionHandler中该方法被标注为抽象方法,具体实现是在ActivityThread内。实际上,ActivityThread内部的H继承了Handler,用于处理各种消息。**这也就是主线程的消息循环。**我们直接来看H的代码:

public final class ActivityThread extends ClientTransactionHandler {
    //...

    class H extends Handler {

        //一系列消息常量的定义..
        public static final int EXECUTE_TRANSACTION = 159;

        public void handleMessage(Message msg) {
            //根据不同的消息类型进行不同的处理
            switch (msg.what) {
                case EXECUTE_TRANSACTION:
                    final ClientTransaction transaction = (ClientTransaction) msg.obj;
                    mTransactionExecutor.execute(transaction);
                    if (isSystem()) {
                        // Client transactions inside system process are recycled on the client side
                        // instead of ClientLifecycleManager to avoid being cleared before this
                        // message is handled.
                        transaction.recycle();
                    }
                    break;
            }
        }

    }
}

这里把处理的逻辑交由给TransactionExecutor来完成,然后进行ClientTransaction的回收。


7-1、TransactionExecutor#execute(ClientTransaction)
TransactionExecutor可以理解为一个执行器,专门用于执行各种ClientTransaction

    /**
     * Resolve transaction.
     * First all callbacks will be executed in the order they appear in the list. If a callback
     * requires a certain pre- or post-execution state, the client will be transitioned accordingly.
     * Then the client will cycle to the final lifecycle state if provided. Otherwise, it will
     * either remain in the initial state, or last state needed by a callback.
     */
    public void execute(ClientTransaction transaction) {
        final IBinder token = transaction.getActivityToken();
        log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);

        executeCallbacks(transaction);

        executeLifecycleState(transaction);
        mPendingActions.clear();
        log("End resolving transaction");
    }

方法内部首先执行executeCallbacks(transaction),由于对于Pause状态来说,并没有添加任何callback,所以我们先省略该方法,接着来看executeLifecycleState(transaction)

7-2、TransactionExecutor#executeLifecycleState(transaction)

/** Transition to the final state if requested by the transaction. */
private void executeLifecycleState(ClientTransaction transaction) {
    //根据之前的代码逻辑,这里的lifecycleItem实际上是PauseLifecycleItem.
    final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest(); 
    
    final IBinder token = transaction.getActivityToken();
    final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);

    //把ActivityClientRecord的状态切换到target状态,这里是pause,表示把Activity切换到暂停状态
    cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */);

    // Execute the final transition with proper parameters.
    lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
    lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}

private void cycleToPath(ActivityClientRecord r, int finish,
        boolean excludeLastState) {
    final int start = r.getLifecycleState();
    //计算从start->finish的状态变化路径
    //比如:onCreate->onResume的变化路径有:onStart、onResume等(不包括初始状态)
    //该方法很简单,读者可以自行去看
    final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);
    performLifecycleSequence(r, path);  //把该Activity的状态沿着这个路径进行切换
}

/** 该方法把Activity的状态沿着路径进行切换 */
private void performLifecycleSequence(ActivityClientRecord r, IntArray path) {
    final int size = path.size();
    for (int i = 0, state; i < size; i++) {
        state = path.get(i);
        switch (state) {
            case ON_CREATE:
                mTransactionHandler.handleLaunchActivity(r, mPendingActions,
                        null /* customIntent */);
                break;
            case ON_START:
                mTransactionHandler.handleStartActivity(r, mPendingActions);
                break;
            case ON_RESUME:
                mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */,
                        r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
                break;
            case ON_PAUSE:
                mTransactionHandler.handlePauseActivity(r.token, false /* finished */,
                        false /* userLeaving */, 0 /* configChanges */, mPendingActions,
                        "LIFECYCLER_PAUSE_ACTIVITY");
                break;
            case ON_STOP:
                mTransactionHandler.handleStopActivity(r.token, false /* show */,
                        0 /* configChanges */, mPendingActions, false /* finalStateRequest */,
                        "LIFECYCLER_STOP_ACTIVITY");
                break;
            case ON_DESTROY:
                mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */,
                        0 /* configChanges */, false /* getNonConfigInstance */,
                        "performLifecycleSequence. cycling to:" + path.get(size - 1));
                break;
            case ON_RESTART:
                mTransactionHandler.performRestartActivity(r.token, false /* start */);
                break;
            default:
                throw new IllegalArgumentException("Unexpected lifecycle state: " + state);
        }
    }
}

上面的代码逻辑还是很清晰的,主要是先计算出Activity由当前状态切换到目标状态所需要走的路径,然后遍历这个路径上的每一个状态,把Activity依次切换到该状态,当遍历到最后一个状态时,Activity便完成了状态的切换。上面代码的最后,又把具体逻辑交给了mTransactionHandler来处理,实际上这里的mTransactionHandler就是ActivityThread,它继承了TransactionHandler。因此我们到ActivityThread里面找相应的方法。

7-3、ActivityThread#handlePauseActivity(params…)
因为我们的目标状态是Pause,所以会调用到handlePauseActivity()方法。

@Override
public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
        int configChanges, PendingTransactionActions pendingActions, String reason) {
    ActivityClientRecord r = mActivities.get(token);
    if (r != null) {
        if (userLeaving) {
            performUserLeavingActivity(r);
        }

        r.activity.mConfigChangeFlags |= configChanges;
        performPauseActivity(r, finished, reason, pendingActions);

        // Make sure any pending writes are now committed.
        if (r.isPreHoneycomb()) {
            QueuedWork.waitToFinish();
        }
        mSomeActivitiesChanged = true;
    }
}

/**
 * Pause the activity.
 * @return Saved instance state for pre-Honeycomb apps if it was saved, {@code null} otherwise.
 */
private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason,
        PendingTransactionActions pendingActions) {
    //Honeycomb版本之前的APP在暂停的时候会保存状态
    final boolean shouldSaveState = !r.activity.mFinished && r.isPreHoneycomb();
    if (shouldSaveState) {
        callActivityOnSaveInstanceState(r);
    }

    performPauseActivityIfNeeded(r, reason);

    // Notify any outstanding on paused listeners
    ArrayList<OnActivityPausedListener> listeners;
    synchronized (mOnPauseListeners) {
        listeners = mOnPauseListeners.remove(r.activity);
    }
    int size = (listeners != null ? listeners.size() : 0);
    for (int i = 0; i < size; i++) {
        listeners.get(i).onPaused(r.activity);
    }

    //省略...

    return shouldSaveState ? r.state : null;
}

private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
    if (r.paused) {
        // You are already paused silly...
        return;
    }

    try {
        r.activity.mCalled = false;
        mInstrumentation.callActivityOnPause(r.activity);
        
    } catch (Exception e) {
        //省略..
    }
    r.setState(ON_PAUSE);
}

经过层层的调用,我们最后发现调用到了mInstrumentation.callActivityOnPause(r.activity),这个Instrumentation在上面的代码解析中也有碰到过,我们话不多说直接来看它的实现:

/**
 * Perform calling of an activity's {@link Activity#onPause} method.  The
 * default implementation simply calls through to that method.
 * 
 * @param activity The activity being paused.
 */
public void callActivityOnPause(Activity activity) {
    activity.performPause();
}

到这里已经很明朗了,已经调用到了Activity#performPause方法,即:

final void performPause() {
    mDoReportFullyDrawn = false;
    mFragments.dispatchPause(); //把暂停事件分发给Fragment,以触发它们暂停
    mCalled = false;
    onPause();          //调用onPause,这是我们业务逻辑层经常接触的一个生命周期方法
    writeEventLog(LOG_AM_ON_PAUSE_CALLED, "performPause");
    mResumed = false;

    //...
}

到现在,已经触发了onPause()这个生命周期方法,整个暂停的流程就已经完成了。那么当一个Activity暂停了,下一步就是执行新Activity的创建流程了。

那么在client端怎么通知server端要执行启动Activity的操作呢?
让我们把目光定位到代码7-2的executeLifecycleState(transaction)方法内部,在方法的最后,会依次执行executepostExecute方法,而这里的lifecycleItem实际上就是PauseActivityItem

7-4、PauseActivityItem#postExecute()

@Override
public void postExecute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
    if (mDontReport) {
        return;
    }
    try {
        //通知AMS,Activity已经暂停完毕,是时候启动Activity了
        ActivityManager.getService().activityPaused(token);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
}

这里直接通过Binder跨进程通信,告诉AMS该Activity已经暂停了,AMS可以开始启动原本打算启动的Activity了。到这一步,APP内的工作暂时完成了,此时进程又会切换到AMS进程内。在开始下一步代码的阅读之前,我们需要小结一下代码6~7客户端所做的所有工作。

**小结:**APP一直都在进行着主线程的消息循环,等待新的消息的到来。此时,AMS通过Binder跨进程调用了ApplicationThread的某个方法(如上面的scheduleTransaction),该方法运行在客户端的一条子线程上,然后该方法通过Handler机制,切换到了主线程。此时在主线程执行handleMessage方法,进而调用到具体的某一方法。其中,涉及到Activity生命周期的信息、操作被封装到了ClientTransaction内部,而具体的每一个生命周期则由ActivityLifecycleItem的子类来表述。在一个操作完成之后(比如上面的pause操作),可能会通知AMS进行下一步操作。然后客户端继续进行主线程的消息循环,等待AMS的下一次通知。


8-1、ActivityManagerService#activityPaused(token)
经过客户端的跨进程调用,AMS的activityPaused(token)被调用了。

    @Override
    public final void activityPaused(IBinder token) {
        final long origId = Binder.clearCallingIdentity();
        synchronized(this) {
            ActivityStack stack = ActivityRecord.getStackLocked(token);
            if (stack != null) {
                stack.activityPausedLocked(token, false);
            }
        }
        Binder.restoreCallingIdentity(origId);
    }

根据token来获取Activity所在的ActivityStack,进一步调用activityPausedLocked(params..)

8-2、ActivityStack#activityPausedLocked(params…)

final void activityPausedLocked(IBinder token, boolean timeout) {
    //先从ActivityStack根据token取出对应的ActivityRecord
    final ActivityRecord r = isInStackLocked(token);
    if (r != null) {
        mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
        //如果二者相等,表示记录的需要暂停的Activity已经暂停完毕
        if (mPausingActivity == r) {
            mService.mWindowManager.deferSurfaceLayout();
            try {
                completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
            } finally {
                mService.mWindowManager.continueSurfaceLayout();
            }
            return;
        } else {
            //省略...
        }
    }
    mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}

这里没什么好说的,我们继续看completePauseLocked(params..)

8-3、ActivityStack#completePauseLocked(params…)

private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
    ActivityRecord prev = mPausingActivity;

    //省略大部分的代码...

    if (resumeNext) {
        final ActivityStack topStack = mStackSupervisor.getFocusedStack();
        if (!topStack.shouldSleepOrShutDownActivities()) {
            mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
        } else {
            //...
        }
    }

}

当代码执行到这里的时候,读者应该对这个方法resumeFocusedStackTopActivityLocked(params..)有点眼熟吧?上面已经执行过该方法了,接下来的调用链都是一样的了,最终会执行到ActivityStackSupervisor#startSpecificActivityLocked(params..)这个方法,进行Activity的真正启动过程。

8-4、ActivityStackSupervisor#startSpecificActivityLocked(params…)

void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    //获取Activity所对应的进程记录
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);

    getLaunchTimeTracker().setLaunchTime(r);

    //如果该进程已经启动了,那么直接开始启动Activity
    if (app != null && app.thread != null) {
        try {
            //若该Activity的flag不包含多进程标志位 或 不是安卓框架的组件
            if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                    || !"android".equals(r.info.packageName)) {
                // Don't add this if it is a platform component that is marked
                // to run in multiple processes, because this is actually
                // part of the framework so doesn't make sense to track as a
                // separate apk in the process.
                // 如果它是一个标记为多进程运行的平台组件,则不要添加该项,
                // 因为这实际上是安卓框架的一部分,因此在进程中作为单独的apk进行跟踪是没有意义的。
                app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
                        mService.mProcessStats);
            }
            //真正地启动一个Activity
            realStartActivityLocked(r, app, andResume, checkConfig);    
            return;
        } catch (RemoteException e) {
            //...
        }

        // If a dead object exception was thrown -- fall through to
        // restart the application.
    }

    //代码9-1:否则,先启动一个新的进程,然后再启动Activity
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

代码的逻辑很清晰明了,主要是先判断Activity所对应的进程是否已经存在,如果存在了那就直接去执行真正的启动Activity过程;如果该进程还不存在,那么就要去启动一个进程。接下来的分析有两条路可以走,一是沿着Activity启动进行分析;二是沿着进程的启动进行分析。实际上进程的启动完毕之后也还是要进行Activity的启动的。也就是说调用了mService.startProcessLocked(params)后,会启动新的进程,然后ActivityStackSupervisor再次调用realStartActivityLocked(params..)在进程内启动Activity。
其实,这个调用顺序符合这一种情况:在进程A的ActivityA内启动了进程B的ActivityB,此时先暂停进程A的ActivityA,然后进程B还没有启动,那么先启动进程B,然后再启动ActivityB。
因此,接下来我们先来看怎样启动一个新的进程。


9-1、ActivityManagerService#startProcessLocked(params…)

final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        String hostingType, ComponentName hostingName, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
    return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
            hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
            null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
            null /* crashHandler */);
}

private final boolean startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
        //省略大部分代码...

        final String entryPoint = "android.app.ActivityThread";
        return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                startTime);
    } 
}
//一系列startProcessLocked(params..)重载方法的调用
//最终会调用下面的startProcess(params..)方法

private ProcessStartResult startProcess(String hostingType, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
        long startTime) {
    try {
        final ProcessStartResult startResult;
        if (hostingType.equals("webview_service")) {
            startResult = startWebView(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, null,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        } else {
            startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, invokeWith,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        }
        return startResult;
    } 
}

中间省略了大部分的重载方法的调用,最后来到了Process.start(params..),把一系列进程有关的信息都传递了进去,根据这些信息来创建一个进程。

9-2、Process#start(params…)
这个类的源码在Android SDK内可以找到,我们直接看它的代码:

public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int runtimeFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String invokeWith,
                              String[] zygoteArgs) {
    return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

这里我们需要关注一个参数processClass,当一个进程被启动后,以processClass为类名的类的main(args)函数会被调用。而这里的processClass是代码9-1中传递进来的“android.app.ActivityThread”。那么也就是说,一个新的进程启动后,它的ActivityThread的main()函数会最先得到执行。所以,ActivityThread#main()是整个应用程序的入口

9-3、zygoteProcess#start(params…)
代码执行到了zygoteProcess的start(params…)方法,我们先来看一下代码的执行:

public final Process.ProcessStartResult start(final String processClass,
        final String niceName,int uid, int gid, int[] gids,
        int runtimeFlags, int mountExternal,int targetSdkVersion,
        String seInfo,String abi,String instructionSet,String appDataDir,
        String invokeWith,String[] zygoteArgs) {
    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                zygoteArgs);
    } catch{
        //...
    }
}

private Process.ProcessStartResult startViaZygote(params...)throws ZygoteStartFailedEx {
    ArrayList<String> argsForZygote = new ArrayList<String>();

    //为zygote进程添加各种参数...
    argsForZygote.add("--runtime-args");
    argsForZygote.add("--setuid=" + uid);
    argsForZygote.add("--setgid=" + gid);
    //省略...

    //这里加了锁,同一时间内只允许一条线程执行创建进程的操作
    synchronized(mLock) {
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    }
}

/**
 * 把新进程的参数发给zygote进程,它会创建一个子进程,并返回子进程的pid
 *
 */
@GuardedBy("mLock")
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, ArrayList<String> args)
        throws ZygoteStartFailedEx {
    try {
        //这里的跨进程通信,使用的是socket通信机制
        //由于这里都是在锁的机制下执行,所以不会出现并发错误  
        final BufferedWriter writer = zygoteState.writer;
        final DataInputStream inputStream = zygoteState.inputStream;

        //把所有新进程的参数都写入缓冲区
        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();
        }

        writer.flush();

        // Should there be a timeout on this?
        Process.ProcessStartResult result = new Process.ProcessStartResult();

        //读取zygote进程返回的值,这就是新进程的pid
        result.pid = inputStream.readInt();
        result.usingWrapper = inputStream.readBoolean();

        if (result.pid < 0) {
            throw new ZygoteStartFailedEx("fork() failed");
        }
        return result;
    } 
}

zygote到底是何方神圣呢?其实在安卓系统启动的过程中,zygote进程就会被启动,它负责了整个frameworks层和application层的所有进程的创建和启动工作。也就是说,所有的进程都是它孕育出来的,都是它的子进程。同时,zygote的中文意思受精卵刚好与它的行为相符合。
需要注意的是,上面的代码都是运行在AMS内,只不过最后通过socket跨进程通信的方式通知了zygote进程来fork一个子进程,并且获取到了子进程的pid。该子进程创建、启动完毕之后,ActivityThread#main()方法就得到了调用。


10-1、ActivityThread#main()
ActivityThread的main()方法可以说是我们应用程序的开端,它运行在一个新的进程空间内。当一个新的进程启动完毕开始运行后,它首先要做的是通知AMS它被启动了,因为此时AMS还等着它去执行启动Activity的后续流程呢。我们来看看main()方法做了什么工作:

public static void main(String[] args) {
    //初始化环境
    Environment.initForCurrentUser();

    // Set the reporter for event logging in libcore
    EventLogger.setReporter(new EventLoggingReporter());

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    Process.setArgV0("<pre-initialized>");

    //为主线程准备Looper
    Looper.prepareMainLooper();

    //从命令行参数中获取序列号
    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    //创建ActivityThread的实例
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);    //通知AMS进行绑定操作

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

    Looper.loop();      //开启主线程的消息循环

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

代码的逻辑很清晰,关键的地方上面也有注释。可以看出,在main()函数的最后,开启了主线程的消息循环,通过Handler和Looper的组合,可以不断地处理AMS、WMS发过来的消息请求等,有关主线程消息循环的内容,有兴趣的可以自行查阅相关的信息,这里不做展开讲述。我们的关注点放在thread.attach(false,startSeq)这行代码内,我们看看它做了什么工作吧。

10-2、ActivityThread#attach(params…)

private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        //获取AMS在客户端的代理对象
        final IActivityManager mgr = ActivityManager.getService();
        try {
            //进行跨进程通信,通知AMS进行绑定操作
            //这里的mAppThread就是ApplicationThread,在ActivityThread
            //被实例化的时候,它也被实例化了。
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        
    } else {
        //...
    }
    //...
}

上面的代码出现了ApplicationThread对象,它在前面已经出现过很多次了,它是一个Binder对象,用于AMS来跨进程与APP进行消息通信。这里通过Binder跨进程通信,调用了AMS的attachApplication(params…)方法。我们再次打开AMS的代码,找到该方法。(需要注意的是:应用程序的主线程执行完该方法之后,继续进行消息循环,以等待下一次AMS的消息。)

10-3、ActivityManagerService#attachApplication(params…)

@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
    synchronized (this) {
        //..
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
    }
}

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    ProcessRecord app;
    long startTime = SystemClock.uptimeMillis();
    //根据pid来获取进程记录
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            app = mPidsSelfLocked.get(pid);
        }
    } else {
        app = null;
    }

    //ProcessRecord保存了当前的IApplicationThread,即保存了客户端的一个代理对象
    //AMS能根据该Binder对象快速找到所指的应用
    app.makeActive(thread, mProcessStats);  
    
    //省略大部分代码...

        if (app.isolatedEntryPoint != null) {
            //...
        } else if (app.instr != null) {
            //代码11-1、跨进程调用ApplicationThread的方法,告诉APP端有关该进程的信息
            thread.bindApplication(processName, appInfo, providers,
                    app.instr.mClass,
                    profilerInfo, app.instr.mArguments,
                    app.instr.mWatcher,
                    app.instr.mUiAutomationConnection, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, isAutofillCompatEnabled);
            } else {
                //...
            }
            
        } 

    // See if the top visible activity is waiting to run in this process...
    if (normalMode) {
        try {
            //代码12-1、告诉ActivityStackSupervisor,该app已经完成了绑定操作,可以启动一个Activity了
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } 
    }
    return true;
}

上面已经省略了大部分的代码,很多都是异常状态的处理以及初始化等逻辑,核心在于thread.bindApplication(params..)mStackSupervisor.attachApplicationLocked(app)这两个方法的调用上。前一行代码通过IApplicationThread跨进程通信,调用了APP端的相应方法,把有关进程的重要信息传递了过去。这样便完成从客户端到服务端的绑定操作。后一行代码,通过ActivityStackSupervisor来找到对应的ActivityStack,然后进行绑定,这样便完成了从服务端到客户端的绑定操作。通过这两个操作,客户端的应用程序知道了自己的应用信息、进程信息等;而服务端则知道了客户端的Binder代理对象,方便之后的跨进程操作。


11-1、ApplicationThread#bindApplication(params…)
我们先来看该方法的调用,我们又从AMS进程回到了应用进程:

public final void bindApplication(params..) {

    if (services != null) {

        // Setup the service cache in the ServiceManager
        ServiceManager.initServiceCache(services);
    }

    setCoreSettings(coreSettings);

    AppBindData data = new AppBindData();
    data.processName = processName;
    data.appInfo = appInfo;
    data.providers = providers;
    //省略赋值代码..
        
    //通过Handler发送消息
    sendMessage(H.BIND_APPLICATION, data);
}

由此可见,App的有关信息从AMS传递了过来,并保存在了AppBindData这个对象内。接着,就是我们熟悉的发送消息过程,通过Handler切换到主线程,在主线程内处理这个消息。代码如下:

public void handleMessage(Message msg) {
    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;        
    }
    Object obj = msg.obj;
    if (obj instanceof SomeArgs) {
        ((SomeArgs) obj).recycle();
    }
}

得益于主线程的消息循环,当H接受到BIND_APPLICATION的消息时,就能马上开始处理这个消息,处理完毕后继续消息循环。

11-2、ActivityThread#handleBindApplication(data)

private void handleBindApplication(AppBindData data) {
    //省略大部分代码...

    //创建上下文环境context
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
        
    Application app;
    try {
        app = data.info.makeApplication(data.restrictedBackupMode, null);
        
        //....
        try {
            mInstrumentation.callApplicationOnCreate(app);
        }
    }
}

以上省略了绝大部分的代码,很多都是初始化代码,比如加载各种库等。当Application初始化完毕之后,调用了mInstrumentation.callApplicationOnCreate(app)

11-3、Instrumentation#callApplicationOnCreate(app)

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

很简单,调用了Application#onCreate()方法,也就是我们业务层常重写的方法之一,代码执行到这里,应用程序的初始化已经完成了。下面就是在应用程序的基础上启动一个Activity了。


12-1、ActivityStackSupervisor#attachApplicationLocked(app)
回到10-3的代码,继续往下执行,接着AMS就会调用mStackSupervisor.attachApplicationLocked(app)方法,可想而知,在方法的内部,应该是要启动一个Activity了。因为一切的准备工作都已经完成了。

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    final String processName = app.processName;
    boolean didSomething = false;
    for (...) {
        for (...) {
            for (int i = 0; i < size; i++) {
                final ActivityRecord activity = mTmpActivityList.get(i);

                //如果该ActivityRecord的进程字段为空 并且进程uid与Activity的进程id相同
                //并且 进程名字与Activity的进程名字相同
                if (activity.app == null && app.uid == activity.info.applicationInfo.uid
                        && processName.equals(activity.processName)) {
                    try {
                        //启动该Activity
                        if (realStartActivityLocked(activity, app,
                                top == activity /* andResume */, true /* checkConfig */)) {
                            didSomething = true;
                        }
                    } 
                }
            }
        }
    }
    return didSomething;
}

上面代码的逻辑主要是遍历所有的任务栈,找到活跃的任务栈后,再在其中找到需要启动的Activity,将它启动。启动的逻辑放在了realStartActivityLocked(params..),终于,我们又看到了这个方法,殊途同归。

12-2、ActivityStackSupervisor#realStartActivityLocked(params…)

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

    //这里进行了判断,如果有Activity处于未暂停的状态,则不能启动一个新的Activity
    //由于我们是从客户端通知server来启动一个Activity的,因此已经不存在未暂停的Activity了
    if (!allPausedActivitiesComplete()) {   
        return false;
    }

    final TaskRecord task = r.getTask();
    final ActivityStack stack = task.getStack();

    try {
            //创建一个客户端的事务
            final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                    r.appToken);
            //添加callback,留意这里的添加了LaunchActivityItem
            clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                    System.identityHashCode(r), r.info,
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                    profilerInfo));

            //为该事务的目标设置为ResumeActivityItem,即启动一个Activity,并改变它
            //的生命周期到Resumed状态
            final ActivityLifecycleItem lifecycleItem;
            if (andResume) {
                lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
            } 
            clientTransaction.setLifecycleStateRequest(lifecycleItem);

            //通过事务管理器执行一个事务
            mService.getLifecycleManager().scheduleTransaction(clientTransaction);
        } 
    return true;
}

可以看到,我们再次遇到了熟悉的ClientTransaction,前面解析暂停Activity时也遇到它,那么接下来的逻辑应该就是与暂停的逻辑差不多了,只不过现在的ActivityLifecycleItem变成了ResumeActivityItem,即Activity的目标状态是resumed。接下来的调用链与前面见过的是一致的,即:ClientLifecycleManager#scheduleTransaction(clientTransaction)
——>ClientTransaction.schedule()
——>IApplicationThread.scheduleTransaction(this)
——>ActivityThread#scheduleTransaction(transaction)
——>H#handleMessage(msg)
——>TransactionExecutor#execute(transaction)
其中,通过IApplicationThread这个Binder对象进行了跨进程调用,调用了APP端的方法,此时从AMS进程切换到了我们的应用进程。紧接着,通过Handler机制切换到了主线程,并在主线程处理EXECUTE_TRANSACTION这个消息,接着进一步交给TransactionExecutor来处理这个事务。


13-1、TransactionExecutor#execute(transaction)
在代码7-1已经介绍过这个方法了,我们再来简单看一下就行:

    public void execute(ClientTransaction transaction) {
        final IBinder token = transaction.getActivityToken();
        log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);

        executeCallbacks(transaction);

        executeLifecycleState(transaction);
        mPendingActions.clear();
        log("End resolving transaction");
    }

在代码12-2中,我们有留意到初始化clientTransaction时,为它添加了一个callback,即LaunchActivityItem,那么这里首先会执行executeCallbacks(transaction)方法。

13-2、TransactionExecutor#executeCallbacks(transaction)

public void executeCallbacks(ClientTransaction transaction) {
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
    if (callbacks == null) {
        // No callbacks to execute, return early.
        return;
    }
    log("Resolving callbacks");

    final IBinder token = transaction.getActivityToken();
    ActivityClientRecord r = mTransactionHandler.getActivityClient(token);

    //根据前面的代码,这里的size为1
    final int size = callbacks.size();
    for (int i = 0; i < size; ++i) {
        final ClientTransactionItem item = callbacks.get(i);
        log("Resolving callback: " + item);

        //这里的Item实际上就是LaunchActivityItem.
        item.execute(mTransactionHandler, token, mPendingActions);
        item.postExecute(mTransactionHandler, token, mPendingActions);

        //...
    }
}

在方法内部调用了LaunchActivityItem的相关方法,其中关键是LaunchActivityItem#execute(params..)

13-3、LaunchActivityItem#execute(params…)

public void execute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
    //实例化一个ActivityClientRecord
    ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
            mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
            mPendingResults, mPendingNewIntents, mIsForward,
            mProfilerInfo, client);
    //实际上调用的是ActivityThread的handleLaunchActivity方法
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}

这里的ClientTransactionHandlerActivityThread的父类,而ActivityThread重写了该方法,因此我们到ActivityThread寻找该方法。

13-4、ActivityThread#handleLaunchActivity(params…)

public Activity handleLaunchActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, Intent customIntent) {
    //....

    final Activity a = performLaunchActivity(r, customIntent);

    //...

    return a;
}

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    
    //省略部分代码..

    ActivityInfo aInfo = r.activityInfo;
    ContextImpl appContext = createBaseContextForActivity(r);   //创建Context
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);    //创建一个新的Activity
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } 

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (activity != null) {
            appContext.setOuterContext(activity);
            //activity绑定application
            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);

            
            if (r.isPersistable()) {
                //前面创建了Activity,接下来触发它的生命周期方法
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }

            r.activity = activity;
        }
        r.setState(ON_CREATE);  //设置Activity此时的状态为onCreate

        mActivities.put(r.token, r);

    return activity;
}

经过一系列的创建、初始化过程,终于到了Instrumentation#callActivityOnCreate(params..),显然,这里就是触发Activity生命周期方法的地方了。

13-5、Instrumentation#callActivityOnCreate(params…)

public void callActivityOnCreate(Activity activity, Bundle icicle) {
     prePerformCreate(activity);
     activity.performCreate(icicle);
     postPerformCreate(activity);
}

没什么好说的,下一步就是Activity#performCreate(bundle)

final void performCreate(Bundle icicle) {
    performCreate(icicle, null);
}

final void performCreate(Bundle icicle, PersistableBundle persistentState) {
    mCanEnterPictureInPicture = true;
    restoreHasCurrentPermissionRequest(icicle);
    if (persistentState != null) {
        onCreate(icicle, persistentState);  
    } else {
        onCreate(icicle);   //onCreate()生命周期方法调用
    }
    writeEventLog(LOG_AM_ON_CREATE_CALLED, "performCreate");
    mActivityTransitionState.readState(icicle);

    mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
            com.android.internal.R.styleable.Window_windowNoDisplay, false);
    mFragments.dispatchActivityCreated();   //告诉Fragment分发create事件
    mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
}

最后,终于来到了Activity#onCreate()方法,也这就是我们应用Activity默认重写的一个方法。到了这一步,一个Activity终于真正地创建、启动成功了。但还没有完成,因为我们的目标状态是resumed,所以我们还要把Activity的状态逐步切换到onResume状态。
让我们回到代码13-1的executeLifecycleState(transaction),这个方法读者应该也是熟悉的了,因为在处理pause状态时也曾经遇到过了。那么接下来的逻辑就显而易见了,具体的逻辑就在代码7-2处,只不过现在的状态路径变成了:onStart和onResume,也就是会分别调用ActivityThread#handleStartActivityActivityThread#handleResumeActivity;接着进一步调用到Activity#performStart()Activity#performResume()。最后,我们熟悉的生命周期方法onStart()onResume()都会得到调用。

本文到这里就告一段落了,整篇文章很长,为耐心看到这里的你点赞~希望这篇文章能对您有所裨益,谢谢阅读!

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值