Android应用程序启动

2018-09-13  本文已影响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(...)
上一篇 下一篇

猜你喜欢

热点阅读