解析Android中Zygote进程是如何fork一个APP进程的

版权声明:本文为博主原创文章,转载请标明出处 https://blog.csdn.net/qq_30993595/article/details/82747738

前言

创建一个线程大家肯定非常熟悉了,继承Thread,实现Runnable接口或者Callable接口;但是线程没有独立的地址空间,而是与所在进程共享内存,其实从Linux角度看,进程线程都是一个task_struct结构体,除了是否共享资源外,并没有其他本质的区别。

但是创建进程可能就没有那么熟悉了,每个APP可能运行在一个进程,也可能在多个进程,这些进程拥有自己独立的资源;然而这些进程都是由Zygote进程fork出来的,再往前一步其实是system server进程使用LocalSocket去通知zygote进程,然后zygote去fork一个子进程,也就是APP进程(更往前一步就是APP进程使用Binder机制去通知system server进程中的ActivityManagerService),注意这里是子进程,不是子线程

强烈推荐

在接下来的讲述中会涉及到system server进程和zygote进程的操作,对于这两个进程不了解的强烈推荐先看下Android系统启动流程概述 init进程启动 zygote进程启动 system server进程启动

进程创建流程

  1. 不管从桌面启动应用还是应用内启动其它应用,如果这个应用所在进程不存在的话,都需要发起进程通过Binder机制告诉system server进程的AMS
  2. system server进程的AMS调用Process.start()方法,通过socket向zygote进程发送创建新进程的请求
  3. 在zygote进程的ZygoteInit.main方法中,有一个runSelectLoop循环体,通过acceptCommandPeer方法获取链接过来的客户端,再通过runOnce方法去创建进程
  4. 新的进程执行handleChildProc方法,最后通过反射调用ActivityThread.main()方法,这样一个新的APP进程就创建完成了

APP启动第三方应用

startActivity

当你在桌面启动一个应用或者在一个APP内启动一个应用,本质都是一样的,因为Android手机桌面其实就是一个APP(这点可参考Android之Activity启动流程源码深入解析),两种方式经过层层调用之后都会走到ActivityStackSupervisor.startSpecificActivityLocked方法,判断如果对方进程不存在,就需要去创建一个进程

startService

调用startService启动一个服务,该方法经过层层调用最终会走到ActiveServices.bringUpServiceLocked方法,如果判断对方进程不存在也会去创建一个新进程

sendBroadcast

调用sendBroadcast方法去发送一个广播,经过层层调用后走到BroadcastQueue.processNextBroadcast方法,也会判断BroadcastReceiver所在进程不存在就需要去创建进程

ContentResolver.query

在ContentProvider的处理过程中,ContentResolver.query方法经过层层调用会走到ActivityManagerService.getContentProviderImpl方法,判断ContentProvider所在的进程不存在就会创建新进程


System Server请求创建进程

以下叙述中ActivityManagerService同意简称为AMS

以下源码基于API24

上述四种途径最终都会走到如下方法

AMS.startProcessLocked

final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
                hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
                null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
                null /* crashHandler */);
}
    
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
            boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
            String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
        long startTime = SystemClock.elapsedRealtime();
        ProcessRecord app;
        //不处于孤立进程
        if (!isolated) {
        	//根据进程名和进程uid获取进程对应的ProcessRecord
        	//ProcessRecord封装了正在运行的进程的完整信息
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            checkTime(startTime, "startProcess: after getProcessRecord");

            if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
                // 如果当前进程处于后台进程,就判断是否在Bad进程列表
                if (mAppErrors.isBadProcessLocked(info)) {
                    return null;
                }
            } else {
                // 如果用户明确启动该进程,则清除其crash计数,保证其不处于Bad进程列表,直到下次再弹出crash框
                mAppErrors.resetProcessCrashTimeLocked(info);
                if (mAppErrors.isBadProcessLocked(info)) {
                    EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
                            UserHandle.getUserId(info.uid), info.uid,
                            info.processName);
                    mAppErrors.clearBadProcessLocked(info);
                    if (app != null) {
                        app.bad = false;
                    }
                }
            }
        } else {
            // 如果是孤立进程,就没办法重用已存在的进程
            app = null;
        }

		......

		//当ProcessRecord已经存在;
		//并且调用者不认为进程已经死亡,或者没有thread对象依附到该进程,这样我们就知道他不会crash;
		//该进程已经分配了pid,说明它正在启动或正在运行
		//这些情况下我们不需要做什么,直接返回
        if (app != null && app.pid > 0) {
            if ((!knownToBeDead && !app.killed) || app.thread == null) {
                //我们已经启动了这个app,或者正在等待它启动(分配了pid但是没有thread依附),就keep it
                // 如果这是该进程中的一个新的package,那就添加到package列表
                app.addPackage(info.packageName, info.versionCode, mProcessStats);
                checkTime(startTime, "startProcess: done, added package to proc");
                return app;
            }

            // 如果ProcessRecord已经attach到先前的进程,那就清除它
            checkTime(startTime, "startProcess: bad proc running, killing");
            killProcessGroup(app.uid, app.pid);
            handleAppDiedLocked(app, true, true);
            checkTime(startTime, "startProcess: done killing old proc");
        }

        String hostingNameStr = hostingName != null
                ? hostingName.flattenToShortString() : null;

        if (app == null) {
            checkTime(startTime, "startProcess: creating new process record");
            // 创建新的Process Record对象
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
            if (app == null) {
                return null;
            }
            app.crashHandler = crashHandler;
            checkTime(startTime, "startProcess: done creating new process record");
        } else {
            // 如果这是该进程中的一个新的package,那就添加到package列表
            app.addPackage(info.packageName, info.versionCode, mProcessStats);
            checkTime(startTime, "startProcess: added package to existing proc");
        }

        // 如果系统还没有准备就绪,那就暂停该进程启动,将当前进程加入到mProcessesOnHold,直到准备就绪
        if (!mProcessesReady
                && !isAllowedWhileBooting(info)
                && !allowWhileBooting) {
            if (!mProcessesOnHold.contains(app)) {
                mProcessesOnHold.add(app);
            }
            if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
                    "System not ready, putting on hold: " + app);
            checkTime(startTime, "startProcess: returning with proc on hold");
            return app;
        }

        checkTime(startTime, "startProcess: stepping in to startProcess");
        startProcessLocked(
                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
        checkTime(startTime, "startProcess: done starting proc!");
        return (app.pid != 0) ? app : null;
}

经过上面重重判断后决定需要创建进程,继续走到startProcessLocked方法,这个方法在AMS里有4个重载的方法

其中的hostingType参数有”activity”,”service”,”broadcast”,”content provider”四个值
hostingNameStr数据类型为ComponentName,封装了组件的包名和自己的路径

继续调用AMS.startProcessLocked

private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        long startTime = SystemClock.elapsedRealtime();
        //当app的pid大于0且不是当前进程的pid,则从mPidsSelfLocked中移除该app.pid
        if (app.pid > 0 && app.pid != MY_PID) {
            checkTime(startTime, "startProcess: removing from pids map");
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.remove(app.pid);
                mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
            }
            checkTime(startTime, "startProcess: done removing from pids map");
            app.setPid(0);
        }

        //从mProcessesOnHold移除该app
        mProcessesOnHold.remove(app);

        checkTime(startTime, "startProcess: starting to update cpu stats");
        updateCpuStats();
        checkTime(startTime, "startProcess: done updating cpu stats");

        try {
            try {
                final int userId = UserHandle.getUserId(app.uid);
                AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
                //当前package已被冻结,则抛出异常
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }

            int uid = app.uid;
            int[] gids = null;
            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
            if (!app.isolated) {
                int[] permGids = null;
                try {
                    checkTime(startTime, "startProcess: getting gids from package manager");
                    //通过Package Manager获取gids
                    final IPackageManager pm = AppGlobals.getPackageManager();
                    permGids = pm.getPackageGids(app.info.packageName,
                            MATCH_DEBUG_TRIAGED_MISSING, app.userId);
                    MountServiceInternal mountServiceInternal = LocalServices.getService(
                            MountServiceInternal.class);
                    mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
                            app.info.packageName);
                } catch (RemoteException e) {
                    throw e.rethrowAsRuntimeException();
                }

      
                 //添加APP和配置文件GID,以便app可以共享某些资源
                if (ArrayUtils.isEmpty(permGids)) {
                    gids = new int[2];
                } else {
                    gids = new int[permGids.length + 2];
                    System.arraycopy(permGids, 0, gids, 2, permGids.length);
                }
                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
            }
            checkTime(startTime, "startProcess: building args");
            
            ......

            app.gids = gids;
            app.requiredAbi = requiredAbi;
            app.instructionSet = instructionSet;
            
			......
						
            // 请求zygote创建进程,成功后会返回新进程的pid,否则会抛出异常
            //ProcessStartResult是Process内部类,封装了启动进程的结果
            //这是一个阻塞过程
            Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);
            checkTime(startTime, "startProcess: returned from zygote!");
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

            ......
            
            //重置ProcessRecord的成员变量
            app.setPid(startResult.pid);
            app.usingWrapper = startResult.usingWrapper;
            app.removed = false;
            app.killed = false;
            app.killedByAm = false;
            checkTime(startTime, "startProcess: starting to update pids map");
            
            synchronized (mPidsSelfLocked) {
                ProcessRecord oldApp;
                // 如果已经有一个app占用了这个尚未清理的pid
                if ((oldApp = mPidsSelfLocked.get(startResult.pid)) != null && !app.isolated) {
                    // 清理与此pid相关联的内容   
                    cleanUpApplicationRecordLocked(oldApp, false, false, -1,
                            true /*replacingPid*/);
                }
                //将新创建的进程添加到mPidsSelfLocked
                this.mPidsSelfLocked.put(startResult.pid, app);
                if (isActivityProcess) {
                    Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                    msg.obj = app;
                    mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                            ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
                }
            }
            checkTime(startTime, "startProcess: done updating pids map");
        } catch (RuntimeException e) {
            // 创建进程失败了,一个常见的情况是由于主动升级导致包被冻结
            forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
                    false, true, false, false, UserHandle.getUserId(app.userId), "start failure");
        }
    }

这个方法中最重要的就是通过Process.start来创建应用进程;原理是通过socket向Zygote进程发送创建新进程的请求;Zygote进程启动后有一个runSelectLoop循环,当收到客户端请求便会执行ZygoteConnection.runOnce()方法,再经过层层调用后fork出新的应用进程,创建新进程后将ActivityThread类加载到新进程,并调用ActivityThread.main()方法

Process.start

//开启一个新的进程
    public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }

Process.startViaZygote

	//通过zygote机制启动新进程
    private static ProcessStartResult startViaZygote(final String processClass,
                                  final String niceName,
                                  final int uid, final int gid,
                                  final int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] extraArgs)
                                  throws ZygoteStartFailedEx {
        synchronized(Process.class) {
            ArrayList<String> argsForZygote = new ArrayList<String>();

            // 主要工作是生成argsForZygote数组,该数组保存了进程的uid、gid、groups、target-sdk、nice-name等一系列的参数
            argsForZygote.add("--runtime-args");
            argsForZygote.add("--setuid=" + uid);
            argsForZygote.add("--setgid=" + gid);
            if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
                argsForZygote.add("--enable-jni-logging");
            }
            if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
                argsForZygote.add("--enable-safemode");
            }
            if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
                argsForZygote.add("--enable-debugger");
            }
            if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
                argsForZygote.add("--enable-checkjni");
            }
            if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0) {
                argsForZygote.add("--generate-debug-info");
            }
            if ((debugFlags & Zygote.DEBUG_ALWAYS_JIT) != 0) {
                argsForZygote.add("--always-jit");
            }
            if ((debugFlags & Zygote.DEBUG_NATIVE_DEBUGGABLE) != 0) {
                argsForZygote.add("--native-debuggable");
            }
            if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
                argsForZygote.add("--enable-assert");
            }
            if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
                argsForZygote.add("--mount-external-default");
            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
                argsForZygote.add("--mount-external-read");
            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
                argsForZygote.add("--mount-external-write");
            }
            argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

            //TODO optionally enable debuger
            //argsForZygote.add("--enable-debugger");

            // --setgroups is a comma-separated list
            if (gids != null && gids.length > 0) {
                StringBuilder sb = new StringBuilder();
                sb.append("--setgroups=");

                int sz = gids.length;
                for (int i = 0; i < sz; i++) {
                    if (i != 0) {
                        sb.append(',');
                    }
                    sb.append(gids[i]);
                }

                argsForZygote.add(sb.toString());
            }

            if (niceName != null) {
                argsForZygote.add("--nice-name=" + niceName);
            }

            if (seInfo != null) {
                argsForZygote.add("--seinfo=" + seInfo);
            }

            if (instructionSet != null) {
                argsForZygote.add("--instruction-set=" + instructionSet);
            }

            if (appDataDir != null) {
                argsForZygote.add("--app-data-dir=" + appDataDir);
            }

            argsForZygote.add(processClass);

            if (extraArgs != null) {
                for (String arg : extraArgs) {
                    argsForZygote.add(arg);
                }
            }

            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

Process.zygoteSendArgsAndGetResult

private static ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            // 如果参数格式错误,就尽早抛出异常.
            int sz = args.size();
            for (int i = 0; i < sz; i++) {
                if (args.get(i).indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
                }
            }

            /**
             * 这里就是通过输出流将参数列表写出去
             * 获取输入流得到创建进程结果
             */
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;

            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }

            writer.flush();

            // 等待socket返回,这里是否需要设置超时时间,google也在考虑,但是暂时没有加
            ProcessStartResult result = new ProcessStartResult();
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();

            if (result.pid < 0) {
	            //创建进程失败,抛出异常
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }

这个方法作用就是通过Socket向zygote进程发送一个参数列表,然后就进入阻塞状态,直到远程Socket服务端返回新创建的进程pid

说到这里我们好像没有见到Socket的影子,只见到了ZygoteState这么一个东西,那它怎么来的呢,可以看见它是上一个方法startViaZygote调用zygoteSendArgsAndGetResult方法传过来的参数,就是这么一句话

 private static ProcessStartResult startViaZygote(final String processClass,
                                  final String niceName,
                                  final int uid, final int gid,
                                  final int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] extraArgs)
                                  throws ZygoteStartFailedEx {
        synchronized(Process.class) {   
	        ......
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

Process.openZygoteSocketIfNeeded

//如果zygote的socket没有打开,那就尝试打开,可能会阻塞或者重连
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
            	//向zygote进程发起连接
                primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
        }

        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }

        //当主zygote没能匹配成功,则采用第二个zygote,发起connect()操作
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            try {
            secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            }
        }

        if (secondaryZygoteState.matches(abi)) {
            return secondaryZygoteState;
        }

        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }

这个方法会根据当前的abi来选择与zygote还是zygote64进行通信,在init进程解析rc文件的时候,会根据abi型号创建两个zygote;该方法最终会返回一个ZygoteState,它是Process的静态内部类,具体连接实现在ZygoteState.connect方法中

Process.ZygoteState

	/**
     * 与zygote进程通信的状态
     *
     * @hide 仅限内部使用
     */
    public static class ZygoteState {
        final LocalSocket socket;
        final DataInputStream inputStream;
        final BufferedWriter writer;
        final List<String> abiList;

        boolean mClosed;

        private ZygoteState(LocalSocket socket, DataInputStream inputStream,
                BufferedWriter writer, List<String> abiList) {
            this.socket = socket;
            this.inputStream = inputStream;
            this.writer = writer;
            this.abiList = abiList;
        }

        public static ZygoteState connect(String socketAddress) throws IOException {
            DataInputStream zygoteInputStream = null;
            BufferedWriter zygoteWriter = null;
            final LocalSocket zygoteSocket = new LocalSocket();

            try {
                zygoteSocket.connect(new LocalSocketAddress(socketAddress,
                        LocalSocketAddress.Namespace.RESERVED));

                zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());

                zygoteWriter = new BufferedWriter(new OutputStreamWriter(
                        zygoteSocket.getOutputStream()), 256);
            } catch (IOException ex) {
                try {
                    zygoteSocket.close();
                } catch (IOException ignore) {
                }

                throw ex;
            }

            String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
            Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString);

            return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                    Arrays.asList(abiListString.split(",")));
        }

        boolean matches(String abi) {
            return abiList.contains(abi);
        }

        public void close() {
            try {
                socket.close();
            } catch (IOException ex) {
                Log.e(LOG_TAG,"I/O exception on routine close", ex);
            }

            mClosed = true;
        }

        boolean isClosed() {
            return mClosed;
        }
    }

可以看到这里是通过LocalSocket进行进程间通信;这种通信的双方一般是Native层的server端,Framework层的Client端,中间涉及到jni调用。

说到LocalSocket,大家肯定会想到平时用到的Socket,Socket通常是为了方便两台不同的机器之间的通信,它封装了TCP/IP协议,向外提供一些API简化了网络通信过程,可以实现不同层面,不同应用,跨进程跨网络的通信;一般由Socket(client)和ServerSocket(Server)组成通信双方。

而Android中的LocalSocket是基于UNIX-domain Socket的,UNIX-domain Socket是在Socket的基础上衍生出来的一种IPC通信机制,因此LocalSocket解决的是同一台主机上不同进程间互相通信的问题。其相对于网络通信使用的socket不需要经过网络协议栈,不需要打包拆包、计算校验,自然的执行效率也高。与大名鼎鼎的binder机制作用一样,都在Android系统中作为IPC通信手段被广泛使用;一般由LocalSocket(Client)和LocalServerSocket(Server)组成通信双方。

那么在本文中AMS所在的system-server进程就充当了Client,zygote进程充当Server,因为zygote进程在创建的时候会在ZygoteInit.main方法中调用ZygoteInit.registerZygoteSocket方法,会实例化一个LocalServerSocket,并且在ZygoteInit.runSelectLoop方法中不停的获取客户端的请求

Zygote

ZygoteInit.main

public static void main(String argv[]) {
    try {
    	registerZygoteSocket(socketName); //为Zygote注册socket
        runSelectLoop(abiList); //进入循环模式,获取客户端连接并处理
        ....
    } catch (MethodAndArgsCaller caller) {
        caller.run();
    } catch (RuntimeException ex) {
        closeServerSocket();
        throw ex;
    }
}

ZygoteInit.runSelectLoop

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    //sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    while (true) {
        StructPollfd[] pollFds = new StructPollfd[fds.size()];
        for (int i = 0; i < pollFds.length; ++i) {
            pollFds[i] = new StructPollfd();
            pollFds[i].fd = fds.get(i);
            pollFds[i].events = (short) POLLIN;
        }
        try {
             //处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里
            Os.poll(pollFds, -1);
        } catch (ErrnoException ex) {
            ...
        }
        
        for (int i = pollFds.length - 1; i >= 0; --i) {
            //采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
            // 否则进入continue,跳出本次循环。
            if ((pollFds[i].revents & POLLIN) == 0) {
                continue;
            }
            if (i == 0) {
                //即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;
                // 则创建ZygoteConnection对象,并添加到fds。
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor()); //添加到fds.
            } else {
                //i>0,则代表通过socket接收来自对端的数据,并执行相应操作
                boolean done = peers.get(i).runOnce();
                if (done) {
                    peers.remove(i);
                    fds.remove(i); //处理完则从fds中移除该文件描述符
                }
            }
        }
    }
}

这里通过acceptCommandPeer方法获取连接过来的客户端,然后执行ZygoteConnection.runOnce方法处理请求

ZygoteConnection.runOnce

/**
     * 从socket读取一个启动命令;如果有就fork一个子进程
     * 如果fork成功,就会抛出 ZygoteInit.MethodAndArgsCaller异常
     */
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;

    try {
        //读取socket客户端发送过来的参数列表
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        ...
        return true;
    }
    ...

    try {
        //将binder客户端传递过来的参数,解析成Arguments对象格式
        parsedArgs = new Arguments(args);
        ...
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
    } catch (Exception e) {
        ...
    }

    try {
        if (pid == 0) {
            //子进程执行
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            //进入子进程流程
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
            return true;
        } else {
            //父进程执行
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

这里先解析客户端发送过来的参数列表,然后调用Zygote.forkAndSpecialize方法

Zygote.forkAndSpecialize

	private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
	/**
     * fork一个新的vm实例, 必须使用-Xzygote标志启动当前VM
     * 新实例保留所有root功能
     */
    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
          String instructionSet, String appDataDir) {
        VM_HOOKS.preFork();
        int pid = nativeForkAndSpecialize(
                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                  instructionSet, appDataDir);

        VM_HOOKS.postForkCommon();
        return pid;
    }

这里在fork新进程的时候会先调用 VM_HOOKS.preFork()

ZygoteHooks.preFork

public void preFork() {
    Daemons.stop(); //停止4个Daemon子线程
    waitUntilAllThreadsStopped(); //等待所有子线程结束
    token = nativePreFork(); //完成gc堆的初始化工作
}

这个方法的主要目的是停止zygote进程的四个daemon子线程,分别是ReferenceQueueDaemon,FinalizerDaemon,FinalizerWatchdogDaemon,HeapTaskDaemon;直到zygote是是单线程,以便于提高fork效率;

fork新进程是调用native方法,经过jni调用

nativeForkAndSpecialize

com_android_internal_os_Zygote.nativeForkAndSpecialize

static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
    JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
    jint debug_flags, jobjectArray rlimits,
    jint mount_external, jstring se_info, jstring se_name,
    jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
    // 将CAP_WAKE_ALARM赋予蓝牙进程
    jlong capabilities = 0;
    if (uid == AID_BLUETOOTH) {
        capabilities |= (1LL << CAP_WAKE_ALARM);
    }

    return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
            rlimits, capabilities, capabilities, mount_external, se_info,
            se_name, false, fdsToClose, instructionSet, appDataDir);
}

com_android_internal_os_Zygote.ForkAndSpecializeCommon

static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                     jint debug_flags, jobjectArray javaRlimits,
                                     jlong permittedCapabilities, jlong effectiveCapabilities,
                                     jint mount_external,
                                     jstring java_se_info, jstring java_se_name,
                                     bool is_system_server, jintArray fdsToClose,
                                     jstring instructionSet, jstring dataDir) {
  //设置子进程的signal信号处理函数
  SetSigChldHandler();
  //fork子进程 
  pid_t pid = fork();
  if (pid == 0) { //进入子进程
    DetachDescriptors(env, fdsToClose); //关闭并清除文件描述符

    if (!is_system_server) {
        //对于非system_server子进程,则创建进程组
        int rc = createProcessGroup(uid, getpid());
    }
    SetGids(env, javaGids); //设置设置group
    SetRLimits(env, javaRlimits); //设置资源limit

    int rc = setresgid(gid, gid, gid);
    rc = setresuid(uid, uid, uid);

    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
    SetSchedulerPolicy(env); //设置调度策略

     //selinux上下文
    rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);

    if (se_info_c_str == NULL && is_system_server) {
      se_name_c_str = "system_server";
    }
    if (se_info_c_str != NULL) {
      SetThreadName(se_name_c_str); //设置线程名为system_server,方便调试
    }
    //在Zygote子进程中,设置信号SIGCHLD的处理器恢复为默认行为
    UnsetSigChldHandler();
    //等价于调用zygote.callPostForkChildHooks() 
    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                              is_system_server ? NULL : instructionSet);
    ...

  } else if (pid > 0) {
    //进入父进程,即Zygote进程
  }
  return pid;
}

这里会通过fork()方法创建进程

fork.fork

int fork() {
  __bionic_atfork_run_prepare(); // fork完成前,父进程回调方法

  pthread_internal_t* self = __get_thread();

  //fork期间,获取父进程pid,并使其缓存值无效
  pid_t parent_pid = self->invalidate_cached_pid();
  //系统调用
  int result = syscall(__NR_clone, FORK_FLAGS, NULL, NULL, NULL, &(self->tid));
  if (result == 0) {
    self->set_cached_pid(gettid());
    __bionic_atfork_run_child(); //fork完成执行子进程回调方法
  } else {
    self->set_cached_pid(parent_pid);
    __bionic_atfork_run_parent(); //fork完成执行父进程回调方法
  }
  return result;
}

fork进程结束后会在ForkAndSpecializeCommon函数中调用CallStaticVoidMethod。这就是反射调用zygote.callPostForkChildHooks()

zygote.callPostForkChildHooks

private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer,
            String instructionSet) {
        VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
    }

ZygoteHooks.postForkChild

public void postForkChild(int debugFlags, String instructionSet) {
    nativePostForkChild(token, debugFlags, instructionSet);
    //将当前时间设置为新进程随机数种子
    Math.setRandomSeedInternal(System.currentTimeMillis());
}

nativePostForkChild又通过jni调用如下函数

dalvik_system_ZygoteHooks.ZygoteHooks_nativePostForkChild

static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags,
                                            jstring instruction_set) {
    //此处token是由nativePreFork()创建的,记录着当前线程
    Thread* thread = reinterpret_cast<Thread*>(token);
    //设置新进程的主线程id
    thread->InitAfterFork();
    ..
    if (instruction_set != nullptr) {
      ScopedUtfChars isa_string(env, instruction_set);
      InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
      Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
      if (isa != kNone && isa != kRuntimeISA) {
        action = Runtime::NativeBridgeAction::kInitialize;
      }

      Runtime::Current()->DidForkFromZygote(env, action, isa_string.c_str());
    } else {
      Runtime::Current()->DidForkFromZygote(env, Runtime::NativeBridgeAction::kUnload, nullptr);
    }
}

Runtime.DidForkFromZygote

void Runtime::DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa) {
  is_zygote_ = false;
  if (is_native_bridge_loaded_) {
    switch (action) {
      case NativeBridgeAction::kUnload:
        UnloadNativeBridge(); //卸载用于跨平台的桥连库
        is_native_bridge_loaded_ = false;
        break;
      case NativeBridgeAction::kInitialize:
        InitializeNativeBridge(env, isa);//初始化用于跨平台的桥连库
        break;
    }
  }
  //创建Java堆处理的线程池
  heap_->CreateThreadPool();
  //重置gc性能数据,以保证进程在创建之前的GCs不会计算到当前app上。
  heap_->ResetGcPerformanceInfo();
  if (jit_.get() == nullptr && jit_options_->UseJIT()) {
    //当flag被设置,并且还没有创建JIT时,则创建JIT
    CreateJit();
  }
  //设置信号处理函数
  StartSignalCatcher();
  //启动JDWP线程,当命令debuger的flags指定"suspend=y"时,则暂停runtime
  Dbg::StartJdwp();
}

fork完成后继续Zygote.forkAndSpecialize方法第三步

ZygoteHooks.postForkCommon

public void postForkCommon() {
    Daemons.start();
}

public static void start() {
    ReferenceQueueDaemon.INSTANCE.start();
    FinalizerDaemon.INSTANCE.start();
    FinalizerWatchdogDaemon.INSTANCE.start();
    HeapTaskDaemon.INSTANCE.start();
}

主要作用是在fork新进程后将之前停掉的四个Daemon线程启动起来

forkAndSpecialize 总结

  • preFork:停止4个Daemon子线程,初始化GC
  • nativeForkAndSpecialize:调用Linux的fork()子进程,设置新进程的主线程id,重置gc性能数据,设置信号处理函数等功能
  • postForkCommon:重新启动四个daemon子线程
  • forkAndSpecialize执行结束,即创建新进程后,会有两次返回,第一次回到ZygoteConnection.runOnce方法,执行子进程handleChildProc方法;第二次回到该方法,执行zygote进程的handleParentProc方法

回调子进程

ZygoteConnection.handleChildProc

/**
     * 处理子进程的post-fork设置,并根据需要关闭套接字,根据需要重新打开stdio,
     * 如果成功则最终抛出MethodAndArgsCaller,如果失败则返回。
     */
    private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {
        /**
         * 当执行到达这里时,native code关闭了两个实际的Zygote socket连接,
         * 并在它们的位置替换了/ dev / null。 LocalSocket对象仍需要正确关闭。
         */

        closeSocket();
        ZygoteInit.closeServerSocket();

        if (descriptors != null) {
            try {
                Os.dup2(descriptors[0], STDIN_FILENO);
                Os.dup2(descriptors[1], STDOUT_FILENO);
                Os.dup2(descriptors[2], STDERR_FILENO);

                for (FileDescriptor fd: descriptors) {
                    IoUtils.closeQuietly(fd);
                }
                newStderr = System.err;
            } catch (ErrnoException ex) {
                Log.e(TAG, "Error reopening stdio", ex);
            }
        }

				 //设置进程名
        if (parsedArgs.niceName != null) {
            Process.setArgV0(parsedArgs.niceName);
        }


        if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.remainingArgs);
        } else {
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }

RuntimeInit.zygoteInit

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
    redirectLogStreams(); //重定向log输出

    commonInit(); // 通用的一些初始化
    nativeZygoteInit(); // zygote初始化 
    applicationInit(targetSdkVersion, argv, classLoader); // 应用初始化
}

RuntimeInit.commonInit

private static final void commonInit() {
    // 设置默认的未捕捉异常处理方法
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());

    // 设置市区,中国时区为"Asia/Shanghai"
    TimezoneGetter.setInstance(new TimezoneGetter() {
        @Override
        public String getId() {
            return SystemProperties.get("persist.sys.timezone");
        }
    });
    TimeZone.setDefault(null);

    //重置log配置
    LogManager.getLogManager().reset();
    new AndroidConfig();

    // 设置默认的HTTP User-agent格式( "Dalvik/1.1.0 (Linux; U; Android 6.0.1;LenovoX3c70 Build/LMY47V)"),用于 HttpURLConnection
    String userAgent = getDefaultUserAgent();
    System.setProperty("http.agent", userAgent);

    // 设置socket的tag,用于网络流量统计
    NetworkManagementSocketTagger.install();
}

RuntimeInit.nativeZygoteInit

nativeZygoteInit()所对应的jni方法如下

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    //此处的gCurRuntime为AppRuntime,是在AndroidRuntime.cpp中定义的
    gCurRuntime->onZygoteInit();
}

app_main.onZygoteInit

virtual void onZygoteInit()
{
    sp<ProcessState> proc = ProcessState::self();
    proc->startThreadPool(); //启动新binder线程
}

ProcessState::self():主要工作是调用open()打开/dev/binder驱动设备,再利用mmap()映射内核的地址空间,将Binder驱动的fd赋值ProcessState对象中的变量mDriverFD,用于交互操作。startThreadPool()是创建一个新的binder线程,不断进行talkWithDriver(),与Binder驱动交流

继续执行zygoteInit方法中的最后一个方法

RuntimeInit.applicationInit

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    //true代表应用程序退出时不调用AppRuntime.onExit(),否则会在退出前调用
    nativeSetExitWithoutCleanup(true);

    //设置虚拟机的内存利用率参数值为0.75
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

    final Arguments args;
    try {
        args = new Arguments(argv); //解析参数
    } catch (IllegalArgumentException ex) {
        return;
    }

    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    //调用startClass的static方法 main() 此处args.startClass为”android.app.ActivityThread”
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

RuntimeInit.invokeStaticMain

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl = Class.forName(className, true, classLoader);
    ...

    Method m;
    try {
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        ...
    } catch (SecurityException ex) {
        ...
    }

    //通过抛出异常,回到ZygoteInit.main()。这样做好处是能清空栈帧,提高栈帧利用率
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

重点看最后一个方法,通过反射获取ActivityThread类的main方法参数,然后抛出MethodAndArgsCaller异常,其中构造方法中m是指main方法,argv是AMS发送过来的参数列表;但是抛出异常后怎么弄呢,我们知道一个方法抛异常,会一直往上走到调用方法,直到一个方法捕获了异常。在这里就会一直抛到ZygoteInit.main方法才捕获了异常,然后去执行MethodAndArgsCaller.run方法

MethodAndArgsCaller.run

public static class MethodAndArgsCaller extends Exception
            implements Runnable {
        /** 调用的方法 在上面的方法可知是main方法 */
        private final Method mMethod;

        /** 参数列表 */
        private final String[] mArgs;

        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }

        public void run() {
            try {
	            //反射调用,由上面可知这里会调用到ActivityThread.main()方法
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Error) {
                    throw (Error) cause;
                }
                throw new RuntimeException(ex);
            }
        }
    }

走到这里就要进入ActivityThread了,它管理着应用程序进程中主线程的执行,在ActivityManager请求时调度和执行Activity,Service,Broadcast和其它操作

ActivityThread.main

public static void main(String[] args) {
				
		......
		//创建主线程的Looper
        Looper.prepareMainLooper();
		//关联AMS
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

		//初始化主线程Handler
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        // 进行主线程消息循环
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

主要工作:设置进程名,打开binder驱动,启动新的binder线程;然后设置art虚拟机参数,再反射调用目标类的main()方法,即ActivityThread.main()方法

至此,进程创建完毕,并且也有了主线程,剩下的便是启动Activity和关联context等初始化操作了

回调zygote进程

子进程fork方法执行完成回调第一次给子进程后,还会回调一次给zygote进程

具体是在ZygoteConnection.runOnce中调用handleParentProc

ZygoteConnection.handleParentProc

private boolean handleParentProc(int pid,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {

        if (pid > 0) {
            setChildPgid(pid);
        }
       ....
        try {
        
            mSocketOutStream.writeInt(pid);
            mSocketOutStream.writeBoolean(usingWrapper);
        } catch (IOException ex) {
            Log.e(TAG, "Error writing to command socket", ex);
            return true;
        }

        return false;
    }

这个方法主要是为了通知system server进程,新进程已经创建完成

注意

  • APP或者桌面启动,需要使用Binder机制告诉AMS(因为启动方有自己的进程,AMS在system server进程),AMS请求zygote进程是通过Socket
  • Process.start方法是阻塞的,只有等进程创建完成才会返回
  • zygote进程fork进程一次,会有两次返回,在zygote进程和子进程分别返回一次,这样子线程就能执行ZygoteConnection.handleChildProc及以后的逻辑;zygote进程通过ZygoteConnection.handleParentProc通知system server进程新进程已经创建完成

fork解释

可能你会疑虑,明明是在zygote进程中的ZygoteConnection.runOnce方法中去执行fork操作,那么fork结束后返回不应该还是在zygote进程中吗?

这里需要了解下fork的逻辑:

fork()采用copy on write技术,这是linux创建进程的标准方法,调用一次,返回两次。当父子进程任一方修改内存数据时(这是on-write时机),才发生缺页中断,从而分配新的物理内存(这是copy操作)。
copy-on-write原理:写时拷贝是指子进程与父进程的页表都所指向同一个块物理内存,fork过程只拷贝父进程的页表,并标记这些页表是只读的。父子进程共用同一份物理内存,如果父子进程任一方想要修改这块物理内存,那么会触发缺页异常(page fault),Linux收到该中断便会创建新的物理内存,并将两个物理内存标记设置为可写状态,从而父子进程都有各自独立的物理内存。

其实就是fork之后,操作系统会复制一个与父进程完全相同的子进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同,子进程拥有父进程当前运行到的位置(两进程的程序计数器pc值相同,也就是说,子进程是从fork返回处开始执行的)

可以这样想象,子进程就是把zygote进程复制了一遍,两个进程都阻塞在这里;但在fork之后,他们就开始分别作不同的工作,正如fork原意【分支】一样,在zygote进程的ZygoteConnection.runOnce方法中,fork返回子进程id,然后执行ZygoteConnection.handleParentProc;但是在子进程的ZygoteConnection.runOnce方法中,fork返回是0,就会去执行ZygoteConnection.handleChildProc;这样父子进程从此分家

猜你喜欢

转载自blog.csdn.net/qq_30993595/article/details/82747738