Android 源码梳理

来源:互联网 发布:大学java期末考试题 编辑:程序博客网 时间:2024/06/15 04:34

Android 源码梳理

前言

作为霜枫司机一年学习的总结,附上帅照一张。
enter image description here


目录

1. Android系统启动过程分析
2. Linux内核文件系统
3. Android进程间通信源码梳理
4. Android匿名共享内存系统源码梳理
5. Android ActivityThread类源码的梳理
6. Android Context类源码的梳理
7. ActivityManagerService源码的梳理
8. Android Activity类源码的梳理
9. Content Provider源码的梳理


Android系统启动过程分析

  Android系统是基于Linux内核,当我们按下电源键以后Android设备执行了一些操作。
  对于Android整个启动过程来说,基本可以划分成三个阶段:Bootloader引导、Linux kernel启动、Android启动。
  下面是系统内核的架构图,我们依据架构图的梳理往上层分析:
  这里写图片描述

第一步Bootloader引导

  BootLoader是在操作系统运行之前运行的一段程序,它的作用是:初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。我们可以理解为它是为操作系统的启动铺垫环境,和电脑上的BIOS比较类似。
  同时BootLoader后期会引导fastboot以及recovery两种模式的启动,这两种模式主要是可以刷入新的安卓系统,或者对已有的系统进行备份或升级。
  不同的主板会对应有不同的BootLoader。

第二步内核启动

  Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。
  这里闲扯一句为什么是寻找文件,在Linux中有句哲学叫做一切皆是文件,不仅普通的文件,目录、字符设备、块设备、 套接字等在 Unix/Linux 中都是以文件被对待;它们虽然类型不同,但是对其提供的却是同一套操作界面。深入的研究这里不做过多的阐述。

第三步init进程启动

  init是一个进程,它是linux系统中用户空间的第一个进程,其进程PID是1,父进程为linux系统内核的0号进程。所以其被赋予很多极其重要的职责,linux内核初始化完成后就开始执行它。init进程是Android内核启动的第一个进程,其进程号(pid)为1,是Android系统所有进程的祖先,因此它肩负着系统启动的重要责任。Android的init源代码位于system/core/init/目录下,伴随Android系统多个版本的迭代,init源代码也几经重构。init目录编译后生成如下Android系统文件,分别是:
  /init/sbin/ueventd–>/init
  /sbin/watchdogd–>/init
  其中ueventd与wathdogd均是指向/init的软链接。(具体实现请阅读init/Android.mk)。
在Android系统早期版本(2.2之前)只有init进程,Android2.2中将创建设备驱动节点文件功能独立到ueventd进程完成,在Android4.1中则添加了watchdogd。前面说过在Linux一切都是文件,init进程的文件在/system/core/init下。其中包含了一组文件,其中 其中init.c是init的主文件。/ueventd用于创建设备驱动节点。 /watchdogd 是看门狗服务进程。
  简要的分析下main函数吧(这里只挑选一些比较重要的部门去研究):

if (!strcmp(basename(argv[0]), "ueventd"))      return ueventd_main(argc, argv);  if (!strcmp(basename(argv[0]), "watchdogd"))      return watchdogd_main(argc, argv);  

  通过命令行判断argv[0]的字符串内容,来区分当前程序是init,ueventd或是watchdogd。
C程序的main函数原型为 main(int argc, char* argv[]), ueventd以及watchdogd的启动都在init.rc中描述,由init进程解析后执行fork、exec启动,因此其入口参数的构造在init代码中,将在init.rc解析时分析。此时我们只需要直到argv[0]中将存储可执行文件的名字。

mkdir("/dev", 0755);  mkdir("/proc", 0755);  mkdir("/sys", 0755);  mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");  mkdir("/dev/pts", 0755);  mkdir("/dev/socket", 0755);  mount("devpts", "/dev/pts", "devpts", 0, NULL);  mount("proc", "/proc", "proc", 0, NULL);  mount("sysfs", "/sys", "sysfs", 0, NULL);

  init进程创建一些目录,包括/dev、/proc 、/sys 并将一些文件系统mount到对应的目录下。
  tmpfs是一个零时文件系统,其实文件系统是存放在内存之中,所以读写速度非常快。
  devpts是虚拟终端文件系统。
  proc也是一种基于内存的文件系统,它可以看做是内核内部数据的接口,通过它可以获得一些系统参数,也能够在运行时修改一些内核的参数。

klog_init();  property_init();  

  初始化log以及一些属性
  3. 解析init.rc脚本文件
  init.rc脚本中含有四种声明:
  Actions(行为)、Commands(命令)、Services(服务)和Options(选项)
  我们可以理解为这是一系列的行为、命令等,执行完成后init主要是启动系统守护进程如adbd, vold, rild等,以及启动了zygote进程。我们主要分析一下Zygote进程的启动。

Android系统进程Zygote启动过程


  所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的。
  在init.rc中通过引入下面的文件被配置Zygote:

import /init.${ro.zygote}.rc

  Google在Android 5.0中加入了对64位CPU的支持,这些Zygote相关的rc文件就是与32位和64位CPU有关系。如果ro.zygote为zygote32,那么说明只支持32位程序;如果是zygote64,那么只支持64位程序;如果是zygote32_64,说明支持32位程序为主,兼容64位程序;如果是zygote64_32说明支持64位程序为主,兼容32位程序。
  下面是zygote64_32.rc中的内容:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote    class main    socket zygote stream 660 root system    onrestart write /sys/android_power/request_state wake    onrestart write /sys/power/state on    onrestart restart media    onrestart restart netdservice zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary    class main    socket zygote_secondary stream 660 root system    onrestart restart zygote

  main函数在app_main.cpp中,另外传入的参数为 -Xzygote /system/bin –zygote –socket-name=zygote (或者zygote_second)

int main(int argc, char* const argv[]){    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));    argc--;    argv++;    int i;    for (i = 0; i < argc; i++) {        if (argv[i][0] != '-') {            break;        }        if (argv[i][1] == '-' && argv[i][2] == 0) {            ++i; // Skip --.            break;        }        runtime.addOption(strdup(argv[i]));    }    bool zygote = false;    bool startSystemServer = false;    bool application = false;    String8 niceName;    String8 className;    ++i;  // Skip unused "parent dir" argument.    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;        } else if (strcmp(arg, "--application") == 0) {            application = true;        } else if (strncmp(arg, "--nice-name=", 12) == 0) {            niceName.setTo(arg + 12);        } else if (strncmp(arg, "--", 2) != 0) {            className.setTo(arg);            break;        } else {            --i;            break;        }    }    Vector<String8> args;    if (!className.isEmpty()) {        args.add(application ? String8("application") : String8("tool"));        runtime.setClassNameAndArgs(className, argc - i, argv + i);    } else {        // We're in zygote mode.        maybeCreateDalvikCache();        if (startSystemServer) {            args.add(String8("start-system-server"));        }        char prop[PROP_VALUE_MAX];        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",                ABI_LIST_PROPERTY);            return 11;        }        String8 abiFlag("--abi-list=");        abiFlag.append(prop);        args.add(abiFlag);        // In zygote mode, pass all remaining arguments to the zygote        // main() method.        for (; i < argc; ++i) {            args.add(String8(argv[i]));        }    }    if (!niceName.isEmpty()) {        runtime.setArgv0(niceName.string());        set_process_name(niceName.string());    }    if (zygote) {        runtime.start("com.android.internal.os.ZygoteInit", args);    } else if (className) {        runtime.start("com.android.internal.os.RuntimeInit", args);    } else {        fprintf(stderr, "Error: no class name or --zygote supplied.\n");        app_usage();        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");        return 10;    }}

  这里main函数中的逻辑不多,首先创建了一个AppRuntime,随后从argv中解析参数,传递的参数包含了–zygote参数和–start-system-server参数,zygote和startSystemServer都为true,所以main函数最后执行的是:

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

  下面进入到的是AppRuntime的start方法:

void AndroidRuntime::start(const char* className, const Vector<String8>& options){    // .....    static const String8 startSystemServer("start-system-server");    for (size_t i = 0; i < options.size(); ++i) {        if (options[i] == startSystemServer) {           /* track our progress through the boot sequence */           const int LOG_BOOT_PROGRESS_START = 3000;           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));        }    }    const char* rootDir = getenv("ANDROID_ROOT");    if (rootDir == NULL) {        rootDir = "/system";        if (!hasDir("/system")) {            LOG_FATAL("No root directory specified, and /android does not exist.");            return;        }        setenv("ANDROID_ROOT", rootDir, 1);    }    JniInvocation jni_invocation;    jni_invocation.Init(NULL);    JNIEnv* env;    if (startVm(&mJavaVM, &env) != 0) {        return;    }    onVmCreated(env);    if (startReg(env) < 0) {        ALOGE("Unable to register all android natives\n");        return;    }    jclass stringClass;    jobjectArray strArray;    jstring classNameStr;    stringClass = env->FindClass("java/lang/String");    assert(stringClass != NULL);    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);    assert(strArray != NULL);    classNameStr = env->NewStringUTF(className);    assert(classNameStr != NULL);    env->SetObjectArrayElement(strArray, 0, classNameStr);    for (size_t i = 0; i < options.size(); ++i) {        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());        assert(optionsStr != NULL);        env->SetObjectArrayElement(strArray, i + 1, optionsStr);    }    /*     * Start VM.  This thread becomes the main thread of the VM, and will     * not return until the VM exits.     */    char* slashClassName = toSlashClassName(className);    jclass startClass = env->FindClass(slashClassName);    if (startClass == NULL) {        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);        /* keep going */    } else {        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",            "([Ljava/lang/String;)V");        if (startMeth == NULL) {            ALOGE("JavaVM unable to find main() in '%s'\n", className);            /* keep going */        } else {            env->CallStaticVoidMethod(startClass, startMeth, strArray);#if 0            if (env->ExceptionCheck())                threadExitUncaughtException(env);#endif        }    }    free(slashClassName);    ALOGD("Shutting down VM\n");    if (mJavaVM->DetachCurrentThread() != JNI_OK)        ALOGW("Warning: unable to detach main thread\n");    if (mJavaVM->DestroyJavaVM() != 0)        ALOGW("Warning: VM did not shut down cleanly\n");}

  start函数主要做了以下一些事情:
  
  1. 启动虚拟机
  初始化JNI环境:

JniInvocation jni_invocation;jni_invocation.Init(NULL);

  这里主要是加载虚拟机的so库,Android 4.4以前使用的Dalvik虚拟机,4.4默认使用Dalvik但是可以切换到ART虚拟机,从5.0开始就是默认使用ART虚拟机了。
  接下来是调用AndroidRuntime的startVm方法启动ART虚拟机。
  onVmCreated是一个虚函数由子类AppRuntime去实现。
  2. 向虚拟机注册需要的Native函数
  3. 加载Java层次的ZygoteInit类
  到这里Android系统从native层进入到了JAVA的世界了。
  下面是ZygoteInit的main函数:

    public static void main(String argv[]) {        try {            // Start profiling the zygote initialization.            SamplingProfilerIntegration.start();            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)) {                    abiList = argv[i].substring(ABI_LIST_ARG.length());                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());                } else {                    throw new RuntimeException("Unknown command line argument: " + argv[i]);                }            }            if (abiList == null) {                throw new RuntimeException("No ABI list supplied.");            }            registerZygoteSocket(socketName);            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,                SystemClock.uptimeMillis());            preload();            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,                SystemClock.uptimeMillis());            // Finish profiling the zygote initialization.            SamplingProfilerIntegration.writeZygoteSnapshot();            // Do an initial gc to clean up after startup            gc();            // Disable tracing so that forked processes do not inherit stale tracing tags from            // Zygote.            Trace.setTracingEnabled(false);            if (startSystemServer) {                startSystemServer(abiList, socketName);            }            Log.i(TAG, "Accepting command socket connections");            runSelectLoop(abiList);            closeServerSocket();        } catch (MethodAndArgsCaller caller) {            caller.run();        } catch (RuntimeException ex) {            Log.e(TAG, "Zygote died with exception", ex);            closeServerSocket();            throw ex;        }    }

  第一个关键点在于:

registerZygoteSocket(socketName);

  这个函数的目的是初始化一个Socket,这里定义的Socket的类型为unix domain socket,它是用来作本地进程间通信用的。UNIX Domain Socket是在Socket架构上发展起来的用于同一台主机的进程间通讯(IPC),它不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。
  函数中会创建一个LocalServerSocket对象,并将其记录在静态变量sServerSocket中,以后zygote进程会循环监听这个socket,一旦accept到连接请求,就创建命令连接(Command Connection)。监听动作的细节是在runSelectLoop()中。
  接下来调用:

preload();

  这个函数会做一些预加载,包括一些类以及一些资源,预加载的目的是让后面使用到这些资源时不必要再去做重复的加载。
  最重要的一步我们贴出代码慢慢分析,总体的流程是先fork一个子进程,然后在子进程中做一些初始化动作,继而执行SystemServer类的main()静态函数。
  第一步执行startSystemServer:

    private static boolean startSystemServer(String abiList, String socketName)            throws MethodAndArgsCaller, RuntimeException {        long capabilities = posixCapabilitiesAsBits(            OsConstants.CAP_BLOCK_SUSPEND,            OsConstants.CAP_KILL,            OsConstants.CAP_NET_ADMIN,            OsConstants.CAP_NET_BIND_SERVICE,            OsConstants.CAP_NET_BROADCAST,            OsConstants.CAP_NET_RAW,            OsConstants.CAP_SYS_MODULE,            OsConstants.CAP_SYS_NICE,            OsConstants.CAP_SYS_RESOURCE,            OsConstants.CAP_SYS_TIME,            OsConstants.CAP_SYS_TTY_CONFIG        );        /* Hardcoded command line to start the system server */        String args[] = {            "--setuid=1000",            "--setgid=1000",            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",            "--capabilities=" + capabilities + "," + capabilities,            "--runtime-init",            "--nice-name=system_server",            "com.android.server.SystemServer",        };        ZygoteConnection.Arguments parsedArgs = null;        int pid;        try {            parsedArgs = new ZygoteConnection.Arguments(args);            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);            /* Request to fork the system server process */            pid = Zygote.forkSystemServer(                    parsedArgs.uid, parsedArgs.gid,                    parsedArgs.gids,                    parsedArgs.debugFlags,                    null,                    parsedArgs.permittedCapabilities,                    parsedArgs.effectiveCapabilities);        } catch (IllegalArgumentException ex) {            throw new RuntimeException(ex);        }        /* For child process */        if (pid == 0) {            if (hasSecondZygote(abiList)) {                waitForSecondaryZygote(socketName);            }            handleSystemServerProcess(parsedArgs);        }        return true;    }

  这个函数分为两部分看,上面组装参数放入到parsedArgs中,接下来调用Zygote.forkSystemServer并将之前组装的对象作为参数传递。
  看一下ZYgote.forkSystemServer函数:

public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,        int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {    VM_HOOKS.preFork();    int pid = nativeForkSystemServer(            uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);    VM_HOOKS.postForkCommon();    return pid;}

  这里调用到了native方法,native方法里面只会其实会调用fork(),而后设置gid、uid等信息。
  native方法里主要调用到了handleSystemServerProcess

   private static void handleSystemServerProcess(           ZygoteConnection.Arguments parsedArgs)           throws ZygoteInit.MethodAndArgsCaller {       closeServerSocket();//------------------因为子进程是system server 不是zygote,所以要关闭zygote socket       // set umask to 0077 so new files and directories will default to owner-only permissions.       Os.umask(S_IRWXG | S_IRWXO);       if (parsedArgs.niceName != null) {           Process.setArgV0(parsedArgs.niceName);//----------------niceName 是 system_server       }       final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");       if (systemServerClasspath != null) {           performSystemServerDexOpt(systemServerClasspath);       }       if (parsedArgs.invokeWith != null) {           String[] args = parsedArgs.remainingArgs;           // If we have a non-null system server class path, we'll have to duplicate the           // existing arguments and append the classpath to it. ART will handle the classpath           // correctly when we exec a new process.           if (systemServerClasspath != null) {               String[] amendedArgs = new String[args.length + 2];               amendedArgs[0] = "-cp";               amendedArgs[1] = systemServerClasspath;               System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);           }           WrapperInit.execApplication(parsedArgs.invokeWith,                   parsedArgs.niceName, parsedArgs.targetSdkVersion,                   null, args);       } else {           ClassLoader cl = null;           if (systemServerClasspath != null) {               cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());               Thread.currentThread().setContextClassLoader(cl);           }           /*            * Pass the remaining arguments to SystemServer.            */           // 此时的remainingArgs就是”com.android.server.SystemServer”           RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);       }       /* should never reach here */   }

  因为parsedArgs.invokeWith没有指定,所以其值为null,于是程序会走到RuntimeInit.zygoteInit():

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)           throws ZygoteInit.MethodAndArgsCaller {       if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");       redirectLogStreams();//-------------在新fork出的系统进程里,需要重新定向系统输出流       commonInit();       nativeZygoteInit();       applicationInit(targetSdkVersion, argv, classLoader);   }

  这里我们又遇到了一个native方法:nativeZygoteInit()

virtual void onZygoteInit()  {      // Re-enable tracing now that we're no longer in Zygote.      atrace_set_tracing_enabled(true);      sp<ProcessState> proc = ProcessState::self();      ALOGV("App process: starting thread pool.\n");      proc->startThreadPool();  }

  它只是简单的初始化了一个ProcessState,这个将用于进程间通信,后面用篇幅再做介绍吧。
  下面是applicationInit方法,这里主要是执行SystemServer类的main()函数,到这里我们就将SystemServer进程给启动起来了。
  SystemServer和Zyoget是Android Java中的两个支柱,缺少任何一个都是世界末日,SystemServer最主要的一个任务是启动一些系统级的服务包括位于第一大类的是Android的核心服务,如ActivityManagerService、WindowManagerService等。位于第二大类的是和通信相关的服务,如Wifi相关服务、Telephone相关服务。位于第三大类的是和系统功能相关的服务,如AudioService、MountService、UsbService等。位于第四大类的是BatteryService、VibratorService等服务。位于第五大类的是EntropyService,DiskStatsService、Watchdog等相对独立的服务。位于第六大类的是蓝牙服务。位于第七大类的是UI方面的服务,如状态栏服务,通知管理服务等。
  启动完SystemServer就进入到runSelectLoop循环中了runSelectLoop主要处理

  • 客户端的连接和请求。前面创建的 LocalServerSocket 对象保存 sServerSocket,这个socket通过 selectReadable 等待 ActivityManagerService(简写 AMS) 与之通信。selectReadable 是一个native函数,内部调用select等待 AMS 连接,AMS 连接上之后就会返回: 返回值 < 0:内部发生错误;返回值 = 0:第一次连接到服务端 ;返回值 > 0:与服务端已经建立连接,并开始发送数据。每一个链接在 zygote 进程中使用 ZygoteConnection 对象表示。
  • 客户端的请求由 ZygoteConnection.runOnce 来处理,这个方法也抛出 MethodAndArgsCaller 异常,从而进入 MethodAndArgsCaller.run 中调用根据客户请求数据反射出的类的 main 方法。

Linux内核文件系统


文件系统的定义

  构成一个操作系统最重要的就是进程管理与文件系统,我们在设备上所做的所有操作归结为原子操作无非就是两个,一个是从存储设备中读取数据由CPU进行操作,另一个是向存储设备中写数据。这正好不就对应了文件中的两个操作读和写,而进程管理我们可以理解为对用户任务的管理。
  Linux文件系统包括:
  文本文件;二进制文件;目录文件;连接文件;设备文件;管道文件(用于进程间通信)。
  
  狭义的文件:指磁盘文件,进入指可以是有序地存储在任何介质中(包括内存)的一组信息。广义的文件:(unix把外部设备也当成文件)凡是可以产生或消耗信息的都是文件;除linux本身的文件系统ext2外,linux还需要支持各种不同的文件系统,为了达到这个目的,linux引入了VFS虚拟文件系统;这个抽象的界面主要由一组标准的、抽象的 统一的 文件操作构成,以系统调用的形式提供于用户程序,如read() write() lseek()等等,然后不同的文件系统再各自实现自己的操作。

相关的数据结构

  Linux下用task_struct结构于描述进程的数据结构,结构体中中有两个指针:fs和files, 一个指向fs_struct数据结构,是关于文件系统的信息; 一个指向files_struct数据结构,是关于已打开文件的信息;
  fs_struct数据结构:

struct fs_struct { atomic_t count; rwlock_t lock; int umask; struct dentry * root, * pwd, * altroot; struct vfsmount * rootmnt, * pwdmnt, * altrootmnt;};

  count:共享这个表的进程个数
  lock:用于表中字段的读/写自旋锁
  umask:当打开文件设置文件权限时所使用的位掩码
  root:根目录的目录项
  pwd:当前工作目录的目录项
  altroot:模拟根目录的目录项(在80x86结构上始终为NULL)
  rootmnt:根目录所安装的文件系统对象
  pwdmnt:当前工作目录所安装的文件系统对象
  altrootmnt:模拟根目录所安装的文件系统对象(在80x86结构上始终为NULL)
  
  files_struct数据结构:

struct files_struct { atomic_t count; struct fdtable *fdt; struct fdtable fdtab; spinlock_t file_lock ____cacheline_aligned_in_smp; int next_fd; struct embedded_fd_set close_on_exec_init; struct embedded_fd_set open_fds_init; struct file * fd_array[NR_OPEN_DEFAULT];};

  files_struct 结构中的主体就是一个file结构数组struct file * fd_array[NR_OPEN_DEFAULT];每打开一个文件以后,进程就通过一个“打开文件号”fid来访问这个文件,而fid就是数组 fd_array[NR_OPEN_DEFAULT]的下标。每个file结构中有个指针f_op,指向该文件所属文件系统的file_operations数据结构。

Android进程间通信源码梳理


Linux下进程间通信的方式

  1.管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
  2.信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期 信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上, 该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,sigaction函数重新实现了signal函数);
  3.报文(Message)队列(消息队列):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
  4.共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针其他通信机制运行效率较低设计的。往往与其它通信机制,如信号量结合使用, 来达到进程间的同步及互斥。
  5.信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
  6.套接字(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix 系统上:Linux和System V的变种都支持套接字。
  在研究Android源码的前提必须要理解清楚Android的进程间通信机制:
  Android系统没有采用上述提到的各种进程间通信机制,而是采用Binder机制,Binder是一种进程间通信机制,它是一种类似于COM和CORBA分布式组件架构,通俗一点,其实是提供远程过程调用(RPC)功能。从英文字面上意思看,Binder具有粘结剂的意思,那么它把什么东西粘结在一起呢?在Android系统的Binder机制中,由一系统组件组成,分别是Client、Server、Service Manager和Binder驱动程序,其中Client、Server和Service Manager运行在用户空间,Binder驱动程序运行内核空间。Binder就是一种把这四个组件粘合在一起的粘结剂了,其中,核心组件便是Binder驱动程序了,Service Manager提供了辅助管理的功能,Client和Server正是在Binder驱动和Service Manager提供的基础设施上,进行Client-Server之间的通信。
    在笔者看来Android的进程间通信就是一个远程组件的调用过程,之前提到过Linux的思想是“一切都是文件”。Android的思想则是“一切进程都是组件”,Android有弱化进程的概念,进程是以组件的形式进行代替,Android中有许多我们看不见的组件在后台运行,例如对四大组件管理的ActivityManagerService组件,这些组件都是运行在不同的进程之中。一个应用启动Activity的过程必须要和ActivityManagerService所在的进程进行交互那么这里就涉及到进程间通信,基于Binder机制的做法就是应用获取到一个ActivityManagerService的远程服务代理类,通过代理类和ActivityManagerService所在的组件进行进程间的数据通信。而底层的数据交互全部交给Binder驱动去处理,我们不必操心数据间的通信,这里只关心ActivityManagerService代理对象提供的接口。这就是一个远程代理对象的调用过程,也是一个面向对象的进程间通信过程,其实也是一种代理设计模式的思想。
  Binder进程间通信其实可以和DNS的原理相比较,浏览器首先需要通过DNS服务器将域名转换为IP地址,这里Client需要通过Service Manager依据服务的名称获取远程服务的接口。

几种基本的数据结构

  1. binder_node(Binder实体对象)
  内核空间的Binder实体对象,主要保存了Binder引用队列列表、指向Server组件的指针、待处理的工作项。
  2. binder_ref(Binder引用对象)
  内核空间的Binder引用对象,主要保存了Binder引用对象的句柄、Binder实体对象指针。
  3. binder_buffer(Binder内核缓冲区)
  内核空间的内核缓冲区最终会被切分成一块一块的binder_buffer,有效数据保存在内部变量data中。
  4. binder_proc(mmap后的进程在内核空间对应的数据结构)
  里面保存了用户空间地址、内核空间地址、内核缓冲区buffer、物理页面、Binder线程池、Binder实体对象红黑树、Binder引用对象红黑树等,这是最重要的结构体。
  5. binder_thread(Binder线程)
  处理Binder通信的线程池,里面保存了等待队列、事务堆栈。
  6. binder_transaction(Binder事务)
  Binder线程处理请求都是以事务为单位的,主要保存发起事务线程、处理事务线程和进程、Binder驱动为事务分配的内核缓冲区。
  7. binder_transaction_data(进程间通信传递数据)
  进程与Binder驱动通信时会将Parcel转换为binder_transaction_data,其中的动态缓冲区中buffer保存通信数据,offsets保存Binder对象flat_binder_object的位置。
  还有两个重要的结构一个是Binder代理对象,一个是Binder本地对象。Binder代理对象对应的就是Client组件,Binder本地对象就是对应的Service组件。它们分别用BpInterface以及BnInterface表示:
  BpInterface:

template<typename INTERFACE>class BpInterface : public INTERFACE, public BpRefBase{public:    BpInterface(const sp<IBinder>& remote);protected:    virtual IBinder* onAsBinder();};

  BnInterface:

template<typename INTERFACE>class BnInterface : public INTERFACE, public BBinder{public:    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);    virtual const String16&     getInterfaceDescriptor() const;protected:    virtual IBinder*            onAsBinder();};

  BnInterface模板类继承于BBinder类:

class BBinder : public IBinder{public:                        BBinder();    virtual status_t    transact(   uint32_t code,                                    const Parcel& data,                                    Parcel* reply,                                    uint32_t flags = 0);    \\............protected:    virtual             ~BBinder();    virtual status_t    onTransact( uint32_t code,                                    const Parcel& data,                                    Parcel* reply,                                    uint32_t flags = 0);\\.......};

  BBinder类有两个重要的函数transact和onTransact。当一个Binder代理对象通过Binder驱动程序向Binder本地对象发出进程间通信请求时,Binder驱动程序会调用该本地对象的onTransact,onTransact则是由BBinder的子类进行重写用于分发与业务相关的通信请求。
  BpInterface模板类继承于BpRefBase类:

class BpRefBase : public virtual RefBase{protected:                            BpRefBase(const sp<IBinder>& o);    virtual                 ~BpRefBase();    virtual void            onFirstRef();    virtual void            onLastStrongRef(const void* id);    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);    inline  IBinder*        remote()                { return mRemote; }    inline  IBinder*        remote() const          { return mRemote; }private:                            BpRefBase(const BpRefBase& o);    BpRefBase&              operator=(const BpRefBase& o);    IBinder* const          mRemote;    RefBase::weakref_type*  mRefs;    std::atomic<int32_t>    mState;};

  BpRefBase类中的重点在于它成员变量mRemote,这个是指向BpBinder的指针,我们可以通过成员函数remote获取BpBinder:

class BpBinder : public IBinder{public:                        BpBinder(int32_t handle);    // ......    virtual status_t    transact(   uint32_t code,                                    const Parcel& data,                                    Parcel* reply,                                    uint32_t flags = 0);    // ......private:    const   int32_t    mHandle;};

  BpBinder中有一个成员变量mHandle我们可以通过这个句柄找到Binder的引用对象,引用对象继而可以找到实体对象,而实体对象中有Binder本地对象的指针,这样就实现了从代理对象到本地对象的一个过程。最后就可以将进程间通信数据发送给Service了。
  BpInterface和BnInterface都是模板类,当我们定义好接口以后代理类和本地类都有了相同的接口,我们可以通过代理类和本地类进行交互。BnInterface和BBinder是继承关系,BpInterface和BpBinder是聚合关系,这里的设计其实很考究。软件设计原则中有这么一个原则叫做合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP):定义是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用这些对象的目的。应首先使用合成/聚合,合成/聚合则使系统灵活,其次才考虑继承,达到复用的目的。而使用继承时,要严格遵循里氏代换原则。有效地使用继承会有助于对问题的理解,降低复杂度,而滥用继承会增加系统构建、维护时的难度及系统的复杂度。 那么在这里BpInterface使用聚合的好处在于如果服务端需要做相应的修改那么不会影响到客户端,从而降低修改的成本。

ServiceManager的启动过程

  下面介绍ServiceManager的启动过程,ServiceManager是在init进程中启动的,并且它是一个系统关键服务用critical字段表示,系统关键服务如果死亡会被系统立即重新启动,用来保证系统的正常运行。如果服务连续死亡四次那么系统也会被重新启动。
  ServiceManager启动分为三个步骤,第一步调用binder_open打开文件设备/dev/binder,以及将它映射到本进程的地址空间;第二步是将自己成为Binder进程间通信的上下文的管理者;第三步是进入一个循环等待client的请求。
  当ServiceManager启动完毕后系统服务进程就可以将自己注册到ServiceManager中。
  Service Manager在用户空间的源代码位于frameworks/base/cmds/servicemanager目录下,主要是由binder.h、binder.c和service_manager.c三个文件组成。Service Manager的入口位于service_manager.c文件中的main函数:

int main(int argc, char **argv)  {      struct binder_state *bs;      void *svcmgr = BINDER_SERVICE_MANAGER;      bs = binder_open(128*1024);      if (binder_become_context_manager(bs)) {          LOGE("cannot become context manager (%s)\n", strerror(errno));          return -1;      }      svcmgr_handle = svcmgr;      binder_loop(bs, svcmgr_handler);      return 0;  } 

  main函数主要有三个功能:一是打开Binder设备文件;二是告诉Binder驱动程序自己是Binder上下文管理者,即我们前面所说的守护进程;三是进入一个无穷循环,充当Server的角色,等待Client的请求。进入这三个功能之间,先来看一下这里用到的结构体binder_state、宏BINDER_SERVICE_MANAGER的定义:

struct binder_state  {      int fd;      void *mapped;      unsigned mapsize;  };  

  fd是文件描述符,即表示打开的/dev/binder设备文件描述符;mapped是把设备文件/dev/binder映射到进程空间的起始地址;mapsize是上述内存映射空间的大小。

#define BINDER_SERVICE_MANAGER ((void*) 0)  

  它表示Service Manager的句柄为0。Binder通信机制使用句柄来代表远程接口,这个句柄的意义和Windows编程中用到的句柄是差不多的概念。前面说到,Service Manager在充当守护进程的同时,它充当Server的角色,当它作为远程接口使用时,它的句柄值便为0,这就是它的特殊之处,其余的Server的远程接口句柄值都是一个大于0 而且由Binder驱动程序自动进行分配的。
函数首先是执行打开Binder设备文件的操作binder_open,这个函数位于

struct binder_state *binder_open(unsigned mapsize)  {      struct binder_state *bs;      bs = malloc(sizeof(*bs));      if (!bs) {          errno = ENOMEM;          return 0;      }      bs->fd = open("/dev/binder", O_RDWR);      if (bs->fd < 0) {          fprintf(stderr,"binder: cannot open device (%s)\n",                  strerror(errno));          goto fail_open;      }      bs->mapsize = mapsize;      bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);      if (bs->mapped == MAP_FAILED) {          fprintf(stderr,"binder: cannot map device (%s)\n",                  strerror(errno));          goto fail_map;      }          /* TODO: check version */      return bs;  fail_map:      close(bs->fd);  fail_open:      free(bs);      return 0;  } 

  我们先看一下file_operations结构体:

static struct file_operations binder_fops = {      .owner = THIS_MODULE,      .poll = binder_poll,      .unlocked_ioctl = binder_ioctl,      .mmap = binder_mmap,      .open = binder_open,      .flush = binder_flush,      .release = binder_release,  };  

  从设备文件的操作方法binder_fops可以看出,前面的binder_open函数执行语句:

static int binder_open(struct inode *nodp, struct file *filp)  {      struct binder_proc *proc;      if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)          printk(KERN_INFO "binder_open: %d:%d\n", current->group_leader->pid, current->pid);      proc = kzalloc(sizeof(*proc), GFP_KERNEL);      if (proc == NULL)          return -ENOMEM;      get_task_struct(current);      proc->tsk = current;      INIT_LIST_HEAD(&proc->todo);      init_waitqueue_head(&proc->wait);      proc->default_priority = task_nice(current);      mutex_lock(&binder_lock);      binder_stats.obj_created[BINDER_STAT_PROC]++;      hlist_add_head(&proc->proc_node, &binder_procs);      proc->pid = current->group_leader->pid;      INIT_LIST_HEAD(&proc->delivered_death);      filp->private_data = proc;      mutex_unlock(&binder_lock);      if (binder_proc_dir_entry_proc) {          char strbuf[11];          snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);          remove_proc_entry(strbuf, binder_proc_dir_entry_proc);          create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc);      }      return 0;  }  

  这个函数的主要作用是创建一个struct binder_proc数据结构来保存打开设备文件/dev/binder的进程的上下文信息,并且将这个进程上下文信息保存在打开文件结构struct file的私有数据成员变量private_data中,这样,在执行其它文件操作时,就通过打开文件结构struct file来取回这个进程上下文信息了。

static int binder_mmap(struct file *filp, struct vm_area_struct *vma)  {      int ret;      struct vm_struct *area;      struct binder_proc *proc = filp->private_data;      const char *failure_string;      struct binder_buffer *buffer;      if ((vma->vm_end - vma->vm_start) > SZ_4M)          vma->vm_end = vma->vm_start + SZ_4M;      if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)          printk(KERN_INFO              "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n",              proc->pid, vma->vm_start, vma->vm_end,              (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,              (unsigned long)pgprot_val(vma->vm_page_prot));      if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {          ret = -EPERM;          failure_string = "bad vm_flags";          goto err_bad_arg;      }      vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;      if (proc->buffer) {          ret = -EBUSY;          failure_string = "already mapped";          goto err_already_mapped;      }      area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);      if (area == NULL) {          ret = -ENOMEM;          failure_string = "get_vm_area";          goto err_get_vm_area_failed;      }      proc->buffer = area->addr;      proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;  #ifdef CONFIG_CPU_CACHE_VIPT      if (cache_is_vipt_aliasing()) {          while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) {              printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);              vma->vm_start += PAGE_SIZE;          }      }  #endif      proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);      if (proc->pages == NULL) {          ret = -ENOMEM;          failure_string = "alloc page array";          goto err_alloc_pages_failed;      }      proc->buffer_size = vma->vm_end - vma->vm_start;      vma->vm_ops = &binder_vm_ops;      vma->vm_private_data = proc;      if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) {          ret = -ENOMEM;          failure_string = "alloc small buf";          goto err_alloc_small_buf_failed;      }      buffer = proc->buffer;      INIT_LIST_HEAD(&proc->buffers);      list_add(&buffer->entry, &proc->buffers);      buffer->free = 1;      binder_insert_free_buffer(proc, buffer);      proc->free_async_space = proc->buffer_size / 2;      barrier();      proc->files = get_files_struct(current);      proc->vma = vma;      /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/      return 0;  err_alloc_small_buf_failed:      kfree(proc->pages);      proc->pages = NULL;  err_alloc_pages_failed:      vfree(proc->buffer);      proc->buffer = NULL;  err_get_vm_area_failed:  err_already_mapped:  err_bad_arg:      printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n", proc->pid, vma->vm_start, vma->vm_end, failure_string, ret);      return ret;  }

  首先是对参数作一些健康体检(sanity check),例如,要映射的内存大小不能超过SIZE_4M,即4M,回到service_manager.c中的main 函数,这里传进来的值是128 * 1024个字节,即128K,这个检查没有问题。通过健康体检后,调用get_vm_area函数获得一个空闲的vm_struct区间,并初始化proc结构体的buffer、user_buffer_offset、pages和buffer_size和成员变量,接着调用binder_update_page_range来为虚拟地址空间proc->buffer ~ proc->buffer + PAGE_SIZE分配一个空闲的物理页面,同时这段地址空间使用一个binder_buffer来描述,分别插入到proc->buffers链表和proc->free_buffers红黑树中去,最后,还初始化了proc结构体的free_async_space、files和vma三个成员变量。
  下一步就是调用binder_become_context_manager来通知Binder驱动程序自己是Binder机制的上下文管理者,即守护进程。

int binder_become_context_manager(struct binder_state *bs)  {      return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);  }  

  进入到Binder驱动程序的binder_ioctl函数,我们只关注BINDER_SET_CONTEXT_MGR命令:

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  {      int ret;      struct binder_proc *proc = filp->private_data;      struct binder_thread *thread;      unsigned int size = _IOC_SIZE(cmd);      void __user *ubuf = (void __user *)arg;      /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/      ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);      if (ret)          return ret;      mutex_lock(&binder_lock);      thread = binder_get_thread(proc);      if (thread == NULL) {          ret = -ENOMEM;          goto err;      }      switch (cmd) {          ......      case BINDER_SET_CONTEXT_MGR:          if (binder_context_mgr_node != NULL) {              printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n");              ret = -EBUSY;              goto err;          }          if (binder_context_mgr_uid != -1) {              if (binder_context_mgr_uid != current->cred->euid) {                  printk(KERN_ERR "binder: BINDER_SET_"                      "CONTEXT_MGR bad uid %d != %d\n",                      current->cred->euid,                      binder_context_mgr_uid);                  ret = -EPERM;                  goto err;              }          } else              binder_context_mgr_uid = current->cred->euid;          binder_context_mgr_node = binder_new_node(proc, NULL, NULL);          if (binder_context_mgr_node == NULL) {              ret = -ENOMEM;              goto err;          }          binder_context_mgr_node->local_weak_refs++;          binder_context_mgr_node->local_strong_refs++;          binder_context_mgr_node->has_strong_ref = 1;          binder_context_mgr_node->has_weak_ref = 1;          break;          ......      default:          ret = -EINVAL;          goto err;      }      ret = 0;  err:      if (thread)          thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;      mutex_unlock(&binder_lock);      wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);      if (ret && ret != -ERESTARTSYS)          printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);      return ret;  }

  binder_context_mgr_node用来表示Service Manager实体,binder_context_mgr_uid表示Service Manager守护进程的uid。在这个场景下,由于当前线程是第一次进到这里,所以binder_context_mgr_node为NULL,binder_context_mgr_uid为-1,于是初始化binder_context_mgr_uid为current->cred->euid,这样,当前线程就成为Binder机制的守护进程了,并且通过binder_new_node为Service Manager创建Binder实体。
  下一步就是调用binder_loop函数进入循环,等待Client来请求了。

Server启动的过程

  下面是注册的步骤
  1. ProcessState::self()是单例模式,第一次调用会打开Binder设备,并且Binder驱动会给Server进程分配(1M-4k * 2)大小的内核缓冲区;
  2. 通过defaultServiceManager()获取到ServiceManager的代理对象。
  3. 初始化Server服务,就是创建一个Server本地对象,然后通过ServiceManager代理注册到ServiceManager里面:
  (1) 使用代理注册时首先是将binder对象使用flat_binder_object结构体写入到Parcel对象中,Parcel格式有两个缓冲区,mData里内容可能是整数、字符串或flat_binder_object,而mObjects保存的是每个flat_binder_object的位置,而且两个缓冲区也会根据需要自动扩展空间。
  (2) 通过Binder代理对象的transaction()发送BC_TRANSACTION命令协议,由于BC_TRANSACTION是通过io命令BINDER_WRITE_READ发送到Binder驱动的,所以要将Parcel对象转化为binder_transaction_data结构体,然后通过writeTransactionData()将此结构体写入到IPCThreadState的命令协议缓冲区mOut中,然后waitForResponse()里面执行一个死循环,调用talkWithDriver()将mOut转换为binder_write_read发送到Binder驱动,另外还会从返回协议缓冲区mIn中读取返回值。
  (3) Binder驱动调用binder_transaction()处理命令请求,根据句柄值找到Binder引用对象,再通过引用对象找到实体对象,然后在目标进程中找到一个等待其它事务但暂时空闲的线程去处理BR_TRANSACTION返回协议,是通过将binder_transaction结构体封装成BINDER_WORK_TRANSACTION工作项加入到目标todo队列,这时候我们需要将源进程中传递的binder_transaction_data中的数据缓冲区拷贝到binder_transaction的数据缓冲区中,然后取出其中的binder对象,在Binder驱动中目标进程创建Binder实体对象和引用对象,并为引用对象分配句柄值。然后通知源进程之前发送的BC_TRANSACTION已经收到,将binder_work结构体封装成BINDER_TRANSACTION_COMPLETE添加到源线程的todo队列中,以便源线程在返回用户空间之前可以处理这个工作项,最后BR_TRANSACTION返回协议就写入到了IPCThreadState的返回协议缓冲区mIn。
  (4)如果是同步请求,则工作项会添加到todo队列中,而如果是异步请求,则会添加到目标Binder实体对象的async_todo队列中,为了节省资源,异步请求每次最多只能执行一个工作项。如果是同步请求,则目标wait队列会被唤醒,继续执行binder_thread_read(),从todo队列中去取BINDER_WORK_TRANSATION工作项,从这个工作项里取出binder_transaction,处理这个工作项的方式是向目标线程发送一个BR_TRANSACTION返回协议,这个协议里包装了binder_transaction_data,这里将binder_transaction里的通信数据拷贝到binder_transaction_data,实际上只是将binder_transaction_data的指针指向了binder_transaction,这些缓冲区都是在内核空间,然后将BR_TRANSACTION返回协议拷贝到目标线程提供的用户空间的数据缓冲区中,这时候ServiceManager在Binder驱动的主线程就会在binder_thread_read被唤醒,返回到用户空间后,就会在binder_parse()中解析BR_TRANSACTION返回协议并将Service添加到svclist中,再通过binder_send_reply()通知Binder驱动返回结果,实际上是发送了BC_REPLY协议,Binder驱动处理完这个协议后,会在请求注册service到servicemanager的线程的todo队列z中添加一个BINDER_WORK_TRANSACTION的工作项,这时候此线程在binder_thread_read()被唤醒,处理这个工作项,然后binder_transaction中返回的目标实体对象是空的,线程将binder_transaction中的通信数据转换为binder_transaction_data,然后包装在BR_REPLY返回协议中拷贝到thread提供的用户空间缓冲区,然后线程切换到用户空间后,就可以在IPCThreadState的waitForResponse()中处理BR_REPLY返回协议了。
  4. 开启Binder线程池首先创建主线程并把主线程加入到Binder线程池里,这是通过向Binder驱动发送BC_ENTER_LOOPER命令协议实现的,如果不是主线程,则发送BC_REGISTER_LOOPER命令协议。
  那么Binder间进程通信的实质在于用户空间和内核空间共享同一块物理页面:2.6后linux系统会为每个进程分配4G的虚拟空间,其中0~3G的用户空间是每个进程独有的,而3G~4G的内核空间是所有进程共享的,进程B在mmap()后Binder驱动为进程分配一块内核缓冲区,最大只能申请4M,用户空间和内核空间共享同一块内存,B进程的用户空间和内核空间同大小,有线性映射关系,内核空间的缓冲数据保存在binder_proc->buffer中。如下图,进程A要将数据发送到进程B,先用copy_from_user()将数据从用户空间拷贝到内核空间的缓冲区中,由于B进程用户空间和内核空间共享内存,当然可以在B进程的用户空间访问。

Android匿名共享内存系统源码梳理


  之前的进程间通信的核心是mmap,通过这样存在一个问题,如果分配的进程空间有部分不需要了,不能单独释放这一块内存。为了弥补这一缺陷,在Android系统中,提供了独特的匿名共享内存子系统Ashmem(Anonymous Shared Memory),它以驱动程序的形式实现在内核空间中。它有两个特点,一是能够辅助内存管理系统来有效地管理不再使用的内存块,二是它通过Binder进程间通信机制来实现进程间的内存共享。
  下面我们分别介绍Android系统匿名共享内存的创建(open)、映射(mmap)、读写(read/write)以及锁定和解锁(pin/unpin)四个使用情景。  

匿名共享内存的创建操作

  在Android应用程序框架层提供MemoryFile类的构造函数中,进行了匿名共享内存的创建操作,我们先来看一下这个构造函数的实现:

public class MemoryFile  {      ......      private static native FileDescriptor native_open(String name, int length) throws IOException;      ......      private FileDescriptor mFD;        // ashmem file descriptor      ......      private int mLength;    // total length of our ashmem region      ......      /**     * Allocates a new ashmem region. The region is initially not purgable.     *     * @param name optional name for the file (can be null).     * @param length of the memory file in bytes.     * @throws IOException if the memory file could not be created.     */      public MemoryFile(String name, int length) throws IOException {          mLength = length;          mFD = native_open(name, length);          ......      }      ......  }

  这里调用JNI方法native_open 会调用到:

int ashmem_create_region(const char *name, size_t size)  {      int fd, ret;      fd = open(ASHMEM_DEVICE, O_RDWR);      if (fd < 0)          return fd;      if (name) {          char buf[ASHMEM_NAME_LEN];          strlcpy(buf, name, sizeof(buf));          ret = ioctl(fd, ASHMEM_SET_NAME, buf);          if (ret < 0)              goto error;      }      ret = ioctl(fd, ASHMEM_SET_SIZE, size);      if (ret < 0)          goto error;      return fd;  error:      close(fd);      return ret;  }

  函数中执行三个方法:一个open和两个ioctl操作,前者是打开设备文件ASHMEM_DEVICE,后者分别是设置匿名共享内存的名称和大小。
  在研究三个方法前我们先研究下Ashmem驱动程序的一个相关数据结构struct ashmem_area:

struct ashmem_area {      char name[ASHMEM_FULL_NAME_LEN];/* optional name for /proc/pid/maps */      struct list_head unpinned_list; /* list of all ashmem areas */      struct file *file;      /* the shmem-based backing file */      size_t size;            /* size of the mapping, in bytes */      unsigned long prot_mask;    /* allowed prot bits, as vm_flags */  };

  这个数据结构就是用来表示一块共享内存,域name表示这块共享内存的名字,这个名字会显示/proc//maps文件中,表示打开这个共享内存文件的进程ID;域unpinned_list是一个列表头,它把这块共享内存中所有被解锁的内存块连接在一起,下面我们讲内存块的锁定和解锁操作时会看到它的用法;域file表示这个共享内存在临时文件系统tmpfs中对应的文件,在内核决定要把这块共享内存对应的物理页面回收时,就会把它的内容交换到这个临时文件中去;域size表示这块共享内存的大小;域prot_mask表示这块共享内存的访问保护位。
  在Ashmem驱动程中,所有的ashmem_area实例都是从自定义的一个slab缓冲区创建的。在Linux内核中,对于大块的内存的管理是用伙伴系统算法(buddy )管理。伙伴系统把所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1, 2, 4, 8, 16, 32, 64, 128, 256,512和1024 个连续的页框。对1024 个页框的最大请求对应着4MB 大小的连续RAM块。每个块的第一个页框的物理地址是该块大小的整数倍。例如,大小为16 个页框的块,其起始地址是16 × 212(212 = 4096,这是一个常规页的大小)的倍数。对于小块的内存则用slab管理。在slab方法中,每种重要的数据结构都有自己专用的缓冲区队列。每个队列中的“对象”的个数是动态变化的,不够时可以增添,空闲的时候可以释放,给系统回收。
  这个slab缓冲区是在驱动程序模块初始化函数创建的,我们来看一个这个初始化函数的相关实现:

static int __init ashmem_init(void)  {      int ret;      ashmem_area_cachep = kmem_cache_create("ashmem_area_cache",          sizeof(struct ashmem_area),          0, 0, NULL);      if (unlikely(!ashmem_area_cachep)) {          printk(KERN_ERR "ashmem: failed to create slab cache\n");          return -ENOMEM;      }      //......      return 0;  } 

  全局变量声明在文件的开头部分:

static struct kmem_cache *ashmem_area_cachep __read_mostly;

  这里就是通过kmem_cache_create函数来创建一个名为”ashmem_area_cache”、对象大小为sizeof(struct ashmem_area)的缓冲区了。缓冲区创建了以后,就可以每次从它分配一个struct ashmem_area对象了。
  我们回到前面的ashmem_create_region函数中:
  首先是文件打开操作:

fd = open(ASHMEM_DEVICE, O_RDWR);

  ASHMEM_DEVICE是一个宏,定义为:#define ASHMEM_DEVICE “/dev/ashmem”
  调用这个open函数最终会进入到Ashmem驱动程序中的ashmem_open函数中去:

static int ashmem_open(struct inode *inode, struct file *file)  {      struct ashmem_area *asma;      int ret;      ret = nonseekable_open(inode, file);      if (unlikely(ret))          return ret;      asma = kmem_cache_zalloc(ashmem_area_cachep, GFP_KERNEL);      if (unlikely(!asma))          return -ENOMEM;      INIT_LIST_HEAD(&asma->unpinned_list);      memcpy(asma->name, ASHMEM_NAME_PREFIX, ASHMEM_NAME_PREFIX_LEN);      asma->prot_mask = PROT_MASK;      file->private_data = asma;      return 0;  } 

  首先是通过nonseekable_open函数来设备这个文件不可以执行定位操作,即不可以执行seek文件操作。接着就是通过kmem_cache_zalloc函数从刚才我们创建的slab缓冲区ashmem_area_cachep来创建一个ashmem_area结构体了,并且保存在本地变量asma中。再接下去就是初始化变量asma的其它域,其中,域name初始为ASHMEM_NAME_PREFIX,这是一个宏,定义为:

#define ASHMEM_NAME_PREFIX "dev/ashmem/"  #define ASHMEM_NAME_PREFIX_LEN (sizeof(ASHMEM_NAME_PREFIX) - 1)  

   函数的最后是把这个ashmem_area结构保存在打开文件结构体的private_data域中,这样,Ashmem驱动程序就可以在其它地方通过这个private_data域来取回这个ashmem_area结构了。
到这里,设备文件/dev/ashmem的打开操作就完成了,它实际上就是在Ashmem驱动程序中创建了一个ashmem_area结构,表示一块新的共享内存。
再回到ashmem_create_region函数中,又调用了两次ioctl文件操作分别来设备这块新建的匿名共享内存的名字和大小。
这样,ashmem_create_region函数就执先完成了,层层返回,最后回到应用程序框架层提供的接口Memory的构造函数中,整个匿名共享内存的创建过程就完成了。前面我们说过过,Ashmem驱动程序不提供read和write文件操作,进程若要访问这个共享内存,必须要把这个设备文件映射到自己的进程空间中,然后进行直接内存访问。
下面看一下映射的过程:

public class MemoryFile  {      ......      // returns memory address for ashmem region      private static native int native_mmap(FileDescriptor fd, int length, int mode)          throws IOException;      ......      private int mAddress;   // address of ashmem memory      ......      /**     * Allocates a new ashmem region. The region is initially not purgable.     *     * @param name optional name for the file (can be null).     * @param length of the memory file in bytes.     * @throws IOException if the memory file could not be created.     */      public MemoryFile(String name, int length) throws IOException {          ......          mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE);          ......      }  }  

  映射匿名共享内存设备文件到进程空间是通过JNI方法native_mmap来进行的:

static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)  {      struct ashmem_area *asma = file->private_data;      int ret = 0;      mutex_lock(&ashmem_mutex);      /* user needs to SET_SIZE before mapping */      if (unlikely(!asma->size)) {          ret = -EINVAL;          goto out;      }      /* requested protection bits must match our allowed protection mask */      if (unlikely((vma->vm_flags & ~asma->prot_mask) & PROT_MASK)) {          ret = -EPERM;          goto out;      }      if (!asma->file) {          char *name = ASHMEM_NAME_DEF;          struct file *vmfile;          if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0')              name = asma->name;          /* ... and allocate the backing shmem file */          vmfile = shmem_file_setup(name, asma->size, vma->vm_flags);          if (unlikely(IS_ERR(vmfile))) {              ret = PTR_ERR(vmfile);              goto out;          }          asma->file = vmfile;      }      get_file(asma->file);      if (vma->vm_flags & VM_SHARED)          shmem_set_file(vma, asma->file);      else {          if (vma->vm_file)              fput(vma->vm_file);          vma->vm_file = asma->file;      }      vma->vm_flags |= VM_CAN_NONLINEAR;  out:      mutex_unlock(&ashmem_mutex);      return ret;  } 

  这个函数的实现也很简单,它调用了Linux内核提供的shmem_file_setup函数来在临时文件系统tmpfs中创建一个临时文件,这个临时文件与Ashmem驱动程序创建的匿名共享内存对应。函数shmem_file_setup是Linux内核中用来创建共享内存文件的方法,而Linux内核中的共享内存机制其实是一种进程间通信(IPC)机制,它的实现相对也是比较复杂。
  最后是返回了一个共享内存的起始地址,我们在读写时就可以在分配好内存后进行数据的读写。

Android ActivityThread类源码的梳理


  ActivityThread它本身并不是一个线程,它是管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IApplicationThread接口,AMS为Client、ActivityThread.ApplicationThread为Server)负责调度和执行activities、broadcasts和其它操作。
  首先我们来看下ActivityThread的一些成员变量

    private ContextImpl mSystemContext;    static IPackageManager sPackageManager;    final ApplicationThread mAppThread = new ApplicationThread();    final Looper mLooper = Looper.myLooper();    final H mH = new H();    final ArrayMap<IBinder, ActivityClientRecord> mActivities            = new ArrayMap<IBinder, ActivityClientRecord>();    // List of new activities (via ActivityRecord.nextIdle) that should    // be reported when next we idle.    ActivityClientRecord mNewActivities = null;    // Number of activities that are currently visible on-screen.    int mNumVisibleActivities = 0;    final ArrayMap<IBinder, Service> mServices            = new ArrayMap<IBinder, Service>();    AppBindData mBoundApplication;    Application mInitialApplication;

  mActivities、mServices、mProviderMap三个都是一个ArrayMap,它们分别保存了应用中Activity、Service以及ContentProvider。这里并没有保存BrodcastReceiver,因为它的生命周期很短。
  mInitialApplication:如果应用没有派生自己的Application类,那么这个类将被用Application类初始化。
  ApplicationThread是ActivityThread的一个内部类,它也不是什么线程,ApplicationThread是一个Binder服务类,Android的ActivityManagerService操作应用就是通过这个接口,整个的处理过程都是通过消息机制,防止处理时间过程影响整个应用。
  

Android Context类源码的梳理


  
  Context的字面意思的含义是上下文的环境,应用上层通过Context类提供的接口来操作Android的四大组件和资源。下面我们看下Context的类图:
  enter image description here
  这个类图在设计模式里面就可以称为装饰模式。Activity组件通过其父类ContextThemeWrapper和ContextWrapper的成员变量mBase来引用了一个ContextImpl对象,这样,Activity组件以后就可以通过这个ContextImpl对象来执行一些具体的操作,例如,启动Service组件、注册广播接收者和启动Content Provider组件等操作。同时,ContextImpl类又通过自己的成员变量mOuterContext来引用了与它关联的一个Activity组件。
  目前Android类对Context的实现只有ContextImpl类,它集成了应用框架里的核心对象。

ActivityManagerService源码的梳理


  之前有讲过Android一切都是组件,是一个无边界的概念ActivityManagerService则是负责管理四大组件,同时也管理和调度用户进程。ActivityManagerService 继承自 ActivityManagerNative 类,并实现了 Watchdog.Monitor 和 BatteryStatsImpl.BatteryCallback 接口;而 ActivityManagerNative 继承自 Binder 类,并实现了 IActivityManager 接口;客户端使用的是 ActivityManager 类,其内部通过调用 ActivityManagerNative.getDefault() 得到一个 ActivityManagerProxy 对象,通过它与 ActivityManagerService 通信;

ActivityManagerService 的构造函数

  ActivityManagerService的初始化是由SystemServer进行初始化的,ActivityManagerService的构造函数如下:

   public ActivityManagerService(Context systemContext) {        mContext = systemContext;        mFactoryTest = FactoryTest.getMode();        mSystemThread = ActivityThread.currentActivityThread();        Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());        mHandlerThread = new ServiceThread(TAG,                android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);        mHandlerThread.start();        mHandler = new MainHandler(mHandlerThread.getLooper());        mFgBroadcastQueue = new BroadcastQueue(this, mHandler,                "foreground", BROADCAST_FG_TIMEOUT, false);        mBgBroadcastQueue = new BroadcastQueue(this, mHandler,                "background", BROADCAST_BG_TIMEOUT, true);        mBroadcastQueues[0] = mFgBroadcastQueue;        mBroadcastQueues[1] = mBgBroadcastQueue;        mServices = new ActiveServices(this);        mProviderMap = new ProviderMap(this);        // TODO: Move creation of battery stats service outside of activity manager service.        File dataDir = Environment.getDataDirectory();        File systemDir = new File(dataDir, "system");        systemDir.mkdirs();        mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);        mBatteryStatsService.getActiveStatistics().readLocked();        mBatteryStatsService.getActiveStatistics().writeAsyncLocked();        mOnBattery = DEBUG_POWER ? true                : mBatteryStatsService.getActiveStatistics().getIsOnBattery();        mBatteryStatsService.getActiveStatistics().setCallback(this);        mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));        mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);        mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));        // User 0 is the first and only user that runs at boot.        mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));        mUserLru.add(Integer.valueOf(0));        updateStartedUserArrayLocked();        GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",            ConfigurationInfo.GL_ES_VERSION_UNDEFINED);        mConfiguration.setToDefaults();        mConfiguration.setLocale(Locale.getDefault());        mConfigurationSeq = mConfiguration.seq = 1;        mProcessCpuTracker.init();        mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);        mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);        mStackSupervisor = new ActivityStackSupervisor(this);        mTaskPersister = new TaskPersister(systemDir, mStackSupervisor);        mProcessCpuThread = new Thread("CpuTracker") {            @Override            public void run() {                while (true) {                    try {                        try {                            synchronized(this) {                                final long now = SystemClock.uptimeMillis();                                long nextCpuDelay = (mLastCpuTime.get()+MONITOR_CPU_MAX_TIME)-now;                                long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;                                //Slog.i(TAG, "Cpu delay=" + nextCpuDelay                                //        + ", write delay=" + nextWriteDelay);                                if (nextWriteDelay < nextCpuDelay) {                                    nextCpuDelay = nextWriteDelay;                                }                                if (nextCpuDelay > 0) {                                    mProcessCpuMutexFree.set(true);                                    this.wait(nextCpuDelay);                                }                            }                        } catch (InterruptedException e) {                        }                        updateCpuStatsNow();                    } catch (Exception e) {                        Slog.e(TAG, "Unexpected exception collecting process stats", e);                    }                }            }        };        mLockToAppRequest = new LockToAppRequestDialog(mContext, this);        Watchdog.getInstance().addMonitor(this);        Watchdog.getInstance().addThread(mHandler);    }

  函数比较长
  获取当前的ActivityThread存放在mSystemThread中。
  创建用于处理消息和线程的Handler。
  创建用于管理广播的数据结构mFgBroadcastQueue和mBgBroadcastQueue。
  创建用于管理Service的mServices。
  创建用于管理provider的mProviderMap。
  得到系统的data、system目录dataDir和systemDir。
  创建Activity的管理对象mStackSupervisor。
  AMS的构造方法主要是构建了四大组件的管理对象。

ActivityManagerService 对进程的管理

  AMS中由两个方法对进程的优先级进行管理,一个函数是updateLruProcessLocked用于调整进程运行的状态。另一个函数是updateOomAdjLocked()方法用来更新进程的优先级。
  updateLruProcessLocked:

    final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,            ProcessRecord client) {        final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities                || app.treatLikeActivity;        final boolean hasService = false; // not impl yet. app.services.size() > 0;        if (!activityChange && hasActivity) {            return;        }        mLruSeq++;        final long now = SystemClock.uptimeMillis();        app.lastActivityTime = now;        // First a quick reject: if the app is already at the position we will        // put it, then there is nothing to do.        if (hasActivity) {            final int N = mLruProcesses.size();            if (N > 0 && mLruProcesses.get(N-1) == app) {                if (DEBUG_LRU) Slog.d(TAG, "Not moving, already top activity: " + app);                return;            }        } else {            if (mLruProcessServiceStart > 0                    && mLruProcesses.get(mLruProcessServiceStart-1) == app) {                if (DEBUG_LRU) Slog.d(TAG, "Not moving, already top other: " + app);                return;            }        }        int lrui = mLruProcesses.lastIndexOf(app);        if (app.persistent && lrui >= 0) {            // We don't care about the position of persistent processes, as long as            // they are in the list.            if (DEBUG_LRU) Slog.d(TAG, "Not moving, persistent: " + app);            return;        }        if (lrui >= 0) {            if (lrui < mLruProcessActivityStart) {                mLruProcessActivityStart--;            }            if (lrui < mLruProcessServiceStart) {                mLruProcessServiceStart--;            }            /*            if (addIndex > lrui) {                addIndex--;            }            if (nextIndex > lrui) {                nextIndex--;            }            */            mLruProcesses.remove(lrui);        }        int nextIndex;        if (hasActivity) {            final int N = mLruProcesses.size();            if (app.activities.size() == 0 && mLruProcessActivityStart < (N-1)) {                // Process doesn't have activities, but has clients with                // activities...  move it up, but one below the top (the top                // should always have a real activity).                if (DEBUG_LRU) Slog.d(TAG, "Adding to second-top of LRU activity list: " + app);                mLruProcesses.add(N-1, app);                // To keep it from spamming the LRU list (by making a bunch of clients),                // we will push down any other entries owned by the app.                final int uid = app.info.uid;                for (int i=N-2; i>mLruProcessActivityStart; i--) {                    ProcessRecord subProc = mLruProcesses.get(i);                    if (subProc.info.uid == uid) {                        // We want to push this one down the list.  If the process after                        // it is for the same uid, however, don't do so, because we don't                        // want them internally to be re-ordered.                        if (mLruProcesses.get(i-1).info.uid != uid) {                            if (DEBUG_LRU) Slog.d(TAG, "Pushing uid " + uid + " swapping at " + i                                    + ": " + mLruProcesses.get(i) + " : " + mLruProcesses.get(i-1));                            ProcessRecord tmp = mLruProcesses.get(i);                            mLruProcesses.set(i, mLruProcesses.get(i-1));                            mLruProcesses.set(i-1, tmp);                            i--;                        }                    } else {                        // A gap, we can stop here.                        break;                    }                }            } else {                // Process has activities, put it at the very tipsy-top.                if (DEBUG_LRU) Slog.d(TAG, "Adding to top of LRU activity list: " + app);                mLruProcesses.add(app);            }            nextIndex = mLruProcessServiceStart;        } else if (hasService) {            // Process has services, put it at the top of the service list.            if (DEBUG_LRU) Slog.d(TAG, "Adding to top of LRU service list: " + app);            mLruProcesses.add(mLruProcessActivityStart, app);            nextIndex = mLruProcessServiceStart;            mLruProcessActivityStart++;        } else  {            // Process not otherwise of interest, it goes to the top of the non-service area.            int index = mLruProcessServiceStart;            if (client != null) {                // If there is a client, don't allow the process to be moved up higher                // in the list than that client.                int clientIndex = mLruProcesses.lastIndexOf(client);                if (DEBUG_LRU && clientIndex < 0) Slog.d(TAG, "Unknown client " + client                        + " when updating " + app);                if (clientIndex <= lrui) {                    // Don't allow the client index restriction to push it down farther in the                    // list than it already is.                    clientIndex = lrui;                }                if (clientIndex >= 0 && index > clientIndex) {                    index = clientIndex;                }            }            if (DEBUG_LRU) Slog.d(TAG, "Adding at " + index + " of LRU list: " + app);            mLruProcesses.add(index, app);            nextIndex = index-1;            mLruProcessActivityStart++;            mLruProcessServiceStart++;        }        // If the app is currently using a content provider or service,        // bump those processes as well.        for (int j=app.connections.size()-1; j>=0; j--) {            ConnectionRecord cr = app.connections.valueAt(j);            if (cr.binding != null && !cr.serviceDead && cr.binding.service != null                    && cr.binding.service.app != null                    && cr.binding.service.app.lruSeq != mLruSeq                    && !cr.binding.service.app.persistent) {                nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,                        "service connection", cr, app);            }        }        for (int j=app.conProviders.size()-1; j>=0; j--) {            ContentProviderRecord cpr = app.conProviders.get(j).provider;            if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.persistent) {                nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,                        "provider reference", cpr, app);            }        }    }

  该方法调整进程很重要的一个依据是查看进程中有没有活动的Activity,除开进程本身存在Activity外,如果进程相关联的客户进程中有Activity也算本进程中拥有Activity。这个方法调整位置主要是为了将来杀死进程和释放内存做准备。如果说一个进程中由关联的Activity和真实存在Activity是一个重要性。Activity是用来显示UI所以Android尽量不关闭这种进程。
  mLruProcessActivityStart指向带有Activity进程,mLruProcessServiceStart指向没有Activity进程。
  如果一个进程拥有Activity,通常会把它插入到队列的最高端位置,否则只会把它放到没有Activity的进程之前。

Android Activity类源码的梳理


  我们从Activity的启动过程看起,Activity的startActivity是调用的Activity中的startActivityForResult:

    public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {        if (mParent == null) {            Instrumentation.ActivityResult ar =                mInstrumentation.execStartActivity(                    this, mMainThread.getApplicationThread(), mToken, this,                    intent, requestCode, options);            if (ar != null) {                mMainThread.sendActivityResult(                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),                    ar.getResultData());            }            if (requestCode >= 0) {                // If this start is requesting a result, we can avoid making                // the activity visible until the result is received.  Setting                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the                // activity hidden during this time, to avoid flickering.                // This can only be done when a result is requested because                // that guarantees we will get information back when the                // activity is finished, no matter what happens to it.                mStartedActivity = true;            }            final View decor = mWindow != null ? mWindow.peekDecorView() : null;            if (decor != null) {                decor.cancelPendingInputEvents();            }            // TODO Consider clearing/flushing other event sources and events for child windows.        } else {            if (options != null) {                mParent.startActivityFromChild(this, intent, requestCode, options);            } else {                // Note we want to go through this method for compatibility with                // existing applications that may have overridden it.                mParent.startActivityFromChild(this, intent, requestCode);            }        }        if (options != null && !isTopOfTask()) {            mActivityTransitionState.startExitOutTransition(this, options);        }    }

  首先是第一个逻辑分之,判定mParent是否为空,mParent是在ActivityGroup中使用而在Fragment出现以后就逐渐废弃了ActivityGroup。所以我们关注第一个分之中的逻辑。实际上是调用了mInstrumentation的execStartActivity:

                mInstrumentation.execStartActivity(                    this, mMainThread.getApplicationThread(), mToken, this,                    intent, requestCode, options);

  mInstrumentation它的类型是Intrumentation,Intrumentation一方面会用于单元测试,另一方面它用来监控应用程序和系统的交互。之前在介绍ActivityThread时讲到过这里通过mMainThread.getApplicationThread获得它里面的ApplicationThread成员变量,它是一个Binder对象,后面我们会看到,ActivityManagerService会使用它来和ActivityThread来进行进程间通信。
  mToken是一个Binder对象。
  下面进入到Intrumentation中的execStartActivity:

    public ActivityResult execStartActivity(        Context who, IBinder contextThread, IBinder token, Fragment target,        Intent intent, int requestCode, Bundle options) {        IApplicationThread whoThread = (IApplicationThread) contextThread;        if (mActivityMonitors != null) {            synchronized (mSync) {                final int N = mActivityMonitors.size();                for (int i=0; i<N; i++) {                    final ActivityMonitor am = mActivityMonitors.get(i);                    if (am.match(who, null, intent)) {                        am.mHits++;                        if (am.isBlocking()) {                            return requestCode >= 0 ? am.getResult() : null;                        }                        break;                    }                }            }        }        try {            intent.migrateExtraStreamToClipData();            intent.prepareToLeaveProcess();            int result = ActivityManagerNative.getDefault()                .startActivity(whoThread, who.getBasePackageName(), intent,                        intent.resolveTypeIfNeeded(who.getContentResolver()),                        token, target != null ? target.mWho : null,                        requestCode, 0, null, options);            checkStartActivityResult(result, intent);        } catch (RemoteException e) {        }        return null;    }

  这里的ActivityManagerNative.getDefault返回ActivityManagerService的远程接口,即ActivityManagerProxy接口,下面就要进入到AMS组件中进行处理了。

    public int startActivity(IApplicationThread caller, Intent intent,              String resolvedType, Uri[] grantedUriPermissions, int grantedMode,              IBinder resultTo, String resultWho,              int requestCode, boolean onlyIfNeeded,              boolean debug) throws RemoteException {          Parcel data = Parcel.obtain();          Parcel reply = Parcel.obtain();          data.writeInterfaceToken(IActivityManager.descriptor);          data.writeStrongBinder(caller != null ? caller.asBinder() : null);          intent.writeToParcel(data, 0);          data.writeString(resolvedType);          data.writeTypedArray(grantedUriPermissions, 0);          data.writeInt(grantedMode);          data.writeStrongBinder(resultTo);          data.writeString(resultWho);          data.writeInt(requestCode);          data.writeInt(onlyIfNeeded ? 1 : 0);          data.writeInt(debug ? 1 : 0);          mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);          reply.readException();          int result = reply.readInt();          reply.recycle();          data.recycle();          return result;      } 

  这里的参数比较多,我们先整理一下。从上面的调用可以知道,这里的参数resolvedType、grantedUriPermissions和resultWho均为null;参数caller为ApplicationThread类型的Binder实体;参数resultTo为一个Binder实体的远程接口,我们先不关注它;参数grantedMode为0,我们也先不关注它;参数requestCode为-1;参数onlyIfNeeded和debug均空false。
  通过Binder驱动程序就进入到ActivityManagerService的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 options) {        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,            resultWho, requestCode, startFlags, profilerInfo, options,            UserHandle.getCallingUserId());    }    @Override    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {        enforceNotIsolatedCaller("startActivity");        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,                false, ALLOW_FULL_ONLY, "startActivity", null);        // TODO: Switch to user app stacks here.        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,                profilerInfo, null, null, options, userId, null, null);    }

  startActivity只是简单地调用了startActivityAsUser方法,Android将用户一次性相关操作中使用的Activity按照先后顺序保存在一个栈(Task)中,这样当用户按Back建时就能按照顺序返回。Task以先进后出的方式管理着Activity。系统运行时内存中会存在多个Task。当我们按下Recent键时,会弹出一个一个列表让你选择,这个列表就是系统中存在的Task的集合。选择一个Task会将他包含的所有的Activity带到前台来。Activity 在 AMS 中的形式是 ActivityRecord,Task 在 AMS 中的形式为TaskRecord。
  在 Android4.4以后,并不采用原先的 mHistory 来管理所有的Activity,而是按层次进行管理:
ActivityStackSupervisor 中 mStacks 中只包含了两个 Stack 就是 mHomeStack 和mFocusStack。mHomeStack 中只保存了 Launcher 的 Task,其他的 Task 则都放入
mFocusStack 中。对 Task 的操作,AMS 使用 mStackSupervisor 来进行。对于 Acitivity 的操作,AMS 使用 ActivityStack 来进行。
(1)管理层次的最上面是一个 ActivityStack 类型的数组 mStacks,用于管理所有的 ActivityStack
(2)系统中只有两个 ActivityStack,一个是 mHomeStack,用于保存 Launcher 的Activity,另一个是 mFocusedStack,用于保存非 Launcher 的 App 的 Activity。
ps:调查发现,长按 home 出现的任务管理界面 Recent 也会保存在 mHomeStack。
(3)mStacks 数组中,只有上述的两个栈,但不知道为什么要用一个 List 来管理这两个元素。
(4)在每个 ActivityStack 中,都可以拥有多个 TaskRecord。这些 TaskRecord 存储在 ActivityStack.java:ArrayList mTaskHistory 之中。
(5)在 TaskRecord 中,包含 ArrayList mActivities,用于存放该Task 中的所有的 Activity 的信息;包含 ActivityStack stack,用于记录所属的栈;包含 int
numActivities,用于记录当前 Task 中的 Activity 数量。
(6)综合上面的分析可知,要想找到某个 Activity,需要按层次查找:先找到对应的栈,再找到栈中的 Task,再在该 Task 中查找 Activity。
  了解了对栈的管理后回到startActivityMayWait方法中:

    final int startActivityMayWait(IApplicationThread caller, int callingUid,            String callingPackage, Intent intent, String resolvedType,            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,            IBinder resultTo, String resultWho, int requestCode, int startFlags,            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,            Bundle options, int userId, IActivityContainer iContainer, TaskRecord inTask) {            ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,                profilerInfo, userId);            // ...........            int res = startActivityLocked(caller, intent, resolvedType, aInfo,                    voiceSession, voiceInteractor, resultTo, resultWho,                    requestCode, callingPid, callingUid, callingPackage,                    realCallingPid, realCallingUid, startFlags, options,                    componentSpecified, null, container, inTask);            // ...........            if (outResult != null) {                outResult.result = res;                if (res == ActivityManager.START_SUCCESS) {                    mWaitingActivityLaunched.add(outResult);                    do {                        try {                            mService.wait();                        } catch (InterruptedException e) {                        }                    } while (!outResult.timeout && outResult.who == null);                } else if (res == ActivityManager.START_TASK_TO_FRONT) {                    ActivityRecord r = stack.topRunningActivityLocked(null);                    if (r.nowVisible && r.state == ActivityState.RESUMED) {                        outResult.timeout = false;                        outResult.who = new ComponentName(r.info.packageName, r.info.name);                        outResult.totalTime = 0;                        outResult.thisTime = 0;                    } else {                        outResult.thisTime = SystemClock.uptimeMillis();                        mWaitingActivityVisible.add(outResult);                        do {                            try {                                mService.wait();                            } catch (InterruptedException e) {                            }                        } while (!outResult.timeout && outResult.who == null);                    }                }            }            return res;        }    }

  首先调用resolveActivity解析Intent中的信息,这些信息将用于Activity的启动,那么随后继续调用startActivityLocked启动Activity,如果需要Result返回那么调用mService.wait()挂起线程等待结果下面我们看startActivityLocked:

    final int startActivityLocked(IApplicationThread caller,            Intent intent, String resolvedType, ActivityInfo aInfo,            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,            IBinder resultTo, String resultWho, int requestCode,            int callingPid, int callingUid, String callingPackage,            int realCallingPid, int realCallingUid, int startFlags, Bundle options,            boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container,            TaskRecord inTask) {        int err = ActivityManager.START_SUCCESS;        ProcessRecord callerApp = null;        if (caller != null) {            callerApp = mService.getRecordForAppLocked(caller);            // .......        }        // .......        final int startAnyPerm = mService.checkPermission(                START_ANY_ACTIVITY, callingPid, callingUid);        // .......        boolean abort = !mService.mIntentFirewall.checkStartActivity(intent, callingUid,                callingPid, resolvedType, aInfo.applicationInfo);        if (mService.mController != null) {            try {                // The Intent we give to the watcher has the extra data                // stripped off, since it can contain private information.                Intent watchIntent = intent.cloneFilter();                abort |= !mService.mController.activityStarting(watchIntent,                        aInfo.applicationInfo.packageName);            } catch (RemoteException e) {                mService.mController = null;            }        }        if (abort) {            if (resultRecord != null) {                resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,                        Activity.RESULT_CANCELED, null);            }            // We pretend to the caller that it was really started, but            // they will just get a cancel result.            ActivityOptions.abort(options);            return ActivityManager.START_SUCCESS;        }        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,                requestCode, componentSpecified, this, container, options);        if (outActivity != null) {            outActivity[0] = r;        }        final ActivityStack stack = getFocusedStack();        if (voiceSession == null && (stack.mResumedActivity == null                || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {            if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,                    realCallingPid, realCallingUid, "Activity start")) {                PendingActivityLaunch pal =                        new PendingActivityLaunch(r, sourceRecord, startFlags, stack);                mPendingActivityLaunches.add(pal);                ActivityOptions.abort(options);                return ActivityManager.START_SWITCHES_CANCELED;            }        }        if (mService.mDidAppSwitch) {            // This is the second allowed switch since we stopped switches,            // so now just generally allow switches.  Use case: user presses            // home (switches disabled, switch to home, mDidAppSwitch now true);            // user taps a home icon (coming from home so allowed, we hit here            // and now allow anyone to switch again).            mService.mAppSwitchesAllowedTime = 0;        } else {            mService.mDidAppSwitch = true;        }        doPendingActivityLaunchesLocked(false);        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,                startFlags, true, options, inTask);        if (err < 0) {            // If someone asked to have the keyguard dismissed on the next            // activity start, but we are not actually doing an activity            // switch...  just dismiss the keyguard now, because we            // probably want to see whatever is behind it.            notifyActivityDrawnForKeyguard();        }        return err;    }

  首先该方法检查了各种错误,然后是检验Intent防火墙是否屏蔽了该Intent,Intent防火墙的规则是通过/data/system/ifw目录下的文件设置的。可以让系统屏蔽一些Intent。
  检查完成后就需要生成一个ActivityRecord,接下来调用getFocusedStack:

    ActivityStack getFocusedStack() {        return mFocusedStack;    }

  Google把ActivityStack分为两类,一类是包含Launcher和后台界面ActivityRecord的mHomeStack,另一类是包含普通应用ActivityRecord的“普通ActivityStack”,mFocusedStack就是所有“普通ActivityStack”中的“焦点ActivityStack”,所谓“焦点ActivityStack”就是接受输入事件和启动下一个Activity,只要存在“普通ActivityStack”,那么mFocusedStack就不为null。但是“终极焦点ActivityStack”是在mHomeStack和所有“普通ActivityStack”中的“焦点ActivityStack”——mFocusedStack”中进行对决产生的,对决函数就是getFocusedStack(),对决策略就是判断mStackState状态值来选择mHomeStack或是mFocusedStack。注意,如果系统中没有启动过普通应用Activity,或是普通应用Activity都被移除了(“普通ActivityStack”中的Task被全部移除掉时会自动销毁掉这个“普通ActivityStack”,所以就会出现不存在“普通ActivityStack”),那么就不存在“普通ActivityStack”,也就是mFocusedStack为null,此时etFocusedStack()自然直接返回mHomeStack。可能是Launcher是个比较特殊的Activity,mHomeStack跟跟“普通ActivityStack”区别很大,如果不加区分地进行统一设计,那么可能代码更加复杂。
  获得用户输入栈以后接着是检查用户输入栈中的mResumedActivity所在的进程是否和当前进程相同,如果不同并且不允许切换进程就将Activity加入到mPendingActivityLaunches中,最后调用startActivityUncheckedLocked。
  startActivityUncheckedLocked函数的实现非常长,我们分两部分研究,第一部分主要是依据启动模式选择合适的栈.
  AMS中使用ActivityStack来管理Task,它管理的Task都放在成员变量mTaskHistory中,mTaskHistory是一个列表,存储的对象是TaskRecord,TaskRecord对象来表示一个Task,它的成员变量mActivities也是一个列表,存储了Task中所有ActivityRecord对象。
  Activity中有一个属性叫做luanchMode一共有四种:
 (1) standard模式:这是Android系统默认的加载模式,这种模式在每次启动Activity时不会重新产生Task,会一直使用一个Task,于是这像是一个标准的栈,每次新的Activity进来就在最上面,如果按回退按钮,它会依次从栈顶开始,呈现每个Activity,并且把栈顶的Activity给依次删除。
 (2)singleTop模式:此模式与标准模式有点类似,区别在,当一个Activity将要启动时,如果当这个Activity此时位于栈顶时,则不重新生成新的Activity,而是直接调用当前栈顶的,当要显示启动的Activity不位于栈顶时,会重新新建一个新的Activity来位于栈顶并显示出来。
 (3)singleTask模式:有点单例的味道,就是在同一个Task里面,只能有一个实例,于是分为三种情况,如果要启动的Activity不存在,则系统会创建新的Activity实例,并将它加入栈顶;如果要启动的Activity已经位于栈顶,此时就跟singleTop模式一样;如果要启动的Activity已经存在了,但是没有位于Task栈顶,系统将会把位于该Activity的上面的其他所有Activity全部从栈移除,从而使得要启动的Activity位于栈顶。
 (4)singleInstance模式 单例模式,只会创建一个Activity,而且会使用一个全新的Task来装载该Activity实例。分两种情况,如果要启动的Activity不存在,则先创建一个Task,再创建一个Activity,并把它加入栈顶。如果Activity已经存在了,无论此时Activity在哪个Task,是否在栈顶,系统都会把它找出来放在最前面显示。
  startActivityUncheckedLocked完成会通过mStackSupervisor的resumeTopActivitiesLocked方法来显示位于Task顶部的Activity。
  resumeTopActivitiesLocked只是简单地调用了ActivityStack中的resumeTopActivitiesLocked,而ActivityStack中的resumeTopActivityInnerLocked:

    final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {        // .........        cancelInitializingActivities();        // Find the first activity that is not finishing.        final ActivityRecord next = topRunningActivityLocked(null);        mStackSupervisor.mUserLeaving = false;        final TaskRecord prevTask = prev != null ? prev.task : null;        if (next == null) {            // There are no more activities!  Let's just start up the            // Launcher...            ActivityOptions.abort(options);            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();            // Only resume home if on home display            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?                    HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();            return isOnHomeDisplay() &&                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "noMoreActivities");        }        next.delayedResume = false;        // If the top activity is the resumed one, nothing to do.        if (mResumedActivity == next && next.state == ActivityState.RESUMED &&                    mStackSupervisor.allResumedActivitiesComplete()) {            // ........            return false;        }        //..............        if (mService.isSleepingOrShuttingDown()                && mLastPausedActivity == next                && mStackSupervisor.allPausedActivitiesComplete()) {            return false;        }        //...........        mStackSupervisor.mStoppingActivities.remove(next);        mStackSupervisor.mGoingToSleepActivities.remove(next);        next.sleeping = false;        mStackSupervisor.mWaitingVisibleActivities.remove(next);        //......................        boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);        if (mResumedActivity != null) {            //........            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);        }        //.........        ActivityStack lastStack = mStackSupervisor.getLastStack();        if (next.app != null && next.app.thread != null) {            if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);            // This activity is now becoming visible.            mWindowManager.setAppVisibility(next.appToken, true);            // schedule launch ticks to collect information about slow apps.            next.startLaunchTickingLocked();            ActivityRecord lastResumedActivity =                    lastStack == null ? null :lastStack.mResumedActivity;            ActivityState lastState = next.state;            mService.updateCpuStats();            if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + next + " (in existing)");            next.state = ActivityState.RESUMED;            mResumedActivity = next;            next.task.touchActiveTime();            mService.addRecentTaskLocked(next.task);            mService.updateLruProcessLocked(next.app, true, null);            updateLRUListLocked(next);            mService.updateOomAdjLocked();            // Have the window manager re-evaluate the orientation of            // the screen based on the new activity order.            boolean notUpdated = true;            if (mStackSupervisor.isFrontStack(this)) {                Configuration config = mWindowManager.updateOrientationFromAppTokens(                        mService.mConfiguration,                        next.mayFreezeScreenLocked(next.app) ? next.appToken : null);                if (config != null) {                    next.frozenBeforeDestroy = true;                }                notUpdated = !mService.updateConfigurationLocked(config, next, false, false);            }            if (notUpdated) {                // The configuration update wasn't able to keep the existing                // instance of the activity, and instead started a new one.                // We should be all done, but let's just make sure our activity                // is still at the top and schedule another run if something                // weird happened.                ActivityRecord nextNext = topRunningActivityLocked(null);                if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG,                        "Activity config changed during resume: " + next                        + ", new next: " + nextNext);                if (nextNext != next) {                    // Do over!                    mStackSupervisor.scheduleResumeTopActivities();                }                if (mStackSupervisor.reportResumedActivityLocked(next)) {                    mNoAnimActivities.clear();                    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();                    return true;                }                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();                return false;            }            try {                // Deliver all pending results.                ArrayList<ResultInfo> a = next.results;                if (a != null) {                    final int N = a.size();                    if (!next.finishing && N > 0) {                        if (DEBUG_RESULTS) Slog.v(                                TAG, "Delivering results to " + next                                + ": " + a);                        next.app.thread.scheduleSendResult(next.appToken, a);                    }                }                if (next.newIntents != null) {                    next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);                }                EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,                        System.identityHashCode(next), next.task.taskId, next.shortComponentName);                next.sleeping = false;                mService.showAskCompatModeDialogLocked(next);                next.app.pendingUiClean = true;                next.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);                next.clearOptionsLocked();                next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,                        mService.isNextTransitionForward(), resumeAnimOptions);                mStackSupervisor.checkReadyForSleepLocked();                if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Resumed " + next);            } catch (Exception e) {                // Whoops, need to restart this activity!                if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to "                        + lastState + ": " + next);                next.state = lastState;                if (lastStack != null) {                    lastStack.mResumedActivity = lastResumedActivity;                }                Slog.i(TAG, "Restarting because process died: " + next);                if (!next.hasBeenLaunched) {                    next.hasBeenLaunched = true;                } else  if (SHOW_APP_STARTING_PREVIEW && lastStack != null &&                        mStackSupervisor.isFrontStack(lastStack)) {                    mWindowManager.setAppStartingWindow(                            next.appToken, next.packageName, next.theme,                            mService.compatibilityInfoForPackageLocked(next.info.applicationInfo),                            next.nonLocalizedLabel, next.labelRes, next.icon, next.logo,                            next.windowFlags, null, true);                }                mStackSupervisor.startSpecificActivityLocked(next, true, false);                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();                return true;            }            // From this point on, if something goes wrong there is no way            // to recover the activity.            try {                next.visible = true;                completeResumeLocked(next);            } catch (Exception e) {                // If any exception gets thrown, toss away this                // activity and try the next one.                Slog.w(TAG, "Exception thrown during resume of " + next, e);                requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,                        "resume-exception", true);                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();                return true;            }            next.stopped = false;        } else {            // Whoops, need to restart this activity!            if (!next.hasBeenLaunched) {                next.hasBeenLaunched = true;            } else {                if (SHOW_APP_STARTING_PREVIEW) {                    mWindowManager.setAppStartingWindow(                            next.appToken, next.packageName, next.theme,                            mService.compatibilityInfoForPackageLocked(                                    next.info.applicationInfo),                            next.nonLocalizedLabel,                            next.labelRes, next.icon, next.logo, next.windowFlags,                            null, true);                }                if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);            }            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Restarting " + next);            mStackSupervisor.startSpecificActivityLocked(next, true, true);        }        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();        return true;    }

  首先找出即将启动的Activity next:

final ActivityRecord next = topRunningActivityLocked(null);

  下面判断如果当前Task没有Activity显示Home Activity:

if (next == null) {            // There are no more activities!  Let's just start up the            // Launcher...            ActivityOptions.abort(options);            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();            // Only resume home if on home display            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?                    HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();            return isOnHomeDisplay() &&                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "noMoreActivities");        }

  如果当前Activity就是要启动的Activity,直接返回:

        if (mResumedActivity == next && next.state == ActivityState.RESUMED &&                    mStackSupervisor.allResumedActivitiesComplete()) {            // ........            return false;        }

  如果系统正准备睡眠或关闭,直接退出:

        if (mService.isSleepingOrShuttingDown()                && mLastPausedActivity == next                && mStackSupervisor.allPausedActivitiesComplete()) {            return false;        }

  将启动的Activity从Stopping、GoingSleep、WaitingVisible队列中移除:

        mStackSupervisor.mStoppingActivities.remove(next);        mStackSupervisor.mGoingToSleepActivities.remove(next);        next.sleeping = false;        mStackSupervisor.mWaitingVisibleActivities.remove(next);

  走到这里我们已经可以确定当前栈的栈顶Activity不是当前需要启动的Activity,那么我们将当前的Activity暂停:

        boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);        if (mResumedActivity != null) {            //........            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);        }

  最后如果Activity所在的应用已经启动起来了,那么先发送结果,再调用Activity的onResume方法,如果没有启动起来那么就需要调用startSpecificActivityLocked启动应用,该方法只是简单地调用realStartActivityLocked如果发现应用没有启动,则调用startProcessLocked启动进程,应用进程fork出来以后将调用ActivityThread的main方法:

    public static void main(String[] args) {        SamplingProfilerIntegration.start();        // CloseGuard defaults to true and can be quite spammy.  We        // disable it here, but selectively enable it later (via        // StrictMode) on debug builds, but using DropBox, not logs.        CloseGuard.setEnabled(false);        Environment.initForCurrentUser();        // Set the reporter for event logging in libcore        EventLogger.setReporter(new EventLoggingReporter());        Security.addProvider(new AndroidKeyStoreProvider());        // Make sure TrustedCertificateStore looks in the right place for CA certificates        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());        TrustedCertificateStore.setDefaultUserDirectory(configDir);        Process.setArgV0("<pre-initialized>");        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        AsyncTask.init();        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

  main函数中逻辑比较简单,首先初始化环境,初始化应用中需要的系统路径,增加一个保存Key的provider,创建一个ActivityThread对象,使用false参数调用attach方法,并且保存一个主线程的Handler以及进入一个消息循环。
  下面看一下attach false分之的代码:

            //.........            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",                                                    UserHandle.myUserId());            RuntimeInit.setApplicationObject(mAppThread.asBinder());            final IActivityManager mgr = ActivityManagerNative.getDefault();            try {                mgr.attachApplication(mAppThread);            } catch (RemoteException ex) {                // Ignore            }            //.........

  这里主要做了两件事,第一件事调用setApplicationObject将mAppThread放入到RuntimeInit的一个静态变量中,第二是调用AMS的attachApplication方法:

    private final boolean attachApplicationLocked(IApplicationThread thread,            int pid) {        ProcessRecord app;        if (pid != MY_PID && pid >= 0) {            synchronized (mPidsSelfLocked) {                app = mPidsSelfLocked.get(pid);            }        } else {            app = null;        }        if (app == null) {            Slog.w(TAG, "No pending application record for pid " + pid                    + " (IApplicationThread " + thread + "); dropping process");            EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);            if (pid > 0 && pid != MY_PID) {                Process.killProcessQuiet(pid);                //TODO: Process.killProcessGroup(app.info.uid, pid);            } else {                try {                    thread.scheduleExit();                } catch (Exception e) {                    // Ignore exceptions.                }            }            return false;        }        // If this application record is still attached to a previous        // process, clean it up now.        if (app.thread != null) {            handleAppDiedLocked(app, true, true);        }        // Tell the process all about itself.        if (localLOGV) Slog.v(                TAG, "Binding process pid " + pid + " to record " + app);        final String processName = app.processName;        try {            AppDeathRecipient adr = new AppDeathRecipient(                    app, pid, thread);            thread.asBinder().linkToDeath(adr, 0);            app.deathRecipient = adr;        } catch (RemoteException e) {            app.resetPackageList(mProcessStats);            startProcessLocked(app, "link fail", processName);            return false;        }        EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);        app.makeActive(thread, mProcessStats);        app.curAdj = app.setAdj = -100;        app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;        app.forcingToForeground = null;        updateProcessForegroundLocked(app, false, false);        app.hasShownUi = false;        app.debugging = false;        app.cached = false;        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);        List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;        if (!normalMode) {            Slog.i(TAG, "Launching preboot mode app: " + app);        }        if (localLOGV) Slog.v(            TAG, "New app record " + app            + " thread=" + thread.asBinder() + " pid=" + pid);        try {            int testMode = IApplicationThread.DEBUG_OFF;            if (mDebugApp != null && mDebugApp.equals(processName)) {                testMode = mWaitForDebugger                    ? IApplicationThread.DEBUG_WAIT                    : IApplicationThread.DEBUG_ON;                app.debugging = true;                if (mDebugTransient) {                    mDebugApp = mOrigDebugApp;                    mWaitForDebugger = mOrigWaitForDebugger;                }            }            String profileFile = app.instrumentationProfileFile;            ParcelFileDescriptor profileFd = null;            int samplingInterval = 0;            boolean profileAutoStop = false;            if (mProfileApp != null && mProfileApp.equals(processName)) {                mProfileProc = app;                profileFile = mProfileFile;                profileFd = mProfileFd;                samplingInterval = mSamplingInterval;                profileAutoStop = mAutoStopProfiler;            }            boolean enableOpenGlTrace = false;            if (mOpenGlTraceApp != null && mOpenGlTraceApp.equals(processName)) {                enableOpenGlTrace = true;                mOpenGlTraceApp = null;            }            // If the app is being launched for restore or full backup, set it up specially            boolean isRestrictedBackupMode = false;            if (mBackupTarget != null && mBackupAppName.equals(processName)) {                isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)                        || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)                        || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);            }            ensurePackageDexOpt(app.instrumentationInfo != null                    ? app.instrumentationInfo.packageName                    : app.info.packageName);            if (app.instrumentationClass != null) {                ensurePackageDexOpt(app.instrumentationClass.getPackageName());            }            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Binding proc "                    + processName + " with config " + mConfiguration);            ApplicationInfo appInfo = app.instrumentationInfo != null                    ? app.instrumentationInfo : app.info;            app.compat = compatibilityInfoForPackageLocked(appInfo);            if (profileFd != null) {                profileFd = profileFd.dup();            }            ProfilerInfo profilerInfo = profileFile == null ? null                    : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,                    isRestrictedBackupMode || !normalMode, app.persistent,                    new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),                    mCoreSettingsObserver.getCoreSettingsLocked());            updateLruProcessLocked(app, false, null);            app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();        } catch (Exception e) {            // todo: Yikes!  What should we do?  For now we will try to            // start another process, but that could easily get us in            // an infinite loop of restarting processes...            Slog.wtf(TAG, "Exception thrown during bind of " + app, e);            app.resetPackageList(mProcessStats);            app.unlinkDeathRecipient();            startProcessLocked(app, "bind fail", processName);            return false;        }        // Remove this record from the list of starting applications.        mPersistentStartingProcesses.remove(app);        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,                "Attach application locked removing on hold: " + app);        mProcessesOnHold.remove(app);        boolean badApp = false;        boolean didSomething = false;        // See if the top visible activity is waiting to run in this process...        if (normalMode) {            try {                if (mStackSupervisor.attachApplicationLocked(app)) {                    didSomething = true;                }            } catch (Exception e) {                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);                badApp = true;            }        }        // Find any services that should be running in this process...        if (!badApp) {            try {                didSomething |= mServices.attachApplicationLocked(app, processName);            } catch (Exception e) {                Slog.wtf(TAG, "Exception thrown starting services in " + app, e);                badApp = true;            }        }        // Check if a next-broadcast receiver is in this process...        if (!badApp && isPendingBroadcastProcessLocked(pid)) {            try {                didSomething |= sendPendingBroadcastsLocked(app);            } catch (Exception e) {                // If the app died trying to launch the receiver we declare it 'bad'                Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);                badApp = true;            }        }        // Check whether the next backup agent is in this process...        if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {            if (DEBUG_BACKUP) Slog.v(TAG, "New app is backup target, launching agent for " + app);            ensurePackageDexOpt(mBackupTarget.appInfo.packageName);            try {                thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,                        compatibilityInfoForPackageLocked(mBackupTarget.appInfo),                        mBackupTarget.backupMode);            } catch (Exception e) {                Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);                badApp = true;            }        }        if (badApp) {            app.kill("error during init", true);            handleAppDiedLocked(app, false, true);            return false;        }        if (!didSomething) {            updateOomAdjLocked();        }        return true;    }

  方法首先检查调用的参数,然后调用ApplicationThread的接口handleBindApplication():

    private void handleBindApplication(AppBindData data) {        mBoundApplication = data;        mConfiguration = new Configuration(data.config);        mCompatConfiguration = new Configuration(data.config);        // ................        Process.setArgV0(data.processName);        android.ddm.DdmHandleAppName.setAppName(data.processName,                                                UserHandle.myUserId());        // ...............        TimeZone.setDefault(null);        Locale.setDefault(data.config.locale);        mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);        mCurDefaultDisplayDpi = data.config.densityDpi;        applyCompatConfiguration(mCurDefaultDisplayDpi);        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);        //...................        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);        if (data.instrumentationName != null) {            InstrumentationInfo ii = null;            try {                ii = appContext.getPackageManager().                    getInstrumentationInfo(data.instrumentationName, 0);            } catch (PackageManager.NameNotFoundException e) {            }            if (ii == null) {                throw new RuntimeException(                    "Unable to find instrumentation info for: "                    + data.instrumentationName);            }            mInstrumentationPackageName = ii.packageName;            mInstrumentationAppDir = ii.sourceDir;            mInstrumentationSplitAppDirs = ii.splitSourceDirs;            mInstrumentationLibDir = ii.nativeLibraryDir;            mInstrumentedAppDir = data.info.getAppDir();            mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();            mInstrumentedLibDir = data.info.getLibDir();            ApplicationInfo instrApp = new ApplicationInfo();            instrApp.packageName = ii.packageName;            instrApp.sourceDir = ii.sourceDir;            instrApp.publicSourceDir = ii.publicSourceDir;            instrApp.splitSourceDirs = ii.splitSourceDirs;            instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs;            instrApp.dataDir = ii.dataDir;            instrApp.nativeLibraryDir = ii.nativeLibraryDir;            LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,                    appContext.getClassLoader(), false, true, false);            ContextImpl instrContext = ContextImpl.createAppContext(this, pi);            try {                java.lang.ClassLoader cl = instrContext.getClassLoader();                mInstrumentation = (Instrumentation)                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();            } catch (Exception e) {                throw new RuntimeException(                    "Unable to instantiate instrumentation "                    + data.instrumentationName + ": " + e.toString(), e);            }            mInstrumentation.init(this, instrContext, appContext,                   new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,                   data.instrumentationUiAutomationConnection);            if (mProfiler.profileFile != null && !ii.handleProfiling                    && mProfiler.profileFd == null) {                mProfiler.handlingProfiling = true;                File file = new File(mProfiler.profileFile);                file.getParentFile().mkdirs();                Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);            }        } else {            mInstrumentation = new Instrumentation();        }        if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {            dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();        }        // Allow disk access during application and provider setup. This could        // block processing ordered broadcasts, but later processing would        // probably end up doing the same disk access.        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();        try {            // If the app is being launched for full backup or restore, bring it up in            // a restricted environment with the base application class.            Application app = data.info.makeApplication(data.restrictedBackupMode, null);            mInitialApplication = app;            // don't bring up providers in restricted mode; they may depend on the            // app's custom Application class            if (!data.restrictedBackupMode) {                List<ProviderInfo> providers = data.providers;                if (providers != null) {                    installContentProviders(app, providers);                    // For process that contains content providers, we want to                    // ensure that the JIT is enabled "at some point".                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);                }            }            // Do this after providers, since instrumentation tests generally start their            // test thread at this point, and we don't want that racing.            try {                mInstrumentation.onCreate(data.instrumentationArgs);            }            catch (Exception e) {                throw new RuntimeException(                    "Exception thrown in onCreate() of "                    + data.instrumentationName + ": " + e.toString(), e);            }            try {                mInstrumentation.callApplicationOnCreate(app);            } catch (Exception e) {                if (!mInstrumentation.onException(app, e)) {                    throw new RuntimeException(                        "Unable to create application " + app.getClass().getName()                        + ": " + e.toString(), e);                }            }        } finally {            StrictMode.setThreadPolicy(savedPolicy);        }    }

  首先创建系统配置对象:

        mConfiguration = new Configuration(data.config);        mCompatConfiguration = new Configuration(data.config);

  设置进程的名称和DDMS中的进程名:

        Process.setArgV0(data.processName);        android.ddm.DdmHandleAppName.setAppName(data.processName,                                                UserHandle.myUserId());

  用系统的配置设置应用的时区:

        TimeZone.setDefault(null);

  用系统的配置设置应用的地区:

        Locale.setDefault(data.config.locale);

  生成资源管理对象,并用系统配置初始化:

        mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);        mCurDefaultDisplayDpi = data.config.densityDpi;        applyCompatConfiguration(mCurDefaultDisplayDpi);

  最后生成ContextImpl对象以及Application对象,安装应用的ContentProvider,调用Instrumentation的onCreate方法,以及Application的onCreate方法。
  这个方法主要是做一些应用级别的初始化工作,attachApplicationLocked会最终执行以下代码:

ActivityRecord hr = mMainStack.topRunningActivityLocked(null);          if (hr != null && normalMode) {              if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid                  && processName.equals(hr.processName)) {                      try {                          if (mMainStack.realStartActivityLocked(hr, app, true, true)) {                              didSomething = true;                          }                      } catch (Exception e) {                          ......                      }              } else {                  ......              }          } 

  realStartActivityLocked最终通过app.thread进入到ApplicationThreadProxy的scheduleLaunchActivity函数中, scheduleLaunchActivity函数会发送一个消息调用ActivityThread类的handleLaunchActivity函数进一步处理。该函数又是主要调用的performLaunchActivity:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {        ActivityInfo aInfo = r.activityInfo;        if (r.packageInfo == null) {            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,                    Context.CONTEXT_INCLUDE_CODE);        }        ComponentName component = r.intent.getComponent();        if (component == null) {            component = r.intent.resolveActivity(                mInitialApplication.getPackageManager());            r.intent.setComponent(component);        }        if (r.activityInfo.targetActivity != null) {            component = new ComponentName(r.activityInfo.packageName,                    r.activityInfo.targetActivity);        }        Activity activity = null;        try {            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();            activity = mInstrumentation.newActivity(                    cl, component.getClassName(), r.intent);            StrictMode.incrementExpectedActivityCount(activity.getClass());            r.intent.setExtrasClassLoader(cl);            r.intent.prepareToEnterProcess();            if (r.state != null) {                r.state.setClassLoader(cl);            }        } catch (Exception e) {            if (!mInstrumentation.onException(activity, e)) {                throw new RuntimeException(                    "Unable to instantiate activity " + component                    + ": " + e.toString(), e);            }        }        try {            Application app = r.packageInfo.makeApplication(false, mInstrumentation);            //........................            if (activity != null) {                Context appContext = createBaseContextForActivity(r, activity);                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());                Configuration config = new Configuration(mCompatConfiguration);                activity.attach(appContext, this, getInstrumentation(), r.token,                        r.ident, app, r.intent, r.activityInfo, title, r.parent,                        r.embeddedID, r.lastNonConfigurationInstances, config,                        r.voiceInteractor);                if (customIntent != null) {                    activity.mIntent = customIntent;                }                r.lastNonConfigurationInstances = null;                activity.mStartedActivity = false;                int theme = r.activityInfo.getThemeResource();                if (theme != 0) {                    activity.setTheme(theme);                }                activity.mCalled = false;                if (r.isPersistable()) {                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);                } else {                    mInstrumentation.callActivityOnCreate(activity, r.state);                }                if (!activity.mCalled) {                    throw new SuperNotCalledException(                        "Activity " + r.intent.getComponent().toShortString() +                        " did not call through to super.onCreate()");                }                r.activity = activity;                r.stopped = true;                if (!r.activity.mFinished) {                    activity.performStart();                    r.stopped = false;                }                if (!r.activity.mFinished) {                    if (r.isPersistable()) {                        if (r.state != null || r.persistentState != null) {                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,                                    r.persistentState);                        }                    } else if (r.state != null) {                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);                    }                }                if (!r.activity.mFinished) {                    activity.mCalled = false;                    if (r.isPersistable()) {                        mInstrumentation.callActivityOnPostCreate(activity, r.state,                                r.persistentState);                    } else {                        mInstrumentation.callActivityOnPostCreate(activity, r.state);                    }                    if (!activity.mCalled) {                        throw new SuperNotCalledException(                            "Activity " + r.intent.getComponent().toShortString() +                            " did not call through to super.onPostCreate()");                    }                }            }            r.paused = true;            mActivities.put(r.token, r);        } catch (SuperNotCalledException e) {            throw e;        } catch (Exception e) {            if (!mInstrumentation.onException(activity, e)) {                throw new RuntimeException(                    "Unable to start activity " + component                    + ": " + e.toString(), e);            }        }        return activity;    }

  要启动的Activity组件的类名保存在变量component。有了这个类名之后,函数就可以调用ActivityThread类的成员变量mInstrumentation所描述一个Instrumentation对象的成员函数newActivity来创建一个Activity组件实例了,并且保存变量activity中。Instrumentation类是用来记录应用程序与系统的交互过程的,创建好了要启动的Activity组件实例之后,函数接下来就可以对它进行初始化了。初始化一个Activity组件实例需要一个Application对象app、一个ContextImpl对象appContext以及一个Configuration对象config,它们分别用来描述该Activity组件实例的应用程序信息、运行上下文环境以及配置信息。这里我们主要关心运行上下文环境的创建过程,即ContextImpl对象appContext的创建过程。ContextImpl对象appContext创建完成之后,函数就会调用它的成员函数setOuterContext来将与它所关联的Activity组件实例activity保存在它的内部。这样,ContextImpl对象appContext以后就可以访问与它所关联的Activity组件的属性或者方法。接着,函数就调用Activity组件实例activity的成员函数attach来将前面所创建的ContextImpl对象appContext以及Application对象app和Configuration对象config保存在它的内部。这样,Activity组件实例activity就可以访问它的运行上下文环境信息了。我们再分析Activity类的成员函数attach的实现。最后,函数又通过调用ActivityThread类的成员变量mInstrumentation所描述一个Instrumentation对象的成员函数callActivityOnCreate来通知Activity组件实例activity,它已经被创建和启动起来了。
  接下来,我们就分别分析Instrumentation类的成员函数newActivity、ContextImpl类的构造函数以及成员函数setOuterContext、Activity类的成员函数attach和Instrumentation类的成员函数callActivityOnCreate的实现。
   Instrumentation.newActivity:

    public Activity newActivity(ClassLoader cl, String className,              Intent intent)              throws InstantiationException, IllegalAccessException,              ClassNotFoundException {          return (Activity)cl.loadClass(className).newInstance();      }  

  参数cl描述的是一个类加载器,而参数className描述的要加载的类。以className为参数来调用cl描述的是一个类加载器的成员函数loadClass,就可以得到一个Class对象。由于className描述的是一个Activity子类,因此,当函数调用前面得到的Class对象的成员函数newInstance的时候,就会创建一个Activity子类实例。这个Activity实例就是用来描述在前面所要启动的Activity组件的。

class ContextImpl extends Context {      ......      private Context mOuterContext;      ......      ContextImpl() {          // For debug only          //++sInstanceCount;          mOuterContext = this;      }      ......  }

  ContextImpl类的成员变量mOuterContext的类型为Context。当一个ContextImpl对象是用来描述一个Activity组件的运行上下文环境时,那么它的成员变量mOuterContext指向的就是该Activity组件。由于一个ContextImpl对象在创建的时候,并没有参数用来指明它是用来描述一个Activity组件的运行上下文环境,因此,这里就暂时将它的成员变量mOuterContext指向它自己。

class ContextImpl extends Context {      ......      private Context mOuterContext;      ......      final void setOuterContext(Context context) {          mOuterContext = context;      }      ......  }

  参数context描述的是一个正在启动的Activity组件,ContextImpl类的成员函数setOuterContext只是简单地将它保存在成员变量mContext中,以表明当前正在处理的一个ContextImpl对象是用来描述一个Activity组件的运行上下文环境的。
  下面比较重要的是Activity的attach方法:

    final void attach(Context context, ActivityThread aThread,            Instrumentation instr, IBinder token, int ident,            Application application, Intent intent, ActivityInfo info,            CharSequence title, Activity parent, String id,            NonConfigurationInstances lastNonConfigurationInstances,            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {        attachBaseContext(context);        mFragments.attachHost(null /*parent*/);        mWindow = new PhoneWindow(this);        mWindow.setCallback(this);        mWindow.setOnWindowDismissedCallback(this);        mWindow.getLayoutInflater().setPrivateFactory(this);        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {            mWindow.setSoftInputMode(info.softInputMode);        }        if (info.uiOptions != 0) {            mWindow.setUiOptions(info.uiOptions);        }        mUiThread = Thread.currentThread();        mMainThread = aThread;        mInstrumentation = instr;        mToken = token;        mIdent = ident;        mApplication = application;        mIntent = intent;        mReferrer = referrer;        mComponent = intent.getComponent();        mActivityInfo = info;        mTitle = title;        mParent = parent;        mEmbeddedID = id;        mLastNonConfigurationInstances = lastNonConfigurationInstances;        if (voiceInteractor != null) {            if (lastNonConfigurationInstances != null) {                mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;            } else {                mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,                        Looper.myLooper());            }        }        mWindow.setWindowManager(                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),                mToken, mComponent.flattenToString(),                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);        if (mParent != null) {            mWindow.setContainer(mParent.getWindow());        }        mWindowManager = mWindow.getWindowManager();        mCurrentConfig = config;    }

  函数首先调用从父类ContextThemeWrapper继承下来的成员函数attachBaseConext来设置运行上下文环境,即将参数context所描述的一个ContextImpl对象保存在内部。接下来调用PolicyManager类的静态成员函数makeNewWindow来创建了一个PhoneWindow,并且保存在Activity类的成员变量mWindow中。这个PhoneWindow是用来描述当前正在启动的应用程序窗口的。这个应用程序窗口在运行的过程中,会接收到一些事件,例如,键盘、触摸屏事件等,这些事件需要转发给与它所关联的Activity组件处理,这个转发操作是通过一个Window.Callback接口来实现的。由于Activity类实现了Window.Callback接口,因此,函数就可以将当前正在启动的Activity组件所实现的一个Window.Callback接口设置到前面创建的一个PhoneWindow里面去,这是通过调用Window类的成员函数setCallback来实现的。
  参数info指向的是一个ActivityInfo对象,用来描述当前正在启动的Activity组件的信息。其中,这个ActivityInfo对象的成员变量softInputMode用来描述当前正在启动的一个Activity组件是否接受软键盘输入。如果接受的话,那么它的值就不等于WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED,并且描述的是当前正在启动的Activity组件所接受的软键盘输入模式。这个软键盘输入模式设置到前面所创建的一个PhoneWindow对象内部去,这是通过调用Window类的成员函数setSoftInputMode来实现的。
  在Android系统中,每一个应用程序窗口都需要由一个窗口管理者来管理,因此,函数再接下来就会调用前面所创建的一个PhoneWindow对象从父类Window继承下来的成员函数setWindowManager来为它设置一个合适的窗口管理者。这个窗口管理者设置完成之后,就可以通过调用Window类的成员函数getWindowManager来获得。获得这个窗口管理者之后,函数就将它保存在Activity类的成员变量mWindowManager中。这样,当前正在启动的Activity组件以后就可以通过它的成员变量mWindowManager来管理与它所关联的窗口。
  除了创建和初始化一个PhoneWindow之外,函数还会分别把参数application和config所描述的一个Application对象和一个Configuration对象保存在Activity类的成员变量mApplication和mCurrentConfig中。这样,当前正在启动的Activity组件就可以访问它的应用程序信息以及配置信息。
  回到performLaunchActivity接下来就会调用Instrumentation类的成员函数callActivityOnCreate来通知当前正在启动的Activity组件,它已经创建和启动完成了。
  接下来我们就PhoneWindow的成员函数做一些详细的分析:
  PolicyManager.makeNewWindow:

public final class PolicyManager {      private static final String POLICY_IMPL_CLASS_NAME =          "com.android.internal.policy.impl.Policy";      private static final IPolicy sPolicy;      static {          // Pull in the actual implementation of the policy at run-time          try {              Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);              sPolicy = (IPolicy)policyClass.newInstance();          } catch (ClassNotFoundException ex) {              throw new RuntimeException(                      POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);          } catch (InstantiationException ex) {              throw new RuntimeException(                      POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);          } catch (IllegalAccessException ex) {              throw new RuntimeException(                      POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);          }      }      ......      // The static methods to spawn new policy-specific objects      public static Window makeNewWindow(Context context) {          return sPolicy.makeNewWindow(context);      }      ......  } 

   PolicyManager是一个窗口管理策略类,它在第一次被使用的时候,就会创建一个Policy类实例,并且保存在静态成员变量sPolicy中,以后PolicyManager类的窗口管理策略就是通过这个Policy类实例来实现的,例如,PolicyManager类的静态成员函数makeNewWindow就是通过调用这个Policy类实例的成员函数makeNewWindow来创建一个具体的应用程序窗口的。
   Policy类的成员函数makeNewWindow的实现很简单,它只是创建了一个PhoneWindow对象,然后返回给调用者。
   看一下构造函数:

    public PhoneWindow(Context context) {        super(context);        mLayoutInflater = LayoutInflater.from(context);    }

  PhoneWindow类的构造函数很简单,它首先调用父类Window的构造函数来执行一些初始化操作,接着再调用LayoutInflater的静态成员函数from创建一个LayoutInflater实例,并且保存在成员变量mLayoutInflater中。这样,PhoneWindow类以后就可以通过成员变量mLayoutInflater来创建应用程序窗口的视图,这个视图使用类型为DecorView的成员变量mDecor来描述。PhoneWindow类还有另外一个类型为ViewGroup的成员变量mContentParent,用来描述一个视图容器,这个容器存放的就是成员变量mDecor所描述的视图的内容,不过这个容器也有可能指向的是mDecor本身。
  应用程序窗口内部所包含的视图对象的实际类型为DecorView。DecorView类继承了View类,是作为容器(ViewGroup)来使用的:
  这里写图片描述
  每一个应用程序窗口的视图对象都有一个关联的ViewRoot对象,这些关联关系是由窗口管理器来维护的。
  这里写图片描述
   简单来说,ViewRoot相当于是MVC模型中的Controller,它有以下职责:
1.  负责为应用程序窗口视图创建Surface。
2.  配合WindowManagerService来管理系统的应用程序窗口。
3.  负责管理、布局和渲染应用程序窗口视图的UI。
我们在实现一个Activity组件的时候,也就是在实现一个Activity子类的时候,一般都会重写成员函数onCreate,以便可以执行一些自定义的初始化工作,其中就包含初始化UI的工作。
其中,调用从父类Activity继承下来的成员函数setContentView就是用来创建应用程序窗口视图对象的。

public class Activity extends ContextThemeWrapper          implements LayoutInflater.Factory,          Window.Callback, KeyEvent.Callback,          OnCreateContextMenuListener, ComponentCallbacks {      ......      private Window mWindow;      ......      public Window getWindow() {          return mWindow;      }      ......      public void setContentView(int layoutResID) {          getWindow().setContentView(layoutResID);      }      ......  }  

  Activity类的成员函数setContentView首先调用另外一个成员函数getWindow来获得成员变量mWindow所描述的一个窗口对象,接着再调用这个窗口对象的成员函数setContentView来执行创建应用程序窗口视图对象的工作。从前面Android应用程序窗口(Activity)的窗口对象(Window)的创建过程分析一文可以知道,Activity类的成员变量mWindow指向的是一个PhoneWindow对象,因此,接下来我们就继续分析PhoneWindow类的成员函数setContentView的实现。

public class PhoneWindow extends Window implements MenuBuilder.Callback {      ......      // This is the view in which the window contents are placed. It is either      // mDecor itself, or a child of mDecor where the contents go.      private ViewGroup mContentParent;      ......      @Override      public void setContentView(int layoutResID) {          if (mContentParent == null) {              installDecor();          } else {              mContentParent.removeAllViews();          }          mLayoutInflater.inflate(layoutResID, mContentParent);          final Callback cb = getCallback();          if (cb != null) {              cb.onContentChanged();          }      }      ......  }  

  PhoneWindow类的成员变量mContentParent用来描述一个类型为DecorView的视图对象,或者这个类型为DecorView的视图对象的一个子视图对象,用作UI容器。当它的值等于null的时候,就说明正在处理的应用程序窗口的视图对象还没有创建。在这种情况下,就会调用成员函数installDecor来创建应用程序窗口视图对象。否则的话,就说明是要重新设置应用程序窗口的视图。在重新设置之前,首先调用成员变量mContentParent所描述的一个ViewGroup对象来移除原来的UI内空。
  由于我们是在Activity组件启动的过程中创建应用程序窗口视图的,因此,我们就假设此时PhoneWindow类的成员变量mContentParent的值等于null。接下来,函数就会调用成员函数installDecor来创建应用程序窗口视图对象,接着再通过调用PhoneWindow类的成员变量mLayoutInflater所描述的一个LayoutInflater对象的成员函数inflate来将参数layoutResID所描述的一个UI布局设置到前面所创建的应用程序窗口视图中去,最后还会调用一个Callback接口的成员函数onContentChanged来通知对应的Activity组件,它的视图内容发生改变了。从前面Android应用程序窗口(Activity)的窗口对象(Window)的创建过程分析一文可以知道,Activity组件自己实现了这个Callback接口,并且将这个Callback接口设置到了与它所关联的应用程序窗口对象的内部去,因此,前面实际调用的是Activity类的成员函数onContentChanged来发出一个视图内容变化通知。
  接下来,我们就继续分析PhoneWindow类的成员函数installDecor的实现,以便可以继续了解应用程序窗口视图对象的创建过程。

public class PhoneWindow extends Window implements MenuBuilder.Callback {      ......      // This is the top-level view of the window, containing the window decor.      private DecorView mDecor;      ......      // This is the view in which the window contents are placed. It is either      // mDecor itself, or a child of mDecor where the contents go.      private ViewGroup mContentParent;      ......      private TextView mTitleView;      ......      private CharSequence mTitle = null;      ......      private void installDecor() {          if (mDecor == null) {              mDecor = generateDecor();              ......          }          if (mContentParent == null) {              mContentParent = generateLayout(mDecor);              mTitleView = (TextView)findViewById(com.android.internal.R.id.title);              if (mTitleView != null) {                  if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {                      View titleContainer = findViewById(com.android.internal.R.id.title_container);                      if (titleContainer != null) {                          titleContainer.setVisibility(View.GONE);                      } else {                          mTitleView.setVisibility(View.GONE);                      }                      if (mContentParent instanceof FrameLayout) {                          ((FrameLayout)mContentParent).setForeground(null);                      }                  } else {                      mTitleView.setText(mTitle);                  }              }          }      }      ......  }  

  由于我们是在Activity组件启动的过程中创建应用程序窗口视图的,因此,我们同时假设此时PhoneWindow类的成员变量mDecor的值等于null。这时候PhoneWindow类的成员函数installDecor就会调用另外一个成员函数generateDecor来创建一个DecorView对象,并且保存在PhoneWindow类的成员变量mDecor中。
  PhoneWindow类的成员函数installDecor接着再调用另外一个成员函数generateLayout来根据当前应用程序窗口的Feature来加载对应的窗口布局文件。这些布局文件保存在frameworks/base/core/res/res/layout目录下,它们必须包含有一个id值为“content”的布局控件。这个布局控件必须要从ViewGroup类继承下来,用来作为窗口的UI容器。PhoneWindow类的成员函数generateLayout执行完成之后,就会这个id值为“content”的ViewGroup控件来给PhoneWindow类的成员函数installDecor,后者再将其保存在成员变量mContentParent中。
  PhoneWindow类的成员函数installDecor还会检查前面加载的窗口布局文件是否包含有一个id值为“title”的TextView控件。如果包含有的话,就会将它保存在PhoneWindow类的成员变量mTitleView中,用来描述当前应用程序窗口的标题栏。但是,如果当前应用程序窗口是没有标题栏的,即它的Feature位FEATURE_NO_TITLE的值等于1,那么PhoneWindow类的成员函数installDecor就需要将前面得到的标题栏隐藏起来。注意,PhoneWindow类的成员变量mTitleView所描述的标题栏有可能是包含在一个id值为“title_container”的容器里面的,在这种情况下,就需要隐藏该标题栏容器。另一方面,如果当前应用程序窗口是设置有标题栏的,那么PhoneWindow类的成员函数installDecor就会设置它的标题栏文字。应用程序窗口的标题栏文字保存在PhoneWindow类的成员变量mTitle中,我们可以调用PhoneWindow类的成员函数setTitle来设置。
  接下来,我们就继续分析ActivityThread类的成员函数handleResumeActivity的实现。

public final class ActivityThread {      ......      final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {          ......          ActivityClientRecord r = performResumeActivity(token, clearHide);          if (r != null) {              final Activity a = r.activity;              ......              // If the window hasn't yet been added to the window manager,              // and this guy didn't finish itself or start another activity,              // then go ahead and add the window.              boolean willBeVisible = !a.mStartedActivity;              if (!willBeVisible) {                  try {                      willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(                              a.getActivityToken());                  } catch (RemoteException e) {                  }              }              if (r.window == null && !a.mFinished && willBeVisible) {                  r.window = r.activity.getWindow();                  View decor = r.window.getDecorView();                  decor.setVisibility(View.INVISIBLE);                  ViewManager wm = a.getWindowManager();                  WindowManager.LayoutParams l = r.window.getAttributes();                  a.mDecor = decor;                  l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;                  ......                  if (a.mVisibleFromClient) {                      a.mWindowAdded = true;                      wm.addView(decor, l);                  }              }               ......          }          ......      }      ......  }  

  ActivityThread类的成员函数handleResumeActivity首先调用另外一个成员函数performResumeActivity来通知Activity组件,它要被激活了,即会导致Activity组件的成员函数onResume被调用。ActivityThread类的成员函数performResumeActivity的返回值是一个ActivityClientRecord对象r,这个ActivityClientRecord对象的成员变量activity描述的就是正在激活的Activity组件a。
  ActivityThread类的成员函数handleResumeActivity接下来判断正在激活的Activity组件接下来是否是可见的。如果是可见的,那么变量willBeVisible的值就会等于true。Activity类的成员变量mStartedActivity用来描述一个Activity组件是否正在启动一个新的Activity组件,并且等待这个新的Activity组件的执行结果。如果是的话,那么这个Activity组件的成员变量mStartedActivity的值就会等于true,表示在新的Activity组件的执行结果返回来之前,当前Activity组件要保持不可见的状态。因此,当Activity组件a的成员变量mStartedActivity的值等于true的时候,它接下来就是不可见的,否则的话,就是可见的。
  虽然说在Activity组件a的成员变量mStartedActivity的值等于true的情况下,它接下来的状态要保持不可见的,但是有可能它所启动的Activity组件的UI不是全屏的。在这种情况下,Activity组件a的UI仍然是有部分可见的,这时候也要将变量willBeVisible的值设置为true。因此,如果前面得到变量willBeVisible的值等于false,那么ActivityThread类的成员函数handleResumeActivity接下来就会通过Binder进程间通信机制来调用ActivityManagerService服务的成员函数willActivityBeVisible来检查位于Activity组件a上面的其它Activity组件(包含了Activity组件a正在等待其执行结果的Activity组件)是否是全屏的。如果不是,那么ActivityManagerService服务的成员函数willActivityBeVisible的返回值就会等于true,表示接下来需要显示Activity组件a。
  前面得到的ActivityClientRecord对象r的成员变量window用来描述当前正在激活的Activity组件a所关联的应用程序窗口对象。当它的值等于null的时候,就表示当前正在激活的Activity组件a所关联的应用程序窗口对象还没有关联一个ViewRoot对象。进一步地,如果这个正在激活的Activity组件a还活着,并且接下来是可见的,即ActivityClientRecord对象r的成员变量mFinished的值等于false,并且前面得到的变量willBeVisible的值等于true,那么这时候就说明需要为与Activity组件a所关联的一个应用程序窗口视图对象关联的一个ViewRoot对象。
  将一个Activity组件的应用程序窗口视图对象与一个ViewRoot对象关联是通过该Activity组件所使用的窗口管理器来执行的。从前面Android应用程序窗口(Activity)的窗口对象(Window)的创建过程分析一文可以知道,一个Activity组件所使用的本地窗口管理器保存它的成员变量mWindowManager中,这可以通过Activity类的成员函数getWindowManager来获得。在接下来,我们再分析Activity类的成员函数getWindowManager的实现。
  由于我们现在要给Activity组件a的应用程序窗口视图对象关联一个ViewRoot对象,因此,我们就需要首先获得这个应用程序窗口视图对象。从前面的Step 6可以知道,一个Activity组件的应用程序窗口视图对象保存在与其所关联的一个应用程序窗口对象的内部,因此,我们又要首先获得这个应用程序窗口对象。与一个Activity组件所关联的应用程序窗口对象可以通过调用该Activity组件的成员函数getWindow来获得。一旦获得了这个应用程序窗口对象(类型为PhoneWindow)之后,我们就可以调用它的成员函数getDecorView来获得它内部的视图对象。
  在关联应用程序窗口视图对象和ViewRoot对象的时候,还需要第三个参数,即应用程序窗口的布局参数,这是一个类型为WindowManager.LayoutParams的对象,可以通过调用应用程序窗口的成员函数getAttributes来获得。一切准备就绪之后,还要判断最后一个条件是否成立,即当前正在激活的Activity组件a在本地进程中是否是可见的,即它的成员变量mVisibleFromClient的值是否等于true。如果是可见的,那么最后就可以调用前面所获得的一个本地窗口管理器wm(类型为LocalWindowManager)的成员函数addView来执行关联应用程序窗口视图对象和ViewRoot对象的操作。
  LocalWindowManager类的成员变量mWindowManager指向的是一个WindowManagerImpl对象,因此,LocalWindowManager类的成员函数addView接下来调用WindowManagerImpl类的成员函数addView来给参数view所描述的一个应用程序窗口视图对象关联一个ViewRoot对象。接下来,我们主要分析以及LocalWindowManager类的成员函数addView的实现:

public class WindowManagerImpl implements WindowManager {      ......      public void addView(View view, ViewGroup.LayoutParams params)      {          addView(view, params, false);      }      ......      private void addView(View view, ViewGroup.LayoutParams params, boolean nest)      {          ......          final WindowManager.LayoutParams wparams                  = (WindowManager.LayoutParams)params;          ViewRoot root;          View panelParentView = null;          synchronized (this) {              // Here's an odd/questionable case: if someone tries to add a              // view multiple times, then we simply bump up a nesting count              // and they need to remove the view the corresponding number of              // times to have it actually removed from the window manager.              // This is useful specifically for the notification manager,              // which can continually add/remove the same view as a              // notification gets updated.              int index = findViewLocked(view, false);              if (index >= 0) {                  if (!nest) {                      throw new IllegalStateException("View " + view                              + " has already been added to the window manager.");                  }                  root = mRoots[index];                  root.mAddNesting++;                  // Update layout parameters.                  view.setLayoutParams(wparams);                  root.setLayoutParams(wparams, true);                  return;              }              // If this is a panel window, then find the window it is being              // attached to for future reference.              if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&                      wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {                  final int count = mViews != null ? mViews.length : 0;                  for (int i=0; i<count; i++) {                      if (mRoots[i].mWindow.asBinder() == wparams.token) {                          panelParentView = mViews[i];                      }                  }              }              root = new ViewRoot(view.getContext());              root.mAddNesting = 1;              view.setLayoutParams(wparams);              if (mViews == null) {                  index = 1;                  mViews = new View[1];                  mRoots = new ViewRoot[1];                  mParams = new WindowManager.LayoutParams[1];              } else {                  index = mViews.length + 1;                  Object[] old = mViews;                  mViews = new View[index];                  System.arraycopy(old, 0, mViews, 0, index-1);                  old = mRoots;                  mRoots = new ViewRoot[index];                  System.arraycopy(old, 0, mRoots, 0, index-1);                  old = mParams;                  mParams = new WindowManager.LayoutParams[index];                  System.arraycopy(old, 0, mParams, 0, index-1);              }              index--;              mViews[index] = view;              mRoots[index] = root;              mParams[index] = wparams;          }          // do this last because it fires off messages to start doing things          root.setView(view, wparams, panelParentView);      }      ......      private View[] mViews;      private ViewRoot[] mRoots;      private WindowManager.LayoutParams[] mParams;      ......  }  

  在WindowManagerImpl类中,两个参数版本的成员函数addView是通过调用三个参数版本的成同函数addView来实现的,因此,我们接下来就主要分析三个参数版本的成员函数addView的实现。
  在分析WindowManagerImpl类的三个参数版本的成员函数addView的实现之前,我们首先了解一下WindowManagerImpl类是如何关联一个应用程序窗口视图对象(View对象)和一个ViewRoot对象的。一个View对象在与一个ViewRoot对象关联的同时,还会关联一个WindowManager.LayoutParams对象,这个WindowManager.LayoutParams对象是用来描述应用程序窗口视图的布局属性的。
  WindowManagerImpl类有三个成员变量mViews、mRoots和mParams,它们分别是类型为View、ViewRoot和WindowManager.LayoutParams的数组。这三个数组的大小是始终保持相等的。这样, 有关联关系的View对象、ViewRoot对象和WindowManager.LayoutParams对象就会分别保存在数组mViews、mRoots和mParams的相同位置上,也就是说,mViews[i]、mRoots[i]和mParams[i]所描述的View对象、ViewRoot对象和WindowManager.LayoutParams对象是具有关联关系的。因此,WindowManagerImpl类的三个参数版本的成员函数addView在关联一个View对象、一个ViewRoot对象和一个WindowManager.LayoutParams对象的时候,只要分别将它们放在数组mViews、mRoots和mParams的相同位置上就可以了。
  理解了一个View对象、一个ViewRoot对象和一个WindowManager.LayoutParams对象是如何关联之后,WindowManagerImpl类的三个参数版本的成员函数addView的实现就容易理解了。
  参数view和参数params描述的就是要关联的View对象和WindowManager.LayoutParams对象。成员函数addView首先调用另外一个成员函数findViewLocked来检查参数view所描述的一个View对象是否已经存在于数组中mViews中了。如果已经存在的话,那么就说明该View对象已经关联过ViewRoot对象以及WindowManager.LayoutParams对象了。在这种情况下,如果参数nest的值等于false,那么成员函数addView是不允许重复对参数view所描述的一个View对象进行重新关联的。另一方面,如果参数nest的值等于true,那么成员函数addView只是重新修改参数view所描述的一个View对象及其所关联的一个ViewRoot对象内部使用的一个WindowManager.LayoutParams对象,即更新为参数params所描述的一个WindowManager.LayoutParams对象,这是通过调用它们的成员函数setLayoutParams来实现的。
  如果参数view所描述的一个View对象还没有被关联过一个ViewRoot对象,那么成员函数addView就会创建一个ViewRoot对象,并且将它与参数view和params分别描述的一个View对象和一个WindowManager.LayoutParams对象保存在数组mViews、mRoots和mParams的相同位置上。注意,如果数组mViews、mRoots和mParams尚未创建,那么成员函数addView就会首先分别为它们创建一个大小为1的数组,以便可以用来分别保存所要关联的View对象、ViewRoot对象和WindowManager.LayoutParams对象。另一方面,如果数组mViews、mRoots和mParams已经创建,那么成员函数addView就需要分别将它们的大小增加1,以便可以在它们的末尾位置上分别保存所要关联的View对象、ViewRoot对象和WindowManager.LayoutParams对象。
  还有另外一个需要注意的地方是当参数view描述的是一个子应用程序窗口的视图对象时,即WindowManager.LayoutParams对象wparams的成员变量type的值大于等于WindowManager.LayoutParams.FIRST_SUB_WINDOW并且小于等于WindowManager.LayoutParams.LAST_SUB_WINDOW时,那么成员函数addView还需要找到这个子视图对象的父视图对象panelParentView,这是通过遍历数组mRoots来查找的。首先,WindowManager.LayoutParams对象wparams的成员变量token指向了一个类型为W的Binder本地对象的一个IBinder接口,用来描述参数view所描述的一个子应用程序窗口视图对象所属的父应用程序窗口视图对象。其次,每一个ViewRoot对象都通过其成员变量mWindow来保存一个类型为W的Binder本地对象,因此,如果在数组mRoots中,存在一个ViewRoot对象,它的成员变量mWindow所描述的一个W对象的一个IBinder接口等于WindowManager.LayoutParams对象wparams的成员变量token所描述的一个IBinder接口时,那么就说明与该ViewRoot对象所关联的View对象即为参数view的父应用程序窗口视图对象。
  成员函数addView为参数view所描述的一个View对象和参数params所描述的一个WindowManager.LayoutParams对象关联好一个ViewRoot对象root之后,最后还会将这个View对view象和这个WindowManager.LayoutParams对象,以及变量panelParentView所描述的一个父应用程序窗视图对象,保存在这个ViewRoot对象root的内部去,这是通过调用这个ViewRoot对象root的成员函数setView来实现的,因此,接下来我们就继续分析ViewRoot类的成员函数setView的实现。
ViewRoot.setView:

public final class ViewRoot extends Handler implements ViewParent,          View.AttachInfo.Callbacks {      ......      final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();      ......      View mView;      ......      final View.AttachInfo mAttachInfo;      ......      boolean mAdded;      ......      public void setView(View view, WindowManager.LayoutParams attrs,              View panelParentView) {          synchronized (this) {              if (mView == null) {                  mView = view;                  mWindowAttributes.copyFrom(attrs);                  ......                  mAttachInfo.mRootView = view;                  .......                  if (panelParentView != null) {                      mAttachInfo.mPanelParentWindowToken                              = panelParentView.getApplicationWindowToken();                  }                  mAdded = true;                  ......                  requestLayout();                  ......                  try {                      res = sWindowSession.add(mWindow, mWindowAttributes,                              getHostVisibility(), mAttachInfo.mContentInsets,                              mInputChannel);                  } catch (RemoteException e) {                      mAdded = false;                      mView = null;                      ......                      throw new RuntimeException("Adding window failed", e);                  } finally {                      if (restore) {                          attrs.restore();                      }                  }                  ......              }              ......          }      }      ......  }  

  参数view所描述的一个View对象会分别被保存在ViewRoot类的成员变量mView以及成员变量mAttachInfo所描述的一个AttachInfo的成员变量mRootView中,而参数attrs所描述的一个WindowManager.LayoutParams对象的内容会被拷贝到ViewRoot类的成员变量mWindowAttributes中去。
  当参数panelParentView的值不等于null的时候,就表示参数view描述的是一个子应用程序窗口视图对象。在这种情况下,参数panelParentView描述的就是一个父应用程序窗口视图对象。这时候我们就需要获得用来描述这个父应用程序窗口视图对象的一个类型为W的Binder本地对象的IBinder接口,以便可以保存在ViewRoot类的成员变量mAttachInfo所描述的一个AttachInfo的成员变量mPanelParentWindowToken中去。这样以后就可以知道ViewRoot类的成员变量mView所描述的一个子应用程序窗口视图所属的父应用程序窗口视图是什么了。注意,通过调用参数panelParentView的所描述的一个View对象的成员函数getApplicationWindowToken即可以获得一个对应的W对象的IBinder接口。
  上述操作执行完成之后,ViewRoot类的成员函数setView就可以将成员变量mAdded的值设置为true了,表示当前正在处理的一个ViewRoot对象已经关联好一个View对象了。接下来,ViewRoot类的成员函数setView还需要执行两个操作:
1. 调用ViewRoot类的另外一个成员函数requestLayout来请求对应用程序窗口视图的UI作第一次布局。
2. 调用ViewRoot类的静态成员变量sWindowSession所描述的一个类型为Session的Binder代理对象的成员函数add来请求WindowManagerService增加一个WindowState对象,以便可以用来描述当前正在处理的一个ViewRoot所关联的一个应用程序窗口。

Content Provider源码的梳理


  这个函数通过应用程序上下文的ContentResolver接口resolver的acquireProvider函数来获得与Articles.CONTENT_URI对应的Content Provider对象的IContentProvider接口。
ContentResolver.acqireProvider:

public abstract class ContentResolver {      ......      public final IContentProvider acquireProvider(Uri uri) {          if (!SCHEME_CONTENT.equals(uri.getScheme())) {              return null;          }          String auth = uri.getAuthority();          if (auth != null) {              return acquireProvider(mContext, uri.getAuthority());          }          return null;      }      ......  }  

  函数首先验证参数uri的scheme是否正确,即是否是以content://开头,然后取出它的authority部分,最后调用另外一个成员函数acquireProvider执行获取ContentProvider接口的操作。
从ContentResolver类的定义我们可以看出,它是一个抽象类,两个参数版本的acquireProvider函数是由它的子类来实现的。回到acquireProvider,这个ContentResolver接口是通过应用程序上下文Context对象的getContentResolver函数来获得的,而应用程序上下文Context是由ContextImpl类来实现的,它定义在

class ContextImpl extends Context {      ......      private ApplicationContentResolver mContentResolver;      ......      final void init(LoadedApk packageInfo,              IBinder activityToken, ActivityThread mainThread,              Resources container) {          ......          mContentResolver = new ApplicationContentResolver(this, mainThread);          ......      }      ......      @Override      public ContentResolver getContentResolver() {          return mContentResolver;      }      ......  }  

  ContextImpl类的init函数是在应用程序启动的时候调用的,因此,在上面的ContentResolver类的acquireProvider函数里面接下来要调用的ApplicationContentResolver类的acquireProvider函数。
ApplicationContentResolve.acquireProvider:

class ContextImpl extends Context {      ......      private static final class ApplicationContentResolver extends ContentResolver {          ......          @Override          protected IContentProvider acquireProvider(Context context, String name) {              return mMainThread.acquireProvider(context, name);          }          ......          private final ActivityThread mMainThread;      }      ......  }  

  它调用ActivityThread类的acquireProvider函数进一步执行获取Content Provider接口的操作。
ActivityThread.acquireProvider:

public final class ActivityThread {      ......      public final IContentProvider acquireProvider(Context c, String name) {          IContentProvider provider = getProvider(c, name);          if(provider == null)              return null;          ......          return provider;      }      ......  }  

  它又是调用了另外一个成员函数getProvider来进一步执行获取Content Provider接口的操作。
ActivityThread.getProvider:

public final class ActivityThread {      ......      private final IContentProvider getExistingProvider(Context context, String name) {          synchronized(mProviderMap) {              final ProviderClientRecord pr = mProviderMap.get(name);              if (pr != null) {                  return pr.mProvider;              }              return null;          }      }      ......      private final IContentProvider getProvider(Context context, String name) {          IContentProvider existing = getExistingProvider(context, name);          if (existing != null) {              return existing;          }          IActivityManager.ContentProviderHolder holder = null;          try {              holder = ActivityManagerNative.getDefault().getContentProvider(                  getApplicationThread(), name);          } catch (RemoteException ex) {          }          IContentProvider prov = installProvider(context, holder.provider,              holder.info, true);          ......          return prov;      }      ......  }  

  这个函数首先会通过getExistingProvider函数来检查本地是否已经存在这个要获取的ContentProvider接口,如果存在,就直接返回了。本地已经存在的ContextProvider接口保存在ActivityThread类的mProviderMap成员变量中,以ContentProvider对应的URI的authority为键值保存。在我们这个情景中,因为是第一次调用ArticlesProvider接口,因此,这时候通过getExistingProvider函数得到的IContentProvider接口为null,于是下面就会调用ActivityManagerService服务的getContentProvider接口来获取一个ContentProviderHolder对象holder,这个对象就包含了我们所要获取的ArticlesProvider接口,在将这个接口返回给调用者之后,还会调用installProvider函数来把这个接口保存在本地中,以便下次要使用这个ContentProvider接口时,直接就可以通过getExistingProvider函数获取了。
  我们先进入到ActivityManagerService服务的getContentProvider函数中看看它是如何获取我们所需要的ArticlesProvider接口的,然后再返回来看看installProvider函数的实现。
ActivityManagerService.getContentProvider:

public final class ActivityManagerService extends ActivityManagerNative          implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {      ......      public final ContentProviderHolder getContentProvider(              IApplicationThread caller, String name) {          ......          return getContentProviderImpl(caller, name);      }      ......  }  

  它调用getContentProviderImpl函数来进一步执行操作。

public final class ActivityManagerService extends ActivityManagerNative          implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {      ......      private final ContentProviderHolder getContentProviderImpl(              IApplicationThread caller, String name) {          ContentProviderRecord cpr;          ProviderInfo cpi = null;          synchronized(this) {              ProcessRecord r = null;              if (caller != null) {                  r = getRecordForAppLocked(caller);                  ......              }              // First check if this content provider has been published...              cpr = mProvidersByName.get(name);              if (cpr != null) {                  ......              } else {                  try {                      cpi = AppGlobals.getPackageManager().                          resolveContentProvider(name,                          STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);                  } catch (RemoteException ex) {                  }                  ......              }              cpr = mProvidersByClass.get(cpi.name);              final boolean firstClass = cpr == null;              if (firstClass) {                  try {                      ApplicationInfo ai =                          AppGlobals.getPackageManager().                          getApplicationInfo(                          cpi.applicationInfo.packageName,                          STOCK_PM_FLAGS);                      ......                      cpr = new ContentProviderRecord(cpi, ai);                  } catch (RemoteException ex) {                      // pm is in same process, this will never happen.                  }              }              if (r != null && cpr.canRunHere(r)) {                  // If this is a multiprocess provider, then just return its                  // info and allow the caller to instantiate it.  Only do                  // this if the provider is the same user as the caller's                  // process, or can run as root (so can be in any process).                  return cpr;              }              ......              // This is single process, and our app is now connecting to it.              // See if we are already in the process of launching this              // provider.              final int N = mLaunchingProviders.size();              int i;              for (i=0; i<N; i++) {                  if (mLaunchingProviders.get(i) == cpr) {                      break;                  }              }              // If the provider is not already being launched, then get it              // started.              if (i >= N) {                  final long origId = Binder.clearCallingIdentity();                  ProcessRecord proc = startProcessLocked(cpi.processName,                      cpr.appInfo, false, 0, "content provider",                      new ComponentName(cpi.applicationInfo.packageName,                      cpi.name), false);                  ......                  mLaunchingProviders.add(cpr);                  ......              }              // Make sure the provider is published (the same provider class              // may be published under multiple names).              if (firstClass) {                  mProvidersByClass.put(cpi.name, cpr);              }              cpr.launchingApp = proc;              mProvidersByName.put(name, cpr);              ......          }          // Wait for the provider to be published...          synchronized (cpr) {              while (cpr.provider == null) {                  ......                  try {                      cpr.wait();                  } catch (InterruptedException ex) {                  }              }          }          return cpr;      }      ......  }

  这个函数比较长,我们一步一步地分析。
函数首先是获取调用者的进程记录块信息:

ProcessRecord r = null;  if (caller != null) {      r = getRecordForAppLocked(caller);      ......  }  

  在ActivityManagerService中,有两个成员变量是用来保存系统中的Content Provider信息的,一个是mProvidersByName,一个是mProvidersByClass,前者是以Content Provider的authoriry值为键值来保存的,后者是以Content Provider的类名为键值来保存的。一个Content Provider可以有多个authority,而只有一个类来和它对应,因此,这里要用两个Map来保存,这里为了方便根据不同条件来快速查找而设计的。下面的代码就是用来检查要获取的Content Provider是否已经加存在的了:

cpr = mProvidersByName.get(name);  if (cpr != null) {      ......  } else {      try {          cpi = AppGlobals.getPackageManager().              resolveContentProvider(name,              STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);      } catch (RemoteException ex) {      }      ......  }  cpr = mProvidersByClass.get(cpi.name);  final boolean firstClass = cpr == null;  if (firstClass) {      try {          ApplicationInfo ai =              AppGlobals.getPackageManager().              getApplicationInfo(              cpi.applicationInfo.packageName,              STOCK_PM_FLAGS);          ......          cpr = new ContentProviderRecord(cpi, ai);      } catch (RemoteException ex) {          // pm is in same process, this will never happen.      }  }  

  在我们这个情景中,由于是第一次调用接口,因此,在mProvidersByName和mProvidersByClass两个Map中都不存在ArticlesProvider的相关信息,因此,这里会通过AppGlobals.getPackageManager函数来获得PackageManagerService服务接口,然后分别通过它的resolveContentProvider和getApplicationInfo函数来分别获取ArticlesProvider应用程序的相关信息,分别保存在cpi和cpr这两个本地变量中。这些信息都是在安装应用程序的过程中保存下来的,具体可以参考Android应用程序安装过程源代码分析一文。
接下去这个代码判断当前要获取的Content Provider是否允许在客户进程中加载,即查看一个这个Content Provider否配置了multiprocess属性为true,如果允许在客户进程中加载,就直接返回了这个Content Provider的信息了:

if (r != null && cpr.canRunHere(r)) {      return cpr;  }  

  在我们这个情景中,如果设置了要在独立的进程中运行,因此,继续往下执行:

final int N = mLaunchingProviders.size();  int i;  for (i=0; i<N; i++) {      if (mLaunchingProviders.get(i) == cpr) {          break;      }  }  

  系统中所有正在加载的Content Provider都保存在mLaunchingProviders成员变量中。在加载相应的Content Provider之前,首先要判断一下它是可否正在被其它应用程序加载,如果是的话,就不用重复加载了。在我们假设没有其他进程在加载,继续往前执行:

// If the provider is not already being launched, then get it  // started.  if (i >= N) {      final long origId = Binder.clearCallingIdentity();      ProcessRecord proc = startProcessLocked(cpi.processName,          cpr.appInfo, false, 0, "content provider",          new ComponentName(cpi.applicationInfo.packageName,          cpi.name), false);      ......      mLaunchingProviders.add(cpr);      ......  }  

  这里的条件i >= N为true,就表明没有其它应用程序正在加载这个Content Provider,因此,就要调用startProcessLocked函数来启动一个新的进程来加载这个Content Provider对应的类了,然后把这个正在加载的信息增加到mLaunchingProviders中去。我们先接着分析这个函数,然后再来看在新进程中加载Content Provider的过程,继续往下执行:

// Make sure the provider is published (the same provider class  // may be published under multiple names).  if (firstClass) {      mProvidersByClass.put(cpi.name, cpr);  }  cpr.launchingApp = proc;  mProvidersByName.put(name, cpr);  

  这段代码把这个Content Provider的信息分别保存到mProvidersByName和mProviderByCalss两个Map中去,以方便后续查询。
因为我们需要获取的Content Provider是在新的进程中加载的,而getContentProviderImpl这个函数是在系统进程中执行的,它必须要等到要获取的Content Provider是在新的进程中加载完成后才能返回,这样就涉及到进程同步的问题了。这里使用的同步方法是不断地去检查变量cpr的provider域是否被设置了。当要获取的Content Provider在新的进程加载完成之后,它会通过Binder进程间通信机制调用到系统进程中,把这个cpr变量的provider域设置为已经加载好的Content Provider接口,这时候,函数getContentProviderImpl就可以返回了。下面的代码就是用来等待要获取的Content Provider是在新的进程中加载完成的:

// Wait for the provider to be published...  synchronized (cpr) {      while (cpr.provider == null) {          ......          try {              cpr.wait();          } catch (InterruptedException ex) {          }      }  }  

  下面我们再分析在新进程中加载Content Provider的过程。
ActivityManagerService.startProcessLocked
 Process.start
 ActivityThread.main
 ActivityThread.attach
 ActivityManagerService.attachApplication
 这五步是标准的Android应用程序启动步骤,具体可以参考之前的启动Android Activity,或者Android系统在新进程中启动自定义服务过程(startService)的原理,这里就不再详细描述了。
  在Android系统中,每一个应用程序进程都加载了一个ActivityThread实例,在这个ActivityThread实例里面,有一个成员变量mAppThread,它是一个Binder对象,类型为ApplicationThread,实现了IApplicationThread接口,它是专门用来和ActivityManagerService服务进行通信的,attachApplication就会进入到应用程序Content Provider进程中的ApplicationThread对象的bindApplication函数中去。在我们这个情景场,这个函数调用中最重要的参数便是第三个参数providers了,它是我们要处理的对象。
  bindApplication函数把相关的信息都封装成一个AppBindData对象,然后以一个消息的形式发送到主线程的消息队列中去等等待处理。这个消息最终是是在ActivityThread类的handleBindApplication函数中进行处理的。handleBindApplication就是调用installContentProviders函数来在本地安装Content Providers信息。

public final class ActivityThread {      ......      private final void installContentProviders(              Context context, List<ProviderInfo> providers) {          final ArrayList<IActivityManager.ContentProviderHolder> results =              new ArrayList<IActivityManager.ContentProviderHolder>();          Iterator<ProviderInfo> i = providers.iterator();          while (i.hasNext()) {              ProviderInfo cpi = i.next();              StringBuilder buf = new StringBuilder(128);              buf.append("Pub ");              buf.append(cpi.authority);              buf.append(": ");              buf.append(cpi.name);              Log.i(TAG, buf.toString());              IContentProvider cp = installProvider(context, null, cpi, false);              if (cp != null) {                  IActivityManager.ContentProviderHolder cph =                      new IActivityManager.ContentProviderHolder(cpi);                  cph.provider = cp;                  results.add(cph);                  // Don't ever unload this provider from the process.                  synchronized(mProviderMap) {                      mProviderRefCountMap.put(cp.asBinder(), new ProviderRefCount(10000));                  }              }          }          try {              ActivityManagerNative.getDefault().publishContentProviders(                  getApplicationThread(), results);          } catch (RemoteException ex) {          }      }      ......  }  

  这个函数主要是做了两件事情,一是调用installProvider来在本地安装每一个Content Proivder的信息,并且为每一个Content Provider创建一个ContentProviderHolder对象来保存相关的信息。ContentProviderHolder对象是一个Binder对象,是用来把Content Provider的信息传递给ActivityManagerService服务的。当这些Content Provider都处理好了以后,还要调用ActivityManagerService服务的publishContentProviders函数来通知ActivityManagerService服务,这个进程中所要加载的Content Provider,都已经准备完毕了,而ActivityManagerService服务的publishContentProviders函数的作用就是用来唤醒在前面等待的线程的了。我们先来看installProvider的实现,然后再来看ActivityManagerService服务的publishContentProviders函数的实现。

public final class ActivityThread {      ......      private final IContentProvider installProvider(Context context,              IContentProvider provider, ProviderInfo info, boolean noisy) {          ContentProvider localProvider = null;          if (provider == null) {              ......              Context c = null;              ApplicationInfo ai = info.applicationInfo;              if (context.getPackageName().equals(ai.packageName)) {                  c = context;              } else if (mInitialApplication != null &&                  mInitialApplication.getPackageName().equals(ai.packageName)) {                      c = mInitialApplication;              } else {                  try {                      c = context.createPackageContext(ai.packageName,                          Context.CONTEXT_INCLUDE_CODE);                  } catch (PackageManager.NameNotFoundException e) {                  }              }              ......              try {                  final java.lang.ClassLoader cl = c.getClassLoader();                  localProvider = (ContentProvider)cl.                      loadClass(info.name).newInstance();                  provider = localProvider.getIContentProvider();                  ......                  // XXX Need to create the correct context for this provider.                  localProvider.attachInfo(c, info);              } catch (java.lang.Exception e) {                  ......              }          } else if (localLOGV) {              ......          }          synchronized (mProviderMap) {              // Cache the pointer for the remote provider.              String names[] = PATTERN_SEMICOLON.split(info.authority);              for (int i=0; i<names.length; i++) {                  ProviderClientRecord pr = new ProviderClientRecord(names[i], provider,                      localProvider);                  try {                      provider.asBinder().linkToDeath(pr, 0);                      mProviderMap.put(names[i], pr);                  } catch (RemoteException e) {                      return null;                  }              }              if (localProvider != null) {                  mLocalProviders.put(provider.asBinder(),                      new ProviderClientRecord(null, provider, localProvider));              }          }          return provider;      }      ......  }  

  这个函数的作用主要就是在应用程序进程中把相应的Content Provider类加载进来了,在我们这个种情景中,就是要在应用程序中把这个Content Provider类加载到内存中来了:

final java.lang.ClassLoader cl = c.getClassLoader();  localProvider = (ContentProvider)cl.      loadClass(info.name).newInstance(); 

  接着通过调用localProvider的getIContentProvider函数来获得一个Binder对象,这个Binder对象返回给installContentProviders函数之后,就会传到ActivityManagerService中去,后续其它应用程序就是通过获得这个Binder对象来和相应的Content Provider进行通信的了。我们看一下这个函数的实现:

public abstract class ContentProvider implements ComponentCallbacks {      ......      private Transport mTransport = new Transport();      ......      class Transport extends ContentProviderNative {          ......      }      public IContentProvider getIContentProvider() {          return mTransport;      }      ......  } 

  下面我们通过应用程序上下文的ContentResolver接口resolver的query函数来分析,Content Provider是如何实现进程间数据共享的:

public abstract class ContentResolver {      ......      public final Cursor query(Uri uri, String[] projection,              String selection, String[] selectionArgs, String sortOrder) {          IContentProvider provider = acquireProvider(uri);          if (provider == null) {              return null;          }          try {              ......              Cursor qCursor = provider.query(uri, projection, selection, selectionArgs, sortOrder);              ......              return new CursorWrapperInner(qCursor, provider);          } catch (RemoteException e) {              ......          } catch(RuntimeException e) {              ......          }      }      ......  }  

  这个函数首先通过调用acquireProvider函数来获得与参数uri对应的Content Provider接口,然后再通过这个接口的query函数来获得相应的数据。我们先来看看acquireProvider函数的实现,再回过头来分析这个Content Provider接口的query函数的实现。
1. ContentResolver.acquireProvider
2. ApplicationContentResolver.acquireProvider
3. ActivityThread.acquireProvider
4. ActivityThread.getProvider
从1到4步骤是中传进来的参数uri对应的Content Provider接口的过程。在前面文章我们已经详细介绍过这个过程了,这里不再详述。不过这里我们假设,这个Content Provider接口之前已经创建好了,因此,在query中的ActivityThread.getProvider函数中,通过getExistingProvider函数就把之前已经好的Content Provider接口返回来了。
  ContentResolver.query函数中,它继续调用这个返回来的Content Provider接口来获取数据。从这篇文章Android应用程序组件Content Provider的启动过程源代码分析中,我们知道,这个Content Provider接口实际上是一个在ContentProvider类的内部所创建的一个Transport对象的远程接口。这个Transport类继承了ContentProviderNative类,是一个Binder对象的Stub类,因此,接下来就会进入到这个Binder对象的Proxy类ContentProviderProxy中执行query函数。

final class ContentProviderProxy implements IContentProvider {      ......      public Cursor query(Uri url, String[] projection, String selection,              String[] selectionArgs, String sortOrder) throws RemoteException {          //TODO make a pool of windows so we can reuse memory dealers          CursorWindow window = new CursorWindow(false /* window will be used remotely */);          BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();          IBulkCursor bulkCursor = bulkQueryInternal(              url, projection, selection, selectionArgs, sortOrder,              adaptor.getObserver(), window,              adaptor);          if (bulkCursor == null) {              return null;          }          return adaptor;      }      ......  }  

  这个函数首先会创建一个CursorWindow对象,前面已经说过,这个CursorWindow对象包含了一块匿名共享内存,它的作用是把这块匿名共享内存通过Binder进程间通信机制传给Content Proivder,好让Content Proivder在里面返回所请求的数据。下面我们就先看看这个CursorWindow对象的创建过程,重点关注它是如何在内部创建匿名共享内存的,然后再回过头来看看它调用bulkQueryInternal函数来做了些什么事情。

public class CursorWindow extends SQLiteClosable implements Parcelable {      ......      private int nWindow;      ......      public CursorWindow(boolean localWindow) {          ......          native_init(localWindow);      }      ......  }  

  这个native方法会最终调用:

static void native_init_empty(JNIEnv * env, jobject object, jboolean localOnly)  {      ......      CursorWindow * window;      window = new CursorWindow(MAX_WINDOW_SIZE);      ......      if (!window->initBuffer(localOnly)) {          ......      }      ......      SET_WINDOW(env, object, window);  }  

   这个函数在C++层创建了一个CursorWindow对象,然后通过调用SET_WINDOW宏来把这个C++层的CursorWindow对象与Java层的CursorWindow对象关系起来。
   下面我们重点关注C++层的CursorWindow对象的initBuffer函数的实现:

bool CursorWindow::initBuffer(bool localOnly)  {      ......      sp<MemoryHeapBase> heap;      heap = new MemoryHeapBase(mMaxSize, 0, "CursorWindow");      if (heap != NULL) {          mMemory = new MemoryBase(heap, 0, mMaxSize);          if (mMemory != NULL) {              mData = (uint8_t *) mMemory->pointer();              if (mData) {                  mHeader = (window_header_t *) mData;                  mSize = mMaxSize;                  ......              }          }          ......      } else {          ......      }  }  

  在CursorWindow类的内部有一个成员变量mMemory,它的类型是MemoryBase。MemoryBase类为我们封装了匿名共享内存的访问以及在进程间的传输等问题,具体可以参考前面文章中对Android系统匿名共享内存的分析,这里就不再详述了。
  我们回到ContentProviderProxy的query中,看看系统是如何把这个匿名共享存传递给Content Provider使用的。在query中,最后调用bulkQueryInternal函数来进一步操作。

final class ContentProviderProxy implements IContentProvider  {      ......      private IBulkCursor bulkQueryInternal(              Uri url, String[] projection,              String selection, String[] selectionArgs, String sortOrder,              IContentObserver observer, CursorWindow window,              BulkCursorToCursorAdaptor adaptor) throws RemoteException {          Parcel data = Parcel.obtain();          Parcel reply = Parcel.obtain();          data.writeInterfaceToken(IContentProvider.descriptor);          url.writeToParcel(data, 0);          int length = 0;          if (projection != null) {              length = projection.length;          }          data.writeInt(length);          for (int i = 0; i < length; i++) {              data.writeString(projection[i]);          }          data.writeString(selection);          if (selectionArgs != null) {              length = selectionArgs.length;          } else {              length = 0;          }          data.writeInt(length);          for (int i = 0; i < length; i++) {              data.writeString(selectionArgs[i]);          }          data.writeString(sortOrder);          data.writeStrongBinder(observer.asBinder());          window.writeToParcel(data, 0);          // Flag for whether or not we want the number of rows in the          // cursor and the position of the "_id" column index (or -1 if          // non-existent).  Only to be returned if binder != null.          final boolean wantsCursorMetadata = (adaptor != null);          data.writeInt(wantsCursorMetadata ? 1 : 0);          mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);          DatabaseUtils.readExceptionFromParcel(reply);          IBulkCursor bulkCursor = null;          IBinder bulkCursorBinder = reply.readStrongBinder();          if (bulkCursorBinder != null) {              bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);              if (wantsCursorMetadata) {                  int rowCount = reply.readInt();                  int idColumnPosition = reply.readInt();                  if (bulkCursor != null) {                      adaptor.set(bulkCursor, rowCount, idColumnPosition);                  }              }          }          data.recycle();          reply.recycle();          return bulkCursor;      }      ......  }  

  函数的目的是将查询参数都写到一个Parcel对象data中去,然后通过下面Binder进程间通信机制把查询请求传给Content Provider处理。
  从这个Binder调用返回以后,就会得到一个IBulkCursor接口,它是一个Binder引用,实际是指向在Content Provider这一侧创建的一个CursorToBulkCursorAdaptor对象,后面我们将会看到。有了这个IBulkCursor接口之后,我们就可以通过Binder进程间调用来访问从Content Provider中查询得到的数据了。这个IBulkCursor接口最终最设置了上面query中创建的BulkCursorToCursorAdaptor对象adaptor中去:

adaptor.set(bulkCursor, rowCount, idColumnPosition);

   BulkCursorToCursorAdaptor类实现了Cursor接口,因此,我们可以通过Curosr接口来访问这些查询得到的共享数据。
   现在,我们重点来关注一下CursorWindow类的writeToParcel函数,看看它是如何把它内部的匿名共享内存对象写到数据流data中去的。

public class CursorWindow extends SQLiteClosable implements Parcelable {      ......      public void writeToParcel(Parcel dest, int flags) {          ......          dest.writeStrongBinder(native_getBinder());          ......      }      ......  }  

  这个函数最主要的操作就是往数据流dest写入一个Binder对象,这个Binder对象是通过调用本地方法native_getBinder来得到的。

static jobject native_getBinder(JNIEnv * env, jobject object)  {      CursorWindow * window = GET_WINDOW(env, object);      if (window) {          sp<IMemory> memory = window->getMemory();          if (memory != NULL) {              sp<IBinder> binder = memory->asBinder();              return javaObjectForIBinder(env, binder);          }      }      return NULL;  }  

  前面我们在C++层创建了一个CursorWindow对象,这个对象保存在Java层创建的CursorWindow对象的成员变量nWindow中,这里通过GET_WINDOW宏来把这个在C++层创建的CurosrWindow对象返回来。
  获得了这个CursorWindow对象以后,就调用它的getMemory函数来获得一个IMemory接口,这是一个Binder接口。
  对象就是之前说过得在initBuffer中创建的MemoryHeapBase对象。
  这样,在第三方应用程序这一侧创建的匿名共享存对象就可以传递给Content Provider来使用了。
  所有的参数都就准备就绪以后,就通过Binder进程间通信机制把数据查询请求发送给相应的Content Proivder了。这个请求是在ContentProviderNative类的onTransact函数中响应的。

abstract public class ContentProviderNative extends Binder implements IContentProvider {      ......      @Override      public boolean onTransact(int code, Parcel data, Parcel reply, int flags)      throws RemoteException {          try {              switch (code) {              case QUERY_TRANSACTION:                  {                      data.enforceInterface(IContentProvider.descriptor);                      Uri url = Uri.CREATOR.createFromParcel(data);                      // String[] projection                      int num = data.readInt();                      String[] projection = null;                      if (num > 0) {                          projection = new String[num];                          for (int i = 0; i < num; i++) {                              projection[i] = data.readString();                          }                      }                      // String selection, String[] selectionArgs...                      String selection = data.readString();                      num = data.readInt();                      String[] selectionArgs = null;                      if (num > 0) {                          selectionArgs = new String[num];                          for (int i = 0; i < num; i++) {                              selectionArgs[i] = data.readString();                          }                      }                      String sortOrder = data.readString();                      IContentObserver observer = IContentObserver.Stub.                          asInterface(data.readStrongBinder());                      CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);                      // Flag for whether caller wants the number of                      // rows in the cursor and the position of the                      // "_id" column index (or -1 if non-existent)                      // Only to be returned if binder != null.                      boolean wantsCursorMetadata = data.readInt() != 0;                      IBulkCursor bulkCursor = bulkQuery(url, projection, selection,                          selectionArgs, sortOrder, observer, window);                      reply.writeNoException();                      if (bulkCursor != null) {                          reply.writeStrongBinder(bulkCursor.asBinder());                          if (wantsCursorMetadata) {                              reply.writeInt(bulkCursor.count());                              reply.writeInt(BulkCursorToCursorAdaptor.findRowIdColumnIndex(                                  bulkCursor.getColumnNames()));                          }                      } else {                          reply.writeStrongBinder(null);                      }                      return true;                  }              ......              }          } catch (Exception e) {              DatabaseUtils.writeExceptionToParcel(reply, e);              return true;          }          return super.onTransact(code, data, reply, flags);      }      ......  }  

  把请求参数从数据流data中读取出来。这里我们同样是重点关注下面这两个参数读取的步骤:

CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);   boolean wantsCursorMetadata = data.readInt() != 0;

  通过调用CursorWindow.CREATOR.createFromParcel函数来从数据流data中重建一个本地的CursorWindow对象;接着又将数据流data的下一个整数值读取出来,如果这个整数值不为0,变量wantsCursorMetadata的值就为true,说明Content Provider在返回IBulkCursor接口给第三方应用程序之前,要先实际执行一把数据库查询操作,以便把结果数据的元信息返回给第三方应用程序。
  调用bulkQuery函数之后,就得到了一个IBulkCursor接口,这表示要返回的数据准备就绪了,但是这时候实际上还没有把结果数据从数据库中提取出来,而只是准备好了一个SQL查询计划,等到真正要使用这些结果数据时,系统才会真正执行查询数据库的操作。
  下面我们就重点关注CursorWindow.CREATOR.createFromParcel函数是如何从数据流data中在本地构造一个CursorWindow对象的。

public class CursorWindow extends SQLiteClosable implements Parcelable {      ......      private CursorWindow(Parcel source) {          IBinder nativeBinder = source.readStrongBinder();          ......          native_init(nativeBinder);      }      ......      public static final Parcelable.Creator<CursorWindow> CREATOR              = new Parcelable.Creator<CursorWindow>() {          public CursorWindow createFromParcel(Parcel source) {              return new CursorWindow(source);          }          ......      };      ......  }  

  在创建CursorWindow对象的过程中,首先是从数据流source中将在前面中写入的Binder接口读取出来,然后使用这个Binder接口来初始化这个CursorWindow对象,通过前面,我们知道,这个Binder接口的实际类型为IMemory,它封装了对匿名共享内存的访问操作。初始化这个匿名共享内存对象的操作是由本地方法native_init函数来实现的,下面我们就看看它的实现。
  函数native_init_memory的实现如下所示:

static void native_init_memory(JNIEnv * env, jobject object, jobject memObj)  {      sp<IMemory> memory = interface_cast<IMemory>(ibinderForJavaObject(env, memObj));      ......      CursorWindow * window = new CursorWindow();      ......      if (!window->setMemory(memory)) {         ......      }      ......      SET_WINDOW(env, object, window);  }  

  函数首先是将前面传进来的Binder接口转换为IMemory接口,接着创建一个C++层的CursorWindow对象,再接着用这个IMemory接口来初始化这个C++层的CursorWindow对象,最后通过宏SET_WINDOW把这个C++层的CursorWindow对象和Java层CursorWindow对象关联起来。

bool CursorWindow::setMemory(const sp<IMemory>& memory)  {      mMemory = memory;      mData = (uint8_t *) memory->pointer();      ......      mHeader = (window_header_t *) mData;      // Make the window read-only      ssize_t size = memory->size();      mSize = size;      mMaxSize = size;      mFreeOffset = size;      ......      return true;  } 

  我们知道,这里得到的IMemory接口,实际上是一个Binder引用,它指向前面在创建的MemoryBase对象,当我们第一次调用这个接口的pointer函数时,它便会通过Binder进程间通信机制去请求这个MemoryBase对象把它内部的匿名共享内存文件描述符返回来给它,而Binder驱动程序发现要传输的是一个文件描述符的时候,就会在目标进程中创建另外一个文件描述符,这个新建的文件描述符与要传输的文件描述符指向的是同一个文件,在我们这个情景中,这个文件就是我们前面创建的匿名共享内存文件了。因此,在目标进程中,即在Content Provider进程中,它可以通过这个新建的文件描述符来访问这块匿名共享内存。
  回到前面的ContentProviderNative的onTransact中,下一步要执行的函数便是bulkQuery了,它的作用为请求的数据制定好一个SQL数据库查询计划。
  这个bulkQuery函数是由一个实现了IContentProvider接口的Binder对象来实现的,前面介绍ContentProvider启动过程时说过这个对象:

public abstract class ContentProvider implements ComponentCallbacks {      ......      class Transport extends ContentProviderNative {          ......          public IBulkCursor bulkQuery(Uri uri, String[] projection,                  String selection, String[] selectionArgs, String sortOrder,                  IContentObserver observer, CursorWindow window) {              ......              Cursor cursor = ContentProvider.this.query(uri, projection,                  selection, selectionArgs, sortOrder);              ......              return new CursorToBulkCursorAdaptor(cursor, observer,                  ContentProvider.this.getClass().getName(),                  hasWritePermission(uri), window);          }          ......      }      ......  } 

  这个函数主要做了两件事情,一是调用ContentProvider的子类的query函数构造一个数据库查询计划,注意,从这个函数返回来的时候,还没有真正执行数据库查询的操作,而只是按照查询条件准备好了一个SQL语句,要等到第一次使用的时候才会去执行数据库查询操作;二是使用前面一步得到的Cursor接口以及传下来的参数window来创建一个CursorToBulkCursorAdaptor对象,这个对象实现了IBulkCursor接口,同时它也是一个Binder对象,是用来返回给第三方应用程序使用的,第三方应用程序必须通过这个接口来获取从ContentProvider中查询得到的数据,而这个CursorToBulkCursorAdaptor对象的功能就是利用前面获得的Cursor接口来执行数据库查询操作,然后把查询得到的结果保存在从参数传下来的window对象内部所引用的匿名共享内存中去。

0 0
原创粉丝点击