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

  • 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(安卓)7.0 虚拟按键(NavigationBar)源码分析 之 View的创建
  2. android手把手教你开发launcher(一)(AndroidStudio版)
  3. 文章关键字 ‘nodpi’
  4. 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得
  5. Android官方开发文档Training系列课程中文版:连接无线设备之网络
  6. Android(安卓)ActivityManagerService(AMS)的进程管理
  7. Android(安卓)权限控制代码分析
  8. Android(安卓)— 创建文件及文件夹
  9. android ContentResolver详解

随机推荐

  1. Android使用webrtc实现检测用户是否在说
  2. apk安装 手机没sd卡安装失败解决方案
  3. Android(安卓)的HashMap介绍
  4. Android学习开发路线图
  5. Android 广播接收器注册与注销源码分析
  6. Android插件开发初探——分析篇
  7. Android Studio 单元测试
  8. android wifi 连接笔记
  9. Android学习笔记(38):Handler消息传递处
  10. Android在MediaMuxer和MediaCodec录制视