Android应用程序进程启动源码解析 - Go语言中文社区

Android应用程序进程启动源码解析


在前面我们从源码层面分析了Android系统启动流程,了解它们也主要是为了我们开发App服务的。应用程序想要启动首先需要应用程序进程存在,而应用程序进程的创建需要SystemServer进程中的ActivityManagerService向Zygote进程发送消息,通过zygote进程fork自身来创建应用程序进程,新创建的应用程序进程就有zygote进程创建的虚拟机实例,同时创建了Binder线程池和Handler消息循环机制,便于进程间消息通信。今天就来从源码角度分析我们关心的Android应用程序进程的启动流程。


Android应用程序进程启动过程(基于9.0源码分析)

应用程序进程的启动我们分为两个部分来分析

  • AMS(ActivityManagerService, 后同) 通过调用startProcessLocked发送创建进程请求。
  • Zygote进程接受请求,创建应用程序进程

AMS向Zygote进程发送创建应用程序进程请求

时序图如下:
在这里插入图片描述

应用程序进程的创建是需要SystemServer进程中的ActivityManagerService向Zygote进程发送消息,进而由Zygote创建进程,然后启动应用程序进程,比如其中有一种AMS.startProcessLocked是在启动Activity时候,源码如下:

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

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
        if (app != null && app.thread != null) {
            try {
                ...
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
              ...
            }
        }
        // 1 
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

在此方法中先判断应用程序进程是都存在,不存在的话就需要进入到注释1的startProcessLocked中,下面我们通过源码进行分析AMS发送请求到Zygote的过程,AMS.startProcessLocked源码如下:

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

	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 */);
    }
	
	@GuardedBy("this")
    private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
            // 1 
        	final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
                            app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
                            requiredAbi, instructionSet, invokeWith, app.startTime);
                    
      }
}

上面注释1处调用了startProcess方法,其中有一个参数是是entryPoint, 追溯源码就会发现它是String entryPoint = "android.app.ActivityThread",接着进入内部查看startProcess源码:

private ProcessStartResult startProcess(String hostingType, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
             /**启动一个进程*/
             ProcessStartResult startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            
    }

上面参数中传入了uid和gid, 接着进入到了Process.start方法,源码如下:

frameworks/base/services/core/java/com/android/os/Process.java

	public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int runtimeFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String invokeWith,
                                  String[] zygoteArgs) {
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }

我们看到调用到了zygoteProcess.start方法,zygoteProcess是和zygote进程保持通信状态的,进入内部查看方法:
frameworks/base/services/core/java/com/android/os/ZygoteProcess.java

	public final Process.ProcessStartResult start(final String processClass,
                                                  final String niceName,
                                                  int uid, int gid, int[] gids,
                                                  int runtimeFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                    zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }

接着调用到了startViaZygote方法:

frameworks/base/services/core/java/com/android/os/ZygoteProcess.java

	private Process.ProcessStartResult startViaZygote(final String processClass,
                                                      final String niceName,
                                                      final int uid, final int gid,
                                                      final int[] gids,
                                                      int runtimeFlags, int mountExternal,
                                                      int targetSdkVersion,
                                                      String seInfo,
                                                      String abi,
                                                      String instructionSet,
                                                      String appDataDir,
                                                      String invokeWith,
                                                      boolean startChildZygote,
                                                      String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<String>();

        // --runtime-args, --setuid=, --setgid=,
        // and --setgroups= must go first
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        argsForZygote.add("--runtime-flags=" + runtimeFlags);
        
        ...

        argsForZygote.add(processClass);

        if (extraArgs != null) {
            for (String arg : extraArgs) {
                argsForZygote.add(arg);
            }
        }
        synchronized(mLock) {
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

可以看到前面大部分工作实在封装参数到argsForZygote,最后用于调用到zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote)。其中第一个参数是一个方法,返回ZygoteState,第二个就是封装的参数argsForZygote,用于zygote进程接受请求后创建进程使用。

我们先看openZygoteSocketIfNeeded,返回一个ZygoteState, 源码如下:

frameworks/base/services/core/java/com/android/os/ZygoteProcess.java

    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                /**1 与zygote进程建立连接*/
                primaryZygoteState = ZygoteState.connect(mSocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
        }
        /**2 连接zygote主模式返回的ZygoteState是否与应用程序进程所需要的ABI匹配,匹配就return返回*/
        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }
        /**3 如果主模式不匹配的话,尝试连接第二种辅助模式*/
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            try {
                secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            }
        }
        /**4 如果辅助模式匹配的话就return返回*/
        if (secondaryZygoteState.matches(abi)) {
            return secondaryZygoteState;
        }

        /**5 如果都不匹配的话就抛出异常*/
        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }

我们在Zygote进程启动篇中分析过了在ZygoteInit的main函数中通过registerZygoteSocket注册了一个名字为zygote的socket, 这里就是尝试与zygote进程的socket通信,返回一个ZygoteState,如果最后都不匹配的话就抛出异常。

返回的ZygoteState作为参数被zygoteSendArgsAndGetResult调用,源码如下:

frameworks/base/services/core/java/com/android/os/ZygoteProcess.java

private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
        	// 1
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;

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

            writer.flush();

            // Should there be a timeout on this?
            Process.ProcessStartResult result = new Process.ProcessStartResult();

            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            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);
        }
    }

从上面注释1处和注释2处我们看到,此方法的主要目的就是将请求的参数args写入到ZygoteState中,ZygoteState是ZygoteProcess的静态内部类,用于表示与Zygote进程通信的状态,到此第一部分AMS发送请求分析完毕。


Zygote进程接受AMS请求创建应用程序进程

时序图如下:
在这里插入图片描述

我们首先回顾下Zygote进程如何处理AMS发送的请求的,不熟悉的小伙伴可以点击Zygote进程启动过程解析查看,它是通过runSelectLoop不停的循环来接受AMS发送的请求,ZygoteInit 9.0的源码和7.0的源码大同小异,我们看main方法:

frameworks/base/core/java/com/android/internal/os/ZygoteInit

public static void main(String argv[]) {
        ZygoteServer zygoteServer = new ZygoteServer();
        ...
		Runnable caller = zygoteServer.runSelectLoop(abiList);
		
        } catch (Throwable ex) {
        } finally {
            zygoteServer.closeServerSocket();
        }
        if (caller != null) {
            caller.run();
        }

接着进入到了runSelectLoop,源码如下:

frameworks/base/core/java/com/android/internal/os/ZygoteServer

Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

        fds.add(mServerSocket.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;
            }
                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    try {
                        ZygoteConnection connection = peers.get(i);
                        // 2
                        final Runnable command = connection.processOneCommand(this);

                        if (mIsForkChild) {
                            return command;
                        } else {
                            if (connection.isClosedByPeer()) {
                                connection.closeSocket();
                                peers.remove(i);
                                fds.remove(i);
                            }
                        }
                    } catch (Exception e) {
                    }
                }
            }
        }
    }

在注释1处i==0说明zygote进程和system_server进程的AMS建立了连接, 通过acceptCommandPeer返回ZygoteConnection,然后将相关对象分别添加到peers和fds中。注释2处i>0说明ActivityManagerService向Zygote进程发送了一个创建应用进程的请求,然后调用ZygoteConnection的processOneCommand函数来创建一个新的应用程序进程, 进入查看源码:

frameworks/base/core/java/com/android/internal/os/ZygoteConnection

    Runnable processOneCommand(ZygoteServer zygoteServer) {
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
                parsedArgs.instructionSet, parsedArgs.appDataDir);
		...
		// 1
		String args[] args = readArgumentList();
        
        // 2
 		parsedArgs = new Arguments(args);
		
		// 3
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
                parsedArgs.instructionSet, parsedArgs.appDataDir);
                
        try {
            if (pid == 0) {
                // in child
                // 4 
                return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.startChildZygote);
            } else {
                handleParentProc(pid, descriptors, serverPipeFd);
                return null;
            }
        }
    }

注释1处读取应用程序启动参数。注释2处将参数封装到Arguments对象中。注释3处开始通过Zygote.forkAndSpecialize创建应用程序进程,参数来自于注释2处,通过fork zygote进程创建应用程序进程,返回了一个pid的值,如果pid=0的话,说明是代码运行在子进程中,我们进入注释4处的handleChildProc查看:

frameworks/base/core/java/com/android/internal/os/ZygoteConnection

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd, boolean isZygote) {
		...
		return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                        null /* classLoader */);
    }

进入到ZygoteInit类的zygoteInit方法,源码如下:

frameworks/base/core/java/com/android/internal/os/ZygoteInit

	public static final Runnable zygoteInit(int targetSdkVersion, 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();
        // 1 
        ZygoteInit.nativeZygoteInit();
        // 2
        return RuntimeInit.
                        
                        
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/oman001/article/details/108926192
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-13 12:13:13
  • 阅读 ( 1386 )
  • 分类:Go应用

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢