这个新进程就是zygote进程通过复制自身来创建的,新进程在启动的过程中还会创建一个Binder线程池(用来做进程通信)和一个消息循环(用来做线程通信) 整个流程如下图所示:

Android persistent进程查询 android进程状态_数据库

  1. 当我们点击应用图标启动应用时或者在应用内启动一个带有process标签的Activity时,都会触发创建新进程的请求,这种请求会先通过Binder 发送给system_server进程,也即是发送给ActivityManagerService进行处理。
  2. system_server进程会调用Process.start()方法,会先收集uid、gid等参数,然后通过Socket方式发送给Zygote进程,请求创建新进程。
  3. Zygote进程接收到创建新进程的请求后,调用ZygoteInit.main()方法进行runSelectLoop()循环体内,当有客户端连接时执行ZygoteConnection.runOnce() 方法,最后fork生成新的应用进程。
  4. 新创建的进程会调用handleChildProc()方法,最后调用我们非常熟悉的ActivityThread.main()方法。

注:整个流程会涉及Binder和Socket两种进程通信方式,这个我们后续会有专门的文章单独分析,这个就不再展开。

整个流程大致就是这样,我们接着来看看具体的代码实现,先来看一张进程启动序列图:

Android persistent进程查询 android进程状态_mysql_02

从第一步到第三步主要是收集整理uid、gid、groups、target-sdk、nice-name等一系列的参数,为后续启动新进程做准备。然后调用openZygoteSocketIfNeeded()方法 打开Socket通信,向zygote进程发出创建新进程的请求。

注:第二步中的Process.start()方法是个阻塞操作,它会一直等待进程创建完毕,并返回pid才会完成该方法。

我们来重点关注几个关键的函数。

1.1 Process.openZygoteSocketIfNeeded(String abi)

关于Process类与Zygote进程的通信是如何进行的呢?🤔

Process的静态内部类ZygoteState有个成员变量LocalSocket对象,它会与ZygoteInit类的成员变量LocalServerSocket对象建立连接,如下所示:

客户端

public static class ZygoteState {
 final LocalSocket socket;
 }

服务端

public class ZygoteInit {
 //该Socket与/dev/socket/zygote文件绑定在一起
 private static LocalServerSocket sServerSocket;
 }

我们来具体看看代码里的实现。

public static class ZygoteState {
public static ZygoteState connect(String socketAddress) throws IOException {
 DataInputStream zygoteInputStream = null;
 BufferedWriter zygoteWriter = null;
 //创建LocalSocket对象
 final LocalSocket zygoteSocket = new LocalSocket();try {
 //将LocalSocket与LocalServerSocket建立连接,建立连接的过程就是
 //LocalSocket对象在/dev/socket目录下查找一个名称为"zygote"的文件
 //然后将自己与其绑定起来,这样就建立了连接。
 zygoteSocket.connect(new LocalSocketAddress(socketAddress,
 LocalSocketAddress.Namespace.RESERVED));//创建LocalSocket的输入流,以便可以接收Zygote进程发送过来的数据
 zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());//创建LocalSocket的输出流,以便可以向Zygote进程发送数据。
 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(“,”)));
 }
 }

建立Socket连接的流程很明朗了,如下所示:

  1. 创建LocalSocket对象。
  2. 将LocalSocket与LocalServerSocket建立连接,建立连接的过程就是LocalSocket对象在/dev/socket目录下查找一个名称为"zygote"的文件,然后将自己与其绑定起来,这样就建立了连接。
  3. 创建LocalSocket的输入流,以便可以接收Zygote进程发送过来的数据。
  4. 创建LocalSocket的输出流,以便可以向Zygote进程发送数据。

1.2 ZygoteInit.main(String argv[])

ZygoteInit是Zygote进程的启动类,该类会预加载一些类,然后便开启一个循环,等待通过Socket发过来的创建新进程的命令,fork出新的 子进程。

ZygoteInit的入口函数就是main()方法,如下所示:

public class ZygoteInit {
public static void main(String argv[]) {
 // Mark zygote start. This ensures that thread creation will throw
 // an error.
 ZygoteHooks.startZygoteNoThreadCreation();try {
 //…
 registerZygoteSocket(socketName);
 //…
 //开启循环
 runSelectLoop(abiList);closeServerSocket();
 } catch (MethodAndArgsCaller caller) {
 caller.run();
 } catch (Throwable ex) {
 Log.e(TAG, “Zygote died with exception”, ex);
 closeServerSocket();
 throw ex;
 }
 }// 开启一个选择循环,接收通过Socket发过来的命令,创建新线程
 private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {ArrayList fds = new ArrayList();
 ArrayList peers = new ArrayList();//sServerSocket指的是Socket通信的服务端,在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) {
 throw new RuntimeException(“poll failed”, ex);
 }
 for (int i = pollFds.length - 1; i >= 0; --i) {//采用IO多路复用机制,当接收到客户端发出的连接请求时或者数据处理请求到来时则
 //往下执行,否则进入continue跳出本次循环。
 if ((pollFds[i].revents & POLLIN) == 0) {
 continue;
 }
 //索引为0,即为sServerSocket,表示接收到客户端发来的连接请求。
 if (i == 0) {
 ZygoteConnection newPeer = acceptCommandPeer(abiList);
 peers.add(newPeer);
 fds.add(newPeer.getFileDesciptor());
 }
 //索引不为0,表示通过Socket接收来自对端的数据,并执行相应的操作。
 else {
 boolean done = peers.get(i).runOnce();
 //处理完成后移除相应的文件描述符。
 if (done) {
 peers.remove(i);
 fds.remove(i);
 }
 }
 }
 }
 }
 }

可以发现ZygoteInit在其入口函数main()方法里调用runSelectLoop()开启了循环,接收Socket发来的请求。请求分为两种:

  1. 连接请求
  2. 数据请求

没有连接请求时Zygote进程会进入休眠状态,当有连接请求到来时,Zygote进程会被唤醒,调用acceptCommadPeer()方法创建Socket通道ZygoteConnection

private static ZygoteConnection acceptCommandPeer(String abiList) {
 try {
 return new ZygoteConnection(sServerSocket.accept(), abiList);
 } catch (IOException ex) {
 throw new RuntimeException(
 “IOException during accept()”, ex);
 }
 }

然后调用runOnce()方法读取连接请求里的数据,然后创建新进程。

此外,连接的过程中服务端接受的到客户端的connect()操作会执行accpet()操作,建立连接手,客户端通过write()写数据,服务端通过read()读数据。

1.3 ZygoteConnection.runOnce()

class ZygoteConnection {
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
 Arguments parsedArgs = null;
 FileDescriptor[] descriptors;try {
 //读取客户端发过来的参数列表
 args = readArgumentList();
 descriptors = mSocket.getAncillaryFileDescriptors();
 } catch (IOException ex) {
 Log.w(TAG, "IOException on command socket " + ex.getMessage());
 closeSocket();
 return true;
 }//… 参数处理
try {
//… 参数处理
//调用Zygote.forkAndSpecialize(来fork出新进程
 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
 parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
 parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
 parsedArgs.appDataDir);
 } catch (ErrnoException ex) {
 logAndPrintError(newStderr, “Exception creating pipe”, ex);
 } catch (IllegalArgumentException ex) {
 logAndPrintError(newStderr, “Invalid zygote arguments”, ex);
 } catch (ZygoteSecurityException ex) {
 logAndPrintError(newStderr,
 "Zygote security policy prevents request: ", ex);
 }try {
 //pid == 0时表示当前是在新创建的子进程重磅执行
 if (pid == 0) {
 // in child
 IoUtils.closeQuietly(serverPipeFd);
 serverPipeFd = null;
 handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);// should never get here, the child is expected to either
 // throw ZygoteInit.MethodAndArgsCaller or exec().
 return true;
 }
 // pid < 0表示创建新进程失败,pid > 0 表示当前是在父进程中执行
 else {
 // in parent…pid of < 0 means failure
 IoUtils.closeQuietly(childPipeFd);
 childPipeFd = null;
 return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
 }
 } finally {
 IoUtils.closeQuietly(childPipeFd);
 IoUtils.closeQuietly(serverPipeFd);
 }
 }
 }

该方法主要用来读取进程启动参数,然后调用Zygote.forkAndSpecialize()方法fork出新进程,该方法是创建新进程的核心方法,它主要会陆续调用三个 方法来完成工作:

  1. preFork():先停止Zygote进程的四个Daemon子线程的运行以及初始化GC堆。这四个Daemon子线程分别为:Java堆内存管理现场、堆线下引用队列线程、析构线程与监控线程。
  2. nativeForkAndSpecialize():调用Linux系统函数fork()创建新进程,创建Java堆处理的线程池,重置GC性能数据,设置进程的信号处理函数,启动JDWP线程。
  3. postForkCommon():启动之前停止的Zygote进程的四个Daemon子线程。

上面的方法都完成会后,新进程会创建完成,并返回pid,接着就调用handleChildProc()来启动新进程。handleChildProc()方法会接着调用RuntimeInit.zygoteInit()来 完成新进程的启动。

1.4 RuntimeInit.zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)

这个就是个关键的方法了,它主要用来创建一些运行时环境,我们来看一看。

public class RuntimeInit {
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
 throws ZygoteInit.MethodAndArgsCaller {
 if (DEBUG) Slog.d(TAG, “RuntimeInit: Starting application from zygote”);Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “RuntimeInit”);
 redirectLogStreams();
 //创建应用进程的时区和键盘等通用信息
 commonInit();
 //在应用进程中创建一个Binder线程池
 nativeZygoteInit();
 //创建应用信息
 applicationInit(targetSdkVersion, argv, classLoader);
 }
 }

该方法主要完成三件事:

  1. 调用commonInit()方法创建应用进程的时区和键盘等通用信息。
  2. 调用nativeZygoteInit()方法在应用进程中创建一个Binder线程池。
  3. 调用applicationInit(targetSdkVersion, argv, classLoader)方法创建应用信息。

Binder线程池我们后续的文章会分析,我们重点来看看applicationInit(targetSdkVersion, argv, classLoader)方法的实现,它主要用来完成应用的创建。

该方法里的argv参数指的就是ActivityThread,该方法会调用invokeStaticMain()通过反射的方式调用ActivityThread类的main()方法。如下所示:

public class RuntimeInit {
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
 throws ZygoteInit.MethodAndArgsCaller {
 //…// Remaining arguments are passed to the start class’s static main
 invokeStaticMain(args.startClass, args.startArgs, classLoader);
 }private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
 throws ZygoteInit.MethodAndArgsCaller {
 Class<?> cl;//通过反射调用ActivityThread类的main()方法
 try {
 cl = Class.forName(className, true, classLoader);
 } catch (ClassNotFoundException ex) {
 throw new RuntimeException(
 "Missing class when invoking static main " + className,
 ex);
 }Method m;
 try {
 m = cl.getMethod(“main”, new Class[] { String[].class });
 } catch (NoSuchMethodException ex) {
 throw new RuntimeException(
 "Missing static main on " + className, ex);
 } catch (SecurityException ex) {
 throw new RuntimeException(
 "Problem getting static main on " + className, ex);
 }
 //…
 }
 }

走到ActivityThread类的main()方法,我们就很熟悉了,我们知道在main()方法里,会创建主线程Looper,并开启消息循环,如下所示:

public final class ActivityThread {
public static void main(String[] args) {
 //…
 Environment.initForCurrentUser();
 //…
 Process.setArgV0(“”);
 //创建主线程looper
 Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();
 //attach到系统进程
 thread.attach(false);if (sMainThreadHandler == null) {
 sMainThreadHandler = thread.getHandler();
 }//主线程进入循环状态
 Looper.loop();throw new RuntimeException(“Main thread loop unexpectedly exited”);
 }
 }

前面我们从Process.start()开始讲起,分析了应用进程的创建及启动流程,既然有启动就会有结束,接下来我们从 Process.killProcess()开始讲起,继续分析进程的结束流程。

二 进程的优先级

进程按照优先级大小不同又可以分为实时进程与普通进程。

Android persistent进程查询 android进程状态_android_03

prio值越小表示进程优先级越高,

  • 静态优先级:优先级不会随时间改变,内核也不会修改,只能通过系统调用改变nice值,优先级映射公式为:static_prio = MAX_RT_PRIO + nice + 20,其中MAX_RT_PRIO = 100,那么取值区间为[100, 139];对应普通进程;
  • 实时优先级:取值区间为[0, MAX_RT_PRIO -1],其中MAX_RT_PRIO = 100,那么取值区间为[0, 99];对应实时进程;
  • 懂爱优先级:调度程序通过增加或者减少进程优先级,来达到奖励IO消耗型或按照惩罚CPU消耗型的进程的效果。区间范围[0, MX_PRIO-1],其中MX_PRIO = 140,那么取值区间为[0,139];

三 进程调度流程

进程的调度在Process类里完成。

3.1 优先级调度

优先级调度方法

setThreadPriority(int tid, int priority)

进程的优先级以及对应的nice值如下所示:

  • THREAD_PRIORITY_LOWEST 19 最低优先级
  • THREAD_PRIORITY_BACKGROUND 10 后台
  • THREAD_PRIORITY_LESS_FAVORABLE 1 比默认略低
  • THREAD_PRIORITY_DEFAULT 0 默认
  • THREAD_PRIORITY_MORE_FAVORABLE -1 比默认略高
  • THREAD_PRIORITY_FOREGROUND -2 前台
  • THREAD_PRIORITY_DISPLAY -4 显示相关
  • THREAD_PRIORITY_URGENT_DISPLAY -8 显示(更为重要),input事件
  • THREAD_PRIORITY_AUDIO -16 音频相关
  • THREAD_PRIORITY_URGENT_AUDIO -19 音频(更为重要)

3.2 组优先级调度

进程组优先级调度方法

setProcessGroup(int pid, int group)
 setThreadGroup(int tid, int group)

组优先级及对应取值

  • THREAD_GROUP_DEFAULT -1 仅用于setProcessGroup,将优先级<=10的进程提升到-2
  • THREAD_GROUP_BG_NONINTERACTIVE 0 CPU分时的时长缩短
  • THREAD_GROUP_FOREGROUND 1 CPU分时的时长正常
  • THREAD_GROUP_SYSTEM 2 系统线程组