摄像头uid怎么获取_我是怎么把一个个app进程创建起来的?

前言

古有女娲造人,今有我zygote造进程!

Linux天字第一号进程【init】把我带来了这个世界,不甘平凡的我,得有自己的一方天地。于是我自创了自己的一方世界【Java】。虽然有了自己的小天地,但只有自己孤零零一个人,未免太孤独了,得为这个世界添加更多的精彩。但凭我一个人干,岂不累死?二话不说,我用自己作为本体,克隆了一份自己,并命名为【system_server】,然后让他去做一些杂七杂八的事,创造各种各样的进程服务。我呢,就留下一个后世联系我的入口,有需要我孵化后代的事,我再出力,其余时间,都是我happy的时间了~~

哈哈,YY结束,开始正文!

概述

在上一篇文章中,我们大概清楚了【Zygote】的启动流程,由init进程解析init.rc文件并启动,然后【Zygote】fork出了[system_server]进程后,创建了名为【zygote】的【socket】,并阻塞监听这个【socket】,响应【AMS】的进程创建请求。那具体这部分是怎么实现的呢?以下分两部分进行分析,分别是【AMS】端的创建请求过程和【Zygote】端的响应创建的过程。

AMS发起进程创建的请求

通过【startActivity】启动有用时,最终会调用到【AMS】的【startProcess】,我们的分析就是从这里开始的。下面先上一张流程图,方便大家有一个总体的流程感。

6ed2536af9c03f481209339bb06f1bfc.png

【AMS】的【startProcess】方法实现如下:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private ProcessStartResult startProcess(String hostingType, String entryPoint,
          ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
          String seInfo, String requiredAbi, String instructionSet, String invokeWith,
          long startTime) {

    ...

     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】方法:

frameworks/base/core/java/android/os/Process.java

 public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int runtimeFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String invokeWith,
                              String[] zygoteArgs) {
    return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

方法很简单,只有一句,通过【zygoteProcess】对象,调用它的start方法,【zygoteProcess】是【ZygoteProcess】类的实例化,这里我们先看看【zygoteProcess】是怎么被new出来的:

frameworks/base/core/java/android/os/ZygoteProcess.java
 public static final ZygoteProcess zygoteProcess =
        new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);

调用【ZygoteProcess】的构造函数,并且传入了两个参数:

frameworks/base/core/java/android/os/ZygoteProcess.java
public static final String ZYGOTE_SOCKET = "zygote";
public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";

这里很重要,传入两个参数,都是跟socket相关,且名称跟【Zygote】相关。这很可能是在为连接【zygote】这个socket做准备。我们看看【ZygoteProcess】的构造方法实现:

frameworks/base/core/java/android/os/ZygoteProcess.java
public ZygoteProcess(String primarySocket, String secondarySocket) {
    this(new LocalSocketAddress(primarySocket, LocalSocketAddress.Namespace.RESERVED),
            new LocalSocketAddress(secondarySocket, LocalSocketAddress.Namespace.RESERVED));
}

构造方法中调用了【this】方法,其实就是另外一个构造方法的调用:

public ZygoteProcess(LocalSocketAddress primarySocket, LocalSocketAddress secondarySocket) {
    mSocket = primarySocket;
    mSecondarySocket = secondarySocket;
}

其实也就是:

mSocket = new LocalSocketAddress(primarySocket, LocalSocketAddress.Namespace.RESERVED);
mSecondarySocket = new LocalSocketAddress(secondarySocket, LocalSocketAddress.Namespace.RESERVED;

这样就获取了【zygote】的socket入口,后面会通过这个地址去跟【zygote】通讯。

我们继续看看【ZygoteProcess】的start方法:

frameworks/base/core/java/android/os/ZygoteProcess.java
public final Process.ProcessStartResult start(final String processClass,
                                              final String niceName,
                                              int uid, int gid, int[] gids,
                                              int runtimeFlags, int mountExternal,
                                              int targetSdkVersion,
                                              String seInfo,
                                              String abi,
                                              String instructionSet,
                                              String appDataDir,
                                              String invokeWith,
                                              String[] zygoteArgs) {
    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
        Log.e(LOG_TAG,
                "Starting VM process through Zygote failed");
        throw new RuntimeException(
                "Starting VM process through Zygote failed", ex);
    }
}

这里注意传入给【startViaZygote】方法的倒数第二个参数,后面会影响到我们分析代码分支走向,这里传进来的是【false】,表示不启动【子Zygote】。【startViaZygote】方法实现如下:

 private Process.ProcessStartResult startViaZygote(final String processClass,
                                                  final String niceName,
                                                  final int uid, final int gid,
                                                  final int[] gids,
                                                  int runtimeFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  boolean startChildZygote,
                                                  String[] extraArgs)
                                                  throws ZygoteStartFailedEx {


    ArrayList<String> argsForZygote = new ArrayList<String>();

    // --runtime-args, --setuid=, --setgid=,
    // and --setgroups= must go first
    argsForZygote.add("--runtime-args");
    argsForZygote.add("--setuid=" + uid);
    argsForZygote.add("--setgid=" + gid);
    ...

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

这个方法主要做了两件事:

1.封装参数。这些参数最终会发给【zygote】,【zygote】就是根据这些参数来创建进程的;

2.调用zygoteSendArgsAndGetResult方法将参数发送数据;具体实现如下:

private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, ArrayList<String> args)
        throws ZygoteStartFailedEx {

        try {

            ...
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;
            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }
            ...

        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
}

在这个方法中,我们看到了【write】的操作,开始正式往【zygote】这个socket发具体的CMD指令了,这个操作主要事由【zygoteState】中的【writer】方法实现,而【zygoteState】作为参数被传进来:

zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);

【zygoteState】是由【openZygoteSocketIfNeeded】创建返回的:

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {

    ...
    try {
        primaryZygoteState = ZygoteState.connect(mSocket);
    } catch (IOException ioe) {
        throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
    }

    return primaryZygoteState;
    ...
}

这里调用了【ZygoteState】的connect方法,创建了socket连接,传入的mSocket参数就是我们上文提到的利用名为【zygote】的字符串构建的。

这里完成connect,然后再调用write进行发送指令。到了这里,【AMS】发起进程创建的请求流程就分析完成,下一步看看【Zygote】是如何接收指令并解析command完成进程创建的。

Zygote端如何响应进程创建请求

就如开头所说的,【zygote】在fork出【system_server】后,就留下了一个供外界联系自己的入口,那就是socket。所以要想响应外界的进程创建需求, 第一步就是要创建socket节点,然后再等待请求,然后解析指令参数,从而创建进程。看看流程图就明白了:

0510133c6023a173737dd218419789d5.png

让我们从socket创建说起吧,这得回到【ZygoteInit】的main方法中,【zygote】真正启动的起点:

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {


    ...

    zygoteServer.registerServerSocketFromEnv(socketName);

    ...

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

    ...
}

socket的创建通过【zygoteserver】的【registerServerSocketFromEnv】方法实现,这里传参【socketName】,我们看看它的具体值:

String socketName = "zygote";

这里看来就是要创建一个名为【zygote】的socket了。我们看看它的实现:

frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
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);
            mServerSocket = new LocalServerSocket(fd);
            mCloseSocketFd = true;
        } catch (IOException ex) {
            throw new RuntimeException(
                    "Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

果然在这边创建了socket。接下来就是监听这个socket,响应各种请求即可。我们看看【runSelectLoop】的实现:

frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

Runnable runSelectLoop(String abiList) {

    fds.add(mServerSocket.getFileDescriptor());
    ...
    while(true) {
        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);
                    ...
                catch (Exception e) {
                    ...
                } finally {

                    ...
                }
            }
        }
    }

}

这里看到该方法中将之前创建的socket对应文件描述符添加进来,然后调用系统的poll方法进行监听。这里poll方法的超时时间设置为-1,即如果无相关指令过来,就会一直阻塞。当有指令过来的时候,首先通过i的值来进行判断,如果是0,则表示此时还未同意客户端的连接请求,需要调用【acceptCommandPeer】方法同意此次请求,并将该【connection】对应的文件描述符添加到监听的集合中,下次发了数据过来,就可以被监听到,然后调用【processOneCommand】方法进行处理:

frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

Runnable processOneCommand(ZygoteServer zygoteServer) {

    ...
    try {
        //读取AMS发过来的参数
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        throw new IllegalStateException("IOException on command socket", ex);
    }

    ...

    //开始解析参数,并保存到parsedArgs中
    parsedArgs = new Arguments(args);

    ...

    //根据解析出来的参数fork进程
    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);

    try {
        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;
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

该方法中主要做了四件事:

1.调用【readArgumentList】方法获取客户端发过来的数据;

2.解析参数,并保存到parsedArgs中;

3.根据解析出来的参数fork进程;

4.处理创建出来的子进程;

我们进入到【handleChildProc】方法中,看看是如何实现的:

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
        FileDescriptor pipeFd, boolean isZygote) {

    ...
    closeSocket(); //子进程由于也复制了zygote的socket资源,这里需要进行关闭,子进程并不需要
    ...
     if (!isZygote) {
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                    null /* classLoader */);
    } else {
        return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                parsedArgs.remainingArgs, null /* classLoader */);
    }
    ...
}

这里有个isZygote变量,决定代码走向。这个变量是从【AMS】中一路传递下来的,在上一个章节中有提到,传递下来的值是false,所以这里我们进入到【zygoteInit】中进行分析:

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
    if (RuntimeInit.DEBUG) {
        Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
    }

    ...
    return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

调用了【RuntimeInit】类的【applicationInit】方法:

 protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
        ClassLoader classLoader) {

    ...
    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
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}

很明显,调用【findStaticMain】获取fork出来的main方法,看看具体实现:

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
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);
}

通过反射获取到对应进程的main方法,然后再将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);
        }
    }
}

这里的run主要通过【invoke】方法调用进程的main方法。

【MethodAndArgsCaller】方法最终返回一个【Runnable】对象,该对象会被一路返回,最终返回到【ZygoteInit】,由caller拿到:

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

然后调用【run】方法启动进程。

结语

到了这里,进程正式启动,开始了它的一生。只要不做什么犯法的事,就不会被杀。当然,关键是不要作(过于占用内存和CPU资源),不然也会被系统杀死。

写得好累,终于撸完。此时此刻想来瓶快乐肥皂水!!!

最后

我在微信公众号也有写文章,更新比较及时,有兴趣者可以微信搜索【Android系统实战开发】,关注有惊喜哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值