Android 源码分析 应用程序启动的过程

Posted 小图包

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 源码分析 应用程序启动的过程相关的知识,希望对你有一定的参考价值。

记录进阶解密学习,再看源码层面思路不会那么杂乱无章,有了一个很清晰的脉络。

启动过程

启动过程可以分为两步:

  1. AMS 发送启动应用程序进程请求

    AMS 如果想要启动应用程序进程,就需要向 Zygote 进程发送创建应用程序进程的请求,AMS 会通过调用 startProcessLocked 方法向 Zygote 进程发送请求。

  2. Zygote 接收请求并创建应用程序进程

出处。

一  AMS 发送启动应用程序进程请求

时序图如下 

 

KykGXn.png

 

AMS 启动应用程序进程,向 Zygote 进程发送创建应用程序进程的请求, AMS 会通过调用 startProcessLocked 函数向 Zygote 进程发送请求 代码如下:

 

//com.android.server.am; ActivityManagerService.java

    /**
     * 启动进程的函数
     * @param app
     * @param hostingType
     * @param hostingNameStr
     * @param abiOverride
     * @param entryPoint
     * @param entryPointArgs
     */
    private final void startProcessLocked(
            ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride,
            String entryPoint, String[] entryPointArgs){
      
        ...
          
        try {
            try {
                final int userId = UserHandle.getUserId(app.uid);
                AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }
             1. 获取要创建的应用程序进程的 用户 id 
            int uid = app.uid;
            int[] gids = null;
            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
            if (!app.isolated) {
              ...

               2. 对 gids 进行创建和赋值
                if (ArrayUtils.isEmpty(permGids)) {
                    gids = new int[3];
                } else {
                    gids = new int[permGids.length + 3];
                    System.arraycopy(permGids, 0, gids, 3, permGids.length);
                }
                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
                gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
            }
           ...
            boolean isActivityProcess = (entryPoint == null);
            
            3. 如果 entryPoint == null 那么将 ActivityThread 全类名赋值给 entryPoint
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkTime(startTime, "startProcess: asking zygote to start proc");
            ProcessStartResult startResult;
            if (hostingType.equals("webview_service")) {
                startResult = startWebView(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, entryPointArgs);
            } else {

                4. 在 AMS 中调用 start 函数进行通知 Zygote fork 进程
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, entryPointArgs);
            }
          ...
    }

总结上面主要做了4个步骤

1 获取创建应用程序进程的用户 ID

2 对用户组 ID(gids)进行创建和赋值

3 如果 entryPoint 为 null ,就把 ActivityThread 全类名赋值给它

4 调用 Process 的 start 函数

 

我们看下 Process 的 start 函数:

//android.os; Process.java

    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 invokeWith,
                                  String[] zygoteArgs) {
      	1. 通过 ZygoteProcess 调用 start 函数
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }

ZygoteProcess 的Start 调用了startViaZygote 方法

//android.os; ZygoteProcess.java

    public final Process.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 invokeWith,
                                                  String[] zygoteArgs) {
        try {
            1
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }

    private Process.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 invokeWith,
                                                      String[] extraArgs)
                                                      throws ZygoteStartFailedEx {

        //创建字符串列表argsForZygote 并将应用进程的启动参数保存到argsForZygote
        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);
      

        synchronized(mLock) {
            2
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

 

看2 处的openZygoteSocketIfNeeded

//android.os; ZygoteProcess.java
    @GuardedBy("mLock")
    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                1
                primaryZygoteState = ZygoteState.connect(mSocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
        }

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

        // 如果不匹配,则尝试连接 zygote 辅模式
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            try {
                3
                secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            }
        }

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

        //如果都不匹配那么就抛一个异常
        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }

总结如上方法

1 连接 zygote 名称为 "zygote" 服务端的 Socket ,建立进程间通信

2 连接 Zygote 主模式返回的 ZygoteState 是否与启动应用程序进程所需要的 ABI 匹配

3 如果不匹配那么就尝试连接 name 为 "zygote_secondary" 的 Socket

4 连接 Zygote 辅模式返回的 ZygoteState 是否与启动应用程序进程所需要的 ABI 匹配

连接成功zygoteSendArgsAndGetResult 做了些什么 

 

//android.os; ZygoteProcess.java
    private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
       			...
            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();

            ...
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }

 

zygote 进程的服务端 Socket 连接成功,那么就将存储起来的应用程序进程启动参数写入到 ZygoteState 中 .ZygoteState是ZygoteProcess的静态内部类,表示与Zygote的状态。

二 Zygote 接收请求并创建应用程序进程

SystemServer 跟应用进程启动在 Zygote 处理 的方式相似,看下时序图

KymKkq.png

服务端的Socket的创建

//com.android.internal.os.ZygoteInit.java
    public static void main(String argv[]) {

	    ....

        try {
          
         

            1 

            zygoteServer.registerServerSocket(socketName);
           
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                2
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }

            ...

            if (startSystemServer) {
                3
                startSystemServer(abiList, socketName, zygoteServer);
            }

            Log.i(TAG, "Accepting command socket connections");
            4 
            zygoteServer.runSelectLoop(abiList);
						//清理或者关闭对应的 Socket
            zygoteServer.closeServerSocket();
        } catch (Zygote.MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        }
    }

总结如上步骤

1 创建服务端的 Socket ,名称为 "zygote"

2 用来预加载资源

3 启动 SystemServer 进程

4 等待 AMS 请求创建新的应用程序进程

看下zygoteServer.runSelectLoop(abiList); 方法

//  com.android.internal.os ZygoteInit.main->runSelectLoop

    void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

        1 
        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null);

        死循环等待 AMS 的请求
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            2
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }

             3
            for (int i = pollFds.length - 1; i >= 0; --i) {

                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                //如果 i == 0 那么就认为 服务端 Socket 与客户端连接上了,就是与 AMS 建立了连接
                if (i == 0) {
                    4
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    //将 ZygoteConnection 添加到 Socket 连接列表中
                    peers.add(newPeer);
                    //将 ZygoteConnection 的文件描述符 添加到 fds 列表中
                    fds.add(newPeer.getFileDesciptor());
                } else {//如果不等于 0 ,那么就说明 AMS 向 Zygote 发送了一个创建应用进程的请求
                    5
                    boolean done = peers.get(i).runOnce(this);
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

上述方法的主要作用

1. 添加获得该 Socket 的 fd 字段的值

2. 将 fds 信息转存到 pollFds 数组中。

3 对 pollFds 信息进行遍历

4 添加到 Socket 连接列表中

5 调用 ZygoteConnection 的 runOnce 函数来创建一个新的应用进程,并在成功创建后将这个连接从 Socket 连接列表中 peers、fd 列表中关闭

如果 AMS 发来了一个新的请求任务,会走5 处通过 peers.get(i).runOnce(this); 来处理请求数据,我们看 runOnce 函数具体实现:

//com.android.internal.os; ZygoteConnection.java
    boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {

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

        try {
            1. 获取应用程序进程的启动参数
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        }
				...
        int pid = -1;
        FileDescriptor childPipeFd = null;
        FileDescriptor serverPipeFd = null;

        try {
            2. 将获取到启动应用程序进程的启动参数 args 数组 封装到 Arguments 类型的 parsedArgs 对象中
            parsedArgs = new Arguments(args);

           ...
            fd = null;

           3. 通过 Zygote 来创建应用程序进程
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        } catch (ErrnoException ex) {
          ...
        }

        try {
            //当前代码逻辑运行在被创建出来的子进程中
            if (pid == 0) {
                // in child
                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                4. 处理应用程序进程
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

                // should never get here, the child is expected to either
                // throw Zygote.MethodAndArgsCaller or exec().
                return true;
            } 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当前程序创建一个子程序的,如果pid等于0 则说明当前的 代码逻辑运行在新创建的子进程的应用程序当中。我们这里来看下 handleChildProc怎么处理应用程序进程

//com.android.internal.os; ZygoteConnection.java    
		private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws Zygote.MethodAndArgsCaller {
        ...
        if (parsedArgs.invokeWith != null) {
            ...
        } else {
           //调用 ZygoteInit 的 zygoteInit 函数
            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }

 

// com.android.internal.os ZygoteInit

    public static final void zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
        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. 启动 Binder 线程池
        ZygoteInit.nativeZygoteInit();
        2. 进入 ActivityThread 的 main 方法
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

 

1 处先启动 Binder 线程池,用于进程间通信,接下来看applicationInit 处理了什么

  //com.android.internal.os RuntimeInit.java
    protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws Zygote.MethodAndArgsCaller {
       	...
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

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

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

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

        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
           ...
        }

        3
        throw new Zygote.MethodAndArgsCaller(m, argv);
    }

总结如上方法做了3件事:

1 通过 className("android.app.ActivityThread" )反射得到 ActivityThread 类

2 获取ActivityThread的main的方法,并将main的方法传入3处的Zygote中的MethodAndArhsCaller类的构造方法当中

3将 m 、argv 传入 MethodAndArgsCaller,然后抛一个异常,并在 ZygoteInit.main 中进行捕获异常

//com.android.internal.os.ZygoteInit.java
    public static void main(String argv[]) {

	    ....

        try {
          
       
            1
            zygoteServer.registerServerSocket(socketName);
           
        	2 
            zygoteServer.runSelectLoop(abiList);

        } catch (Zygote.MethodAndArgsCaller caller) {
            3
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        }
    }


1 创建服务端的 Socket ,名称为 "zygote"

2. 等待 AMS 请求

3. 捕获到 RuntimeInit applicationInit 中的异常

看 RuntimeInit applicationInit 中的异常,然后看它的 run 函数

com.android.internal.os Zygote.java

    public static class MethodAndArgsCaller extends Exception
            implements Runnable {
        /** method to call */
        private final Method mMethod;

        /** argument array */
        private final String[] mArgs;

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

        public void run() {
            try {
                1. 这里就开始执行 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 main 都已经执行,我们看下ActivityThread消息的创建处理

//android.app; ActivityThread.java
    //通过 ZygoteInit 反射调用执行的
    public static void main(String[] args) {
        ...
        1
        Looper.prepareMainLooper();
        2
        ActivityThread thread = new ActivityThread();
        
        thread.attach(false);
	    3
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
      
        4
        Looper.loop();

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

 

1 主线程消息循环 Looper 创建

2 创建 ActivityThread 对象

3 拿到H类的Hander并且 赋值给sMainThreadHandler

4 开启 Looper开启了循环,使得Looper开始处理消息。

通过对系统源码的源码的分析,对系统进程、系统桌面 Launcher 进程、应用程序进程的启动过程,Binder,Hander的更加深的理解, 后续将对四大组件启动流程进行分析.

 

以上是关于Android 源码分析 应用程序启动的过程的主要内容,如果未能解决你的问题,请参考以下文章

Android 源码分析 应用程序启动的过程

Android 4.0 Launcher2源码分析——启动过程分析

Android 源码分析 StartService 启动

Android 源码分析 StartService 启动

Android 源码分析 StartService 启动

Android 源码分析 启动广播的发送和接收过程