【Android开发高级系列】Android多进程专题

1 进程启动过程

         Android应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信机制;这两个特点都是在进程的初始化过程中实现的,本文将详细分析Android应用程序进程创建过程中是如何实现这两个特点的。

        Android应用程序框架层创建的应用程序进程的入口函数是ActivityThread.main比较好理解,即进程创建完成之后,Android应用程序框架层就会在这个进程中将ActivityThread类加载进来,然后执行它的main函数,这个main函数就是进程执行消息循环的地方了。Android应用程序框架层创建的应用程序进程天然支持Binder进程间通信机制这个特点应该怎么样理解呢?前面我们在学习Android系统的Binder进程间通信机制时说到,它具有四个组件,分别是驱动程序、守护进程、Client以及Server,其中Server组件在初始化时必须进入一个循环中不断地与Binder驱动程序进行到交互,以便获得Client组件发送的请求,具体可参考Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析一文,但是,当我们在Android应用程序中实现Server组件的时候,我们并没有让进程进入一个循环中去等待Client组件的请求,然而,当Client组件得到这个Server组件的远程接口时,却可以顺利地和Server组件进行进程间通信,这就是因为Android应用程序进程在创建的时候就已经启动了一个线程池来支持Server组件和Binder驱动程序之间的交互了,这样,极大地方便了在Android应用程序中创建Server组件。

        在Android应用程序框架层中,是由ActivityManagerService组件负责为Android应用程序创建新的进程的,它本来也是运行在一个独立的进程之中,不过这个进程是在系统启动的过程中创建的。ActivityManagerService组件一般会在什么情况下会为应用程序创建一个新的进程呢?当系统决定要在一个新的进程中启动一个Activity或者Service时,它就会创建一个新的进程了,然后在这个新的进程中启动这个Activity或者Service,具体可以参考Android系统在新进程中启动自定义服务过程(startService)的原理分析、Android应用程序启动过程源代码分析和Android应用程序在新的进程中启动新的Activity的方法和过程分析这三篇文章。

        ActivityManagerService启动新的进程是从其成员函数startProcessLocked开始的,在深入分析这个过程之前,我们先来看一下进程创建过程的序列图,然后再详细分析每一个步骤。

Step 1.ActivityManagerService.startProcessLocked

        这个函数定义在frameworks/base/services/Java/com/android/server/am/ActivityManagerService.java文件中:

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

    ......

    private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr){

        ......

        try{

            int uid = app.info.uid;

            int[] gids = null;

            try{

                gids = mContext.getPackageManager().getPackageGids(app.info.packageName);

            } catch(PackageManager.NameNotFoundException e) {

                ......

            }

            ......

            int debugFlags = 0;

            ......

            int pid = Process.start("android.app.ActivityThread", mSimpleProcessManagement ? app.processName : null, uid, uid, gids, debugFlags, null);

            ......

        } catch(RuntimeException e) {

            ......

        }

    }

    ......

} 

        它调用了Process.start函数开始为应用程序创建新的进程,注意,它传入一个第一个参数为"android.app.ActivityThread",这就是进程初始化时要加载的Java类了,把这个类加载到进程之后,就会把它里面的静态成员函数main作为进程的入口点,后面我们会看到。


Step 2. Process.start

        这个函数定义在frameworks/base/core/java/android/os/Process.java文件中:

public class Process {

    ......

    public static final int start(final String processClass, final String niceName, int uid, int gid, int[] gids, int debugFlags, String[] zygoteArgs)

    {

        if(supportsProcesses()) {

           try{

               return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, zygoteArgs);

            } catch(ZygoteStartFailedEx ex) {

                ......

            }

        } else{

            ......

            return 0;

        }

    }

    ......

}

       这里的supportsProcesses函数返回值为true,它是一个Native函数,实现在frameworks/base/core/jni/android_util_Process.cpp文件中:

jboolean android_os_Process_supportsProcesses(JNIEnv* env, jobject clazz)

{

    return ProcessState::self()->supportsProcesses();

}

       ProcessState::supportsProcesses函数定义在frameworks/base/libs/binder/ProcessState.cpp文件中:

bool ProcessState::supportsProcesses() const

{

    return mDriverFD >= 0;

}

       这里的mDriverFD是设备文件/dev/binder的打开描述符,如果成功打开了这个设备文件,那么它的值就会大于等于0,因此,它的返回值为true。

       回到Process.start函数中,它调用startViaZygote函数进一步操作。


Step3. Process.startViaZygote

       这个函数定义在frameworks/base/core/java/android/os/Process.java文件中:

public class Process {

    ......

    private static int startViaZygote(final String processClass, final String niceName, final int uid, 

    final int gid, final int[] gids, int debugFlags, String[] extraArgs) throwsZygoteStartFailedEx 

    {

        int pid;

        synchronized(Process.class) {    

            ArrayList argsForZygote = new ArrayList();

            // --runtime-init, --setuid=, --setgid=,

            // and --setgroups= must go first

            argsForZygote.add("--runtime-init");

            argsForZygote.add("--setuid="+ uid);

            argsForZygote.add("--setgid="+ gid);

            if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {

                argsForZygote.add("--enable-safemode");

            }

            if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {

                argsForZygote.add("--enable-debugger");    

            }

            if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {

                argsForZygote.add("--enable-checkjni");

            }

            if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {

                argsForZygote.add("--enable-assert");

            }

            //TODO optionally enable debuger

            //argsForZygote.add("--enable-debugger");

            // --setgroups is a comma-separated list

            if (gids != null && gids.length > 0) {

                StringBuilder sb = new StringBuilder();

                sb.append("--setgroups=");

                int sz = gids.length;

                for (int i = 0; i < sz; i++) {

                    if (i != 0) {

                        sb.append(',');

                    }

                    sb.append(gids[i]);

                }

                argsForZygote.add(sb.toString());

            }

            if (niceName != null) {

                argsForZygote.add("--nice-name="+ niceName);

            }

            argsForZygote.add(processClass);

            if (extraArgs != null) {

                for(String arg : extraArgs) {

                    argsForZygote.add(arg);

                }

            }

            pid = zygoteSendArgsAndGetPid(argsForZygote);

        }

    }

......

}  

        这个函数将创建进程的参数放到argsForZygote列表中去,如参数"--runtime-init"表示要为新创建的进程初始化运行时库,然后调用zygoteSendAndGetPid函数进一步操作。


Step 4. Process.zygoteSendAndGetPid

        这个函数定义在frameworks/base/core/java/android/os/Process.java文件中:

public class Process {

    ......

    private static int zygoteSendArgsAndGetPid(ArrayList args) throws ZygoteStartFailedEx 

    {

        int pid;

        openZygoteSocketIfNeeded();

        try{

            /**

            * See com.android.internal.os.ZygoteInit.readArgumentList()

            * Presently the wire format to the zygote process is:

            * a) a count of arguments (argc, in essence)

            * b) a number of newline-separated argument strings equal to count

            *

            * After the zygote process reads these it will write the pid of

            * the child or -1 on failure.

            */

            sZygoteWriter.write(Integer.toString(args.size()));

            sZygoteWriter.newLine();

            int sz = args.size();

            for (int i = 0; i < sz; i++) {

                String arg = args.get(i);

                if (arg.indexOf('\n') >= 0) {

                    throw new ZygoteStartFailedEx("embedded newlines not allowed");

                }

                sZygoteWriter.write(arg);

                sZygoteWriter.newLine();

            }

            sZygoteWriter.flush();

            // Should there be a timeout on this?

            pid = sZygoteInputStream.readInt();

            if (pid < 0) {

                throw new ZygoteStartFailedEx("fork() failed");

            }

        } catch(IOException ex) {

        ......

        }

        return pid;

    }

    ......

}

         这里的sZygoteWriter是一个Socket写入流,是由openZygoteSocketIfNeeded函数打开的:

public class Process {

    ......

    /**

    * Tries to open socket to Zygote process if not already open. If

    * already open, does nothing.  May block and retry.

    */

    private static void openZygoteSocketIfNeeded() throws ZygoteStartFailedEx 

    {

        int retryCount;

        if(sPreviousZygoteOpenFailed) {

            /*

            * If we've failed before, expect that we'll fail again and

            * don't pause for retries.

            */

            retryCount = 0;

        } else{

            retryCount = 10;

        }

        /*

        * See bug #811181: Sometimes runtime can make it up before zygote.

        * Really, we'd like to do something better to avoid this condition,

        * but for now just wait a bit...

        */

        for (int retry = 0; (sZygoteSocket == null) && (retry < (retryCount + 1)); retry++ ) 

        {

                if (retry > 0) {

                    try{

                        Log.i("Zygote", "Zygote not up yet, sleeping...");

                        Thread.sleep(ZYGOTE_RETRY_MILLIS);

                    } catch(InterruptedException ex) {

                        // should never happen

                    }

                }

                try{

                    sZygoteSocket = new LocalSocket();

                    sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET, LocalSocketAddress.Namespace.RESERVED));

                    sZygoteInputStream = new DataInputStream(sZygoteSocket.getInputStream());

                    sZygoteWriter = new BufferedWriter(new OutputStreamWriter(sZygoteSocket.getOutputStream()), 256);

                    Log.i("Zygote", "Process: zygote socket opened");

                    sPreviousZygoteOpenFailed = false;

                    break;

                } catch(IOException ex) {

                    ......

                }

            }

            ......

        }

        ......

    }

        这个Socket由frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中的ZygoteInit类在runSelectLoopMode函数侦听的。


Step 5. ZygoteInit.runSelectLoopMode

        这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

public class ZygoteInit {

    ......

    /**

    * Runs the zygote process's select loop. Accepts new connections as

    * they happen, and reads commands from connections one spawn-request's

    * worth at a time.

    *

    * @throws MethodAndArgsCaller in a child process when a main() should

    * be executed.

    */

    private static void runSelectLoopMode() throws MethodAndArgsCaller {

        ArrayList fds = new ArrayList();

        ArrayList peers = new ArrayList();

        FileDescriptor[] fdArray = new FileDescriptor[4];

        fds.add(sServerSocket.getFileDescriptor());

        peers.add(null);

        int loopCount = GC_LOOP_COUNT;

        while (true) {

            int index;

            /*

            * Call gc() before we block in select().

            * It's work that has to be done anyway, and it's better

            * to avoid making every child do it.  It will also

            * madvise() any free memory as a side-effect.

            *

            * Don't call it every time, because walking the entire

            * heap is a lot of overhead to free a few hundred bytes.

            */

            if (loopCount <= 0) {

                gc();

                loopCount = GC_LOOP_COUNT;

            } else{

                loopCount--;

            }

            try{

                fdArray = fds.toArray(fdArray);

                index = selectReadable(fdArray);

            } catch(IOException ex) {

                throw new RuntimeException("Error in select()", ex);

            }

            if (index < 0) {

                throw new RuntimeException("Error in select()");

            } else if (index == 0) {

                ZygoteConnection newPeer = acceptCommandPeer();

                peers.add(newPeer);

                fds.add(newPeer.getFileDesciptor());

            } else{

                boolean done;

                done = peers.get(index).runOnce();

                if(done) {

                    peers.remove(index);

                    fds.remove(index);

                }

            }

        }

    }

    ......

}

        当Step 4将数据通过Socket接口发送出去后,就会下面这个语句:

done = peers.get(index).runOnce();

        这里从peers.get(index)得到的是一个ZygoteConnection对象,表示一个Socket连接,因此,接下来就是调用ZygoteConnection.runOnce函数进一步处理了。


Step 6. ZygoteConnection.runOnce

        这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java文件中:

class ZygoteConnection 

{

    ......

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller 

    {

        String args[];

        Arguments parsedArgs = null;

        FileDescriptor[] descriptors;

        try{

            args = readArgumentList();

            descriptors = mSocket.getAncillaryFileDescriptors();

        } catch(IOException ex) {

            ......

            return true;

        }

        ......

        /** the stderr of the most recent request, if avail */

        PrintStream newStderr = null;

        if (descriptors != null && descriptors.length >= 3) {

            newStderr = new PrintStream(new FileOutputStream(descriptors[2]));

        }

        int pid;

        try{

            parsedArgs = new Arguments(args);

            applyUidSecurityPolicy(parsedArgs, peer);

            applyDebuggerSecurityPolicy(parsedArgs);

            applyRlimitSecurityPolicy(parsedArgs, peer);

            applyCapabilitiesSecurityPolicy(parsedArgs, peer);

            int[][] rlimits = null;

            if (parsedArgs.rlimits != null) {

                rlimits = parsedArgs.rlimits.toArray(intArray2d);

            }

            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits);

        } catch(IllegalArgumentException ex) {

            ......

        } catch(ZygoteSecurityException ex) {

            ......

        }

        if (pid == 0) {

            // in child

            handleChildProc(parsedArgs, descriptors, newStderr);

            // should never happen

            return true;

        } else { /* pid != 0 */

            // in parent...pid of < 0 means failure

            return handleParentProc(pid, descriptors, parsedArgs);

        }

    }

    ......

}

         真正创建进程的地方就是在这里了:

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits);

        有Linux开发经验的读者很容易看懂这个函数调用,这个函数会创建一个进程,而且有两个返回值,一个是在当前进程中返回的,一个是在新创建的进程中返回,即在当前进程的子进程中返回,在当前进程中的返回值就是新创建的子进程的pid值,而在子进程中的返回值是0。因为我们只关心创建的新进程的情况,因此,我们沿着子进程的执行路径继续看下去:

if (pid == 0) {

    // in child

    handleChildProc(parsedArgs, descriptors, newStderr);

    // should never happen

    return true;

} else { 

    /* pid != 0 */

    ......

}

        这里就是调用handleChildProc函数了。


Step7. ZygoteConnection.handleChildProc

        这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java文件中:

class ZygoteConnection {

     ......

    private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller 

    {

        ......

        if(parsedArgs.runtimeInit) {

            RuntimeInit.zygoteInit(parsedArgs.remainingArgs);

        } else{

            ......

        }

    }

    ......

}

        由于在前面的Step 3中,指定了"--runtime-init"参数,表示要为新创建的进程初始化运行时库,因此,这里的parseArgs.runtimeInit值为true,于是就继续执行RuntimeInit.zygoteInit进一步处理了。


Step 8. RuntimeInit.zygoteInit

        这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

public class RuntimeInit {

    ......

    public static final void zygoteInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller 

    {

        // TODO: Doing this here works, but it seems kind of arbitrary. Find

        // a better place. The goal is to set it up for applications, but not

        // tools like am.

        System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));

        System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));

        commonInit();

        zygoteInitNative();

        int curArg = 0;

        for ( /* curArg */; curArg < argv.length; curArg++) {

            String arg = argv[curArg];

            if (arg.equals("--")) {

                curArg++;

                break;

            } else if (!arg.startsWith("--")) {

                break;

            } else if (arg.startsWith("--nice-name=")) {

                String niceName = arg.substring(arg.indexOf('=') + 1);

                Process.setArgV0(niceName);

            }

        }

        if(curArg == argv.length) {

            Slog.e(TAG, "Missing classname argument to RuntimeInit!");

            // let the process exit

            return;

        }

        // Remaining arguments are passed to the start class's static main

        String startClass = argv[curArg++];

        String[] startArgs = new String[argv.length - curArg];

        System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);

        invokeStaticMain(startClass, startArgs);

    }

    ......

}  

        这里有两个关键的函数调用,一个是zygoteInitNative函数调用,一个是invokeStaticMain函数调用,前者就是执行Binder驱动程序初始化的相关工作了,正是由于执行了这个工作,才使得进程中的Binder对象能够顺利地进行Binder进程间通信,而后一个函数调用,就是执行进程的入口函数,这里就是执行startClass类的main函数了,而这个startClass即是我们在Step 1中传进来的"android.app.ActivityThread"值,表示要执行android.app.ActivityThread类的main函数。

        我们先来看一下zygoteInitNative函数的调用过程,然后再回到RuntimeInit.zygoteInit函数中来,看看它是如何调用android.app.ActivityThread类的main函数的。


step 9. RuntimeInit.zygoteInitNative

        这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

public class RuntimeInit {

    ......

    public static final native void zygoteInitNative();

    ......

}

        这里可以看出,函数zygoteInitNative是一个Native函数,实现在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz)

{

    gCurRuntime->onZygoteInit();

}

        这里它调用了全局变量gCurRuntime的onZygoteInit函数,这个全局变量的定义在frameworks/base/core/jni/AndroidRuntime.cpp文件开头的地方:

static AndroidRuntime* gCurRuntime = NULL;

        这里可以看出,它的类型为AndroidRuntime,它是在AndroidRuntime类的构造函数中初始化的,AndroidRuntime类的构造函数也是定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

AndroidRuntime::AndroidRuntime()

{

    ......

    assert(gCurRuntime == NULL);        // one per process

    gCurRuntime = this;

}

        那么这个AndroidRuntime类的构造函数又是什么时候被调用的呢?AndroidRuntime类的声明在frameworks/base/include/android_runtime/AndroidRuntime.h文件中,如果我们打开这个文件会看到,它是一个虚拟类,也就是我们不能直接创建一个AndroidRuntime对象,只能用一个AndroidRuntime类的指针来指向它的某一个子类,这个子类就是AppRuntime了,它定义在frameworks/base/cmds/app_process/app_main.cpp文件中:

int main(int argc, const char* constargv[])

{

    ......

    AppRuntime runtime;

    ......

}

        而AppRuntime类继续了AndroidRuntime类,它也是定义在frameworks/base/cmds/app_process/app_main.cpp文件中:

class AppRuntime : public AndroidRuntime

{

    ......

};

        因此,在前面的com_android_internal_os_RuntimeInit_zygoteInit函数,实际是执行了AppRuntime类的onZygoteInit函数。


Step 10. AppRuntime.onZygoteInit

        这个函数定义在frameworks/base/cmds/app_process/app_main.cpp文件中:

class AppRuntime : public AndroidRuntime

{

    ......

    virtual void onZygoteInit()

    {

        sp proc = ProcessState::self();

        if(proc->supportsProcesses()) {

            LOGV("App process: starting thread pool.\n");

            proc->startThreadPool();

        }

    }

    ......

};

        这里它就是调用ProcessState::startThreadPool启动线程池了,这个线程池中的线程就是用来和Binder驱动程序进行交互的了。


Step 11. ProcessState.startThreadPool

        这个函数定义在frameworks/base/libs/binder/ProcessState.cpp文件中:

void ProcessState::startThreadPool()

{

    AutoMutex _l(mLock);

    if(!mThreadPoolStarted) {

        mThreadPoolStarted = true;

        spawnPooledThread(true);

    }

}

        ProcessState类是Binder进程间通信机制的一个基础组件,它的作用可以参考浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路、Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析和Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析这三篇文章。这里它调用spawnPooledThread函数进一步处理。


Step 12. ProcessState.spawnPooledThread

        这个函数定义在frameworks/base/libs/binder/ProcessState.cpp文件中:

void ProcessState::spawnPooledThread(bool isMain)

{

    if(mThreadPoolStarted) {

        int32_t s = android_atomic_add(1, &mThreadPoolSeq);

        char buf[32];

        sprintf(buf, "Binder Thread #%d", s);

        LOGV("Spawning new pooled thread, name=%s\n", buf);

        sp t = new PoolThread(isMain);

        t->run(buf);

    }

}  

        这里它会创建一个PoolThread线程类,然后执行它的run函数,最终就会执行PoolThread类的threadLoop函数了。


Step 13. PoolThread.threadLoop

        这个函数定义在frameworks/base/libs/binder/ProcessState.cpp文件中:

class PoolThread : public Thread

{

    public:

        PoolThread(bool isMain) : mIsMain(isMain)

        {

        }

    protected:

        virtual bool threadLoop()

        {

            IPCThreadState::self()->joinThreadPool(mIsMain);

            return false;

        }

        const bool mIsMain;

};

        这里它执行了IPCThreadState::joinThreadPool函数进一步处理。IPCThreadState也是Binder进程间通信机制的一个基础组件,它的作用可以参考浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路、Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析和Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析这三篇文章。


Step14. IPCThreadState.joinThreadPool

        这个函数定义在frameworks/base/libs/binder/IPCThreadState.cpp文件中:

void IPCThreadState::joinThreadPool(bool isMain)

{

    ......

    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

    ......

    status_t result;

    do{

        int32_t cmd;

        ......

        // now get the next command to be processed, waiting if necessary

        result = talkWithDriver();

        if(result >= NO_ERROR) {

            size_t IN = mIn.dataAvail();

            if (IN < sizeof(int32_t)) continue;

            cmd = mIn.readInt32();

            ......

            result = executeCommand(cmd);

        }

       ......

    } while(result != -ECONNREFUSED && result != -EBADF);

    ......

    mOut.writeInt32(BC_EXIT_LOOPER);

    talkWithDriver(false);

}

        这个函数首先告诉Binder驱动程序,这条线程要进入循环了:

mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

        然后在中间的while循环中通过talkWithDriver不断与Binder驱动程序进行交互,以便获得Client端的进程间调用:

result = talkWithDriver();

        获得了Client端的进程间调用后,就调用excuteCommand函数来处理这个请求:

result = executeCommand(cmd);

        最后,线程退出时,也会告诉Binder驱动程序,它退出了,这样Binder驱动程序就不会再在Client端的进程间调用分发给它了:

mOut.writeInt32(BC_EXIT_LOOPER);

talkWithDriver(false);

        我们再来看看talkWithDriver函数的实现。


Step 15. talkWithDriver

        这个函数定义在frameworks/base/libs/binder/IPCThreadState.cpp文件中:

status_t IPCThreadState::talkWithDriver(bool doReceive)

{

    ......

    binder_write_read bwr;

    // Is the read buffer empty?

    const bool needRead = mIn.dataPosition() >= mIn.dataSize();

    // We don't want to write anything if we are still reading

    // from data left in the input buffer and the caller

    // has requested to read the next data.

    const size_toutAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

    bwr.write_size = outAvail;

    bwr.write_buffer = (long unsigned int)mOut.data();

    // This is what we'll read.

    if(doReceive && needRead) {

        bwr.read_size = mIn.dataCapacity();

        bwr.read_buffer = (long unsigned int)mIn.data();

    } else{

        bwr.read_size = 0;

    }

    ......

    // Return immediately if there is nothing to do.

    if ((bwr.write_size == 0) && (bwr.read_size == 0)) 

        return NO_ERROR;

    bwr.write_consumed = 0;

    bwr.read_consumed = 0;

    status_t err;

    do{

        ......

#if defined(HAVE_ANDROID_OS)

        if(ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)

            err = NO_ERROR;

        else

            err = -errno;

#else

            err = INVALID_OPERATION;

#endif

            ......

        }

    } while(err == -EINTR);

    ....

    if(err >= NO_ERROR) {

        if(bwr..write_consumed > 0) {

            if(bwr.write_consumed < (ssize_t)mOut.dataSize())

                mOut.remove(0, bwr.write_consumed);

            else

                mOut.setDataSize(0);

        }

        if(bwr.read_consumed > 0) {

            mIn.setDataSize(bwr.read_consumed);

            mIn.setDataPosition(0);

        }

        ......

        return NO_ERROR;

    }

    return err;

}

        这个函数的具体作用可以参考Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析一文,它只要就是通过ioctl文件操作函数来和Binder驱动程序交互的了:

ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)

        有了这个线程池之后,我们在开发Android应用程序的时候,当我们要和其它进程中进行通信时,只要定义自己的Binder对象,然后把这个Binder对象的远程接口通过其它途径传给其它进程后,其它进程就可以通过这个Binder对象的远程接口来调用我们的应用程序进程的函数了,它不像我们在C++层实现Binder进程间通信机制的Server时,必须要手动调用IPCThreadState.joinThreadPool函数来进入一个无限循环中与Binder驱动程序交互以便获得Client端的请求,这样就实现了我们在文章开头处说的Android应用程序进程天然地支持Binder进程间通信机制。

        细心的读者可能会发现,从Step 1到Step 9,都是在Android应用程序框架层运行的,而从Step 10到Step 15,都是在Android系统运行时库层运行的,这两个层次中的Binder进程间通信机制的接口一个是用Java来实现的,而另一个是用C++来实现的,这两者是如何协作的呢?这就是通过JNI层来实现的了,具体可以参考Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析一文。

        回到Step 8中的RuntimeInit.zygoteInit函数中,在初始化完成Binder进程间通信机制的基础设施后,它接着就要进入进程的入口函数了。


Step 16. RuntimeInit.invokeStaticMain

        这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

public class ZygoteInit {

    ......

    static void invokeStaticMain(ClassLoader loader, String className, String[] argv) throws ZygoteInit.MethodAndArgsCaller 

    {

        Class cl;

        try{

            cl = loader.loadClass(className);

        } catch(ClassNotFoundException ex) {

            ......

        }

        Method m;

        try{

            m = cl.getMethod("main", new Class[] { String[].class});

        } catch(NoSuchMethodException ex) {

            ......

        } catch(SecurityException ex) {

            ......

        }

        int modifiers = m.getModifiers();

        ......

        /*

        * This throw gets caught in ZygoteInit.main(), which responds

        * by invoking the exception's run() method. This arrangement

        * clears up all the stack frames that were required in setting

        * up the process.

        */

        throw new ZygoteInit.MethodAndArgsCaller(m, argv);

    }

    ......

}

        前面我们说过,这里传进来的参数className字符串值为"android.app.ActivityThread",这里就通ClassLoader.loadClass函数将它加载到进程中:

cl = loader.loadClass(className);

        然后获得它的静态成员函数main:

m = cl.getMethod("main", new Class[] { String[].class});

        函数最后并没有直接调用这个静态成员函数main,而是通过抛出一个异常ZygoteInit.MethodAndArgsCaller,然后让ZygoteInit.main函数在捕获这个异常的时候再调用android.app.ActivityThread类的main函数。为什么要这样做呢?注释里面已经讲得很清楚了,它是为了清理堆栈的,这样就会让android.app.ActivityThread类的main函数觉得自己是进程的入口函数,而事实上,在执行android.app.ActivityThread类的main函数之前,已经做了大量的工作了。


        我们看看ZygoteInit.main函数在捕获到这个异常的时候做了什么事:

public class ZygoteInit {

    ......

    public static void main(String argv[]) {

        try{

            ......

        } catch(MethodAndArgsCaller caller) {

            caller.run();

        } catch(RuntimeException ex) {

            ......

        }

    }

    ......

}

        它执行MethodAndArgsCaller的run函数:

public class ZygoteInit {

    ......

    public static class MethodAndArgsCaller extends Exception 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) {

                ......

            } catch(InvocationTargetException ex) {

                ......

            }

        }

    }

    ......

}

        这里的成员变量mMethod和mArgs都是在前面构造异常对象时传进来的,这里的mMethod就对应android.app.ActivityThread类的main函数了,于是最后就通过下面语句执行这个函数:

mMethod.invoke(null, new Object[] { mArgs });

        这样,android.app.ActivityThread类的main函数就被执行了。


Step 17. ActivityThread.main

        这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {

    ......

    public static final void main(String[] args) 

    {

        SamplingProfilerIntegration.start();

        Process.setArgV0("");

        Looper.prepareMainLooper();

        if (sMainThreadHandler == null) {

            sMainThreadHandler = new Handler();

        }

        ActivityThread thread = new ActivityThread();

        thread.attach(false);

        if (false) {

            Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));

        }

        Looper.loop();

        if(Process.supportsProcesses()) {

            throw new RuntimeException("Main thread loop unexpectedly exited");

        }

        thread.detach();

        String name = (thread.mInitialApplication != null) ? thread.mInitialApplication.getPackageName()

            : "";

        Slog.i(TAG, "Main thread of " + name + " is now exiting");

    }

    ......

}

        从这里我们可以看出,这个函数首先会在进程中创建一个ActivityThread对象:

ActivityThread thread = new ActivityThread();

        然后进入消息循环中:

Looper.loop();

        这样,我们以后就可以在这个进程中启动Activity或者Service了。


     至此,Android应用程序进程启动过程的源代码就分析完成了,它除了指定新的进程的入口函数是ActivityThread的main函数之外,还为进程内的Binder对象提供了Binder进程间通信机制的基础设施,由此可见,Binder进程间通信机制在Android系统中是何等的重要,而且是无处不在,想进一步学习Android系统的Binder进程间通信机制,请参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。

2 进程创建

Android系统中的进程管理:进程的创建

http://mobile.51cto.com/android-520139.htm

2.1 概述

        Android系统以Linux内核为基础,所以对于进程的管理自然离不开Linux本身提供的机制。例如:

    · 通过fork来创建进行

    · 通过信号量来管理进程

    · 通过proc文件系统来查询和调整进程状态等

        对于Android来说,进程管理的主要内容包括以下几个部分内容:

    · 进程的创建

    · 进程的优先级管理

    · 进程的内存管理

    · 进程的回收和死亡处理

        本文会专门讲解进程的创建,其余部分将在后面的文章中讲解。


2.2 主要模块

        为了便于下文的讲解,这里先介绍一下Android系统中牵涉到进程创建的几个主要模块。同时为了便于读者更详细的了解这些模块,这里也同时提供了这些模块的代码路径。

        这里提到的代码路径是指AOSP的源码数中的路径。

        关于如何获取AOSP源码请参见这里:Downloading the Source。

        本文以Android N版本的代码为示例,所用到的Source Code Tags是:android-7.0.0_r1。

相关模块:

    · app_process

代码路径:frameworks/base/cmds/app_process

        说明:app_process是一个可执行程序,该程序的主要作用是启动zygote和system_server进程。

    · Zygote

代码路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

        说明:zygote进程是所有应用进程的父进程,这是系统中一个非常重要的进程,下文我们会详细讲解。

[if !supportLists]·      [endif]ActivityManager

代码路径:frameworks/base/services/core/java/com/android/server/am/

    说明:am是ActivityManager的缩写。

        这个目录下的代码负责了Android全部四大组件(Activity,Service,ContentProvider,BroadcastReceiver)的管理,并且还掌控了所有应用程序进程的创建和进程的优先级管理。

        因此,这个部分的内容将是本系列文章讲解的重点。


2.3 关于进程

        在Android系统中,进程可以大致分为系统进程和应用进程两大类。

        系统进程是系统内置的(例如:init,zygote,system_server进程),属于操作系统必不可少的一部分。系统进程的作用在于:

    · 管理硬件设备

    · 提供访问设备的基本能力

    · 管理应用进程

        应用进程是指应用程序运行的进程。这些应用程序可能是系统出厂自带的(例如Launcher,电话,短信等应用),也可能是用户自己安装的(例如:微信,支付宝等)。

        系统进程的数量通常是固定的(出厂或者系统升级之后就确定了),并且系统进程通常是一直存活,常驻内存的。系统进程的异常退出将可能导致设备无法正常使用。

        而应用程序和应用进程在每个人使用的设备上通常是各不一样的。如何管理好这些不确定的应用进程,就是操作系统本身要仔细考虑的内容。也是衡量一个操作系统好坏的标准之一。

        在本文中,我们会介绍init,zygote和system_server三个系统进程。

        除此之外,本系列文章将会把主要精力集中在讲解Android系统如何管理应用进程上。


2.4 init进程(核心)

        init进程是一切的开始,在Android系统中,所有进程的进程号都是不确定的,唯独init进程的进程号一定是1。因为这个进程一定是系统起来的第一个进程。并且,init进程掌控了整个系统的启动逻辑。

        我们知道,Android可能运行在各种不同的平台,不同的设备上。因此,启动的逻辑是不尽相同的。为了适应各种平台和设备的需求,init进程的初始化工作通过init.rc配置文件来管理。你可以在AOSP源码的system/core/rootdir/路径找到这些配置文件。配置文件的主入口文件是init.rc,这个文件会通过import引入其他几个文件。

        在本文中,我们统称这些文件为init.rc。init.rc通过Android Init Language来进行配置。

        建议读者大致阅读一下其语法说明 。

        init.rc中配置了系统启动的时候该做哪些事情,以及启动哪些系统进程。

        这其中有两个特别重要的进程就是:zygote和system_server进程。

    · zygote的中文意思是“受精卵“。这是一个很有寓意的名称:所有的应用进程都是由zygote fork出来的子进程,因此zygote进程是所有应用进程的父进程。

    · system_server 这个进程正如其名称一样,这是一个系统服务器。Framework层的几乎所有服务都位于这个进程中。这其中就包括管理四大组件的ActivityManagerService。


2.5 Zygote进程

        init.rc文件会根据平台不一样,选择下面几个文件中的一个来启动zygote进程:

    · init.zygote32.rc

    · init.zygote32_64.rc

    · init.zygote64.rc

    · init.zygote64_32.rc

        这几个文件的内容是大致一致的,仅仅是为了不同平台服务的。这里我们以init.zygote32.rc的文件为例,来看看其中的内容:

service zygote/system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

class main


socket zygote stream 660root system

onrestart write/sys/android_power/request_state wake

onrestart write/sys/power/state on

onrestart restartaudioserver

onrestart restartcameraserver

onrestart restart media

onrestart restart netd


writepid/dev/cpuset/foreground/tasks /dev/stune/foreground/tasks


        在这段配置文件中(如果你不明白这段配置的含义,请阅读一下文档:Android Init Language),启动了一个名称叫做zygote的服务进程。这个进程是通过/system/bin/app_process这个可执行程序创建的。

        并且在启动这个可执行程序的时候,传递了`-Xzygote/system/bin --zygote --start-system-server

    class main`这些参数。

        要知道这里到底做了什么,我们需要看一下app_process的源码。app_process的源码在这个路径:frameworks/base/cmds/app_process/app_main.cpp。    

        这个文件的main函数的有如下代码:

int main(int argc, char*const argv[])

{

    ...

    while (i < argc) {

        const char* arg = argv[i++];

        if (strcmp(arg, "--zygote")== 0) {

            zygote = true;

            niceName = ZYGOTE_NICE_NAME;

        } else if (strcmp(arg,"--start-system-server") == 0) {

            startSystemServer = true;

        ...

    }

    ...

   if (!className.isEmpty()) {

        ...

    } else {

       ...


       if (startSystemServer) {

          args.add(String8("start-system-server"));

       }

    }

    ...

    if (zygote) {

       runtime.start("com.android.internal.os.ZygoteInit", args,zygote);

    } else if (className) {

        runtime.start("com.android.internal.os.RuntimeInit",args, zygote);

    } else {

        fprintf(stderr, "Error: no classname or --zygote supplied.\n");

        app_usage();

        LOG_ALWAYS_FATAL("app_process: noclass name or --zygote supplied.");

        return 10;

    }

} 

        这里会判断,

    · 如果执行这个命令时带了--zygote参数,就会通过runtime.start启动com.android.internal.os.ZygoteInit。

    · 如果参数中带有--start-system-server参数,就会将start-system-server添加到args中。

        这段代码是C++实现的。在执行这段代码的时候还没有任何Java的环境。而runtime.start就是启动Java虚拟机,并在虚拟机中启动指定的类。于是接下来的逻辑就在ZygoteInit.java中了。

        这个文件的main函数主要代码如下:

public static voidmain(String argv[]) {

   ...

   try {

       ...

       boolean startSystemServer = false;

       String socketName = "zygote";

       String abiList = null;

       for (int i = 1; i < argv.length; i++){

           if("start-system-server".equals(argv[i])) {

               startSystemServer = true;

           } else if(argv[i].startsWith(ABI_LIST_ARG)) {

               ...

           }

       }

       ...

       registerZygoteSocket(socketName);

       ...

       preload();

       ...

       Zygote.nativeUnmountStorageOnInit();

      ZygoteHooks.stopZygoteNoThreadCreation();


       if (startSystemServer) {

           startSystemServer(abiList,socketName);

       }


       Log.i(TAG, "Accepting commandsocket connections");

       runSelectLoop(abiList);

       closeServerSocket();

   } catch (MethodAndArgsCaller caller) {

       caller.run();

   } catch (RuntimeException ex) {

       Log.e(TAG, "Zygote died withexception", ex);

       closeServerSocket();

       throw ex;

   }

} 

  在这段代码中,我们主要关注如下几行:

    1. 通过 registerZygoteSocket(socketName); 注册Zygote Socket

    2. 通过 preload(); 预先加载所有应用都需要的公共资源

    3. 通过 startSystemServer(abiList, socketName); 启动system_server

    4. 通过 runSelectLoop(abiList); 在Looper上等待连接

        这里需要说明的是:zygote进程启动之后,会启动一个socket套接字,并通过Looper一直在这个套接字上等待连接。

        所有应用进程都是通过发送数据到这个套接字上,然后由zygote进程创建的。

        这里还有一点说明的是:

        在Zygote进程中,会通过preload函数加载需要应用程序都需要的公共资源。

        预先加载这些公共资源有如下两个好处:

    · 加快应用的启动速度 因为这些资源已经在zygote进程启动的时候加载好了

    · 通过共享的方式节省内存 这是Linux本身提供的机制:父进程已经加载的内容可以在子进程中进行共享,而不用多份数据拷贝(除非子进程对这些数据进行了修改。)

        preload的资源主要是Framework相关的一些基础类和Resource资源,而这些资源正是所有应用都需要的:

        开发者通过Android SDK开发应用所调用的API实现都在Framework中。

static void preload() {

   Log.d(TAG,"begin preload");

   Trace.traceBegin(Trace.TRACE_TAG_DALVIK,"BeginIcuCachePinning");

  beginIcuCachePinning();

  Trace.traceEnd(Trace.TRACE_TAG_DALVIK);


   Trace.traceBegin(Trace.TRACE_TAG_DALVIK,"PreloadClasses");

   preloadClasses();

  Trace.traceEnd(Trace.TRACE_TAG_DALVIK);


  Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadResources");

  preloadResources();

  Trace.traceEnd(Trace.TRACE_TAG_DALVIK);


  Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");

   preloadOpenGL();

  Trace.traceEnd(Trace.TRACE_TAG_DALVIK);


  preloadSharedLibraries();

  preloadTextResources();


  WebViewFactory.prepareWebViewInZygote();

  endIcuCachePinning();

  warmUpJcaProviders();

   Log.d(TAG,"end preload");

} 


2.6 system_server进程

        上文已经提到,zygote进程起来之后会根据需要启动system_server进程。system_server进程中包含了大量的系统服务。例如:

    · 负责网络管理的NetworkManagementService;

    · 负责窗口管理的WindowManagerService;

    · 负责震动管理的VibratorService;

    · 负责输入管理的InputManagerService;

        等等。关于system_server,我们今后会其他的文章中专门讲解,这里不做过多说明。

        在本文中,我们只关注system_server中的ActivityManagerService这个系统服务。


2.7 ActivityManagerService

        上文中提到:zygote进程在启动之后会启动一个socket,然后一直在这个socket等待连接。而会连接它的就是ActivityManagerService。因为ActivityManagerService掌控了所有应用进程的创建。所有应用程序的进程都是由ActivityManagerService通过socket发送请求给Zygote进程,然后由zygote fork创建的。

        ActivityManagerService通过Process.start方法来请求zygote创建进程:

public static finalProcessStartResult start(final String processClass, final String niceName, int uid, int gid,int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String[]zygoteArgs)

{

   try {

       return startViaZygote(processClass,niceName, uid, gid, gids,

               debugFlags, mountExternal, targetSdkVersion, seInfo,

               abi, instructionSet, appDataDir,zygoteArgs);

   } catch (ZygoteStartFailedEx ex) {

       Log.e(LOG_TAG, "Starting VM processthrough Zygote failed");

       throw newRuntimeException("Starting VM process through Zygote failed", ex);

   }

} 

        这个函数会将启动进程所需要的参数组装好,并通过socket发送给zygote进程。然后zygote进程根据发送过来的参数将进程fork出来。

        在ActivityManagerService中,调用Process.start的地方是下面这个方法:

private final void startProcessLocked(ProcessRecord app, String hostingType,

       String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) 

{

    ...

    Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,  app.info.dataDir, entryPointArgs);

    ...

} 

        下文中我们会看到,所有四大组件进程的创建,都是调用这里的startProcessLocked这个方法而创建的。

        对于每一个应用进程,在ActivityManagerService中,都有一个ProcessRecord与之对应。这个对象记录了应用进程的所有详细状态。

        PS:对于ProcessRecord的内部结构,在下一篇文章中,我们会讲解。

        为了查找方便,对于每个ProcessRecord会存在下面两个集合中。

    · 按名称和uid组织的集合:

/** 

* All of the applications we currently have running organized by name. 

* The keys are strings of the application package name (as 

* returned by the package manager), and the keys are ApplicationRecord 

* objects. 

*/ 

final ProcessMap mProcessNames = new ProcessMap(); 


· 按pid组织的集合:

/** 

* All of the processes we currently have running organized by pid. 

* The keys are the pid running the application. 

 * NOTE: This object is protected by its own lock, NOT the global 

* activity manager lock! 

*/ 

final SparseArray mPidsSelfLocked = new SparseArray(); 

        下面这幅图小节了上文的这些内容:


2.8 关于应用组件

Processes and Threads 提到:

        “当某个应用组件启动且该应用没有运行其他任何组件时,Android 系统会使用单个执行线程为应用启动新的 Linux 进程。”

        因此,四大组件中的任何一个先起来都会导致应用进程的创建。下文我们就详细看一下,它们启动时,各自是如何导致应用进程的创建的。

        PS:四大组件的管理本身又是一个比较大的话题,限于篇幅关系,这里不会非常深入的讲解,这里主要是讲解四大组件与进程创建的关系。

        在应用程序中,开发者通过:

    · startActivity(Intent intent) 来启动Activity

    · startService(Intent service) 来启动Service

    · sendBroadcast(Intent intent) 来发送广播

    · ContentResolver 中的接口来使用ContentProvider

        这其中,startActivity,startService和sendBroadcast还有一些重载方法。

        其实这里提到的所有这些方法,最终都是通过Binder调用到ActivityManagerService中,由其进行处理的。

        这里特别说明一下:应用进程和ActivityManagerService所在进程(即system_server进程)是相互独立的,两个进程之间的方法通常是不能直接互相调用的。

        而Android系统中,专门提供了Binder框架来提供进程间通讯和方法调用的能力。

        调用关系如下图所示:


2.9 Activity与进程创建

        在ActivityManagerService中,对每一个运行中的Activity都有一个ActivityRecord对象与之对应,这个对象记录Activity的详细状态。

       ActivityManagerService中的startActivity方法接受Context.startActivity的请求,该方法代码如下:

@Override 

public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) 

{ 

    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, UserHandle.getCallingUserId()); 

}

        Activity的启动是一个非常复杂的过程。这里我们简单介绍一下背景知识:

    • ActivityManagerService中通过Stack和Task来管理Activity

    • 每一个Activity都属于一个Task,一个Task可能包含多个Activity。一个Stack包含多个Task

    • ActivityStackSupervisor类负责管理所有的Stack

    • Activity的启动过程会牵涉到:

        o Intent的解析

        o Stack,Task的查询或创建

        o Activity进程的创建

        o Activity窗口的创建

        o Activity的生命周期调度

        Activity的管理结构如下图所示:

        在Activity启动的最后,会将前一个Activity pause,将新启动的Activity resume以便被用户看到。

        在这个时候,如果发现新启动的Activity进程还没有启动,则会通过startSpecificActivityLocked将其启动。整个调用流程如下:

    · ActivityManagerService.activityPaused =>

    · ActivityStack.activityPausedLocked =>

    · ActivityStack.completePauseLocked =>

    · ActivityStackSupervisor.ensureActivitiesVisibleLocked=>

    · ActivityStack.makeVisibleAndRestartIfNeeded =>

    · ActivityStackSupervisor.startSpecificActivityLocked =>

    · ActivityManagerService.startProcessLocked

    · ActivityStackSupervisor.startSpecificActivityLocked

        关键代码如下:

void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) 

{

    // Is this activity's application already running?

    ProcessRecordapp = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true);

   r.task.stack.setLaunchTime(r);


    if (app != null&& app.thread != null) {

        ...

    }

   mService.startProcessLocked(r.processName, r.info.applicationInfo, true,0, "activity", r.intent.getComponent(), false, false, true);

}

        这里的ProcessRecord app 描述了Activity所在进程。

2.10 Service与进程创建

        Service的启动相对于Activity来说要简单一些。在ActivityManagerService中,对每一个运行中的Service都有一个ServiceRecord对象与之对应,这个对象记录Service的详细状态。

       ActivityManagerService中的startService方法处理Context.startServiceAPI的请求,相关代码:

@Override

public ComponentName startService(IApplicationThread caller, Intent service,  String resolvedType, String callingPackage, int userId) throwsTransactionTooLargeException 

{

    ...

   synchronized(this) {

       final intcallingPid = Binder.getCallingPid();

       final intcallingUid = Binder.getCallingUid();

       final longorigId = Binder.clearCallingIdentity();

       ComponentNameres = mServices.startServiceLocked(caller, service, resolvedType, callingPid,callingUid, callingPackage, userId);

      Binder.restoreCallingIdentity(origId);

       return res;

    }

}

        这段代码中的mServices对象是ActiveServices类型的,这个类专门负责管理活动的Service。

        启动Service的调用流程如下:

    · ActivityManagerService.startService =>

    · ActiveServices.startServiceLocked =>

    · ActiveServices.startServiceInnerLocked =>

    · ActiveServices.bringUpServiceLocked =>

    · ActivityManagerService.startProcessLocked

        ActiveServices.bringUpServiceLocked会判断如果Service所在进程还没有启动,则通过ActivityManagerService.startProcessLocked将其启动。相关代码如下:

// Not running -- get it started, and enqueue this servicerecord

// to be executed when the app comes up.

if (app == null && !permissionsReviewRequired) {

  if((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, "service", r.name, false, isolated, false)) == null) {

      String msg ="Unable to launch app " + r.appInfo.packageName + "/" + r.appInfo.uid + " for service" + r.intent.getIntent() + ": process is bad";

      Slog.w(TAG,msg);

     bringDownServiceLocked(r);

      return msg;

  }

  if (isolated) {

      r.isolatedProc= app;

  }

}

    这里的mAm 就是ActivityManagerService。


2.11 Provider与进程创建

        在ActivityManagerService中,对每一个运行中的ContentProvider都有一个ContentProviderRecord对象与之对应,这个对象记录ContentProvider的详细状态。

        开发者通过ContentResolver中的insert, delete, update, query这些API来使用ContentProvider。在ContentResolver的实现中,无论使用这里的哪个接口,ContentResolver都会先通过acquireProvider 这个方法来获取到一个类型为IContentProvider的远程接口。这个远程接口对接了ContentProvider的实现提供方。

        同一个ContentProvider可能同时被多个模块使用,而调用ContentResolver接口的进程只是ContentProvider的一个客户端而已,真正的ContentProvider提供方是运行自身的进程中的,两个进程的通讯需要通过Binder的远程接口形式来调用。如下图所示:

        ContentResolver.acquireProvider最终会调用到ActivityManagerService.getContentProvider中,该方法代码如下:

@Override 

public final ContentProviderHolder getContentProvider(IApplicationThread caller, String name, int userId, boolean stable) 

{ 

    enforceNotIsolatedCaller("getContentProvider"); 

    if (caller == null) { 

        String msg ="null IApplicationThread when getting content provider " + name; 

        Slog.w(TAG, msg);

        throw new SecurityException(msg);

   }

        // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal with cross-user grant. 

    return getContentProviderImpl(caller, name, null, stable, userId); 

}

        而在getContentProviderImpl这个方法中,会判断对应的ContentProvider进程有没有启动,如果没有,则通过startProcessLocked方法将其启动。

2.12 Receiver与进程创建

        开发者通过Context.sendBroadcast接口来发送广播。ActivityManagerService.broadcastIntent方法了对应广播发送的处理。

        广播是一种一对多的消息形式,广播接受者的数量是不确定的。因此发送广播本身可能是一个很耗时的过程(因为要逐个通知)。

        在ActivityManagerService内部,是通过队列的形式来管理广播的:

    · BroadcastQueue 描述了一个广播队列

    · BroadcastRecord 描述了一个广播事件

        在ActivityManagerService中,如果收到了一个发送广播的请求,会先创建一个BroadcastRecord接着将其放入BroadcastQueue中。

        然后通知队列自己去处理这个广播。然后ActivityManagerService自己就可以继续处理其他请求了。

        广播队列本身是在另外一个线程处理广播的发送的,这样保证的ActivityManagerService主线程的负载不会太重。

         在BroadcastQueue.processNextBroadcast(boolean fromMsg) 方法中真正实现了通知广播事件到接受者的逻辑。在这个方法,如果发现接受者(即BrodcastReceiver)还没有启动,便会通过ActivityManagerService.startProcessLocked方法将其启动。相关如下所示:

final void processNextBroadcast(boolean fromMsg) 

{ 

    ... 

    // Hard case: need to instantiate the receiver, possibly starting its application process to host it. 


    ResolveInfo info = (ResolveInfo)nextReceiver; 

         ComponentName component = new ComponentName(info.activityInfo.applicationInfo.packageName, info.activityInfo.name); 

     ... 

      // Not running -- get it started, to be executed when the app comes up. 

    if (DEBUG_BROADCAST)

         Slog.v(TAG_BROADCAST,"Need to start app [" + mQueueName + "] " + targetProcess + " for broadcast " + r); 

    if ((r.curApp=mService.startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, "broadcast", r.curComponent, (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) == null) 

    { 

        // Ah, this recipient is unavailable.  Finish it if necessary, 

        //and mark the broadcast record as ready for the next.                         Slog.w(TAG,"Unable to launch app " + info.activityInfo.applicationInfo.packageName + "/" + info.activityInfo.applicationInfo.uid + " for broadcast " + r.intent + ": process is bad"); 

        logBroadcastReceiverDiscardLocked(r);

        finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); 

        scheduleBroadcastsLocked();

        r.state = BroadcastRecord.IDLE;

        return; 

    } 


     mPendingBroadcast = r; 

     mPendingBroadcastRecvIndex = recIdx; 

  } 

} 

    至此,四大组件的启动就已经分析完了。


3 参考链接

Android开发之多进程详解

http://blog.csdn.net/feiyang877647044/article/details/51673466


Android 应用内多进程实现 单APK应用多进程

http://blog.csdn.net/a78270528/article/details/51143740


ANDROID多进程需要注意的一个地方

http://www.cnblogs.com/John-Chen/p/4364275.html


Android 开发中踩过的坑之八:多进程问题

https://my.oschina.net/u/1393188/blog/491568


Android中应用多进程的整理总结

http://www.jb51.net/article/104173.htm


Android 后台任务型App多进程架构演化

http://www.jianshu.com/p/4ac1f373e8cd


Android应用内多进程分析和研究

http://blog.csdn.net/goodlixueyong/article/details/49853079


Android开启多进程

http://www.2cto.com/kf/201512/455410.html


Android中单APK应用多进程

http://blog.csdn.net/hudashi/article/details/7858125


Android单应用开多进程与单进程跑多应用

http://blog.csdn.net/Ragnaro/article/details/51569096


Android应用程序进程启动过程的源代码分析

http://blog.csdn.net/luoshengyang/article/details/6747696


Android应用程序在新的进程中启动新的Activity的方法和过程分析

http://shangxun.iteye.com/blog/2124498


(Good)深入理解Dalvik虚拟机- Android应用进程启动过程分析

http://blog.csdn.net/threepigs/article/details/50779056


Android基础 Android应用内多进程分析和研究

http://blog.csdn.net/qq_33326449/article/details/52748710


Android后台保活实践总结:即时通讯应用无法根治的“顽疾”

http://www.52im.net/thread-429-1-1.html


Android系统中的进程管理:进程的创建

http://mobile.51cto.com/android-520139.htm


理解Android进程创建流程

http://gityuan.com/2016/03/26/app-process-create/


Android 通过JNI实现守护进程

https://blog.csdn.net/yyh352091626/article/details/50542554


android应用创建子进程的方法探究

https://blog.csdn.net/a332324956/article/details/9114919


UNIX环境高级编程(第3版)

深入理解LINUX内核(第3版)

Processes and Threads

Android Booting

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容