Android源码阅读:AMS启动新进程(二)

215 阅读9分钟

本文基于android-13.0.0_r1,源码参考: cs.android.com/android/pla…

四、ProcessList#startProcess

startProcess函数整体有systrace追踪(可在systrace搜索"Start proc:"),该函数内容较多,可以根据checkSlow判断都做了什么事情。
根据checkSlow,这个函数的内容是请求zygote启动进程,并且结束时zygote已返回结果。
注意checkSlow带的字符串代表“正要做的事情”

    private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
            int mountExternal, String seInfo, String requiredAbi, String instructionSet,
            String invokeWith, long startTime) {
        try {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkSlow(startTime, "startProcess: asking zygote to start proc");

            // ...这里内容好多先跳过
            
            final Process.ProcessStartResult startResult;
            boolean regularZygote = false;
            if (hostingRecord.usesWebviewZygote()) {
                // 第一种类型:webview Zygote
                startResult = startWebView(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, app.info.packageName,
                        app.getDisabledCompatChanges(),
                        new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
            } else if (hostingRecord.usesAppZygote()) {
                // 第二种类型:App Zygote
                final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);

                // We can't isolate app data and storage data as parent zygote already did that.
                startResult = appZygote.getProcess().start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, app.info.packageName,
                        /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
                        app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap,
                        false, false,
                        new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
            } else {
                // 第三种类型:常规 Zygote
                regularZygote = true;
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
                        isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap,
                        allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
                        new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
            }
            // ...
            checkSlow(startTime, "startProcess: returned from zygote!");
            return startResult;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }

最后这部分根据webview Zygote、App Zygote、常规 Zygote进行启动,没有仔细看区别。
按照常规Zygote的话,请求Zygote启动进程就是在Process.start中做的。

前面的entryPoint是"android.app.ActivityThread",这里作为第一个参数processClass传入,作为进程的入口类。
frameworks/base/core/java/android/os/Process.java

    /**
     * State associated with the zygote process.
     * @hide
     */
    public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();

    public static ProcessStartResult start(@NonNull final String processClass,
                                           @Nullable final String niceName,
                                           int uid, int gid, @Nullable int[] gids,
                                           int runtimeFlags,
                                           int mountExternal,
                                           int targetSdkVersion,
                                           @Nullable String seInfo,
                                           @NonNull String abi,
                                           @Nullable String instructionSet,
                                           @Nullable String appDataDir,
                                           @Nullable String invokeWith,
                                           @Nullable String packageName,
                                           int zygotePolicyFlags,
                                           boolean isTopApp,
                                           @Nullable long[] disabledCompatChanges,
                                           @Nullable Map<String, Pair<String, Long>>
                                                   pkgDataInfoMap,
                                           @Nullable Map<String, Pair<String, Long>>
                                                   whitelistedDataInfoMap,
                                           boolean bindMountAppsData,
                                           boolean bindMountAppStorageDirs,
                                           @Nullable String[] zygoteArgs) {
        return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, packageName,
                    zygotePolicyFlags, isTopApp, disabledCompatChanges,
                    pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
                    bindMountAppStorageDirs, zygoteArgs);
    }

后续是继续请求zygote启动新的进程,新的进程将会执行ActivityThread的静态main函数。

五、ProcessList#handleProcessStartedLocked

上接三,在startProcess中请求zygote启动新的进程后,调用handleProcessStartedLocked
打印am_proc_start、ActivityManager: Start proc两个log,以及更新ProcessRecord都在这个函数中进行。

    @GuardedBy("mService")
    boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
            long expectedStartSeq, boolean procAttached) {
        mPendingStarts.remove(expectedStartSeq);
        final String reason = isProcStartValidLocked(app, expectedStartSeq);
        if (reason != null) {
            // 从expectedStartSeq判断启动不符合预期,静默查杀启动的进程,返回false
            Slog.w(TAG_PROCESSES, app + " start not valid, killing pid=" +
                    pid
                    + ", " + reason);
            app.setPendingStart(false);
            killProcessQuiet(pid);
            Process.killProcessGroup(app.uid, app.getPid());
            noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
                    ApplicationExitInfo.SUBREASON_INVALID_START, reason);
            return false;
        }
        mService.mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
        checkSlow(app.getStartTime(), "startProcess: done updating battery stats");

        // 打印am_proc_start的event log
        // 分别是:UserID、pid、Uid、processName、hostingType、hostingName(正在启动的进程的组件)
        // am_proc_start: [0,29705,10283,com.taobao.taobao,next-top-activity,{com.taobao.taobao/com.taobao.tao.welcome.Welcome}]
        EventLog.writeEvent(EventLogTags.AM_PROC_START,
                UserHandle.getUserId(app.getStartUid()), pid, app.getStartUid(),
                app.processName, app.getHostingRecord().getType(),
                app.getHostingRecord().getName() != null ? app.getHostingRecord().getName() : "");

        try {
            // PKMS:将进程启动信息(包括基本 APK 哈希)记录到安全日志中。
            AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.info.packageName,
                    app.processName, app.uid, app.getSeInfo(), app.info.sourceDir, pid);
        } catch (RemoteException ex) {
            // Ignore
        }

        Watchdog.getInstance().processStarted(app.processName, pid);

        // 打印 ActivityManager: Start proc 日志
        // ActivityManager: Start proc 9113:com.taobao.taobao/u0a211 for next-top-activity {com.taobao.taobao/com.taobao.tao.welcome.Welcome}
        checkSlow(app.getStartTime(), "startProcess: building log message");
        StringBuilder buf = mStringBuilder;
        buf.setLength(0);
        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());

        // 设置pid
        synchronized (mProcLock) {
            app.setPid(pid);
            app.setUsingWrapper(usingWrapper);
            app.setPendingStart(false);
        }
        checkSlow(app.getStartTime(), "startProcess: starting to update pids map");
        ProcessRecord oldApp;
        synchronized (mService.mPidsSelfLocked) {
            oldApp = mService.mPidsSelfLocked.get(pid);
        }
        // If there is already an app occupying that pid that hasn't been cleaned up
        // 是否已经有一个ProcessRecord占用了这个pid,但还没被清理
        if (oldApp != null && !app.isolated) {
            // Clean up anything relating to this pid first
            // 先清理与这个pid有关的任何东西
            Slog.wtf(TAG, "handleProcessStartedLocked process:" + app.processName
                    + " startSeq:" + app.getStartSeq()
                    + " pid:" + pid
                    + " belongs to another existing app:" + oldApp.processName
                    + " startSeq:" + oldApp.getStartSeq());
            mService.cleanUpApplicationRecordLocked(oldApp, pid, false, false, -1,
                    true /*replacingPid*/, false /* fromBinderDied */);
        }

        // 把 ProcessRecord 放进map中
        mService.addPidLocked(app);
        synchronized (mService.mPidsSelfLocked) {
            if (!procAttached) {
                // 看了下在startProcessLocked中同步和异步启动进程时,都是直接传进来false
                Message msg = mService.mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                msg.obj = app;
                mService.mHandler.sendMessageDelayed(msg, usingWrapper
                        ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
            }
        }
        checkSlow(app.getStartTime(), "startProcess: done updating pids map");
        return true;
    }

六、新进程执行的ActivityThread.main和attach

6.1 main静态函数和请求attach

main静态函数中最主要的就是实例化ActivityThread,并调用attach函数,attach中主要是通过Binder调用AMS的attachApplication
frameworks/base/core/java/android/app/ActivityThread.java

    final ApplicationThread mAppThread = new ApplicationThread();

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        // ...

        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
        // It will be in the format "seq=114"
        // 如果命令行上提供了 PROC_START_SEQ_IDENT 的值,请查找该值。 格式为“seq=114”
        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,调用attach
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

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

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        // 完成之后开始loop,等待执行msg
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    
    @UnsupportedAppUsage
    private void attach(boolean system, long startSeq) {
        if (!system) {
            final IActivityManager mgr = ActivityManager.getService();
            try {
                // 通过binder调用到AMS的attachApplication
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        } else {
            // ...
        }
    }

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    @Override
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        if (thread == null) {
            throw new SecurityException("Invalid application interface");
        }
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            Binder.restoreCallingIdentity(origId);
        }
    }

新进程通过Binder在AMS的线程中调用attachApplication,获取发起端也就是新进程的Pid、Uid等,加AMS锁继续调用attachApplicationLocked
attachApplicationLocked函数内容比较多,分三部分,分别是bindApplication之前、bindApplication、和bindApplication之后

6.2 attach第一部分:bindApplication之前

主要是针对ProcessRecord做得操作,注意这里和AMS启动进程时的ProcessRecord操作不一样,这里是进程已经启动,通过Binder调用AMS的attach,AMS此时只知道发起端的pid等信息。

    @GuardedBy("this")
    private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {

        // Find the application record that is being attached...  either via
        // the pid if we are running in multiple processes, or just pull the
        // next app record if we are emulating process with anonymous threads.
        // 查找正在被attach的application record(怀疑这里其实指的是ProcessRecord)..
        // 如果我们在多个进程中运行,则通过 pid,
        // 或者如果我们 使用匿名线程模拟进程,则仅提取下一个app record。
        ProcessRecord app;
        long startTime = SystemClock.uptimeMillis();
        long bindApplicationTimeMillis;
        if (pid != MY_PID && pid >= 0) {
            // 上面说还有“匿名线程模拟进程”的情况,这里按新进程启动的话,肯定是pid != MY_PID
            synchronized (mPidsSelfLocked) {
                app = mPidsSelfLocked.get(pid);
            }
            // ...看不懂省略
        } else {
            app = null;
        }
        
        // It's possible that process called attachApplication before we got a chance to
        // update the internal state.
        // 有可能 在我们有机会更新内部状态之前,进程已经调用了 attachApplication。
        if (app == null && startSeq > 0) {
            // ...没细看
        }

        // 这里发现app还是空的话,就开始杀进程了,因为身份未知
        if (app == null) {
            // ...killProcessQuiet
            return false;
        }

        // If this application record is still attached to a previous
        // process, clean it up now.
        // 如果application  record(ProcessRecord)仍然绑定到之前的进程,就现在清理掉
        if (app.getThread() != null) {
            handleAppDiedLocked(app, pid, true, true, false /* fromBinderDied */);
        }

        // 打印 am_proc_bound 日志,通常紧跟在am_proc_start之后
        // 类似 am_proc_bound: [0,29702,com.taobao.taobao]
        EventLogTags.writeAmProcBound(app.userId, pid, app.processName);

        synchronized (mProcLock) {
            // 设置一些初始状态,包括adj等
            app.mState.setCurAdj(ProcessList.INVALID_ADJ);
            app.mState.setSetAdj(ProcessList.INVALID_ADJ);
            // ....
        }

        // 超时监测的msg,在ProcessList#handleProcessStartedLocked发出来的
        // 即与zygote通信完成后发出,到新进程请求AMS attach时结束
        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

        // bindApplication前的准备工作完成,主要是针对ProcessRecord app,
        // 从 mPidsSelfLocked 中根据pid获取app,然后做一系列初始化
        checkTime(startTime, "attachApplicationLocked: before bindApplication");

6.3 attach第二部分:bindApplication

这部分主要是用传进来的ApplicationThread进行bindApplication,ApplicationThread可以看前面ActivityThread,是其中的一个内部类,用来和新进程Binder通信的。
有点绕,其实就是新进程起来后,通过Binder调用到AMS进行attach,而AMS又通过Binder调用到新进程进行bindApplication

        // ...
        try {
            // 前面这段干啥的看不懂
            checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
            
            if (app.getIsolatedEntryPoint() != null) {
                // This is an isolated process which should just call an entry point instead of
                // being bound to an application.
                // 这是一个isolated进程,它应该只调用一个entry point而不是绑定到一个app。
                // 这里可以看出isolated进程的含义,isolated进程不会绑定到app
                thread.runIsolatedEntryPoint(
                        app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
            } else if (instr2 != null) {
                thread.bindApplication(processName, appInfo,/*...*/);
            } else {
                thread.bindApplication(processName, appInfo,/*...*/);

            // Make app active after binding application or client may be running requests (e.g
            // starting activities) before it is ready.
            // 绑定后使ProcessRecord处于活跃状态,或者客户端可能在准备就绪之前运行请求(例如启动activity)。
            synchronized (mProcLock) {
                app.makeActive(thread, mProcessStats);
                checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
            }
            
            // 更新LRU队列
            updateLruProcessLocked(app, false, null);
            checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
            final long now = SystemClock.uptimeMillis();
            synchronized (mAppProfiler.mProfilerLock) {
                app.mProfile.setLastRequestedGc(now);
                app.mProfile.setLastLowMemory(now);
            }
        } catch (Exception e) {
            // ...
        }

ApplicationThread在ActivityThread中,可以看到bindApplication实际是异步地发送BIND_APPLICATION的msg,不过注意的是,虽然发送并没有带延时,但是此时还处于新进程的attach阶段,attach完成之后才开始loop接收消息,所以真正的接收BIND_APPLICATION消息开始执行还得等一会儿。
frameworks/base/core/java/android/app/ActivityThread.java

    private class ApplicationThread extends IApplicationThread.Stub {
        // ...
        
        @Override
        public final void bindApplication(String processName, ApplicationInfo appInfo,/*...*/) {
            // ...
            sendMessage(H.BIND_APPLICATION, data);
        }

现在知道attach中所谓的bindApplication只是Binder调用回新进程发了个消息,继续看attach后续做的事情吧

6.4 attach第三部分:bindApplication之后

回到AMS的attachApplicationLocked,bindApplication之后依次检查是否有新的activity、service等要在这个进程上运行。比如有应用的activity需要在这个进程上运行,那么AMS就需要通知到WMS,mAtmInternal就是wm下面的ATMS,调用ATMS的attachApplication,接下来就属于activity启动的范畴了。

        boolean badApp = false;
        boolean didSomething = false;

        // See if the top visible activity is waiting to run in this process...
        // 康康 顶部可见activity 是否正在等待要在此进程中运行...
        if (normalMode) {
            try {
                // mAtmInternal是ATMS,调用mRootWindowContainer.attachApplication
                didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }

        // Find any services that should be running in this process...
        // 查找 应在此进程中运行的 任何service...
        if (!badApp) {
            try {
                didSomething |= mServices.attachApplicationLocked(app, processName);
                checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
                badApp = true;
            }
        }

        // Check if a next-broadcast receiver is in this process...
        // 检查下一个广播接收者是否在此过程中...
        if (!badApp && isPendingBroadcastProcessLocked(pid)) {
            // ...
        }
        
        // ...
        
        if (badApp) {
            app.killLocked("error during init", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
                    true);
            handleAppDiedLocked(app, pid, false, true, false /* fromBinderDied */);
            return false;
        }

        if (!didSomething) {
            // 什么都没做时,调整到process begin级别的adj
            updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
            checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
        }
        
        return true;
    }

用badApp和didSomething两个布尔变量记录是否出错、是否做了什么事情(activity、service等),最后attach结束。

七、ActivityThread#handleBindApplication

六中讲到main函数中做了attach后开始loop,而attach中AMS通过Binder调用回新进程发送了一个BIND_APPLICATION的msg

    class H extends Handler {
        public static final int BIND_APPLICATION        = 110;
        // ...
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                // ...其他的case

            }
        }
    }

新进程的Handler接收到BIND_APPLICATION消息,在systrace追踪中进行handleBindApplication
handleBindApplication中的内容非常多,看不懂,systrace中看主要耗时的是makeApplication和app.onCreate

        if (ii != null) {
            initInstrumentation(ii, data, appContext);
        } else {
            mInstrumentation = new Instrumentation();
            mInstrumentation.basicInit(this);
        }

            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            catch (Exception e) {
                // ...
            }
            try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                // ...
            }

大概到这里新的进程就启动完成了,Looper开始接收消息并执行。