【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 charconstargv[])

{

    ......

    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(nullnew Object[] { mArgs });

            } catch(IllegalAccessException ex) {

                ......

            } catch(InvocationTargetException ex) {

                ......

            }

        }

    }

    ......

}

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

mMethod.invoke(nullnew 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 nameint 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, falsefalse)) == 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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容