【Android 14源码分析】Activity启动流程-3

news2024/11/24 17:59:09

忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。
                  
                  
                                           – 服装学院的IT男

本篇已收录于Activity短暂的一生系列
欢迎一起学习讨论Android应用开发或者WMS
V:WJB6995
Q:707409815

正文

由于篇幅原因,整个启动流程分为以下3篇进行分析:

Activity启动流程-1

Activity启动流程-2

Activity启动流程-3

本篇介绍阶段三的逻辑,这部分的分析上篇阶段二的触发点是同级的,也就是在阶段一中 TaskFragment::resumeTopActivity 触发的。
进程是怎么创建的不是当前分析的重点,所以快速过一遍流程。

1 阶段三–触发进程创建

执行pause后会执行 ActivityTaskManagerService::startProcessAsync,最后也是通过 ActivityManagerService来触发启动进程的。
看看AMS这块执行进程创建的调用流程

# ActivityTaskManagerService

    void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
            String hostingType) {
        try {
            if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "dispatchingStartProcess:"
                        + activity.processName);
            }

            // 发送消息,启动进程,调用 ActivityManagerInternal::startProcess
            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);
        }
    }

这里通过 Handler 来完成,ActivityManagerInternal::startProcess 的实现在 ActivityManagerService 的内部类 LocalService 中。

# ActivityManagerService$LocalService

        public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
                boolean isTop, String hostingType, ComponentName hostingName) {
            try {
                if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "startProcess:"
                            + processName);
                }
                synchronized (ActivityManagerService.this) {
                    // 继续调用
                    startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
                            new HostingRecord(hostingType, hostingName, isTop),
                            ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
                            false /* isolated */);
                }
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
        }
        @GuardedBy("this")
        final ProcessRecord startProcessLocked(String processName,
                ApplicationInfo info, boolean knownToBeDead, int intentFlags,
                HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
                boolean isolated) {
            return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
                    hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
                    false /* isSdkSandbox */, 0 /* sdkSandboxClientAppUid */,
                    null /* sdkSandboxClientAppPackage */,
                    null /* ABI override */, null /* entryPoint */,
                    null /* entryPointArgs */, null /* crashHandler */);
        }

流程走到 ProcessList::startProcessLocked 。

# ProcessList
    boolean startProcessLocked(......) {
                ......
                mService.mProcStartHandler.post(() -> handleProcessStart(
                    app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal,
                    requiredAbi, instructionSet, invokeWith, startSeq));     
                ......   
        }
        private void handleProcessStart(......) {
            创建一个用于启动进程的 Runnable 对象
            final Runnable startRunnable = () -> {
                try {    // 调用 startProcess 方法启动进程,并获取启动结果 ProcessStartResult
                        final Process.ProcessStartResult startResult = startProcess(app.getHostingRecord(),
                            entryPoint, app, app.getStartUid(), gids, runtimeFlags, zygotePolicyFlags,
                            mountExternal, app.getSeInfo(), requiredAbi, instructionSet, invokeWith,
                            app.getStartTime());
                         // 在锁定 ActivityManagerService 后,处理进程启动结果
                        synchronized (mService) {
                            // 更新应用的状态,如设置PID,更新生命周期状态等
                            handleProcessStartedLocked(app, startResult, startSeq);
                        }
                } catch (RuntimeException e) {
                    ......异常处理
                }
            };
            ......
        }
    
    1. 通过 ProcessList::startProcess 来启动应用进程
    1. 启动玩之后 ProcessList::handleProcessStartedLocked 会更新应用的状态,如设置PID,更新生命周期状态等

ProcessList::handleProcessStartedLocked 经过几次重载会调用下面的方法

# ProcessList
    ActivityManagerService mService = null;

    boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
                long expectedStartSeq, boolean procAttached) {
                ......
                StringBuilder buf = mStringBuilder;
                buf.append("Start proc ");
                buf.append(pid);
                buf.append(':');
                buf.append(app.processName);
                buf.append('/');
                UserHandle.formatUid(buf, app.getStartUid());
                if (app.getIsolatedEntryPoint() != null) {
                    buf.append(" [");
                    buf.append(app.getIsolatedEntryPoint());
                    buf.append("]");
                }
                buf.append(" for ");
                buf.append(app.getHostingRecord().getType());
                if (app.getHostingRecord().getName() != null) {
                    buf.append(" ");
                    buf.append(app.getHostingRecord().getName());
                }
                // 输出日志
                mService.reportUidInfoMessageLocked(TAG, buf.toString(), app.getStartUid());
                ......
        }

1.1创建进程小结

创建进行逻辑我没深入了解过,所以简单看了下调用逻辑,以 AMS::reportUidInfoMessageLocked 结束的原因是因为其会打印下面的这个创建进程的关键日志:

07-26 19:19:05.477  8737  8782 I ActivityManager: Start proc 19643:com.example.myapplication/u0a198 for next-top-activity {com.example.myapplication/com.example.myapplication.MainActivity}

经常看日志看启动了哪个进程搜的日志就是在这里打印的。

这部分的调用链如下:

ActivityTaskManagerService::startProcessAsync
    ActivityManagerService$LocalService::startProcess
        ActivityManagerService::startProcessLocked
            ProcessList::startProcessLocked
                ProcessList::handleProcessStart
                    ProcessList::startProcess                               -- 启动进程
                    ProcessList::handleProcessStartedLocked
                        ActivityManagerService::reportUidInfoMessageLocked  -- 打印日志

2. 阶段三–应用进程创建

进程创建完成后会执行 ActivityThread::main 方法,所以应用端进程创建结束的逻辑从这个方法开始分析。

2.1 应用端处理

# ActivityThread

    // ApplicationThread 是 AMS 作为 C 端时,与应用进程通信的方式
    final ApplicationThread mAppThread = new ApplicationThread();

    public static void main(String[] args) {
        ......
        // 主线程Looper
        Looper.prepareMainLooper();
        ......
        ActivityThread thread = new ActivityThread();
        // 下一步
        thread.attach(false, startSeq);
        // 主线程Looper
         Looper.loop();
    }
    private void attach(boolean system, long startSeq) {
        ......
            final IActivityManager mgr = ActivityManager.getService();
            try {
                //重点 *2. 将mAppThread告知AMS,用于AMS与应用进程通信
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        ......
    }

应用端的调用链比较简单:

ActivityThread::main
    Looper::prepareMainLooper
    ActivityThread::init
    ActivityThread::attach
        ActivityManagerService::attachApplication  -- 跨进程
    Looper::loop

应用进程(电话)创建完毕后,在 main 方法里会执行 attach 就是要将自己的信息告知AMS,毕竟 AMS 是管理模块。

2.2 system_service端处理

system_service 端 ActivityManagerService 知道有进程启动了,这个行为也可能会触发系统组显示逻辑的改变,所以比如也会做响应处理

2.1 调用链

ActivityManagerService::attachApplication
    ActivityManagerService::attachApplicationLocked
        ActivityThread::bindApplication
            ActivityTaskManagerService.LocalService::attachApplication  
                WindowContainer::forAllRootTasks  --- 省略forAllRootTasks等固定堆栈
                    Task::forAllRootTasks
                        WindowContainer::forAllActivities
                            ActivityRecord::forAllActivities
                                RootWindowContainer.AttachApplicationHelper::test
                                    RootWindowContainer.AttachApplicationHelper::test
                                        ActivityTaskSupervisor::realStartActivityLocked  -- 构建LaunchActivityItem

在这里插入图片描述
接上一篇知道如果进程启动了 ActivityTaskSupervisor::startSpecificActivity 就会走进去ActivityTaskSupervisor::realStartActivityLocked 。
但是可能会好奇怎么就知道要执行应用 MainActivity 到 onCreate 就一定是在这个方法里呢? 调试方法有很多,比如加 log ,打堆栈,但是对应这个逻辑比较简单的是,需要执行 Activity 启动到 onCreate 的控制在 LaunchActivityItem 中,而 LaunchActivityItem在 framework 的引用除了本身,就只有在 ActivityTaskSupervisor。

在这里插入图片描述

2.2 主流程

# ActivityManagerService

    // 当应用进程调用attachApplication 执行
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        if (thread == null) {
            throw new SecurityException("Invalid application interface");
        }
        synchronized (this) {
            // 获取 应用进程的信息后执行attachApplicationLocked
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            // 执行
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            Binder.restoreCallingIdentity(origId);
        }
    }

    private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
            // 需要启动应用的进程数据
            ProcessRecord app;
            ......
            if (pid != MY_PID && pid >= 0) {
                synchronized (mPidsSelfLocked) {
                    // 通过mPidsSelfLocked获取
                    app = mPidsSelfLocked.get(pid);
                }
                ......
            } 
            ...... 
            // 触发ActivityThread::bindApplication 逻辑
            if (app.getIsolatedEntryPoint() != null) {
                ......
            } else if (instr2 != null) {
                // bindApplication
                ......    
            } else {
                // 重点* 1. bindApplication
                thread.bindApplication(processName, appInfo,
                        app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
                        providerList, null, profilerInfo, null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                        new Configuration(app.getWindowProcessController().getConfiguration()),
                        app.getCompat(), getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, autofillOptions, contentCaptureOptions,
                        app.getDisabledCompatChanges(), serializedSystemFontMap,
                        app.getStartElapsedTime(), app.getStartUptime());
            }
            ......
            if (!mConstants.mEnableWaitForFinishAttachApplication) {
                // 重点* 2. 
                finishAttachApplicationInner(startSeq, callingUid, pid);
            } else {
                  app.setPendingFinishAttach(true);
            }
            ......
    }

ActivityManagerService::finishAttachApplicationInner 是 U 把原来的逻辑提取新增的方法。

# ActivityManagerService

        public ActivityTaskManagerInternal mAtmInternal;

        private void finishAttachApplicationInner(long startSeq, int uid, int pid) {
            ......
            if (normalMode) {
                try {
                    // 重点 触发构建 LaunchActivityItem 流程
                    didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
                } catch (Exception e) {
                    Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                    badApp = true;
                }
            }
            ......
        }

这里是触发 LaunchActivityItem 的流程主线, mAtmInternal是 ATMS 的内部类 LocalService 。

# ActivityTaskManagerService$LocalService

        @Override
        public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
            ......
            return mRootWindowContainer.attachApplication(wpc);
            ......
        }

流程来到 RootWindowContainer 预感要开始处理窗口显示逻辑。

# RootWindowContainer
        private final AttachApplicationHelper mAttachApplicationHelper = new AttachApplicationHelper();

        boolean attachApplication(WindowProcessController app) throws RemoteException {
            try {
                return mAttachApplicationHelper.process(app);
            } finally {
                mAttachApplicationHelper.reset();
            }
        }

# RootWindowContainer
    // 实现 Consumer 接口
    private class AttachApplicationHelper implements Consumer<Task>, Predicate<ActivityRecord> {
        ......
        boolean process(WindowProcessController app) throws RemoteException {
            mApp = app;
            for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
                // 重点* 调用每个容器的 forAllRootTasks
                getChildAt(displayNdx).forAllRootTasks(this);
                ......
            }
            ......
        }
        ......
    }

这里看到传递了“this”,所以 AttachApplicationHelper 必然实现了 Consumer 接口, 直接看其 accept 实现即可。

# RootWindowContainer$AttachApplicationHelper

  private class AttachApplicationHelper implements Consumer<Task>, Predicate<ActivityRecord> {
        ......
        boolean process(WindowProcessController app) throws RemoteException {
            mApp = app;
            for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
                // 重点*1. 调用每个容器的 forAllRootTasks
                getChildAt(displayNdx).forAllRootTasks(this);
                ......
            }
            ......
        }
        @Override
        public void accept(Task rootTask) {
            ......
            if (rootTask.getVisibility(null /* starting */)
                    == TASK_FRAGMENT_VISIBILITY_INVISIBLE) {
                // 如果Task 不可见则不需要处理
                return;
            }
            // 执行 topRunningActivity
            mTop = rootTask.topRunningActivity();
            // 重点*2. 执行accept 让容器下的每个 ActivityRecord 执行 test
            rootTask.forAllActivities(this);
        }
        @Override
        public boolean test(ActivityRecord r) {
            // 判断 ActivityRecord 是否满足需要启动条件
            if (r.finishing || !r.showToCurrentUser() || !r.visibleIgnoringKeyguard
                    || r.app != null || mApp.mUid != r.info.applicationInfo.uid
                    || !mApp.mName.equals(r.processName)) {
                return false;
            }
            try {
                // 重点*3. 执行 realStartActivityLocked  尝试实际启动 Activity
                if (mTaskSupervisor.realStartActivityLocked(r, mApp,
                        mTop == r && r.getTask().canBeResumed(r) /* andResume */,
                        true /* checkConfig */)) {
                    mHasActivityStarted = true;
                }
            } catch (RemoteException e) {
                ......
            }
            return false;
        }
  }

这部分的逻辑也就是一路执行,比较疑惑的点也许是进入 AttachApplicationHelper::proces 方法后的几个 Lambda 表达式容易绕晕。
简单梳理一下,首先是从 RootWindowContainer 开始执行的,目的就是想要执行到所有 ActivityRecord 然后判断一下它的情况是不是需要启动对应的 Activity 。

    1. AttachApplicationHelper::proces 里的 “getChildAt” 对应的是每个屏幕,也就是 DisplayContent ,然后再遍历其下的每个 RootTask ,让其执行 accept 函数
    1. AttachApplicationHelper::accept 目前是对象是 Task ,准确的说是 RootTask 。如果这个 Task 是可见的,则又开始遍历其下的所有 ActivityRecord ,让其执行 test 函数
    1. AttachApplicationHelper::test 方法是真正干活的地方,所有一堆条件判断这个 ActivityRecord 是否满足
    • r.finishing:活动是否正在结束
    • !r.showToCurrentUser() :活动是否对当前用户可见
    • !r.visibleIgnoringKeyguard :活动是否可见,即使有屏幕保护器
    • r.app != null :活动的应用程序是否已经存在
    • mApp.mUid != r.info.applicationInfo.uid :应用程序的UID是否与预期的不同
    • !mApp.mName.equals(r.processName):应用程序的名称是否与活动的进程名称不同
      感觉比较重要的就是前面3个条件,这个 ActivityRecord 是不是需要显示给用户,如果需要则执行 ActivityTaskSupervisor::realStartActivityLocked 试图启动 Activity 。

3. 阶段三总结

阶段三的流程相对来逻辑简单一些,知道个调用链就好,流程目的就是执行 ActivityTaskSupervisor::realStartActivityLocked 。

这部分的堆栈如下图:

在这里插入图片描述

加上应用端的调用链,完成调用链如下:

ActivityThread::main
    Looper::prepareMainLooper
    ActivityThread::init
    ActivityThread::attach
        ActivityManagerService::attachApplication  -- 跨进程
            ActivityManagerService::attachApplicationLocked
                ActivityThread::bindApplication
                ActivityManagerService::finishAttachApplicationInner
                    ActivityTaskManagerService$LocalService::attachApplication
                        RootWindowContainer::attachApplication
                            RootWindowContainer$AttachApplicationHelper::process -- 开始遍历
                                WindowContainer::forAllRootTasks  --- 省略forAllRootTasks等固定堆栈
                                    Task::forAllRootTasks  -- 1. 遍历所有root Task
                                        RootWindowContainer$AttachApplicationHelper::accept  -- 1.1 root Task执行accept
                                            WindowContainer::forAllActivities  -- 2. 遍历下面的所有ActivityRecord
                                                ActivityRecord::forAllActivities 
                                                    RootWindowContainer$AttachApplicationHelper::test  -- 2.1 ActivityRecord执行test
                                                        ActivityTaskSupervisor::realStartActivityLocked  -- 试图启动Activity
    Looper::loop

对应时序图:

在这里插入图片描述
大概流程图如下:

在这里插入图片描述
这一阶段主要就是应用进程启动后,试图拉起对应的 Activity ,能不能启动的条件就是没有正在 pause 的 Activity 了。
主要逻辑就是触发 ActivityTaskSupervisor::realStartActivityLocked

4. 阶段四–真正启动Activity

阶段四其实就是触发应用端创建 Activity 。

4.1 realStartActivityLocked

这个方法是要真去触发 Activity 启动的,根据前面的流程图,阶段二,三的最终就是想执行到这个方法里面,来触发 Activity 启动。

这个方法的最终目的就是通过事务执行 LaunchActivityItem 和 PauseActivityItem ,也就是会触发应用端 TargetActivity 启动,并执行生命周期到 onCreate 和 onResume 。

# ActivityTaskSupervisor 

    boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
            boolean andResume, boolean checkConfig) throws RemoteException {
            //  重点* 1. 判断是否执行完了pause 
            if (!mRootWindowContainer.allPausedActivitiesComplete()) {
                // While there are activities pausing we skipping starting any new activities until
                // pauses are complete. NOTE: that we also do this for activities that are starting in
                // the paused state because they will first be resumed then paused on the client side.
                // 如果还有Activity没完成pause,则打印日志并return
                ProtoLog.v(WM_DEBUG_STATES,
                        "realStartActivityLocked: Skipping start of r=%s some activities pausing...",
                        r);
                return false;
            }
            // 重点* 2. 表示ActivityRecord已连接到相应的进程
            r.setProcess(proc);
            ......
            // event日志: wm_restart_activity 
            EventLogTags.writeWmRestartActivity(r.mUserId, System.identityHashCode(r),
                        task.mTaskId, r.shortComponentName);
            ......
                // 重点* 3.1 创建事务,用于Activity启动
                // Create activity launch transaction.
                final ClientTransaction clientTransaction = ClientTransaction.obtain(
                        proc.getThread(), r.token);
                final boolean isTransitionForward = r.isTransitionForward();

                // 获取Activity所在 TaskFragment Token
                final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
                // 重点* 3.2 将构建的 LaunchActivityItem 添加到 clientTransaction 中
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
                        proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
                        results, newIntents, r.takeOptions(), isTransitionForward,
                        proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
                        r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));

                // 重点* 3.3 设置预期的最终状态为 ResumeActivityItem
                final ActivityLifecycleItem lifecycleItem;
                if (andResume) {
                    // Resume逻辑,启动走的这。 表示需要执行到onCreate
                    lifecycleItem = ResumeActivityItem.obtain(isTransitionForward);
                } else {
                    //  Pause 逻辑
                    lifecycleItem = PauseActivityItem.obtain();
                }
                clientTransaction.setLifecycleStateRequest(lifecycleItem);
                // 重点* 3.4 执行事务
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);
                ......
    }

根据代码的标注解释:

    1. 根据注释,如果有 Activity 正在 pause 则不允许任何 Activity 启动。换句话说就是想要启动一个 Activity 必须其他的 Activity 需要 pause 的都完成了 pause 流程
    1. 对应上一篇提到的 ActivityRecord::attachedToProcess 方法如果需要返回 true ,则必须在这里执行 setProcess 方法,否则 ActivityRecord 下的 app 变量就是 null
    1. 这里就是开始真正执行启动 Activity 的地方了,是通过事务执行的,分为以下几步
    • 3.1 构建一个事务
    • 3.2 设置 LaunchActivityItem ,这一步会将 Activity 的生命周期执行到 onCreate
    • 3.3 设置 ResumeActivityItem ,这一步会将 Activity 的生命周期执行到 onResume
    • 3.4 执行事务

后续逻辑就是在应用端执行 Activity 的创建,以及生命周期处理了,这部分本篇大概看一遍流程,以分析到 Activity 的创建为止。

4.2 创建Activity

这部分的调用链如下:

LaunchActivityItem::execute
    ActivityThread::handleLaunchActivity
        ActivityThread::performLaunchActivity
            Instrumentation::newActivity -- 创建Activity
            Activity::attach  -- 处理Window相关
                Window::init
                Window::setWindowManager
            Instrumentation::callActivityOnCreate -- onCreate流程
                Activity::performCreate
                    Activity::onCreate  --over

时序图图下:

在这里插入图片描述

接下来看 LaunchActivityItem::execute

# LaunchActivityItem 
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
                client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
                mTaskFragmentToken);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

这里的 client 是 ClientTransactionHandler 类型, 而 ActivityThread 是 ClientTransactionHandler 子类。

重点是这边创建了 ActivityClientRecord ,第一个参数就是我们要找的token

逻辑来到应用进程 ActivityThread

# ActivityThread

    public Activity handleLaunchActivity(ActivityClientRecord r,
                PendingTransactionActions pendingActions, Intent customIntent) {
                    ......
                    
                    final Activity a = performLaunchActivity(r, customIntent);
                    ......
                }

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
                Activity activity = null;
                try {
                    // 重点* 1. 通过Instrumentation 反射创建Activity
                    java.lang.ClassLoader cl = appContext.getClassLoader();
                    activity = mInstrumentation.newActivity(
                            cl, component.getClassName(), r.intent);
                    ......
                }
                try {
                    ......
                    // 重点* 2. 执行 attach 流程
                    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.activityConfigCallback,
                            r.assistToken, r.shareableActivityToken);
                    ......
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                    } else {
                        重点* 3. onCreate流程
                        mInstrumentation.callActivityOnCreate(activity, r.state);
                    }
                }
        ......
    }

这里有3个重点:

    1. Activity 是通过反射创建的。 到这里其实 Activity 启动流程基本分析完了
    1. 执行 Activity::attach 。这里会触发创建 Window
    1. 触发 Activity::onCreate

Activity 已经创建好了,那就剩下 onCreate 了。

# Instrumentation
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        prePerformCreate(activity);
        // onCreate流程
        activity.performCreate(icicle);
        postPerformCreate(activity);
    }

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

    final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        ......
        if (persistentState != null) {
            onCreate(icicle, persistentState);
        } else {
            // 执行onCreate
            onCreate(icicle);
        }
        ......
    }

写过应用的都知道,默认都是一个参数的onCreate。

至此,Activity 启动流程分析完毕。

在 ActivityTaskSupervisor::realStartActivityLocked 方法看到给事务加了个 ResumeActivityItem , 因为 LaunchActivityItem 只是创建,但是创建完成后,需要执行到对应的生命周期。

正常情况都是希望执行到onResume,所以会设置 ResumeActivityItem 。

4.3 阶段四小结

在这里插入图片描述
无论是阶段二还是阶段三触发了 ActivityTaskSupervisor::realStartActivityLocked 方法,并且还满足启动 Activity 条件,则会触发应用端进程 Activity 的创建和生命周期的执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2185829.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

后台管理系统脚手架

后台管理系统脚手架 介绍 在快速迭代的软件开发世界里&#xff0c;时间就是生产力&#xff0c;效率决定成败。对于构建复杂而庞大的后台系统而言&#xff0c;一个高效、可定制的后台脚手架&#xff08;Backend Scaffold&#xff09;无疑是开发者的得力助手。 脚手架 后台脚…

Python案例--这天第几天

如何使用Python计算一年中的第几天&#xff1a;详细指南 在处理日期和时间时&#xff0c;我们经常需要确定一个特定日期是一年中的第几天。这在许多应用场景中都非常有用&#xff0c;比如日历应用程序、数据分析和时间管理工具。Python&#xff0c;作为一种广泛使用的编程语言…

低功耗4G模组Air780E之串口通信篇

你对低功耗4G模组Air780E有多少了解&#xff1f; 今天我们来讲解低功耗4G模组Air780E的串口通信的基本用法&#xff0c;小伙伴们&#xff0c;学起来吧&#xff01; 一、硬件准备 780E开发板一套&#xff0c;包括天线、USB数据线。 USB转TTL工具或线&#xff08;例如ch340、…

用CSS创造三角形案例

6.3.2 用CSS创造三角形 用div来创建&#xff0c;角上是平分的&#xff0c;所以要是内部宽高为0&#xff0c;其他边透明&#xff0c;正好是三角形。 代码 div {border: 12px solid;width: 0;height: 0;border-color: transparent red transparent transparent; } 与伪元素aft…

基于SSM的校园社团管理系统的设计 社团信息管理 智慧社团管理社团预约系统 社团活动管理 社团人员管理 在线社团管理社团资源管理(源码+定制+文档)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

【rCore OS 开源操作系统】Rust 字符串(可变字符串String与字符串切片str)

【rCore OS 开源操作系统】Rust 语法详解: Strings 前言 这次涉及到的题目相对来说比较有深度&#xff0c;涉及到 Rust 新手们容易困惑的点。 这一次在直接开始做题之前&#xff0c;先来学习下字符串相关的知识。 Rust 的字符串 Rust中“字符串”这个概念涉及多种类型&…

Pikachu-xss实验案例-钓鱼

攻击思路&#xff1a;提供一个与攻击网站相似的登陆的钓鱼页面&#xff1b;让用户输入登陆信息 查看项目源代码&#xff0c;首先访问 fish.php ,提供输入的登陆框&#xff0c; 从登陆框获取到账号、密码后&#xff0c;重定向到xfish.php 做保存&#xff1b; 因此&#xff0c;需…

遥感图像变换检测实践上手(TensorRT+UNet)

目录 简介 分析PyTorch示例 onnx模型转engine 编写TensorRT推理代码 main.cpp测试代码 小结 简介 这里通过TensorRTUNet&#xff0c;在Linux下实现对遥感图像的变化检测&#xff0c;示例如下&#xff1a; 可以先拉去代码&#xff1a;RemoteChangeDetection 分析PyTorch示…

C++基类构造器的自动调用

C基类构造器的自动调用 虽然基类的构造器和解构器不会被派生类继承&#xff0c;但它们会被派生类的构造器和解构器自动调用&#xff0c;今天我们用代码实证一下。 验证代码 源代码&#xff0c;仔细看注释内容&#xff1a; D:\YcjWork\CppTour>vim c2004.cpp #include &l…

特征工程与选择:优化模型性能的关键步骤----示例:特征工程在泰坦尼克号生存预测中的应用、使用递归特征消除(RFE)进行特征选择

特征工程和特征选择是机器学习流程中至关重要的环节&#xff0c;直接影响到模型的性能。特征工程涉及从原始数据中提取或构造有用的特征&#xff0c;而特征选择则是从已有的特征集中挑选出最相关的子集。 特征工程 特征工程是指创建能够使机器学习算法更好地理解数据的新特征的…

平面电磁波(解麦克斯韦方程)

注意无源代表你立方程那个点xyzt处没有源&#xff0c;电场磁场也是这个点的。 j电流面密度&#xff0c;电流除以单位面积&#xff0c;ρ电荷体密度&#xff0c;电荷除以单位体积。 j方程组有16个未知数&#xff0c;每个矢量有三个xyz分量&#xff0c;即三个未知数&#xff0c;…

样式重置 normalize.css

安装normalize.css npm install --save normalize.csspnpm add normalize.css安装less yarn add less -Dmain.ts import { createApp } from vue import App from ./App.vue // 引入 import normalize.csscreateApp(App).mount(#app)index.less import less中的语法 imp…

JDBC 概述

JDBC 概述 JDBC的基本概念与功能JDBC的工作原理JDBC的组件与类JDBC的类型与特性JDBC的应用场景 JDBC&#xff08;Java Database Connectivity&#xff09;即Java数据库连接&#xff0c;是Java编程语言用于与数据库进行连接和操作的API&#xff08;应用程序编程接口&#xff09;…

K8s域名解析方案CoreDNS(K8s Domain Name Resolution Solution CoreDNS)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

MFC工控项目实例二十一型号选择界面删除参数按钮禁用切换

承接专栏《MFC工控项目实例二十手动测试界面模拟量输入实时显示》 对于禁止使用的删除、参数按钮&#xff0c;在选中列表控件选项时切换为能够使用。 1、在TypDlg.h文件中添加代码 #include "ShadeButtonST.h" #include "BtnST.h" class CTypDlg : publi…

(C语言贪吃蛇)9.贪吃蛇撞墙找死

目录 游戏说明​ 1.撞墙死翘翘的情况 2.如何解决初始化问题 封装函数initSnake(); 注意事项 解决方法 总结 效果演示 游戏说明 玩家通过上下左右按键来控制小蛇的移动&#xff0c;我们之前的内容完成了小蛇每按下一次右键小蛇便向右移动一格&#xff0c;但是玩贪吃蛇一…

(笔记)第三期书生·浦语大模型实战营(十一卷王场)--书生入门岛通关第2关Python 基础知识

学员闯关手册&#xff1a;https://aicarrier.feishu.cn/wiki/ZcgkwqteZi9s4ZkYr0Gcayg1n1g?open_in_browsertrue 课程视频&#xff1a;https://www.bilibili.com/video/BV1mS421X7h4/ 课程文档&#xff1a;https://github.com/InternLM/Tutorial/tree/camp3/docs/L0/Python 关…

某度假村定岗定编项目成功案例纪实

某度假村定岗定编项目成功案例纪实 引入分级定编系统&#xff0c;将个人工资和度假村当日绩效总额挂钩&#xff0c;解决忙闲不均带来的人工成本问题 【客户行业】文旅行业、酒店行业、度假村 【问题类型】定岗定编 【客户背景】 某度假村是一家集住宿、娱乐、健身等服务为…

【Nacos架构 原理】内核设计之Nacos寻址机制

文章目录 前提设计内部实现单机寻址文件寻址地址服务器寻址 前提 对于集群模式&#xff0c;集群内的每个Nacos成员都需要相互通信。因此这就带来一个问题&#xff0c;该以何种方式去管理集群内部的Nacos成员节点信息&#xff0c;即Nacos内部的寻址机制。 设计 要能够感知到节…

MybatisPlus代码生成器的使用

在使用MybatisPlus以后&#xff0c;基础的Mapper、Service、PO代码相对固定&#xff0c;重复编写也比较麻烦。因此MybatisPlus官方提供了代码生成器根据数据库表结构生成PO、Mapper、Service等相关代码。只不过代码生成器同样要编码使用&#xff0c;也很麻烦。 这里推荐大家使…