Android Framework- Activity启动2

写在最前面

juejin.cn/post/740445...

这篇文章写了一年有余,我前几天哥们问启动流程的时候 。 我信誓旦旦这玩意简单,张口就来。然后嗯啊了半天,什么也没说出来,丢了个大的。 进入了张无忌学太极拳的境界,我已经全部忘记了。

所以要理解去记。 带几个疑问去看代码,才能真的记下来,不要死记方法,知道核心点就行。

梳理问题

  • 系统是怎么判断进程是否存在的?
  • 那系统是怎么启动一个新的进程的?
  • 系统启动进程后,是怎么把我们要的Activity拉起来的?

问题梳理

系统是怎么判断进程是否存在的?

让我们梦回ActivityTaskSupervisorstartSpecificActivity()

js 复制代码
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;
        // Remove the process record so it won't be considered as alive.
        mService.mProcessNames.remove(wpc.mName, wpc.mUid);
        mService.mProcessMap.remove(wpc.getPid());
        
        
        //省略部分代码
        
        
mService.startProcessAsync(r, knownToBeDead, isTop,
        isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY
                : HostingRecord.HOSTING_TYPE_ACTIVITY);

    }

我们可以看到 有一句注释 Is this activity's application already running? 其实很简单 就是去 ATMS 根据processNameuid 去查一下,你的wpc 是否存在 并且你的 ApplicationThread 也存在,就证明你的进程是存在的。 就可以直接启动对应页面。然后 return

总结一下

看看进程对应的WindowProcessControllerApplicationThread 是否存在。

那系统是怎么启动一个新的进程的?

我们看到上面代码部分有 调用到 mService.startProcessAsync 这里一路调用下去 会进入ZygoteProcessopenZygoteSocketIfNeeded 然后调用到 attemptConnectionToPrimaryZygote();

java 复制代码
@GuardedBy("mLock")
private void attemptConnectionToPrimaryZygote() throws IOException {
    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        primaryZygoteState =
                ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);

        maybeSetApiDenylistExemptions(primaryZygoteState, false);
        maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
    }
}

这里不要记代码,就知道最后搞了个socket进行了通信。 我们这里要知道和哪里进行了通信。 其实这个是在ZygoteInitmain 方法里

java 复制代码
zygoteServer = new ZygoteServer(isPrimaryZygote);


if (startSystemServer) {
    Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
    // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
    // child (system_server) process.
    if (r != null) {
        r.run();
        return;
    }
}


// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);

这里 的zygoteServer.runSelectLoop(abiList) 上面注释 意思就是等待一个字进程来fork 在这里面。不贴代码了,这里主要是根据连接过来的的句柄,然后进行返回一个 Runnable,咱们简单理解就是你socket 一连,这边发现多一个,嘿, 帮你构建一个Runnable 返回回去。

java 复制代码
final Runnable command =
        connection.processCommand(this, multipleForksOK);
      
if (mIsForkChild) {
    // We're in the child. We should always have a command to run at
    // this stage if processCommand hasn't called "exec".
    if (command == null) {
        throw new IllegalStateException("command == null");
    }

    return command;
}
java 复制代码
//ZygoteConnection
Runnable result = Zygote.forkSimpleApps(argBuffer,
        zygoteServer.getZygoteSocketFileDescriptor(),
        peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName);

最后调用到 RunTimeInit.applicationInit(),其实就构建了 反射调用 ActivityThreadmain 方法的一个Runnable 并传入了 参数 "seq=42",这里的42并不是固定值,我只是演示用。 最后返回 Runnable 被执行,反射启动了ActivityThread

总结一下。

在启动 SystemSerVer的时候,启动了一个死循环,等待Socket的连接, 当我们启动Activity 发现进程没启动的时候,会构建Socket 和这里链接,反射构建了ActivityThreadmain 方法并传入了参数 seq=x。 其实到这里还没有解决第三个问题,怎么启动的Activity,我们放到第三个问题里回答。

系统启动进程后 是怎么把我们要的Activity拉起来的?

ActivityThreadmain 方法部分解析

java 复制代码
//ActivityThread

final ApplicationThread mAppThread = new ApplicationThread();

public static final String PROC_START_SEQ_IDENT = "seq=";
public static vodi  main(String[] args){
//省略部分代码。。。
long startSeq = 0;
if (args != null) {
    for (int i = args.length - 1; i >= 0; --i) {
        if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
            startSeq = Long.parseLong(
                    args[i].substring(PROC_START_SEQ_IDENT.length()));
        }
    }
}

ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
//省略部分代码。。。

//调用到attachApplication 
attachApplication(mAppThread, startSeq);

}

其实上面代码就是把seq 进行了获取,比如我们拿到了42,然后调用 ActivityThreadattch 方法。 调用到了AMSattachApplication 方法 ,继续调用到了 attachApplicationLocked, 注意 在ActivityThread 里面的 ApplicationThread 是直接构建出来的 ,后面直接作为参数传到了AMS

java 复制代码
//AMS
 private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {

     
        ProcessRecord app;
      //省略。。
      
   
   //seq的使用
if (app == null && startSeq > 0) {
    final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq);
    if (pending != null && pending.getStartUid() == callingUid
            && pending.getStartSeq() == startSeq
            && mProcessList.handleProcessStartedLocked(pending, pid,
                pending.isUsingWrapper(), startSeq, true)) {
        app = pending;
    }
}


 //省略。。

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 (normalMode) {
    try {
        didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
    } catch (Exception e) {
        Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
        badApp = true;
    }
}

}

这里可以根据传入的thread 也就是 我们从ActivityThread ,调用了bindApplication ,回到了ActivitThread ,最终回调了 handleBindApplication(data); 开始了Application的构建。这里不展开拓展。但是这里要看到 AMSApp之间的交互 ,依赖于ApplicationThread

到这里是Application的构建,那我们要启动的Activity 去哪里了?

其实是在 mAtmInternal.attachApplication 方法里。注意他的参数是app.getWindowProcessController()。 也就是我们之前说如何判断app进程是否存在的抓手。 然后调用到 mRootWindowContainer.attachApplication(wpc); 继续调用RootWindowContainer 内部的, AttachApplicationHelperprocess 方法。 process 方法会调用到他自己的 test方法 。该方法里调用到了mTaskSupervisor.realStartActivityLocked() 方法。 这里我们就很熟悉了,然后就是熟悉的构建 ActivityLifecycleItem mService.getLifecycleManager().scheduleTransaction(clientTransaction); 推进生命周期,触发对应Activity的生命周期 ,这里不浪费篇幅。

总结一下

Application 构建以后,会进入 RootWindowContainer 它通过遍历任务栈、筛选符合条件的 Activity,并构建LifeItem进行页面生命周期启动。

相关推荐
米豆同学4 小时前
SystemUI plugin 开发
android
lichong9515 小时前
【混合开发】vue+Android、iPhone、鸿蒙、win、macOS、Linux之video 的各种状态和生命周期调用说明
android·vue.js·macos
app出海创收老李6 小时前
海外独立创收日记(1)-我是如何从0到1在Google Play获得睡后被动收入的?
android·程序员
lang9998886 小时前
kodi在Android4.0.4安装播放歌曲显示歌词
android·kodi·歌词插件
yzx9910136 小时前
构建未来:深度学习、嵌入式与安卓开发的融合创新之路
android·人工智能·深度学习
前行的小黑炭6 小时前
Android :如何快速让布局适配手机和平板?
android·java·kotlin
Yang-Never10 小时前
Kotlin协程 -> Job.join() 完整流程图与核心源码分析
android·开发语言·kotlin·android studio
一笑的小酒馆16 小时前
Android性能优化之截屏时黑屏卡顿问题
android
懒人村杂货铺19 小时前
Android BLE 扫描完整实战
android