美文网首页
Android应用程序启动

Android应用程序启动

作者: 码上就说 | 来源:发表于2018-09-13 20:47 被阅读571次

    本文开始的时候,先提一个面试中常问的问题:

    • Android应用程序启动的入口到底在哪儿?

    你可能会回答:

    • 启动Activity的onCreate(...)中?
    • Application中的onCreate(...)中?

    两样都不是?接下来可能就是一段长时间的沉默,你可以回家了,这个问题很基本,但是不看过源码的人很多都不知道。接下来我们就分析一下Android应用程序的启动流程,告诉你Android应用程序真正的启动入口在什么地方。

    一、应用程序进程介绍

    一个应用程序的进程名称就是AndroidManifest.xml中定义的标签:
    manifest节点中的package标签。
    应用程序四要素:

    • 有一段程序供其运行
    • 拥有专用的系统堆栈空间
    • 在内核存在对应的进程控制块
    • 拥有独立的用户存储空间

    通常情况下,我们开发的一个应用程序至少有一个独立的进程,在这个进程中,我们有独立的存储空间,可以分配一些资源,处理一些特定的事情。
    之前的文章<Service组件源码全面剖析><Android广播剖析之发送广播、接收广播>都明确讲过,在处理service和分发广播之前,都会判断当前的应用程序进程是否存在,如果存在则复用,如果不存在就创建一个。
    这个创建是怎么个创建法?谁创建?这是我们本章探讨的重点。

    二、应用程序创建

    当前应用进程不存在,创建进程的起点就是AMS->startProcessLocked(...)
    这儿不得不贴一些代码,见谅。

    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) {
            app.pendingStart = true;
            app.killedByAm = false;
            app.removed = false;
            app.killed = false;
            final long startSeq = app.startSeq = ++mProcStartSeqCounter;
            app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime);
            if (mConstants.FLAG_PROCESS_START_ASYNC) {
                mProcStartHandler.post(() -> {
                    try {
                        synchronized (ActivityManagerService.this) {
                            final String reason = isProcStartValidLocked(app, startSeq);
                            if (reason != null) {
                                app.pendingStart = false;
                                return;
                            }
                            app.usingWrapper = invokeWith != null
                                    || SystemProperties.get("wrap." + app.processName) != null;
                            mPendingStarts.put(startSeq, app);
                        }
                        final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
                                app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
                                requiredAbi, instructionSet, invokeWith, app.startTime);
                        synchronized (ActivityManagerService.this) {
                            handleProcessStartedLocked(app, startResult, startSeq);
                        }
                    } catch (RuntimeException e) {
                        synchronized (ActivityManagerService.this) {
                            mPendingStarts.remove(startSeq);
                            app.pendingStart = false;
                            forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
                                    false, false, true, false, false,
                                    UserHandle.getUserId(app.userId), "start failure");
                        }
                    }
                });
                return true;
            } else {
                try {
                    final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
                            uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
                            invokeWith, startTime);
                    handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                            startSeq, false);
                } catch (RuntimeException e) {
                    app.pendingStart = false;
                    forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
                            false, false, true, false, false,
                            UserHandle.getUserId(app.userId), "start failure");
                }
                return app.pid > 0;
            }
        }
    

    代码比较长。核心判断就是当前是异步启动进程吗?当前是异步启动进程。

    final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
                                app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
                                requiredAbi, instructionSet, invokeWith, app.startTime);
    

    真正核心的调用时这句代码,传入了启动进程必要的参数。其中这个entryPoint是什么?循着调用的路径向上找一下。找上一步调用中发现了:

    final String entryPoint = "android.app.ActivityThread";
    return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                        runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                        startTime);
    

    这儿赋值为android.app.ActivityThread,接下来看他怎么用。

    AMS->startProcess

    这里面还分为两种情况,webview_service和其他的情况,普通的应用程序就是其他的情况。直接调用的函数是:

    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});
    

    Process->start

    ZygoteProcess->start

    ZygoteProcess->startViaZygote

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

    用一个ArrayList将要用的参数加到列表中。执行openZygoteSocketIfNeeded(...)

    ZygoteProcess->openZygoteSocketIfNeeded(...)

    ZygoteState->connect(...)

    public static ZygoteState connect(LocalSocketAddress address) throws IOException {
                DataInputStream zygoteInputStream = null;
                BufferedWriter zygoteWriter = null;
                final LocalSocket zygoteSocket = new LocalSocket();
                try {
                    zygoteSocket.connect(address);
                    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);
                return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                        Arrays.asList(abiListString.split(",")));
            }
    

    zygoteSocket连接的address是在Porcess中定义的zygoteProcess变量:

    public static final String ZYGOTE_SOCKET = "zygote";
    public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
    public static final ZygoteProcess zygoteProcess =
                new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
    

    两个zygoteSocket服务,当第一个没有连接上,尝试第二个,保证socket通信正常。
    创建了名为zygote的socket,此socket与本地的驱动设备/dev/socket/zygote绑定一起,通过LocalSocket找到/dev/socket/目录下的zygote文件,然后与之绑定在一起,连接成功。
    其中zygoteInputStream为获取当前Zygote socket的输入流对象,然后定义zygoteWriter的写对象,以便向socket中写入数据。

    三、socket接收

    Zygote进程启动的时候,会执行一个函数,等待一个名为zygote或者zygote_secondary的socket,执行的函数在ZygoteInit->forkSystemServer(...)

    ZygoteInit->forkSystemServer(...)

    /* For child process */
            if (pid == 0) {
                if (hasSecondZygote(abiList)) {
                    waitForSecondaryZygote(socketName);
                }
    
                zygoteServer.closeServerSocket();
                return handleSystemServerProcess(parsedArgs);
            }
    

    这在创建system_sever进程函数中会执行waitForSecondaryZygote(...)函数。

    ZygoteInit->waitForSecondaryZygote

    private static void waitForSecondaryZygote(String socketName) {
            String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ?
                    Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
            ZygoteProcess.waitForConnectionToZygote(otherZygoteName);
        }
    

    也会连接到这个socket上,然后双方都会连接到socket上,然后会执行

    caller = zygoteServer.runSelectLoop(abiList);
    if (caller != null) {
                caller.run();
            }
    

    启动一个线程专门监听/dev/socket/zygote是否有信息发送,如果有信息发送,则执行ZygoteServer->run()中的:

    final Runnable command = connection.processOneCommand(this);
    

    ZygoteConnection->processOneCommand(...)

    执行到native层fork一个新的进程,进程名就是传入的pkgName。

    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);
    

    创建进程成功之后,会进入下面的判断流程:

              if (pid == 0) {
                    // in child
                    zygoteServer.setForkChild();
    
                    zygoteServer.closeServerSocket();
                    IoUtils.closeQuietly(serverPipeFd);
                    serverPipeFd = null;
    
                    return handleChildProc(parsedArgs, descriptors, childPipeFd,
                            parsedArgs.startChildZygote);
                } else {
                    // In the parent. A pid < 0 indicates a failure and will be handled in
                    // handleParentProc.
                    IoUtils.closeQuietly(childPipeFd);
                    childPipeFd = null;
                    handleParentProc(pid, descriptors, serverPipeFd);
                    return null;
                }
    

    当pid=0,表明是在当前新创建的子进程中执行的,一般就是我们认为的应用程序进程。

    ZygoteConnection->handleChildProc(...)

          if (parsedArgs.invokeWith != null) {
                WrapperInit.execApplication(parsedArgs.invokeWith,
                        parsedArgs.niceName, parsedArgs.targetSdkVersion,
                        VMRuntime.getCurrentInstructionSet(),
                        pipeFd, parsedArgs.remainingArgs);
    
                // Should not get here.
                throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
            } else {
                if (!isZygote) {
                    return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                            null /* classLoader */);
                } else {
                    return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                            parsedArgs.remainingArgs, null /* classLoader */);
                }
            }
    

    当前传入的invokeWith为null,执行else下面的判断。

    ZygoteInit->zygoteInit(...)

    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
            RuntimeInit.commonInit();
            ZygoteInit.nativeZygoteInit();
            return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
        }
    

    RuntimeInit->applicationInit(...)

    这儿设置了虚拟机的targetSdk以及对大小等等虚拟机设置。

    RuntimeInit->findStaticMain(...)

    protected static Runnable findStaticMain(String className, String[] argv,
                ClassLoader classLoader) {
            Class<?> cl;
    
            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);
            }
    
            int modifiers = m.getModifiers();
            if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
                throw new RuntimeException(
                        "Main method is not public and static on " + className);
            }
            return new MethodAndArgsCaller(m, argv);
        }
    

    通过classLoader反射调用ActivityThread->main(...)方法,最终的执行在MethodAndArgsCaller静态内部类中执行了反射的调用:

    static class MethodAndArgsCaller 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 {
                    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);
                }
            }
        }
    

    四、未决的问题

    • Binder线程池什么地方创建的?
    • 消息循环什么时候创建的?

    这两个问题很重要,没有Binder线程池,那么在此进程空间中,和外部的进程binder调用,就会耗时耗内存,产生很大的性能问题,启动了Binder线程池,可以提升这些问题。同样的,如果没有消息循环,Android基本的运行框架都不存在的,无法处理一个个消息,图形无法展示,事情无法处理。

    4.1 Binder线程池创建

    ZygoteInit.nativeZygoteInit();
    此函数建立Binder线程池。深入看其中的代码调用流程。

    4.2 消息循环

    ActivityThread->main(...)中执行的有关消息循环的代码如下:

    Looper.prepareMainLooper();
    //......
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    //......
    Looper.loop();
    

    应用程序进程中创建一个主线程的Looper,启动loop(),开始消息循环机制,我们就可以在进程中处理消息机制了。Android的核心机制就是消息机制。

    五、小结

    通过上面文章的分析,我们知道了启动一个应用程序进程需要下面的几步:

    • zygote进程创建socket监听
    • 应用程序需要创建的时候向socket发送数据,带上启动进程所需的必要信息。
    • 启动crash log监听handler
    • 创建binder线程池
    • 开启消息循环机制
    • Android应用程序的入口----> ActivityThread->main(...)

    相关文章

      网友评论

          本文标题:Android应用程序启动

          本文链接:https://www.haomeiwen.com/subject/vlfugftx.html