likes
comments
collection
share

一文搞定面试 | Activity启动流程之冷热启动(下)

作者站长头像
站长
· 阅读数 13

Activity启动流程由于篇幅较长,将分述两篇文章进行讲解。

上文主要进行概念提要和流程综述,下文主要从源码角度逐步探寻流程经过

一图看懂

在上一篇中,已经大致将流程从概念上进行梳理了一遍,在结尾中给出了这么一张图,那么本文将从源码角度还原这张图的全部流程和细节。本文基于Android 31源码进行解析

一文搞定面试 | Activity启动流程之冷热启动(下)

图片取自 # Android Application 启动流程分析及其源码调用探究

源码深入

startActivity的起点

对于Launcher点击应用图标来说,也是startActivity的调用。最终均通过Instrumentation这个工具类,向AMS发起startActivity的Binder通信行为

// Activity.java
public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}

startActivity
    >>>startActivityForResult(这里有很多分支,但最终都会走下一路径)
        >>>Instrumentation.execStartActivity

// Instrumentation.java
public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    // ……
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    // ……
    // 注意下面的ActivityTaskManager.getService()
    // 这里即相当于调用了AMS的startActivity()
    // 同时关注下第一个参数,whoThread,传入的是IApplicationThread对象,而这个来源于Activity对应的ActivityThread里的mAppThread
    // 也就是应用进程创建之初创建的主线程,而IApplicationThread是Stub,即Binder的服务端
    // 这里留个心眼,后面有呼应
    int result = ActivityTaskManager.getService().startActivity(whoThread,
            who.getOpPackageName(), who.getAttributionTag(), intent,
            intent.resolveTypeIfNeeded(who.getContentResolver()), token,
            target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
    // ……
}

public static IActivityTaskManager getService() {
    return IActivityTaskManagerSingleton.get();
}

@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
        new Singleton<IActivityTaskManager>() {
            @Override
            protected IActivityTaskManager create() {
                // 这里从ServiceManager中获取到了ACTIVITY_TASK_SERVICE即AMS的Binder对象,并最终将其包装成Proxy返回供外部调用
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                return IActivityTaskManager.Stub.asInterface(b);
            }
        };

AMS创建Activity环节

AMS中的startActivity目前均交由ActivityTaskManagerService进行代理,当前已进入System Server进程,在该流程return前,Client即发起startActivity的应用进程均处于挂起状态

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

ActivityTaskManagerService.startActivity() >>> startActivityAsUser()
        >>> ActivityStarter.execute() >>> executeRequest() >>> startActivityUnchecked() >>> startActivityInner()
            >>> RootWindowContainer.resumeFocusedTasksTopActivities()
                >>> Task.resumeTopActivityUncheckedLocked() >>> resumeTopActivityInnerLocked()
                    >>> ActivityTaskSupervisor.startSpecificActivity()
        
// ActivityStarter.java 
// 这个类的含义很好理解,启动器嘛
private int executeRequest(Request request) {
    // ……这个方法内可以看到 确定Intent和flag应如何转换为活动以及相关的任务和堆栈
    // r是新build出来的ActivityRecord对象
    startActivityUnchecked(r, sourceRecord, voiceSession,
            request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
            restrictedBgActivity, intentGrants);
}

// ActivityTaskSupervisor.java
// 这是之前提到过的大管家
void startSpecificActivity(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()) {
        // 热启动和暖启动流程,最后会一起提到,先不讲,先继续看冷启动fork进程
        try {
            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;
    }

    r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
    // 冷启动,创建应用进程
    final boolean isTop = andResume && r.isTopRunningActivity();
    // 这一块关于socket是如何发送的,待补充
    mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}

Zygote孵化应用进程

Zygote的主要职责就是孵化进程,其中包括管理AMS的System Server进程也由它进行孵化。通信采用Soceket Server持续监听。新的子应用进程孵化完成后,将会反射调用ActivityThread.main()

// ZygoteInit.java
// Zygote进程启动类
public static void main(String[] argv) {
    caller = zygoteServer.runSelectLoop(abiList);
}

// ZygoteServer.java
// Zygote Socket服务端
Runnable runSelectLoop(String abiList) {
    while (true) {
        // connect就是AMS Client发起的连接请求
        try {
            ZygoteConnection connection = peers.get(pollIndex);
            final Runnable command =
                    connection.processCommand(this, multipleForksOK);
        } catch (Exception e) {
            // 这里贴一段官方注释,注意processCommand将会执行ActivityThread的main方法
            // We're in the child so any exception caught here has happened post
            // fork and before we execute ActivityThread.main (or any other
            // main() method). Log the details of the exception and bring down
            // the process.
        }
    }
}

// ZygoteConnection.java
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
    // 我们的目的是为了看进程fork,所以找关键词:进程号pid
    // 这里Zygote完成了子进程fork创建
    // 然后根据该方法内的注释,我们又关注到了handleChildProc()
    pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
            parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
            parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
            fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
            parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
            parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
            parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
            parsedArgs.mBindMountAppStorageDirs);
    // ……
    return handleChildProc(parsedArgs, childPipeFd,
            parsedArgs.mStartChildZygote);
}

private Runnable handleChildProc(ZygoteArguments parsedArgs,
        FileDescriptor pipeFd, boolean isZygote) {
    // 由于需要fork子进程,所以isZygote为true,走childZygoteInit
    if (!isZygote) {
        return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                parsedArgs.mDisabledCompatChanges,
                parsedArgs.mRemainingArgs, null /* classLoader */);
    } else {
        // 这里的调用链就很简单了,就反射执行main方法,而class对象上面的注释里就提到了,是ActivityThread
        // 至于这块逻辑怎么就确认是ActivityThread,我解释不了hh
        return ZygoteInit.childZygoteInit(
                parsedArgs.mRemainingArgs  /* classLoader */);
    }
}

应用进程创建后

应用进程创建后,被反射执行了ActivityThread.main(),内容比较少,主体流程就是将自身ActivityThread实例attach给AMS

// ActivityThread.java
public static void main(String[] args) {
    // 关于looper的内容就不多阐述了,对handler这块想要了解的就去翻下我前面的文章叭
    Looper.prepareMainLooper();
    
    // 这里就要开始绑定了
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

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

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }
    Looper.loop();

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

private void attach(boolean system, long startSeq) {
    if (!system) {
        // 因为传进来的是false,所以走这里
        final IActivityManager mgr = ActivityManager.getService();
        try {
            // 那这个老生常谈了,那就是去AMS看下文喽
            // 所以当AMS完成attach后,该线程才会唤醒,去执行之后的loop()
            // 前面startActivity中调用AMS时,传入了同样的参数类型:IApplicationThread
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
}

应用进程向AMS发起请求时,通过ServiceManager得到AMS注册的Binder从而得到Proxy代理类,而AMS需要向应用进程发起调度时,则通过作为服务端时接受的IApplicationThread对象以进行工作 一文搞定面试 | Activity启动流程之冷热启动(下) 那不如看看IApplicationThread能做些什么吧?在ActivityThread中,mAppThread是ApplicationThread

// ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
    // 由于里面的方法大同小异,随意选取一个眼熟的,四大组件之一的Service
    // sendMessage通过外部类ActivityThread发送handler消息,最终会回调执行Service.onCreate()
    // 那把其他方法大致可以扫一眼,四大组件的一些处理皆需要通过这里发起
    // 那发起的客户端应该就是AMS了,所以为什么说AMS是四大组件的集中管理者
    public final void scheduleCreateService(IBinder token,
            ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
        updateProcessState(processState, false);
        CreateServiceData s = new CreateServiceData();
        s.token = token;
        s.info = info;
        s.compatInfo = compatInfo;

        sendMessage(H.CREATE_SERVICE, s);
    }
}

// handleMessage
case CREATE_SERVICE:
    if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                ("serviceCreate: " + String.valueOf(msg.obj)));
    }
    handleCreateService((CreateServiceData)msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;

AMS绑定应用进程

AMS完成了Application创建后,通知ActivityThread进行生命周期回调

ActivityManagerService.attachApplication() >>> attachApplicationLocked() // 这里对ProcessRecord进行了一些状态设置……
    >>> IApplicationThread.bindApplication() // 这里又回去了,不用解释了吧,在ActivityThread里发送对应的handler消息
        >>> ActivityThread.handleBindApplication() 
            // 这里就接近尾声了,完成了application的创建,onCreate这块是在主线程,所以注意尽可能避免耗时操作
            >>> makeApplication() + mInstrumentation.callApplicationOnCreate

是不是觉得哪里不对劲?Activity还没启动呢!想一想一件事,Binder的挂机机制,回到AMS中调用bindApplication的后面

// ActivityManagerService.java
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
    // ……
    thread.bindApplication()
    // ……
    // 这个时候,Application已经完成了onCreate()
    // 一开始我也找了好久,很多文章中也没有提到这一茬,直到我仔细看了官方注释
    // See if the top visible activity is waiting to run in this process...
    if (normalMode) {
        try {
            // attachApplication全局搜了下只剩下RootWindowContainer里还有了,去看看吧
            // 当然喔,这里只是我的想法,但是他们的方法名、入参、返回值一模一样,我也就不多想了
            didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }
}

// RootWindowContainer
boolean attachApplication(WindowProcessController app) throws RemoteException {
    // 看来看去,startActivityForAttachedApplicationIfNeeded这个最顺眼
    final PooledFunction c = PooledLambda.obtainFunction(
            RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
            PooledLambda.__(ActivityRecord.class), app,
            rootTask.topRunningActivity());
    rootTask.forAllActivities(c);
    c.recycle();
}

private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
        WindowProcessController app, ActivityRecord top) {
    // realStartActivityLocked这个方法熟不熟悉
    if (mTaskSupervisor.realStartActivityLocked(r, app,
            top == r && r.isFocusable() /*andResume*/, true /*checkConfig*/)) {
        mTmpBoolean = true;
    }
}

如果你忘了realStartActivityLocked在哪见过的话,我帮你回忆回忆。现在想起来了嘛

// ActivityTaskSupervisor.java
void startSpecificActivity(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 {
            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;
    }

    r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
    // 冷启动,创建应用进程
    final boolean isTop = andResume && r.isTopRunningActivity();
    // 这一块关于socket是如何发送的,待补充
    mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}

Activity最终启动

对于这块的调用链,不同版本源码可能有所不同,但最终都将通过ActivityThread.performLaunchActivity或类似方法名展开。当然这里举例的是冷启动状态下,Activity处于ON_CREATE阶段的情况,如果是热启动的话,只需要快速进行状态恢复就好了

ActivityTaskSupervisor.realStartActivityLocked()
    >>> ClientLifecycleManager.scheduleTransaction() 
        >>> ClientTransaction.schedule()
            >>> IApplicationThread.scheduleTransaction()
                // 这里在ActivityThread里没找到对应的方法,在其父类中找到
                >>> ActivityThread:ClientTransactionHandler.scheduleTransaction() // 发送了EXECUTE_TRANSACTION
                    >>> TransactionExecutor.execute() >>> executeCallbacks() >>> cycleToPath() >>> performLifecycleSequence()
                        // 这次是父类引用,子类实现了
                        // 当然这里是根据lifecycle生命周期变化调度对应方法,热启动就不需要launchActivity了
                        >>> ActivityThread:ClientTransactionHandler.handleLaunchActivity()
                            >>> ActivityThread.performLaunchActivity()
                                // 包括其他生命周期分发也都能看到
                                >>> Instrumentation.callActivityOnCreate()
                                    >>> Activity.performCreate()

现在再来对比一下这张图,有所区别的就是14.1和14.2的方法名,但整体调用链却是一模一样。对于Activity启动的整体流程,无论是冷启动还是热启动,可以不用过于关注细节的方法调用链,应该关心如图几个具有关键职能的类之间的调度流转。

在厘清这个之后,再回头去过一遍源码细节,相信你会有所收获

灵魂发问

暂无,等待大佬们提供面试问题……欢迎评论

拜读

第一篇主攻源码流程,第二篇主攻概念及思路解析,两篇的阅读顺序可以不一定,但结合起来,非常有助于理解

# Android Application 启动流程分析及其源码调用探究

如果觉得本文对你有帮助,不妨 点赞+收藏+关注 支持一波,感谢肯定和青睐

当然,更希望初读点赞再读收藏三而关注