应用程序进程启动过程

分析的源码基于android-8.0.0_r4

《安卓进阶解密》读书笔记

应用程序进程启动过程

在「Android系统启动」笔记中提到,Zygote进程中会有一个Server端的Socket,等待AMS请求"创建新的应用程序进程",这里会将「AMS请求」与「Zygote进程响应,创建应用程序进程」这两部分联系起来。因为应用程序进程由Zygote进程Fork而来,所以应用程序进程可以获得Zygote进程在启动时创建的虚拟机实例。

AMS发送请求

时序图如下

应用程序进程启动过程_1
  • AMS的startProcessLocked方法:获取要创建的应用程序进程的相关信息,作为参数传入下一个方法中
  • Process的start方法、ZygoteProcess的start方法:这两个方法没有做什么实际的事情,就是把前面传入的"应用程序进程的相关信息",作为下一个要调用的方法的参数传入
  • ZygoteProcess的startViaZygote方法:根据传入的"应用程序进程的相关信息",创建一个名称为argsForZygoteArrayList<String>,在argsForZygote里面保存"应用进程的启动参数",最终走到了下面的语句
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
  • 这里先看openZygoteSocketIfNeeded方法,这里会与ZygoteState尝试进行connect
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        try {
            //与Zygote进程建立Socket连接
            primaryZygoteState = ZygoteState.connect(mSocket);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
        }
    }

    //连接Zygote主模式返回的ZygoteState是否与启动应用程序进程所需要的ABI匹配
    if (primaryZygoteState.matches(abi)) {
        return primaryZygoteState;
    }

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

    //连接Zygote辅模式返回的ZygoteState是否与启动应用程序进程所需要的ABI匹配
    if (secondaryZygoteState.matches(abi)) {
        return secondaryZygoteState;
    }

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

这里就是与Zygote进程的等待AMS请求的Socket建立连接。Zygote的启动脚本有4种,如init.zygote64.rc,就只会有Zygote主模式;如init.zygote32_64.rc,就有主模式的Zygote,也有附模式的Zygote,所以这里就有了代码中的两次连接操作。

  • ZygoteProcesszygoteSendArgsAndGetResult方法,在上面的startViaZygote方法中,先调用openZygoteSocketIfNeeded尝试与Zygote进程建立Socket连接,假如成功建立连接,会返回的ZygoteState对象,接着会调用zygoteSendArgsAndGetResult方法并将ZygoteState对象作为方法参数传入
    # zygoteState:与Zygote进程成功建立Socket连接后返回的对象
	# args:应用进程的启动参数
	private static Process.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");
                }
            }

            /**
             * See com.android.internal.os.SystemZygoteInit.readArgumentList()
             * Presently the wire format to the zygote process is:
             * a) a count of arguments (argc, in essence)
             * b) a number of newline-separated argument strings equal to count
             *
             * After the zygote process reads these it will write the pid of
             * the child or -1 on failure, followed by boolean to
             * indicate whether a wrapper process was used.
             */
            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();          
            Process.ProcessStartResult result = new Process.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);
        }
    }

该方法的主要作用是将应用进程的启动参数args写入ZygoteState之中,ZygoteStateZygoteProcess的静态内部类,用于表示与Zygote进程通信的状态,另外,上面的一大段英文注释挺重要的

  /**
    * See com.android.internal.os.SystemZygoteInit.readArgumentList()
    * Presently the wire format to the zygote process is:
    * a) a count of arguments (argc, in essence)
    * b) a number of newline-separated argument strings equal to count
    *
    * After the zygote process reads these it will write the pid of
    * the child or -1 on failure, followed by boolean to
    * indicate whether a wrapper process was used.
    */

它表示的是与后面「Zygote接收请求」的一个交互过程,在「AMS发送请求」中,将应用进程的启动参数写入ZygoteState中,在Zygote进程中,会在ZygoteConnectionrunOnce方法中,调用readArgumentList方法,来读取应用进程的启动参数,在Zygote进程读取完应用进程的启动参数之后,它会往输出流里面写入"应用进程pid或者-1"、“一个布尔值”,接着在AMS这边,会读取这些信息

Zygote接收请求

这里描述的是一个Zygote接收请求并创建应用程序进程的过程

时序图如下

应用程序进程启动过程_2

Fork进程

  • ZygoteInit的main、ZygoteServer的runSelectLoop:在「Android系统启动」笔记中,提到Zygote进程会通过调用ZygoteServer的runSelectLoop方法等待AMS的请求,代码如下
    void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
        ...
        while (true) {
			...
            for (int i = pollFds.length - 1; i >= 0; --i) {
                ...
                if (i == 0) {
                    /*
                    * i==0的时候,说明当前fds里面只有mServerSocker的文件描述符,说明此时
                    * 没有"创建应用程序进程"的请求,通过acceptCommandPeer方法等待连接
                    */
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    /*
                    * i不等于0,说明这是一个"创建应用程序进程"的请求,通过调用ZygoteConnection
                    * 的runOnce方法,来创建一个"新的应用程序进程"
                    */
                    boolean done = peers.get(i).runOnce(this);
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }
  • ZygoteConnection的runOnce:
  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;
        }

        ...
        try {
            //2.将args包装到parsedArgs对象中
            parsedArgs = new Arguments(args);

            ...

            //3.通过fork当前进程,创建应用程序进程
            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 {
            //4.子进程会执行If(pid == 0)的分支
            if (pid == 0) {
                // in child
                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                //5.处理应用程序进程
                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);
        }
    }

第1步:这里读取到的"应用进程的启动参数",正是「AMS发送请求」笔记中提到的,AMS在zygoteSendArgsAndGetResultZygoteState写入的"应用进程的启动参数"

抛出异常-清理栈帧

后面的套路就和SystemServer进程启动时的套路一样了,这里简单说明

  • ZygoteConnection的handleChildProc方法:这里会调用到ZygoteInitzygoteInit方法
  • ZygoteInitzygoteInit方法:
    public static final void zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
        ...
        //1.启动Binder线程池
        ZygoteInit.nativeZygoteInit();
        //2.进入ActivityThread的main方法
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

第1步:关于"启动Binder线程池"这一部分,参数书本P75

  • RuntimeInit的applicationInit方法:
	protected static void applicationInit(int targetSdkVersion, String[] argv,  
        	 ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
    	...
        invokeStaticMain(args.startClass, args.startArgs, classLoader);    
    }
  • RuntimeInit的invokeStaticMain方法:
	# className:android.app.ActivityThread
	# argv:应用程序进程的一些启动参数
	# classLoader:null
	private static void invokeStaticMain(String className, String[] argv, ClassLoader 
        classLoader) throws Zygote.MethodAndArgsCaller {
		Class<?> cl;

        try {
        	//获取android.app.ActivityThread类
            cl = Class.forName(className, true, classLoader);
        } ...

        Method m;
        try {
        	//获取ActivityThread的main方法
            m = cl.getMethod("main", new Class[] { String[].class });
        } ...


        /*
         * This throw gets caught in ZygoteInit.main(), which responds
         * by invoking the exception's run() method. This arrangement
         * clears up all the stack frames that were required in setting
         * up the process.
         */
        throw new Zygote.MethodAndArgsCaller(m, argv);
    }

这里的抛出异常-清理栈帧的套路和SystemServer进程启动时的套路是一样的,这样做的理由在「SystemServer进程启动过程」中已经详细说明,这里不再赘述,最终会在ZygoteInitmain方法捕获异常,调用MethodAndArgsCallerrun方法,接着会调用到ActivityThreadmain方法,到了这里,应用程序进程就创建完成了并且运行了主线程的管理类ActivityThread

补充几点

  • MethodAndArgsCallerZygote.java的静态内部类
  • ActivityThread:这是应用程序主线程的管理类

ActivityThread.main

看一下ActivityThreadmain方法

# args:应用程序进程的一些启动参数
public static void main(String[] args) {
	...
    //1.创建主线程Looper
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

	//2.若Handler类型的sMainThreadHandler为null
    if (sMainThreadHandler == null) {
    	//3.获取H类并赋值给sMainThreadHandler
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                                            LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    //4.Looper开始工作
    Looper.loop();

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

H类:H类继承至Handler,是ActivityThread的内部类,用于处理主线程的消息循环

参考

《安卓进阶解密》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值