捋一捋 Android 启动应用进程的前因后果

捋一捋 Android 启动应用进程的前因后果,第1张

概述点击桌面应用图标后前面(Android进阶解密阅读笔记2)已经知道启动应用程序进程是由AMS向zygote进程发起申请,后面由zygote进程监听处理。但一般场景下,用户只有点了桌面应用图标才会打开应用,可见AMS也是收到了某种响应才会发起申请。在Android进阶解密阅读笔记3中 点击桌面应用图标后

前面(Android 进阶解密阅读笔记2)已经知道启动应用程序进程是由 AMS 向 zygote 进程发起申请,后面由 zygote 进程监听处理。但一般场景下,用户只有点了桌面应用图标才会打开应用,可见 AMS 也是收到了某种响应才会发起申请。在 Android 进阶解密阅读笔记3 中我们知道启动根 Activity 最终会走到 ActivityStackSupervisor 的 startSpecificActivityLocked 方法,而这个方法中的逻辑也包含着启动应用进程,这就是比 AMS 发起创建应用进程请求更早的地方。(以下代码基于 API 28)

voID startSpecificActivityLocked(ActivityRecord r,boolean andResume, boolean checkConfig) {    ProcessRecord app = mService.getProcessRecordLocked(r.processname, r.info.applicationInfo.uID, true);    //省略...    if(app != null && app.thread != null) {        //省略...        realStartActivityLocked(r, app, andResume, checkConfig);        return;    }    mService.startProcessLocked(r.processname,r.info.applicationInfo, true, 0,"activity", r.intent.getComponent(), false, false,true);}

大致可见,AMS 根据应用进程的一些信息去获取 ProcessRecord。如果启动根 Activity 时,发现 app 为 null 的话就会调用 AMS 启动应用进程。那在应用进程启动后并调用 ActivityThread 的 main,这个 main 具体又做了什么呢?

ActivityThread 的 main 方法做了什么
public static voID main(String[] args) {    //简单来说 main 方法里创建了主线程的消息循环    Looper.prepareMainLooper();    //另外一件事就在这里    ActivityThread thread = new ActivityThread();    thread.attach(false, startSeq);        if(sMainThreadHandler == null) {        sMainThreadHandler = thread.getHandler();    }        Looper.loop();}private voID attach(boolean system, long startSeq) {    final IActivityManager mgr = ActivityManager.getService();    try {        //通过 AMS 代理类去绑定应用        mgr.attachApplication(mAppThread, startSeq);    } catch(remoteexception ex) {        throw ex.rethorwFromSystemServer();    }}

在 AMS 做了一些逻辑后,又会交还给 ActivityThread 的内部类 ApplicationThread 来处理。

public final voID bindApplication(...) {    //通过消息机制,发送 BIND_APPliCATION 的消息交给 mH 处理    AppBindData data = new AppBindData();    data.processname = processname;    data.appInfo = appInfo;    data.provIDers = provIDers;    data.instrumentationname = instrumentationname;    //省略部分...    sendMessage(H.BIND_APPliCATION, data);}

通过消息机制,最终会交给 ActivityThread 对象去调用 handleBindApplication 方法,这里为什么通过消息机制呢?我想是不是做到了进程切换,即进程间通信。由 AMS 所在的 SystemServer 进程进入了应用进程。「不是很肯定,后面再查资料证实」

handleBindApplication 方法很大,这里只了解大致逻辑。1.加载 InstrumentationInfo,注释说会影响 class loader,要事先加载。2.生成 ApplicationInfo, LoadedApk 用于创建 ContextImpl 对象实例,而这个实例用于创建 class loader。前面加载的 InstrumentationInfo 用在了 ApplicationInfo 的创建。3.接着用 class loader 加载 Instrumentation 对象实例,并做 init *** 作。4.通过 LoadedApk 对象间接创建 Application 对象,实际上是调用了 ActivityThread 对象的 mInstrumentation 对象的 newApplication 方法。5.再往下调用了 mInstrumentation 对象的 callApplicationOnCreate 方法,此时也就触发了 Application 对象的 onCreate 方法

创建 Application
//LoadedApkpublic Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {    ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);    app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);}//Instrumentationpublic Application newApplication(ClassLoader cl, String classname, Context context) {    Application app = getFactory(context.getPackagename()).instantiateApplication(cl, classname);    //这里传入的 context 就是 Application 调用 *getBaseContext* 获取到的 mBase     app.attach(context);    return app;}
小结

到这我们理清楚了三个东西,1.启动应用进程时最初的出发点就是 Launcher 响应用户点击应用图标的 *** 作。2.Application 在何时创建,并何时调用了 onCreate 方法。3.Application 类是继承自 Contextwrapper 的,其方法 getBaseContext 的 mBase 对象实例是何时实现赋值的。

不过还有一点还没理清楚,就是我们最终是想打开应用的,目前由于应用进程没启动,我们去启动应用进程了,那根 Activity 怎么继续启动呢?

再回到启动应用进程
//AMSfinal ProcessRecord startProcessLocked(...太多了,省略...) {    ProcessRecord app;    if(!isolated) {        //方法内通过应用进程名称从 mProcessnames 这个 ProcessMap 结构中获取 app        //按当前情况应该获取不到返回 null        app = getProcessRecordLocked(processname, info.uID, keepIfLarge);    }        if(app == null) {        //创建新的 ProcessRecord 对象        app = newProcessRecordLocked(info, processname, isolated, isolatedUID);    }    //开始启动应用进程   	final boolean success = startProcessLocked(app, hostingType, hostingnameStr, abiOverrIDe);    return success ? app : null;}final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess, boolean isolated, int isolatedUID) {    final ProcessRecord r = new ProcessRecord(this, stats, info, proc, uID);    //这里是将新建的 ProcessRecord 保存起来    addProcessnameLocked(r);    return r;}private final voID addProcessnameLocked(ProcessRecord proc) {    //保险起见,先从缓存里做移除 *** 作,正常来说是没有的    ProcessRecord old = removeProcessnameLocked(proc.processname, proc.uID);    // UIDRecord 存着进程 UID 相关信息    UIDRecord uIDRec = mActiveUIDs.get(proc.uID);    if(uIDRec == null) {        uIDRec = new UIDRecord(proc.uID);        mActiveUIDs.put(proc.uID, uIDRec);    }    proc.uIDRecord = uIDRec;    //把新建的 processRecord 存起来    mProcessnames.put(proc.processname, proc.uID, proc);    if(proc.isolated) {        mIsolatedProcesses.put(proc.uID, proc);    }}//中间还会再调一层 startProcessLocked 方法,接着就到下面的方法了private final boolean startProcessLocked(ProcessRecord app, String hostingType,String hostingnameStr, boolean disableHIDdenAPIChecks, String abiOverrIDe) {    if(app.pID > 0 && app.pID != MY_PID) {        synchronized(mPIDsSelfLocked) {            //mPIDsSelfLocked 这个东西类似 mProcessnames 是个集合用来维护进程            //这里做了移除,可见后面应该会有添加            mPIDsSelfLocked.remove(app.pID);        }    }    //这里继续启动应用进程    return startProcessLocked(hostingType, hostingnameStr, entryPoint, app, uID, gIDs, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime);}private boolean startProcessLocked(String hostingType, String hostingnameStr, String entryPoint,ProcessRecord app, int uID, int[] gIDs, int runtimeFlags, int mountExternal,String seInfo, String requiredAbi, String instructionSet, String invokeWith,long startTime) {    //这里会继续启动应用进程,并返回启动结果    final ProcessstartResult startResult = startProcess(app.hostingType, entryPoint,app, app.startUID, gIDs, runtimeFlags, mountExternal, app.seInfo,requiredAbi, instructionSet, invokeWith, app.startTime);    synchronized(ActivityManagerService.this) {        //看下这个启动结果怎么处理        handleProcessstartedLocked(app, startResult, startSeq);    }}private boolean handleProcessstartedLocked(ProcessRecord pending,            ProcessstartResult startResult, long expectedStartSeq) {    //再进一层看看    return handleProcessstartedLocked(pending, startResult.pID,                    startResult.usingWrapper,expectedStartSeq, false);}private boolean handleProcessstartedLocked(ProcessRecord app, int pID, boolean usingWrapper,long expectedStartSeq, boolean procAttached) {    ProcessRecord oldApp;    synchronized(mPIDsSelfLocked) {        //这里类似之前的 *** 作,取出已有的做清除 *** 作,但这种情况一般是没有的        oldApp = mPIDsSelfLocked.get(pID);    }    synchronized(mPIDsSelfLocked) {        //关键的一句,终于看见它把新建的 processRecord 存进去了        this.mPIDsSelfLocked.put(pID, app);    }}

为什么要关注 mPIDsSelfLocked 呢,后面就会知道了。
来看应用进程启动后执行 ActivityThread 对象实例的 attach 方法

//AMS//最后又来到了 AMS 里private final boolean attachApplicationLocked(IApplicationThread thread,            int pID, int callingUID, long startSeq) {    ProcessRecord app;    //因为 AMS 是在 SystemServer 进程创建的,所以 pID != 当前进程ID    if(pID != MY_PID && pID > 0) {        synchronized(mPIDsSelfLocked) {            //这里就是之前启动应用进程时存起来的 processRecord,            //这么一来 app 不就有值了么             app = mPIDsSelfLocked.get(pID);        }    }    //这里就会去调用 ApplicationThread 的方法,其实就是用消息机制处理    thread.bindApplication(...);        if(normalMode) {        try{            //这里就是看看是否有 Activity 等待启动            //显然我们启动应用进程就是因为要启动 Activity            if(mStackSupervisor.attachApplicationLocked(app)) {                dIDSomething = true;            }        }    }    if(!badApp) {        try {            //这里粗看起来是用来启动 Service 服务的            dIDSomething |= mServices.attachApplicationLocked(app, processname);        }    }    if(!badApp && isPendingbroadcastProcessLocked(pID)) {        try {            //这里用来启动广播            dIDSomething |= sendPendingbroadcastsLocked(app);        }    }}//ActivityStackSupervisorboolean attachApplicationLocked(ProcessRecord app) {    final ActivityRecord top = stack.topRunningActivityLocked();    final int size = mTmpActivityList.size();    for (int i = 0; i < size; i++) {        final ActivityRecord activity = mTmpActivityList.get(i);        if (activity.app == null && app.uID == activity.info.applicationInfo.uID             && processname.equals(activity.processname)) {            try {                //这个不就是启动 Activity 的最终方法么                if(realStartActivityLocked(activity, app, top == activity, true)) {                    dIDSomething = true;                }            }        }    }    return dIDSomething;}

这么看来,应用进程启动后,会通过事先保存的 ProcessRecord 继续启动之前想要启动的 Activity 的。并且这也解释了,Application 的 onCreate 方法会先于 Activity 的 onCreate 执行。

参考文章
Android应用程序启动过程源代码分析

总结

以上是内存溢出为你收集整理的捋一捋 Android 启动应用进程的前因后果全部内容,希望文章能够帮你解决捋一捋 Android 启动应用进程的前因后果所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1051199.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存