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

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

你可能会回答:

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

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

一、应用程序进程介绍

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

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

通常情况下,我们开发的一个应用程序至少有一个独立的进程,在这个进程中,我们有独立的存储空间,可以分配一些资源,处理一些特定的事情。
之前的文章和都明确讲过,在处理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(...)

更多相关文章

  1. 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得
  2. Android ActivityManagerService(AMS)的进程管理
  3. Android应用程序模拟手机按键
  4. Android学习笔记Android线程模型解析
  5. 第一个Android应用程序
  6. Android应用程序包含的各个文件

随机推荐

  1. Android初级教程 - DatePicker的使用(日历
  2. Android中定义接口的方法
  3. android 显示通知栏
  4. android用户界面教程实例汇总
  5. Android(安卓)Studio Error:Unable to re
  6. Android中的Typeface
  7. Android获取CPU信息(主频,使用率)
  8. weex android 选择文件 拍照 获得uri 并
  9. Android之平时遇见的异常和错误总结(不断
  10. Android(安卓)学习笔记(二) 各种技巧小知识