分析Activity启动过程

时间:2021-09-11 16:25:40

Android6.0

Activity启动的过程

本质上,apk只是一个资源包,所以我们说的,启动app,启动activity,启动server的主要执行者都是system_server。以activity的启动为例子,有几个步骤

system_server process

1,ActivityManagerService.startActivity

向AMS(ActivityManagerService)发起startActivity/Intent
不管是从桌面点击lunch,还是用脚本敲入am start,还是应用内或者应用间的Intent

@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
    enforceNotIsolatedCaller("startActivity");
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
            false, ALLOW_FULL_ONLY, "startActivity", null);
    // TODO: Switch to user app stacks here.
    return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, options, false, userId, null, null);
}

system_server process

2,ActivityStackSupervisor.startSpecificActivity

ActivityStackSupervisor会从AppGlobals.getPackageManager().activitySupportsIntent查询启动的Activity的信息,这里会检查启动者(caller)的权限信息,caller在这里很重要。

ActivityStackSupervisor中持有了许多ActivityDisplay ,它的数据结构很有意思,有几个信息,显示设备,还有ActivityStack。ActivityDisplay是什么东西呢,我觉得是分了一层,方便多物理屏幕的扩展。

int mDisplayId;
Display mDisplay;
DisplayInfo mDisplayInfo = new DisplayInfo();
final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
ActivityRecord mVisibleBehindActivity;

ActivityStack就是我们通常说的Activity栈,还记得几种启动模式吗?就是这个feature。ActivityStack会和Window、Process相关联,所以这里要独立出来成为一个对象。

接上一步的说,startActivityMayWait会handle到ActivityStack中,ActivityStack继续发起
ActivityStackSupervisor.startSpecificActivityLocked

ActivityStackSupervisor中通过AMS.getProcessRecordLocked 已经知道当前有没有Application存在。


如果不存在 system_server

3.1 AMS.startProcessLocked

Process.ProcessStartResult startResult = Process.start(...);

所以java层/system_server的创建进程就是在Process中。Process发指令给zygote的

zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);

argsForZygote就是新建进程的一堆指令,通过socket,把这些参数传递给zygote。为什么要这么麻烦的弄一个zygote呢?一个是它是创世者,所以android上层封装都是它的子进程。另外一个是有一个统一的初始化的地方,可以控制进程属性/能力。为什么用socket呢?是为了最大程度的解耦合。

java层的ZygoteInit.java是这样的

public static void main(String argv[]) {
    ...
    startSystemServer(abiList, socketName);
    ...

    runSelectLoop(abiList);
    closeServerSocket();
}

看到有个 runSelectLoop 就是在这里等socket发过来的新建指令

ZygoteConnection.runOnce
ZygoteConnection.handleChildProc
RuntimeInit.zygoteInit
RuntimeInit.applicationInit
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
    ...
    // Remaining arguments are passed to the start class's static main
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

这个时候就新建了一个进程,然后反射执行了ActivityThread中的main方法(invokeStaticMain)。这时候再继续走callActivity的流程。


如果存在 user process

3.2 ActivityStackSupervisor.realStartActivityLocked

调用到ActivityStackSupervisor.realStartActivityLocked
注意的是,进程优先级的概念就是在这里给proc下的一个节点赋的值。在这里通过binder跨进程,跨完之后在
ActivityThread.ApplicationThread.scheduleLaunchActivity

看ActivityThread的代码可以发现

final ApplicationThread mAppThread

mAppThread是ActivityThread的内部类&&成员变量,那么他们再不在一个进程呢?当然是在的,这就是我们ps出来看到的包名的进程。这里应该叫process更好一点。单进程,和线程几乎没一点点关系。

这个时候打开Activity的信息就被Handle到H中去处理

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

r.packageInfo = getPackageInfoNoCheck(
        r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

Trace.traceBegin、Trace.traceEnd是两个钩子,留作性能分析用。所以到了ActivityThread就两个步骤:
一个是解析资源getPackageInfoNoCheck,加载类,大部分的动态补丁和什么多开就是去hook
getPackageInfoNoCheck相关的方法
二是handleLaunchActivity 准备好窗口。performLaunchActivity,一个重点是这里会把appContext挂到Activity中,之后就是喜闻乐见的onCreate

分析Activity启动过程