学习笔记--Launcher应用的进程启动流程

Launcher应用的进程启动流程

紧接上篇从开机到SystemServer系统服务启动,这篇分析Launcher应用进程是怎么启动的。

注意事项写在前头:
  • 本篇的阅读顺序为启动关键类介绍--关键类的概述---启动流程图----围绕启动流程图的源码分析。
  • 本篇的源码分析部分(包括已作省略的伪代码)都务必配合注释食用,才能便于理解。
  • 完整分析可以从下面开始看起(顺序由上至下):
Launcher启动相关类
Launcher启动相关类
启动流程关键类的概述(重点)
  1. ActivityManagerService:Activity生命周期管理类,在SystemServer.java开启了所有服务之后会调用其systemReady方法调起Launcher应用
  2. ActivityTaskManagerService:原先在ActivityManagerService中管理Activity的工作转移到了ActivityTaskManagerService中(Android10.0重构加入)。
  3. RootActivityContainer:调用PackageManagerService查询已安装在设备中的应用中符合Launcher的标准,并构造Intent对象。
  4. ActivityStarter:获取RootActivityContainer中构造的Intent对象来进一步启动Launcher的Activity,在其中会做启动前的检查,比如Activity是否在清单文件注册,Activity的class文件是否存在,是否有权限启动等等。
  5. ActivityRecord:是在Server端对Activity的映射(因为Server端无法获取Activity实例),记录和存储了Activity的所有信息。
  6. TaskRecord:常说的任务栈,其中记录了一个或多个ActivityRecord实例对象。
  7. ActivityStack:直接翻译像是任务栈,但实际上是任务栈(TaskRecord)的管理者角色,一个应用运行时有可能有多个任务栈,这些任务栈交由ActivityStack管理。
  8. ActivityStackSupervisor:设备运行时会产生一个或多个应用,此时会产生一个或多个ActivityStack对象。ActivityStackSupervisor正是用来管理Launcher和非Launcher应用的ActivityStack实例。
  9. ProcessList:作用是原先在ActivityManagerService中的启动进程的工作转移到了ProcessList(Android10.0加入)。
  10. ZygoteProcess:建立起与Zygote进程的socket链接,将创建进程的所需的信息发送到Zygote中,由Zygote创建Launcher进程。
讲讲所谓任务栈

这里就先来简单讲讲ActivityStackSupervisor,ActivityStack,TaskRecord,ActivityRecord这几个类。
ActivityRecord、TaskRecord、ActivityStack三个类之间有共同点:都是继承自ConfigurationContainer,字面意思是配置容器,包括了这些配置(仅举例,详情可自行查资料了解):

  • 字体缩放比例;
  • 移动国家码(MCC)、移动网络码(MNC);
  • 区域(语言);
  • 颜色模式(饱和度、HDR);
  • 屏幕布局(尺寸(小中大超大)、是否宽屏或长屏幕、布局方向(从左到右、从右到左)、是否圆角屏幕);
  • Window边界范围(l, t, r, b)、Window方向;
  • Window显示模式(全屏、画中画、分屏模式-主屏幕、分屏模式-副屏幕、自由拖动);
  • Activity类型(普通、启动器/桌面、最近任务/任务管理器、语音助手);
  • 触屏类型(无触屏、手写笔、手指);
  • 键盘类型(无键盘、QWERTY键盘、12键)、键盘是否可用/弹出;
  • 非触摸导航设备(无、方向键(上下左右确定返回)、轨迹球、方向盘)
  • UI类型(普通(常规手机)、桌面(电脑版)、车载、智能电视、嵌入式终端机、智能手表、VR设备)、UI模式(日间、夜间);
  • 屏幕密度、可用屏幕宽度、可用屏幕高度;

首先看到ConfigurationContainer是一个抽象类,总共有三个抽象方法

//------------------------------ConfigurationContainer.java------------------------------

/**
 * Contains common logic for classes that have override configurations and are organized in a
 * hierarchy.
 */
 // 官方注释:包含具有覆盖配置并按层次结构组织的类的通用逻辑。
public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
    ...
    abstract protected int getChildCount();

    abstract protected E getChildAt(int index);

    abstract protected ConfigurationContainer getParent();
}

而在ActivityRecord中对其的的实现:

//------------------------------ActivityRecord.java------------------------------

final class ActivityRecord extends ConfigurationContainer { 

    private TaskRecord task; // the task this is in.

    @Override
    protected int getChildCount() {
        // {@link ActivityRecord} is a leaf node and has no children.
        return 0;
    }

    @Override
    protected ConfigurationContainer getChildAt(int index) {
        return null;
    }

    @Override
    protected ConfigurationContainer getParent() {
        return getTaskRecord();
    }

    TaskRecord getTaskRecord() {
        return task;
    }
}

ActivityRecord的getChildCount返回0,getChildAt返回null,而getParent返回的是它持有的一个TaskRecord实例。

接下来看看TaskRecord:

//------------------------------TaskRecord.java------------------------------

class TaskRecord extends ConfigurationContainer {
    /** List of all activities in the task arranged in history order */
    final ArrayList<ActivityRecord> mActivities;

    /** Current stack. Setter must always be used to update the value. */
    private ActivityStack mStack;
    
    @Override
    protected int getChildCount() {
        return mActivities.size();
    }

    @Override
    protected ActivityRecord getChildAt(int index) {
        return mActivities.get(index);
    }

    @Override
    protected ConfigurationContainer getParent() {
        return mStack;
    }
}

TaskRecord的getChildCount返回ActivityRecord集合的容量,getChildAt返回在mActivities集合取对应ActivityRecord实例,而getParent返回的是它持有的一个ActivityStack实例。

最后来看看ActivityTask:

//------------------------------ActivityStack.java------------------------------

class ActivityStack extends ConfigurationContainer {

    private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
    protected final RootActivityContainer mRootActivityContainer;

    @Override
    protected int getChildCount() {
        return mTaskHistory.size();
    }

    @Override
    protected TaskRecord getChildAt(int index) {
        return mTaskHistory.get(index);
    }

    @Override
    protected ActivityDisplay getParent() {
        return getDisplay();
    }

    ActivityDisplay getDisplay() {
        return mRootActivityContainer.getActivityDisplay(mDisplayId);
    }
}

ActivityStack的getChildCount返回TaskRecord集合的容量,getChildAt返回在TaskRecord集合取对应TaskRecord实例,而getParent返回的是它持有的一个ActivityDisplay实例.

ActivityDisplay不是我们重点分析的对象,但我们还是来看下它的源码

//------------------------------ActivityDisplay.java------------------------------

class ActivityDisplay extends ConfigurationContainer<ActivityStack>
        implements WindowContainerListener {
    private RootActivityContainer mRootActivityContainer;
    
    /**
     * All of the stacks on this display. Order matters, topmost stack is in front of all other
     * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
     * changing the list should also call {@link #onStackOrderChanged()}.
     */
    private final ArrayList<ActivityStack> mStacks = new ArrayList<>();
    
    @Override
    protected int getChildCount() {
        return mStacks.size();
    }

    @Override
    protected ActivityStack getChildAt(int index) {
        return mStacks.get(index);
    }

    @Override
    protected ConfigurationContainer getParent() {
        return mRootActivityContainer;
    }
}

ActivityDisplay的的getChildCount返回ActivityStack集合的容量,getChildAt返回在ActivityStack集合取对应TaskRecord实例,而getParent返回的是它持有的一个RootActivityContainer实例.

既然追踪到这就追踪完吧
RootActivityContainer

//------------------------------RootActivityContainer.java------------------------------

/**
 * Root node for activity containers.
 * TODO: This class is mostly temporary to separate things out of ActivityStackSupervisor.java. The
 * intention is to have this merged with RootWindowContainer.java as part of unifying the hierarchy.
 */
 // 官方注释:表示Activity Containers的根节点,只是暂时从ActivityStackSupervisor.java分离出来的功能,将来可以统一到RootWindowContainer.java中
class RootActivityContainer extends ConfigurationContainer
        implements DisplayManager.DisplayListener {
    /**
     * List of displays which contain activities, sorted by z-order.
     * The last entry in the list is the topmost.
     */
    private final ArrayList<ActivityDisplay> mActivityDisplays = new ArrayList<>();
    
    @Override
    protected int getChildCount() {
        return mActivityDisplays.size();
    }

    @Override
    protected ActivityDisplay getChildAt(int index) {
        return mActivityDisplays.get(index);
    }

    @Override
    protected ConfigurationContainer getParent() {
        return null;
    }
}

在RootActivityContainer这个类中,getChildCount返回ActivityDisplay集合的容量,getChildAt返回在ActivityDisplay集合取对应TaskRecord实例,而getParent返回的为null了.

从上面的分析之后可以得到这样一个图:


任务栈相关类层级图

正如上面的ActivityRecord,TaskRecord,ActivityStack的概括:
ActivityRecord对应着一个Activity实例,TaskRecord对应着一个任务栈,所以它们都以ArrayList集合的形式存在,而ActivityStack也以ArrayList集合的形式存在则是因为Activity启动时,系统会根据该Activity的类型和Window显示模式来决定它所对应的TaskRecord应该放在哪个Stack(如果没有合适的就创建)
比如:

  • HOME_STACK(启动器/桌面专属Stack);
  • RECENTS_STACK( 最近任务/任务管理器专属);
  • ASSISTANT_STACK(语音助手专属);
  • FULLSCREEN_WORKSPACE_STACK(全屏应用专属);
  • PINNED_STACK(画中画专属);
  • FREEFORM_WORKSPACE_STACK(自由拖动窗口专属);

简单分析完任务栈相关内容,继续对Launcher的启动流程的分析,上篇从开机到SystemServer系统服务启动的分析中,在最后SystemSever#startOtherServices方法在开启了必须的系统服务后会调用ActivityManagerService的systemReady方法去调起Launcher应用。

先看看Launcher启动流程图:

先看下流程图,熟悉关键流程,再进行源码分析。

Launcher启动关键类流程图

关键处的源码分析

RootActivityContainer.java
//------------------------------RootActivityContainer.java------------------------------

boolean startHomeOnAllDisplays(int userId, String reason) {
    boolean homeStarted = false;
    // 遍历设备连接的所有屏幕获取其DisplayId,依次调用startHomeOnDisplay
    // 即依次启动桌面应用
    for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
        final int displayId = mActivityDisplays.get(i).mDisplayId;
        homeStarted |= startHomeOnDisplay(userId, reason, displayId);
    }
    return homeStarted;
}

继续跟进会到

//------------------------------RootActivityContainer.java------------------------------

// 重点在中文注释的两处
boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,
        boolean fromHomeKey) {
    // Fallback to top focused display if the displayId is invalid.
    if (displayId == INVALID_DISPLAY) {
        displayId = getTopDisplayFocusedStack().mDisplayId;
    }

    Intent homeIntent = null;
    ActivityInfo aInfo = null;
    if (displayId == DEFAULT_DISPLAY) {
        // 这里的mService为ActivityTaskManagerService
        // 调用ActivityTaskManagerService#getHomeIntent()方法返回符合Home类型的Intent
        // mark住该处,可先追踪下面的ActivityTaskManagerService#getHomeIntent()分析,再回到此处继续分析
        homeIntent = mService.getHomeIntent();
        // 这里调用的PackageManagerService的检索Intent方法
        // mark住该处,可先追踪下面的resolveHomeActivity分析,再回到此处继续分析
        aInfo = resolveHomeActivity(userId, homeIntent);
    } else if (shouldPlaceSecondaryHomeOnDisplay(displayId)) {
        Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, displayId);
        aInfo = info.first;
        homeIntent = info.second;
    }
    if (aInfo == null || homeIntent == null) {
        return false;
    }

    if (!canStartHomeOnDisplay(aInfo, displayId, allowInstrumenting)) {
        return false;
    }

    // Updates the home component of the intent.
    homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
    homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
    // Updates the extra information of the intent.
    if (fromHomeKey) {
        homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
    }
    // Update the reason for ANR debugging to verify if the user activity is the one that
    // actually launched.
    final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
            aInfo.applicationInfo.uid) + ":" + displayId;
    // 此处会跳转到ActivityStartController的startHomeActivity中
    mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
            displayId);
    return true;
}



//------------------------------ActivityTaskManagerService.java------------------------------

// ActivityTaskManagerService#getHomeIntent()
Intent getHomeIntent() {
    Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
    intent.setComponent(mTopComponent);
    intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
    if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
        // 重点在这里,返回一个Category为Intent.CATEGORY_HOME的Intent
        intent.addCategory(Intent.CATEGORY_HOME);
    }
    return intent;
}



//------------------------------RootActivityContainer.java------------------------------

// RootActivityContainer#resolveHomeActivity(),通过PackageManagerService检索出符合的Activity
ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
    final int flags = ActivityManagerService.STOCK_PM_FLAGS;
    final ComponentName comp = homeIntent.getComponent();
    ActivityInfo aInfo = null;
    try {
        if (comp != null) {
            // Factory test.
            aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
        } else {
            final String resolvedType =
                    homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver());
            final ResolveInfo info = AppGlobals.getPackageManager()
                    .resolveIntent(homeIntent, resolvedType, flags, userId);
            if (info != null) {
                aInfo = info.activityInfo;
            }
        }
    } catch (RemoteException e) {
        // ignore
    }

    if (aInfo == null) {
        Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable());
        return null;
    }

    aInfo = new ActivityInfo(aInfo);
    aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
    return aInfo;
}

至此流程从ActivityTaskManagerService到RootActivityContainer中,
小结:

  • RootActivityContainer通过PackageManagerService检索出符合启动的Launcher Activity,返回其对应的ActivityInfo实例(该实例包含了清单文件对Activity的配置信息等)
  • 跳转到ActivityStartController的startHomeActivity中,ActivityStartController类的作用是配置Activity启动前的信息并且传递个ActivityStarter。
ActivityStarter.java

追踪上文中ActivityStartController的startHomeActivity会一路追踪到ActivityStarter#execute方法(省略了一些非关键处).

//------------------------------ActivityStartController.java------------------------------

void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) {
    ...
    // obtainStarter()方法返回ActivityStarter实例
    // set系列方法向ActivityStarter实例传递参数,最终调用execute方法
    mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
            .setOutActivity(tmpOutRecord)
            .setCallingUid(0)
            .setActivityInfo(aInfo)
            .setActivityOptions(options.toBundle())
            .execute();
    ...
}

继续分析下execute方法

//------------------------------ActivityStarter.java------------------------------

/**
 * Starts an activity based on the request parameters provided earlier.
 * @return The starter result.
 */
 // 官方注释:会根据request参数启动Activity
int execute() {
    try {
        // TODO(b/64750076): Look into passing request directly to these methods to allow
        // for transactional diffs and preprocessing.
        // 由于启动流程中没有配置过mayWait参数,所以其为默认值false,进入else分支
        if (mRequest.mayWait) {
            return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                    mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid,
                    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,
                    mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
        } else {
            // 跳转自身的startActivity(...)方法
            return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                    mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
                    mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                    mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
                    mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
                    mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
                    mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
                    mRequest.outActivity, mRequest.inTask, mRequest.reason,
                    mRequest.allowPendingRemoteAnimationRegistryLookup,
                    mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
        }
    } finally {
        onExecutionComplete();
    }
}

继续跟进会startActivity方法,会在它某个的重载方法中看到一些清单文件检验,权限检查等操作,我们来看下其中比较重要的几处代码.

//------------------------------ActivityStarter.java------------------------------

private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        SafeActivityOptions options,
        boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
        TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
        PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
        ...
        // 创建err变量,默认为ActivityManager.START_SUCCESS
        // 该int值就是本次启动Activity的反馈值,所以可以通过追踪它的赋值来查看该方法执行的Activity校验流程
        int err = ActivityManager.START_SUCCESS;
        ...
        // caller是IApplicationThread类型,该参数是作为传参传递进来的
        // 只有当进程创建完成之后,caller才不为null。由于追踪分析的流程仍未创建进程,所以不会进入if分支
        if (caller != null) {
            callerApp = mService.getProcessController(caller);
            if (callerApp != null) {
                callingPid = callerApp.getPid();
                callingUid = callerApp.mInfo.uid;
            } else {
                Slog.w(TAG, "Unable to find app for caller " + caller
                        + " (pid=" + callingPid + ") when starting: "
                        + intent.toString());
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }
        ...
        // 这个if分支是判断Activity是否在清单文件中注册,如果没有注册的话,Intent的getComponent会返回null
        if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
            // We couldn't find a class that can handle the given Intent.
            // That's the end of that!
            // 表示Activity没在清单文件注册
            err = ActivityManager.START_INTENT_NOT_RESOLVED;
        }
        
        // 这个if分支是判断Activity的Java文件是否存在,如果Activity的Java文件不存在的话,aInfo为null
        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
            // We couldn't find the specific class specified in the Intent.
            // Also the end of the line.
            // 表示没找到Activity的Java文件,为Activity启动之前的安全校验
            err = ActivityManager.START_CLASS_NOT_FOUND;
        }
        ...
        // 还有会对Activity的后台启动做判断
        // Android9.0以后就不允许Activity后台启动打动用户的操作
        ...
        // 还会对Activity的启动权限做校验
        // 如果在AndroidManifest.xml中配置了android:permission=""权限
        // 如果想要启动这个Activity,则要申请这个权限
        ...
        // 还会对Activity是否可见做校验
        // 如果在AndroidManifest.xml中配置了android:exported="false"
        // 别的app就无法启动该Activity
        ...
        // 最后这个方法又调用了startActivity的重载方法,继续跟进
        final int res = startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                true /* doResume */, checkedOptions, inTask, outActivity, restrictedBgActivity);
        mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outActivity[0]);
        return res;
        
}
// 此处可以看到Framework层对Activity的启动会做很多判断,而热修复中的动态加载Activity技术,部分Activity是根本没在清单文件进行注册的。
// 在一般情况下动态加载(未在清单文件中注册)的Activity根本无法启动(因为在ActivityStarter会进行多种校验),而热修复团队就是了解了Activity启动流程,从而想到了解决办法。

跟进下一个startActivity的重载方法发现它没做什么重要操作(跳过分析),然后就调用了startActivityUnchecked方法。该方法需要重点关注,因为它会记录这个Activity要以何种方法启动以及入栈的方式(启动时要不要创建新的任务栈,要不要复用栈中已存在的Activity实例并回调它的newIntent,还是创建新的Activity对象然后再加入任务栈)

//------------------------------ActivityStarter.java------------------------------

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
        ActivityRecord[] outActivity, boolean restrictedBgActivity) {
    ...
    // 根据Activity的LaunchMode和Intent.flag计算出Activity的入栈方式
    computeLaunchingTaskFlags();
    
    // 计算出该Activity的任务栈,也就是从哪个任务栈启动Activity
    computeSourceStack();
    
    mIntent.setFlags(mLaunchFlags);

    // getReusableIntentActivity从当前的任务栈中取出是否有可复用的ActivityRecord对象,可为null
    ActivityRecord reusedActivity = getReusableIntentActivity();
    ...
    
    // 表示当前任务栈中存在可以复用的Activity
    if (reusedActivity != null) {
        ...
        // 执行其newIntent流程,onNewIntent
        deliverNewIntent(top);
        ...
    }
    ...
    // 该方法的出口会调用RootActivityContainer#resumeFocusedStacksTopActivities方法
    mRootActivityContainer.resumeFocusedStacksTopActivities(
                        mTargetStack, mStartActivity, mOptions);
}

经过上述startActivityUnchecked方法的大量计算,在Server进程中要启动的Activity对应的ActivityRecord对象就会入栈了,但是此时Activity实例还未创建,更别说显示。在方法出口处会调用RootActivityContainer#resumeFocusedStacksTopActivities方法.

//------------------------------RootActivityContainer.java------------------------------

// 经过上个方法的计算已经确定要启动Activity的所处的ActivityStack任务栈,以何种方式入栈
// 所以该方法就是去启动栈顶的Activity
boolean resumeFocusedStacksTopActivities(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
    ...
    // 经过该循环判断Activity是否已经处在Resume状态,很明显新入栈待启动的Activity还未创建成功,更别说resume,显示,所以resumedOnDisplay为false
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        boolean resumedOnDisplay = false;
        ...
        // resumedOnDisplay为false进入分支,最终调用ActivityStack的resumeTopActivityUncheckedLocked方法
        if (!resumedOnDisplay) {
            // In cases when there are no valid activities (e.g. device just booted or launcher
            // crashed) it's possible that nothing was resumed on a display. Requesting resume
            // of top activity in focused stack explicitly will make sure that at least home
            // activity is started and resumed, and no recursion occurs.
            final ActivityStack focusedStack = display.getFocusedStack();
            if (focusedStack != null) {
                focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
            }
        }
    }                
}

至此流程会从ActivityStarter走到ActivityStack类中,
小结:

  • ActivityStarter中对待启动Activity的清单文件配置,启动权限校验,Java文件是否存在等进行判断
  • 并且根据启动模式/Intent.flag等计算出所属的任务栈,并将其在Server进程对应的ActivityRecord进栈,但此时Activity真正实例仍未创建,更别说显示
ActivityStack.java

resumeTopActivityUncheckedLocked什么都没做,紧接着调用resumeTopActivityInnerLocked,所以我们分析resumeTopActivityInnerLocked

//------------------------------ActivityStack.java------------------------------

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    ...
     // Find the next top-most activity to resume in this stack that is not finishing and is
    // focusable. If it is not focusable, we will fall into the case below to resume the
    // top activity in the next focusable task.
    // 官方注释很清晰:获取栈顶的ActivityRecord对象
    ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
    ...
    // 判断待启动Activity的进程是否已经创建,仍未创建所以走else分支
    if (next.attachedToProcess()) {
        ...
    } else {
        ...
        // 跳转ActivityStackSupervisor中
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }
}

至此流程从ActivityStack走到ActivityStackSupervisor类中,
小结:

  • 判断待启动Activity的进程是否已经创建
ActivityStackSupervisor.java

这里我们直接进行startSpecificActivityLocked的源码分析,配合注释来理解流程。

//------------------------------ActivityStackSupervisor.java------------------------------

void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    // 再次判断进程是否已经被创建
    final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);
    
    boolean knownToBeDead = false;
    if (wpc != null && wpc.hasThread()) {
        try {
            // 如果wpc不为null,则会真正去启动Activity
            // 但此时我们追踪的Launcher进程还没被创建,所以不会进入这个分支
            realStartActivityLocked(r, wpc, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }

        // If a dead object exception was thrown -- fall through to
        // restart the application.
        knownToBeDead = true;
    }
    
    // Suppress transition until the new activity becomes ready, otherwise the keyguard can
    // appear for a short amount of time before the new process with the new activity had the
    // ability to set its showWhenLocked flags.
    if (getKeyguardController().isKeyguardLocked()) {
        r.notifyUnknownVisibilityLaunched();
    }

    try {
        if (Trace.isTagEnabled(TRACE_TAG_ACTIVITY_MANAGER)) {
            Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dispatchingStartProcess:"
                    + r.processName);
        }
        // Post message to start process to avoid possible deadlock of calling into AMS with the
        // ATMS lock held.
        // 所以Launcher启动流程会执行到这里
        // ActivityManagerInternal::startProcess的写法是用于适配Java8之前的方法传参,实际是调用ActivityManagerService#LocalService的startProcess方法
        final Message msg = PooledLambda.obtainMessage(
                ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
                r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
        mService.mH.sendMessage(msg);
    } finally {
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
    ...
}

至此流程从ActivityStackSupervisor类结束,之后会跳转到ActivityManagerService#LocalService的startProcess方法中
小结:

  • ActivityStackSupervisor#startSpecificActivityLocked会再次判断待启动Activity进程是否已存在,若存在则真正启动Activity,调用其realStartActivityLocked方法
  • 若不存在,则调用ActivityManagerService#LocalService的startProcess方法创建进程
ProcessList.java

流程从ActivityStackSupervisor类又回到了ActivityManagerService类中,确实在旧的版本中创建进程的工作是由ActivityManagerService完成的,但是Google团队觉得ActivityManagerService已经十分臃肿,所以在Android10.0之后增加了ProcessList类将之前在AMS的工作转移到其中.

startProcess方法跳转到startProcessLocked方法之后,会发现直接进入ProcessList的流程中(省略部分非关键处),所以我们直接追踪ProcessList#startProcessLocked方法

//------------------------------ProcessList.java------------------------------

/**
 * Activity manager code dealing with processes.
 *
 * Method naming convention:
 * <ul>
 * <li> Methods suffixed with "LS" should be called within the {@link #sLmkdSocketLock} lock.
 * </ul>
 */
 // 官方注释: 管理Activity的进程的工作
public final class ProcessList {
    ...
    // 该方法以及在本类跳转的系列方法主要作用都是在进程创建之前配置其必要的参数,比如abi类型,版本号
    // 其中有一个很重要的参数,需要了解,就是final String entryPoint = "android.app.ActivityThread";(该参数会在系列跳转方法中使用,这里我们直接指出来)
    // ActivityThread这就是应用进程的入口类,并不是我们熟知的Application
    final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
            boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
            String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
        ...
        ...
        
    }
    ...
}

至此从ProcessList所在流程追踪到这,进程的配置完成之后会跳转到ZygoteProcess.java类
小结:

  • ProcessList的流程主要是在进程创建之前配置其必要的参数,比如abi类型,版本号,其中其中有一个很重要的参数需要了解,就是final String entryPoint = "android.app.ActivityThread";
  • 表明了应用进程的入口类,并不是我们熟知的Application,而是ActivityThread。
ZygoteProcess.java

此时仍处于SystemServer进程中,这个类的目的是创建本地Socket连接对象,并且连接远在Zygote进程的Socket服务

//------------------------------ZygoteProcess.java------------------------------

/**
 * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
 * already open. If a compatible session socket is already open that session socket is returned.
 * This function may block and may have to try connecting to multiple Zygotes to find the
 * appropriate one.  Requires that mLock be held.
 */
 // 创建本地Socket连接对象,并且连接远在Zygote进程的Socket服务,这里我们就不重点分析了,感兴趣的童鞋可以追踪下源码
@GuardedBy("mLock")
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    try {
        attemptConnectionToPrimaryZygote();

        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }

        if (mZygoteSecondarySocketAddress != null) {
            // The primary zygote didn't match. Try the secondary.
            attemptConnectionToSecondaryZygote();

            if (secondaryZygoteState.matches(abi)) {
                return secondaryZygoteState;
            }
        }
    } catch (IOException ioe) {
        throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
    }

    throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}

至此流程从ZygoteProcess走到Zygote进程中,小结:

  • 在ZygoteProcess会创建本地Socket连接对象,并且连接远在Zygote进程的Socket服务
  • 然后通过字符输入流将进程创建所需参数发送到Zygote进程中
Zygote进程

最后Zygote进程会创建出新的进程,在进程创建完毕之后,会根据进程传递的入口类(ActivityThread)由ZygoteInit进行反射执行,这样调用到了App应用进程的入口类ActivityThread。Launcher应用的进程启动流程分析也就到一段落了。

最后,来讲下Framework源码分析套路

在Framework层中有许多面向接口的设计模式,这种设计模式可以保证在接口不变的情况下改变其真正的实现,但对于源码分析追踪并不友好,下面是一个被总结出来的源码分析套路:当遇到分析跳转的是xxxManagerInternal抽象类时,可以尝试寻找xxxManagerService$LocalService是否存在并继承于xxxManagerInternal抽象类。如果是,这一般就是其真正的实现类。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342