自学内容网 自学内容网

Application启动流程分析一 Zygote是如何fork进程的

一个App启动另外一个App不会直接启动Application,而是启动另外一个App的MainActivity
在这里插入图片描述

应用进程启动

当System_service进程里面的ATMS检查到要启动的Activity对应的进程还没启动的时候,就会通过socket机制通知Zygote进程fork出对应的APP进程。

在这里插入图片描述

ActivityStackSupervisor类的startSpecificActivity,判断Activity对应的进程是否被启动

ActivityStackSupervisor类里面的startSpecificActivity是真正启动Activity之前执行的函数,这个函数首先判断了Activity对应的进程是否创建,创建了的话直接启动Activity,否则为app启动一个进程。

 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;
// 进程已经创建的话,直接启动activity
        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();
//进程不存在的话,为app启动一个进程
        mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
    }

真正启动进程—》ATMS的startProcessAsync怎么启动一个进程?

 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);
            }
            // Post message to start process to avoid possible deadlock of calling into AMS with the
            // ATMS lock held.
            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);
        }
    }

通过代码可以看到是通过ActivityManagerInternal的startProcess方法启动一个进程。ActivityManagerInternal是AMS里面的一个内部类,这个内部类里面有AMS大部分的服务。

 public final class LocalService extends ActivityManagerInternal

在LocalService的startProcess方法里面最后会调入到AMS的startProcessLocked方法。

    @GuardedBy("this")
    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
                hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
                keepIfLarge, null /* ABI override */, null /* entryPoint */,
                null /* entryPointArgs */, null /* crashHandler */);
    }

ProcessRecord和ProcessList

ProcessRecord记录App进程相关信息的重要类。

  • 1.ApplicationInfo info:AndroidManifest.xml中定义的Application信息
    2.boolean isolated:是不是isolated进程
    3.int uid:进程uid
    4.int userId:这个是android做的多用户系统id,就像windows可以登录很多用户一样,android 也希望可以实现类似的多用户
    5.String processName:进程名字,默认情况下是包名
    6.UidRecord uidRecord:记录已经使用的uid
    7.IApplicationThread thread:这个很重要,它是ApplicationThread的客户端,AMS就是通过这 个对象给apk进程发送异步消息的(管理四大组件的消息),所以只有这个对象不为空的情况下, 才代表apk进程可是使用了

AMS管理手机里面所有App进程,AMS如何管理这一系列的ProcessRecord?尤其是正在运行的App和对应的ProcessRecord。
会有一个ProcessList类管理所有的正在运行的进程对应的ProcessRecord。

 /**
     * List of running applications, sorted by recent usage.
     * The first entry in the list is the least recently used.
     */
     //存放正在运行的app进程对应的ProcessRecord,会通过最近的使用情况来进行排序
    final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>();// 正在运行的app进程

    /**
     * The currently running isolated processes.
     */
     //存放正在运行的隔离的进程对应的ProcessRecord
    final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>();

AMS通过持有ProcessList类,进而持有所有进程对应的ProcessRecord。
那么进程的优先级怎么去管理?通过ProcessList里面的mOomAdj 整形数组去设置进程优先级。

    // These are the various interesting memory levels that we will give to
    // the OOM killer.  Note that the OOM killer only supports 6 slots, so we
    // can't give it a different value for every possible kind of process.
    private final int[] mOomAdj = new int[] {
            FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
            PERCEPTIBLE_LOW_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_LMK_FIRST_ADJ
    };

AMS通过startProcessAsync调用到ProcessList的startProcess方法

mProcessList.startProcessLocked最后会调用到重载方法startProcessLocked通过startProcess启动进程。

@GuardedBy("mService")
    boolean startProcessLocked(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 {
                final Process.ProcessStartResult startResult = startProcess(hostingRecord,
                        entryPoint, app,
                        uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
                        requiredAbi, instructionSet, invokeWith, startTime);
                handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                        startSeq, false);
            } 
            ......
        }
    }

    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) {
            ......
            if (hostingRecord.usesWebviewZygote()) {
                //webview进程启动
                startResult = startWebView(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, app.info.packageName, app.mDisabledCompatChanges,
                        new String[]{PROC_START_SEQ_IDENT + app.startSeq});
            } else if (hostingRecord.usesAppZygote()) {
                //隔离进程启动
                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.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap,
                        false, false,
                        new String[]{PROC_START_SEQ_IDENT + app.startSeq});
            } else {
                //普通进程启动
                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.mDisabledCompatChanges, pkgDataInfoMap,
                        whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
                        new String[]{PROC_START_SEQ_IDENT + app.startSeq});
            }
            ......
            }

Process工具类通过ZygoteProcess工具类的帮助,使用socket给Zygote发送fork进程的信息

Process类只是一个java工具类,里面的都是一些static方法。

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);
    }

ZygoteProcess同样是一个工具类,里面也是static方法,专门提供给Process工具类,用于通过Zygote进程fork出App进程。ZygoteProcess的start最后会调用到attemptZygoteSendArgsAndGetResult方法,这个方法里面通过socket把进程的相关信息,名称,pid,target-sdk-version,package-name等发送给Zygote进程。

    private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
            ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
        try {
            final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
            final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;

            zygoteWriter.write(msgStr);
            zygoteWriter.flush();  // 发送 socket信号

            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            Process.ProcessStartResult result = new Process.ProcessStartResult();
            result.pid = zygoteInputStream.readInt();  // 读socket 结果
            result.usingWrapper = zygoteInputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }

            return result;
        } catch (IOException ex) {
            zygoteState.close();
            Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
                    + ex.toString());
            throw new ZygoteStartFailedEx(ex);
        }
    }

ZygoteServer收到fork进程的socket信息

我们都知道zygoteInit创建后,会创建一个ZygoteServer,然后执行runSelectLoop函数,这个函数开启一个死循环,不断的循环去接收Socket信息。如果有信息过来就fork出一个进程。

ZygoteServer收到socket信息后,真正执行fork的是在ZygoteConnection的processOneCommand函数里面

       // Fork子进程,得到一个新的pid
        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.mWhitelistedDataInfoList,
                parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
                try {
                
            if (pid == 0) {
                // in child
                zygoteServer.setForkChild();

                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;

                //处理子进程
                return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
            } else {
                // In the parent. A pid < 0 indicates a failure and will be handled in
                // handleParentProc.
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                handleParentProc(pid, serverPipeFd);
                return null;
            }
        } 

Zygote.forkAndSpecialize会返回两个结果(两个pid),Zygote进程中执行fork函数的地方只是这个进程的一部分,fork出两个进程后,这两个进程都会有一个正在执行的fork函数,两个进程会返回两个pid。如果返回的pid是0,说明是子进程在执行;大于0是Zygote进程;如果是-1则是fork失败。

Zygote进程fork出的孩子的进程后怎么处理

Zygote进程有一个socket服务器,fork出来的子进程也有一个socket服务器。这个socket服务器对于子进程来说是没用的,首先给他关掉。
其次调用ZygoteConnection里面的handleChildProc方法,这个方法会跑到ZygoteInit里面执行ZygoteInit方法。

    public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();//初始化运行环境 
        ZygoteInit.nativeZygoteInit();//启动Binder ,方法在 androidRuntime.cpp中注册(启动Binder驱动,启动Binder线程池)
        // 通过反射创建程序入口函数的 Method 对象,并返回 Runnable 对象
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    }

zygoteInit函数里面首先初始化运行环境,接着调用ZygoteInit.nativeZygoteInit,这是native方法,会通过JNI去调用到app_main.cpp的onZygoteInit方法。

 virtual void onZygoteInit()
    {
        //打开binder物理驱动,再通过mmap()映射内核的地址空间,将Binder驱动的fd赋值ProcessState对象中的变量mDriverFD,用于交互操作
        //并且设置了Binder最大线程为15
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        //创建一个新的Binder线程,不断进行talkWithDriver()
        proc->startThreadPool();
    }

其实我们ActivityThread里面的内部类ApplicationThread就是Binder线程池里面的一个线程,所以我们通过ApplicationThread去处理各种生命周期的时候,我们要通过sendMessage发送消息给主线程,通过主线程去处理。

private class ApplicationThread extends IApplicationThread.Stub

最后会执行RuntimeInit.applicationInit方法

 protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        ......
        // startClass: 如果AMS通过socket传递过来的是 ActivityThread
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }

protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;

        try {
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }

        Method m;
        try {
            // 通过反射拿到对应类的main方法的Method对象
            m = cl.getMethod("main", new Class[] { String[].class });
        }
        ......
    }

static class MethodAndArgsCaller implements Runnable {
        ......
        //调用 run 方法,执行对应类的main方法(SystemServer或者ActivityThread)
        public void run() {
            try {
                mMethod.invoke(null, new Object[] { mArgs });
            } 
            ......
    }

可以看到是通过反射去创建对应App进程的main函数。

为什么使用反射执行对应的main方法

因为Zygote进程不仅仅要创建App进程,还得创建Sysytem_service进程等,这个进程的main函数方法不一样。我们通过反射,全路径名称Zygote会通过socket通信传给我们,我们拿到全路径就可以直接统一反射创建对象,再反射执行对应的main函数。


原文地址:https://blog.csdn.net/qq_42426725/article/details/135911594

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!