分析Android 9.0的系统启动

系统启动大致流程

流程这个我用一段文字来大概概括,因为流程并不是重点,一方面是大部分blog都是在讲流程我啰嗦了也没意思,其次是流程又长又臭一般记不住。还是研究点有意思的吧。
大概流程如下

  1. system/core/init/init.cpp 里面解析system/core/rootdir/init.rc
  2. 以64位处理器为例,在被拆分放在system/core/rootdir/init.zygote64.rc里面有启动zygote的配置
  3. sytem/core/init/service.cpp 的start函数会创建zygote的子进程并调用其main函数
  4. 对应就是frameworks/base/cmds/app_process/app_main.cpp的main函数中执行了runtime.start(...)
  5. frameworks/base/core/jni/AndroidRuntime.cpp中启动java虚拟机和注册JNI方法打开了Java新世界的大门
    ------------------Java新世界的大门分割线--------------------
  6. 再通过JNI调用ZygoteInit的main方法
  7. main方法在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java里面,执行registerServerSocketFromEnv,注册socket
  8. main方法接着通过forkSystemServer启动SystemServer
  9. main方法接着执行runSelectLoop等待AMS的请求。
    SystemServer的main函数会启动一些重要的系统服务如AMS,和启动Launcher。

大致流程就是上面这样,看过很多文章看完后,得到的知识跟上面的差不多,挺枯燥的没什么意思(没卵用)。

了解registerServerSocketFromEnv

void registerServerSocketFromEnv(String socketName) {
        if (mServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }

            try {
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                //通过了fileDesc的唯一来保证了mServerSocked的唯一
                mServerSocket = new LocalServerSocket(fd);
                mCloseSocketFd = true;
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

这里主要是通过fd参数实例化了一个LocalServerSocket。

public LocalServerSocket(FileDescriptor fd) throws IOException
    {
        impl = new LocalSocketImpl(fd);
        impl.listen(LISTEN_BACKLOG);
        localAddress = impl.getSockAddress();
    }

LocalServerSocket用了代理模式,实际上是由LocalSocketImpl来实现的。

class LocalSocketImpl
{
    private SocketInputStream fis;
    private SocketOutputStream fos;
    private Object readMonitor = new Object();
    private Object writeMonitor = new Object();

    /** null if closed or not yet created */
    private FileDescriptor fd;
    /** whether fd is created internally */
    private boolean mFdCreatedInternally;

    // These fields are accessed by native code;
    /** file descriptor array received during a previous read */
    FileDescriptor[] inboundFileDescriptors;
    /** file descriptor array that should be written during next write */
    FileDescriptor[] outboundFileDescriptors;

看的出具体的socket的读写都封装在LocalSocketImpl了。

了解runSelectLoop

Runnable runSelectLoop(String abiList) {
        ArrayList fds = new ArrayList();
        ArrayList peers = new ArrayList();
        //实际上这里mServerSocket.getFileDescriptor()就是上面的fd,只有一个
        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null); //很巧妙的在初始化的时候add了一个null

        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                //阻塞住,等待消息
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
...
for (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }

                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    try {
                        ZygoteConnection connection = peers.get(i);
                        final Runnable command = connection.processOneCommand(this);

开始pollFds的长度为1,所以如果有客户端请求连接,会来到i==0的逻辑,实例化好ZygoteConnection 添加到peers,所以当继续有信息过来即可认为是i==1的情况,此时peer.get(1)就是在i==0的时候实例好的ZygoteConnection 。然后接着执行processOneCommand,之前的版本叫runOnce,其实一样是解析socket传过来的参数来执行对应的操作。

了解processOneCommand

Runnable processOneCommand(ZygoteServer zygoteServer) {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;

        try {
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            throw new IllegalStateException("IOException on command socket", ex);
        }

先是通过String数组存放readAgumentList解析从socket传过来的信息

   private String[] readArgumentList()
            throws IOException {
        int argc;

        try {
            //第一行存放的参数数量
            String s = mSocketReader.readLine();

            if (s == null) {
                // EOF reached.
                return null;
            }
            //再把数量string转成integer类型
            argc = Integer.parseInt(s);
        } catch (NumberFormatException ex) {
            Log.e(TAG, "invalid Zygote wire format: non-int at argc");
            throw new IOException("invalid wire format");
        }

        // See bug 1092107: large argc can be used for a DOS attack
      //  通过判断其数量大小判断是不是dos攻击,防止被dos攻击
        if (argc > MAX_ZYGOTE_ARGC) {
            throw new IOException("max arg count exceeded");
        }
        //最后遍历参数,存放再result 的String数组
        String[] result = new String[argc];
        for (int i = 0; i < argc; i++) {
            result[i] = mSocketReader.readLine();
            if (result[i] == null) {
                // We got an unexpected EOF.
                throw new IOException("truncated request");
            }
        }

        return result;
}

在封装在变量中parsedArgs = new Arguments(args);
最后执行forkAndSpecialize,参数都是来自parsedArgs的,有个返回值pid

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

当返回值pid 为0代表fork的是zygote的子进程,通知zygoteServer更改一些状态和关掉socket,因为任务完成了,接着执行handleChildProc,这里参数上继续传了parsedArgs等参数。
来到

  if (!isZygote) {
                return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                        null /* classLoader */);
            } else {
                return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs, null /* classLoader */);
            }

会执行zygoteInit

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();// 通用的一些初始化
        ZygoteInit.nativeZygoteInit();// zygote初始化 
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);// 应用初始化
    }

我们接着跟踪argv的参数传过去的地方看看applicationInit

  //args 存放了应用的startClass 和startArgs
        return findStaticMain(args.startClass, args.startArgs, classLoader);
 //通过反射来获得startClass的main方法
        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);
        }
        return new MethodAndArgsCaller(m, argv);

最后return这一步以前是通过throw操作来回到ZygoteInit的main函数,为了能清空栈,新版本是通过一堆的runnable来衔接,最后在ZygoteInit执行caller.run来实现。
关于MethodAndArgsCaller最后里面的run。

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

到底执行了哪个类的哪个方法?这个肯定要从arg里面的信息才知道,arg归根到底是从发送方通过socket传过来的,那么问题来了发送方是谁?发了什么?
弄清楚这个之前先来看一下上面还没有说的forkSystemServer。

了解forkSystemServer

这个本质上也是zegote的fork子进程的,虽然跟fork应用的子进程有点不一样,但其实差不多。
跟fork应用不同的是,因为这个forkSystemServer方法的调用是在zegoteinit的main函数上的,就没必要再通过socket来通知zegote fork子进程了。

  /* Hardcoded command line to start the system server */
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
...

上面的代码看出来,还是使用了 ZygoteConnection.Arguments来包装参数,证明这两种fork的传参方式是一样的。

static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities,
        jlong effectiveCapabilities) {
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                      runtime_flags, rlimits,
                                      permittedCapabilities, effectiveCapabilities,
                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                      NULL, false, NULL, NULL);

在JNI调用里面看的出实际上也调用跟fork应用子进程一样的ForkAndSpecializeCommon的方法。显然fork子进程的方式也一样。
现在再看看包装和解析参数的过程。

 private void parseArgs(String args[])
                throws IllegalArgumentException {
            int curArg = 0;

            boolean seenRuntimeArgs = false;

            boolean expectRuntimeArgs = true;
            if (arg.equals("--")) {
                    curArg++;
                    break;
                } else if (arg.startsWith("--setuid=")) {
                    if (uidSpecified) {
                        throw new IllegalArgumentException(
                                "Duplicate arg specified");
                    }
                    uidSpecified = true;
                    uid = Integer.parseInt(
                            arg.substring(arg.indexOf('=') + 1));
                } else if (arg.startsWith("--setgid=")) {
                    if (gidSpecified) {
                        throw new IllegalArgumentException(
                                "Duplicate arg specified");
                    }
                    gidSpecified = true;
                    gid = Integer.parseInt(
                            arg.substring(arg.indexOf('=') + 1));
                }
...
//剩下非选项类参数,即不是--开头的参数,用remainingArgs存起来。
            else if (expectRuntimeArgs) {
                if (!seenRuntimeArgs) {
                    throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
                }

                remainingArgs = new String[args.length - curArg];
                System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
            }

forkSystemServer的过程的参数里非“--.."开头的只有"com.android.server.SystemServer",所以remainingArgs存放的就是这个字符串了,也就是类名。
包装起来的parsedArgs在子进程systemserver创建成功后会接着传入handleSystemServerProcess执行

/* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

在handleSystemServerPorcess中最后执行这段代码

if (systemServerClasspath != null) {
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);

                Thread.currentThread().setContextClassLoader(cl);
            }

            /*
             * Pass the remaining arguments to SystemServer.
             */
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);

显然这里传的是remainingArgs,对于systemserver而言就是只有一个类名的String数组。
接着执行

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();// 通用的一些初始化
        ZygoteInit.nativeZygoteInit();// zygote初始化
 //argv包含的是类名和其他参数
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);// 应用初始化
    }

applicationInit里面通过Arguments把argv包装,然后执行

 final Arguments args = new Arguments(argv);

        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        // Remaining arguments are passed to the start class's static main
        //选项的参数都是--开头的,第一个非选项的参数就类名,然后startArgs就是类名之后的参数
        //args 存放了应用的startClass 和startArgs
        return findStaticMain(args.startClass, args.startArgs, classLoader);

看一下Arguments 的代码

 private void parseArgs(String args[])
                throws IllegalArgumentException {
            int curArg = 0;
            for (; curArg < args.length; curArg++) {
                String arg = args[curArg];

                if (arg.equals("--")) {
                    curArg++;
                    break;
                } else if (!arg.startsWith("--")) {
                    break;
                }
            }

            if (curArg == args.length) {
                throw new IllegalArgumentException("Missing classname argument to RuntimeInit!");
            }
             //这里curArg的位置就是非选项类的第一个,即类名,curArg ++ 指向类名之后的参数位置
            startClass = args[curArg++];
//把类名之后的参数复制到startArgs的数组中
            startArgs = new String[args.length - curArg];
            System.arraycopy(args, curArg, startArgs, 0, startArgs.length);
        }
    }

经过解析后得到的startClass 就是类名,startArgs就是类名之后的参数。

到这里我们就知道最后执行了com.android.server.SystemServer的main函数。

你可能感兴趣的:(分析Android 9.0的系统启动)