系统启动流程分析之Launcher应用进程启动流程(总结篇)

436 阅读6分钟

我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!

Launcher应用进程启动流程 总结篇

在此前的Launcher应用启动流程Launcher应用启动流程(上)Launcher应用启动流程(中)Launcher应用启动流程(下)三篇文章的分析中,将Launcher应用进程的代码流程分析了一遍,本篇将对上述的整体流程进行总结汇总

Launcher应用流程启动

在安卓系统启动过程中,创建的第一个进程是zygote,在zygote中会分裂一个system_server进程,而在system_server进程后会启动各种服务等,而在这个过程中会初始化ActivityManagerService(简称AMS)服务,同时在最后通过调用AMS的systemReady函数来完成AMS的启动,在systemReady函数中,通过调用ActivityTaskManagerService(简称ATMS)的startHomeOnAllDisplays函数

mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");

mAtmInternal参数是一个ActivityTaskManagerInternal对象,关于其的类图结构如下

classDiagram
ActivityTaskManagerInternal <|-- LocalService
ActivityTaskManagerService *-- LocalService
class ActivityTaskManagerInternal {
    +startHomeOnAllDisplays(int userId, String reason)* boolean
}
class ActivityTaskManagerService {
    ~LocalService
}
class LocalService {
    <<final>>
	+startHomeOnAllDisplays(int userId, String reason) boolean
}

从这个类图结构来看,ActivityTaskManagerInternal类是一个抽象类,而且startHomeOnAllDisplays函数是一个抽象方法,继承该类的LocalService实现了该抽象函数,且LocalService是ATMS的内部类

而且从ATMS服务的初始化中可以知道,其对象的mAtmInternal参数为ATMS.LocalService的实例

RootWindowContainer对象函数调用

RootWindowContainer对象是窗口绘制中的一个重要的类,它继承自WindowContainer对象,如下为其类图结构

classDiagram
WindowToken <|-- ActivityRecord
AppFreezeListener <|.. ActivityRecord
WindowManagerService *-- AppFreezeListener
WindowContainer <|-- WindowToken
ConfigurationContainer <|-- WindowContainer
Animatable <|.. WindowContainer
Freezable <|.. WindowContainer
TransactionReadyListener <|.. WindowContainer
Comparable <|.. WindowContainer
<<interface>> Animatable
<<interface>> Freezable
<<interface>> TransactionReadyListener
<<interface>> Comparable
SurfaceFreezer *-- Freezable
BLASTSyncEngine *-- TransactionReadyListener
<<abstract>> ConfigurationContainer
Task <|-- ActivityStack
WindowContainer <|-- Task
WindowContainer <|-- DisplayContent
DisplayContentInfo <|-- DisplayContent
<<interface>> DisplayContentInfo
WindowManagerPolicy <|-- DisplayContentInfo
<<interface>> WindowManagerPolicy
WindowContainer <|-- RootWindowContainer
class AppFreezeListener {
	<<interface>>
	#onAppFreezeTimeout() void
}
class ActivityRecord {
	-Task task 
	#asActivityRecord() ActivityRecord
	#getTask() Task
}
class WindowContainer {
	#asActivityRecord() ActivityRecord
}
class ConfigurationContainer {
	#getChildCount()* int
	#getChildAt(int index) * E
	#getParent()* ConfigurationContainer
}
class Animatable {
	#start() void
	#stop() void
	#isRunning() boolean
}

ATMS.LocalService的startHomeOnAllDisplays函数会调用RootWindowContainer对象的startHomeOnAllDisplays函数,在这个函数中会获取当前设备系统中支持的所有显示设备,并对每一个设备获取其DisplayId并调用RootWindowContainer对象的startHomeOnDisplay函数

而在startHomeOnDisplay函数中会获取对应的显示设备Display的显示区域,并调用其startHomeOnTaskDisplayArea函数,而 在该函数中,

  1. 会通过ATMS的getHomeIntent函数获取需要查找的Intent意图,并且根据这个意图查找系统支持的ActivityInfo
  2. 同时调用ActivityStartController对象的startHomeActivity函数,正式开始启动对应Activity的流程
boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
        boolean allowInstrumenting, boolean fromHomeKey) {
    // ......
    Intent homeIntent = null;
    ActivityInfo aInfo = null;
    if (taskDisplayArea == getDefaultTaskDisplayArea()) {
        homeIntent = mService.getHomeIntent();
        aInfo = resolveHomeActivity(userId, homeIntent);
    }
    // ......
    mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
            taskDisplayArea);
    return true;
}

ActivityStarter

ActivityStartController对象是一个Activity启动控制器,其主要是将外部请求启动的Activity整理完成后交给ActivityStarter进行处理和启动,同时它还会为这些Activity加上一些必要的逻辑信息等,而在ActivityStartController对象的startHomeActivity函数中,主要做了

  1. 为将要启动的Activity设置对应的条件ActivityOptions
  2. 然后将上述生成的ActivityInfo交给ActivityStarter进行处理
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, TaskDisplayArea taskDisplayArea) {
    final ActivityOptions options = ActivityOptions.makeBasic();
    options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
    if (!ActivityRecord.isResolverActivity(aInfo.name)) {
        // The resolver activity shouldn't be put in home stack because when the foreground is
        // standard type activity, the resolver activity should be put on the top of current
        // foreground instead of bring home stack to front.
        options.setLaunchActivityType(ACTIVITY_TYPE_HOME);
    }
    final int displayId = taskDisplayArea.getDisplayId();
    options.setLaunchDisplayId(displayId);
    options.setLaunchTaskDisplayArea(taskDisplayArea.mRemoteToken
            .toWindowContainerToken());

    // ......

    mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
            .setOutActivity(tmpOutRecord)
            .setCallingUid(0)
            .setActivityInfo(aInfo)
            .setActivityOptions(options.toBundle())
            .execute();
    // ......
}

ActivityStarter对象在初始化后,为其设置对应参数后,调用execute函数来运行和启动这个ActivityInfo,ActivityStarter类中包含有一个内部类Request,这个类在ActivityStarter启动时主要包含了所有请求启动的数据。

接下来会调用其executeRequest函数来运行这个请求,在这个函数中

  1. 首先通过上述添加的ActivityOptions和ActivityInfo等参数为本次启动设置必要的参数
  2. 其次初始化一个包含所有Activity信息的ActivityRecord对象,并且调用startActivityUnchecked函数
  3. 在调用startActivityUnchecked函数后,通过ActivityStack的startActivityLocked函数将要启动的ActivityRecord添加到Activity堆栈中,从而在最后调用RootWindowContainer的resumeFocusedStacksTopActivities函数来启动这个Activity
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, Task inTask,
        boolean restrictedBgActivity, NeededUriGrants intentGrants) {
    // ......
    mTargetStack.startActivityLocked(mStartActivity,
            topStack != null ? topStack.getTopNonFinishingActivity() : null, newTask,
            mKeepCurTransition, mOptions);
    if (mDoResume) {
        // ......
        if (!mTargetStack.isTopActivityFocusable()
                || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
                && mStartActivity != topTaskActivity)) {
            // ......
        } else {
            // ......
            mRootWindowContainer.resumeFocusedStacksTopActivities(
                    mTargetStack, mStartActivity, mOptions);
        }
    }
    // ......
    return START_SUCCESS;
}

RootWindowContainer中恢复Activity启动

RootWindowContainer的resumeFocusedStacksTopActivities函数中,主要调用ActivityStack对象的resumeTopActivityUncheckedLocked函数,从而进一步调用resumeTopActivityInnerLocked函数,最终进入ActivityStackSupervisor的startSpecificActivity函数

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    // ......

    if (next.attachedToProcess()) {
        // ......
    } else {
        // ......
        mStackSupervisor.startSpecificActivity(next, true, true);
    }
    return true;
}

通过ActivityStackSupervisor的startSpecificActivity函数,从而进入Launcher进程启动阶段

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
    // ......
    mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}

Launcher应用进程启动

ATMS的startProcessAsync函数

void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop, String hostingType) {
    try {
        // ......
        // Post message to start process to avoid possible deadlock of calling into AMS with the
        // ATMS lock held.
        final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
                mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
                isTop, hostingType, activity.intent.getComponent());
        mH.sendMessage(m);
    } finally {
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
}

主要通过初始化一个Message对象,并且通过AMS.H对象的sendMessage来处理这个Message消息 PooledLambda的obtainMessage函数中,会初始化一个PooledRunnable对象,并将其设置为生成的Message对象的Callback

其类图结构如下

classDiagram
PooledLambda <|-- PooledRunnable
Runnable <|-- PooledRunnable
ThrowingRunnable <|-- PooledRunnable
TraceNameSupplier <|-- PooledRunnable
<<interface>>PooledRunnable
<<interface>>PooledLambda
<<interface>>Runnable
<<interface>>ThrowingRunnable
<<interface>>TraceNameSupplier

PooledRunnable继承自Runnable是一个线程

而AMS.H的sendMessage函数,会将上述生成的Message对象添加到MessageQueue中,并且通过dispatchMessage函数分发这些Message给到AMS.H来处理

而根据Handler源码可知,当其所分发的Message包含Callback不为null的时候,会直接调用该Handler对象的handleCallback,从而直接运行这个Callback(此处为PooledRunnable对象)

从而直接调用ATMS的mAmInternal参数的startProcess函数,而mAmInternal为ActivityManagerInternal对象实例,

而ActivityManagerInternal类结构图如下

classDiagram
ActivityManagerInternal <|-- LocalService
<<abstract>> ActivityManagerInternal
<<final>> LocalService
ActivityManagerService *-- LocalService
class ActivityManagerInternal {
	+startProcess(String, ApplicationInfo, boolean, boolean, String, ComponentName)* void
}
class LocalService {
	+startProcess(String, ApplicationInfo, boolean, boolean, String, ComponentName) void
}

因此,最终会调用AMS.LocalService的startProcess函数,最终在ProcessList对象的startProcess函数中,调用Process.start函数通过zygote生成一个进程并启动

@Override
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
        boolean isTop, String hostingType, ComponentName hostingName) {
    try {
        // ......
        synchronized (ActivityManagerService.this) {
            // ......
            startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
                    new HostingRecord(hostingType, hostingName, isTop),
                    ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
                    false /* isolated */, true /* keepIfLarge */);
        }
    }
    // ......
}

final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
    return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
            hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
            keepIfLarge, null /* ABI override */, null /* entryPoint */,
            null /* entryPointArgs */, null /* crashHandler */);
}

// ....... 重载函数省略

boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
            int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
    // ......
    if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
        // ......
    } else {
        try {
            final Process.ProcessStartResult startResult = startProcess(hostingRecord,
                    entryPoint, app,
                    uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
                    requiredAbi, instructionSet, invokeWith, startTime);
            handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                    startSeq, false);
        }
        // ......
    }
}

private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
            int mountExternal, String seInfo, String requiredAbi, String instructionSet,
            String invokeWith, long startTime) {
    // ......
    startResult = Process.start(entryPoint,
            app.processName, uid, uid, gids, runtimeFlags, mountExternal,
            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
            app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
            isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,
            whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
            new String[]{PROC_START_SEQ_IDENT + app.startSeq});
    // ......
}

如此,Launcher应用进程被创建以及启动

Launcher应用进程启动流程时序图

图片.png

感想

因为个人一边工作一边分析这个流程,同时Launcher应用进程启动流程非常复杂(针对于我的个人感受),分析过程中代码分支非常多,且参数详细结果不清晰,导致不仅花费时间长,且进展缓慢,由此如下的几点真实感受分享一下

  1. 对于源码分析,分支和结构复杂的模块,需要自己添加一些日志或者调试数据协助分析,而不能想当然的认为某一个分支应该走到或者不应该走到,这样容易误入歧途
  2. 源码分析的手段需要加强,很多很有用的调试工具,如AS的DEBUG功能,源码查看工具,流程图等一些协助源码分析的工具需要加强应用
  3. 源码分析过程中,有时需要追根溯源,有时需要浏览带过,度要自己把握