Android 系统Framework 机制探究

在学习Andorid系统服务之前,为了便于理解,先看下系统进程及主要服务在手机中的信息。如下如果涉及到源码,使用的是android8.0的代码,不排除个别代码是从其他博客中复制的或者不同的android8.0代码有个别差异,故如果有和读者理解及查看不一样的地方,请读者注意

首先查看手机中的进程

直观的感受下系统进程
开启一个 android 5.0的模拟(小编使用android 7.0的模拟器及android 8.0的华为手机,使用 adb shell ps 命令没有信息,这个问题已经解决,见Android 高版本(8、9、10)查看手机中进程信息、线程信息)
打开一个cmd终端,输入如下命令

adb shell
ps  #列出系统中所有进程信息

在这里插入图片描述
在这里插入图片描述
USER:进程当前用户;
PID(Process Id):当前进程id;
PPID(Process Parent ID):父进程ID;
VSIZE(Virtual Size):当前进程虚拟内存的大小;
RSS(Resident Set Size):实际驻留在内存中的没存大小;
WCHAN:休眠进程在内核中的地址;
PC(program counter):计算机中提供要从[存储器]中取出的下一个指令地址的[寄存器];
NAME:进程状态值及名称;一般情况下,如果是app,则进程名默认是其包名
Android中 adb shell ps 查看手机中进程信息

高版本查看进程问题

adb shell ps -A

Android高版本adb shell ps不能查看其他进程问题

这里看几个关键的进程

servicemanager进程,其是由init进程fork的。其先于zygote进程创建
在这里插入图片描述
zygote、system_server进程。zygote输入root用户的进程
在这里插入图片描述
在这里插入图片描述

可以看到很多进程的PPID都是 1182,即它们的父进程是zygote64,即网上常说的zygote进程,system_server的父进程也是zygote进程,所以它们都是zygote进程孵化(fork)的,而zygote进程是由1号进程 init进程孵化的。

ps |grep keyword

keyword是我们想要找的进程名字的全称或者是一部分,也就是app的包名或者包名的一部分,比如我们的包名是com.xxxxx.yyyy,keyword可以是com.xxxxx.yyyy,也可以是xxxxx或者yyyy。该命令会把我们要找的进程范围缩减到最小
另外,这里顺便补充两种杀死进程的方法:
第一种:kill -9 进程号
举例:adb shell kill -9 1137
第二种:adb shell am force-stop 包名全称,该方法不支持部分匹配,所以一定要是包名的全称。
举例:adb shell am force-stop com.xxxxx.yyyy

查看特定进程的线程信息

在ps命令中,“-t”选项可以开启线程查看
在这里插入图片描述
在这里插入图片描述
注意:这里线程名称显示字符长度是有限制的。故显示为ActivityManager名称的线程可能就是ActivityManagerService的线程,同样PowerManagerSer名称的线程就是PowerManagerService线程。很多常用的系统服务都是一个特定的线程,运行在system_server进程中。小编在android 4.4的模拟器上能看到WindowManager字样的线程名,但是5.0的模拟器没有看到,有可能改名称了,这个需要跟源码。
Android的ps命令参数: -t -x -P -p -c [pid|name]

  • -t 显示进程下的线程列表
  • -x 显示进程耗费的用户时间和系统时间,格式:(u:0, s:0),单位:秒(s)
  • -P 显示调度策略,通常是bg或fg,当获取失败将会是un和er
  • -p 显示进程的优先级和nice等级
  • -c 显示进程耗费的CPU时间 (可能不兼容Android 4.0以前的老版本系统)
  • [pid] 过滤指定的进程PID
  • [name] 过滤指定的进程NAME

adb shell查看进程方法
ADB之adb shell ps命令查看信息
Android中 adb shell ps 查看手机中进程信息
Android中 adb shell ps 查看手机中进程信息
zygote fork是单线程,为了避免造成死锁或者状态不一致等问题

孵化应用进程为什么不给SystemServer来做,而专门设计一个Zygote?

我们知道,应用在启动的时候需要做很多准备工作,包括启动虚拟机,加载各类系统资源等等,这些都是非常耗时的,如果能在zygote里就给这些必要的初始化工作做好,子进程在fork的时候就能直接共享,那么这样的话效率就会非常高。这个就是zygote存在的价值,这一点呢SystemServer是替代不了的,主要是因为SystemServer里跑了一堆系统服务,这些是不能继承到应用进程的。而且我们应用进程在启动的时候,内存空间除了必要的资源外,最好是干干净净的,不要继承一堆乱七八糟的东西。所以呢,不如给SystemServer和应用进程里都要用到的资源抽出来单独放在一个进程里,也就是这的zygote进程,然后zygote进程再分别孵化出SystemServer进程和应用进程。孵化出来之后,SystemServer进程和应用进程就可以各干各的事了。

Zygote的IPC通信机制为什么不采用binder?如果采用binder的话会有什么问题?

android间的进程通信是使用Binder,唯独Zygote和SystemService是使用socket
第一种解释:
第一个原因,我们可以设想一下采用binder调用的话该怎么做,首先zygote要启用binder机制,需要打开binder驱动,获得一个描述符,再通过mmap进行内存映射,还要注册binder线程,这还不够,还要创建一个binder对象注册到serviceManager,另外AMS要向zygote发起创建应用进程请求的话,要先从serviceManager查询zygote的binder对象,然后再发起binder调用,这来来回回好几趟非常繁琐,相比之下,zygote和SystemServer进程本来就是父子关系,对于简单的消息通信,用管道或者socket非常方便省事。第二个原因,如果zygote启用binder机制,再fork出SystemServer,那么SystemServer就会继承了zygote的描述符以及映射的内存,这两个进程在binder驱动层就会共用一套数据结构,这显然是不行的,所以还得先给原来的旧的描述符关掉,再重新启用一遍binder机制,这个就是自找麻烦了。
android大致的启动三段式
进程启动 -> 准备工作 -> loop循环(接收消息,处理消息 socket,messagequeue消息,binder驱动发来的消息)
android 学习之 zygote作用
第二种解释:
怕父进程binder线程有锁,然后子进程的主线程一直在等其子线程(从父进程拷贝过来的子进程)的资源,但是其实父进程的子进程并没有被拷贝过来,造成死锁,所以fork不允许存在多线程。而非常巧的是Binder通讯偏偏就是多线程,所以干脆父进程(Zgote)这个时候就不使用binder线程。
Android Framework层学习——为什么SystemServer进程与Zygote进程通讯采用Socket而不是Binder

app_process进程解释:

在看网上技术博客的时候,你会发现有说到app_process进程的
Zygote是一个Native的应用程序,是由init进程根据init.rc文件中的配置项创建的,它最初的名字为“app_process”,这个名字是在Android.mk(路径为frameworks\base\cmds\app_process)文件中指定的,

LOCAL_MODULE:= app_process
include $(BUILD_EXECUTABLE)

在运行的过程中,app_process通过将自己的名字换成了“zygote”,就成了现在我们看到的zygote。
frameworks\base\cmds\app_process\app_main.cpp中

int main(int argc, char* const argv[])
{
    
    
    if (!LOG_NDEBUG) {
    
    
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
    
    
        argv_String.append("\"");
        argv_String.append(argv[i]);
        argv_String.append("\" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.string());
    }

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;

    // Everything up to '--' or first non '-' arg goes to the vm.
    //
    // The first argument after the VM args is the "parent dir", which
    // is currently unused.
    //
    // After the parent dir, we expect one or more the following internal
    // arguments :
    //
    // --zygote : Start in zygote mode
    // --start-system-server : Start the system server.
    // --application : Start in application (stand alone, non zygote) mode.
    // --nice-name : The nice name for this process.
    //
    // For non zygote starts, these arguments will be followed by
    // the main class name. All remaining arguments are passed to
    // the main method of this class.
    //
    // For zygote starts, all remaining arguments are passed to the zygote.
    // main function.
    //
    // Note that we must copy argument string values since we will rewrite the
    // entire argument block when we apply the nice name to argv0.
    //
    // As an exception to the above rule, anything in "spaced commands"
    // goes to the vm even though it has a space in it.
    const char* spaced_commands[] = {
    
     "-cp", "-classpath" };
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    bool known_command = false;

    int i;
    for (i = 0; i < argc; i++) {
    
    
        if (known_command == true) {
    
    
          runtime.addOption(strdup(argv[i]));
          ALOGV("app_process main add known option '%s'", argv[i]);
          known_command = false;
          continue;
        }

        for (int j = 0;
             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
             ++j) {
    
    
          if (strcmp(argv[i], spaced_commands[j]) == 0) {
    
    
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }

        if (argv[i][0] != '-') {
    
    
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
    
    
            ++i; // Skip --.
            break;
        }

        runtime.addOption(strdup(argv[i]));
        ALOGV("app_process main add option '%s'", argv[i]);
    }

    // Parse runtime arguments.  Stop at first unrecognized option.
    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;//设置进程名称为 zygote
        } 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()) {
    
    
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);

        if (!LOG_NDEBUG) {
          String8 restOfArgs;
          char* const* argv_new = argv + i;
          int argc_new = argc - i;
          for (int k = 0; k < argc_new; ++k) {
            restOfArgs.append("\"");
            restOfArgs.append(argv_new[k]);
            restOfArgs.append("\" ");
          }
          ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
        }
    } 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(), true /* setProcName */);
    }

    if (zygote) {
    
    
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
    
    
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
    
    
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}


Init.rc文件中zygote的配置:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    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 netd

app_process对应的源文件为App_main.cpp,它的main函数处理完传入的参数后,便将进程的名字改成了“zygote”,然后最重要的工作就交给了AppRuntime类的start方法:

set_process_name("zygote");
runtime.start("com.android.internal.os.ZygoteInit",startSystemServer ? "start-system-server": "");

AppRuntime类继承了AndroidRuntime类,并重载了onStarted、onZygoteInit和onExit函数。
Android启动流程------Zygote和Systemserver的分析

SystemServer,SystemService,SystemServiceManager,ServiceManager类

SystemServer:这个类 每执行到一个阶段都会调用SystemServiceManager的startBootPhase函数
我们下面看下SystemServiceManager的startBootPhase函数,它会把mServices中的service取出来,调用onBootPhase函数

SystemServiceManager:这个类只是管理各个service,用SystemServiceManager启动service的时候,会把service加入自己的链表。并且调用相应service的onStart函数。

SystemService:这个类一般是一些系统service来继承这个类。例PowerManagerService,其中实现了onStart和onBootPhase函数,其中publishBinderService函数是SystemService中的函数,最后是调用了ServiceManager.addService。
ServiceManager:这个类,是java层用来和servicemanager进程通信的

Zygote与system_server共存亡
system_server是一个很重要的进程,如果挂了,Zygote必须重启,如果不重启,手机就会进入假死的状态,手机黑屏,无声,无法跟用户交互等
system_server采用抛出异常和捕捉异常的方式启动,可以清除进程的堆栈,减少内存占用。
system_server与Zygote共存亡是通过父进程调用waitpid的方式监听子进程system_server的死亡,当子进程死亡的时候,父进程就自杀
Framework基础:源于异常的System_Server与受精卵Zygote的共存亡

Android系统的分层
在这里插入图片描述
android可以理解为一直循环处理消息的系统。

init进程

android\system\core\init\init.cpp

init.cpp中的main方法是其入口函数,主要做:
创建文件,挂载,初始化安全策略,初始化属性相关资源,解析init.rc文件,性能分析和执行其它进程
Android系统启动(二)-Init篇
Android系统启动分析(Init->Zygote->SystemServer->Home activity)

zygote进程:

可以理解为其是不断循环处理socket消息的进程。
1、开启虚拟机
2、注册JNI
3、创建Socket服务端
4、预加载资源、类、虚拟机实例
5、启动system_server进程
6、循环等待socket消息
当与system_server交互时,system_server是socket客户端,zygote是socket服务端。
zygote进程是由init进程启动的,init进程(linux中的1号进程)启动之后会在system/core/init/init.cpp中解析init.rc文件,init.rc文件路径

android/system/core/rootdir/init.rc

其中import导入部分

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

init.rc不再直接引入一个固定的文件,而是根据属性ro.zygote(ro.zygote的值是在mk文件中定义的,知道即可)的内容来引入不同的文件。因为Android 5.0以后开始支持64位程序,为了兼容32位和64位才这样定义。不同的zygote.rc内容大致相同,主要区别体现在启动的是32位,还是64位的程.init.zygote32_64.rc和init.zygote64_32.rc会启动两个进程,且存在主次之分。
在这里插入图片描述在system/core/rootdir/这个路径下还包括四个关于zygote的rc文件。分别是Init.zygote32.rc,Init.zygote32_64.rc,Init.zygote64.rc,Init.zygote64_32.rc。通过ro.zygote的定义来决定使用哪个文件。

  • init.zygote32.rc:zygote进程对应的执行程序是app_process(纯32bit模式)
  • init.zygote64.rc:zygote进程对应的执行程序是app_process64(纯64bit模式)
  • init.zygote32_64.rc:启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别是app_process32(主模式)、app_process64
  • init.zygote64_32.rc:启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别是app_process64(主模式)、app_process32

android/system/core/rootdir/Init.zygote32.rc文件中,代码如下:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main  #class是一个option,指定zygote服务的类型是main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system #socket关键字表示一个option。创建一个名为dev/socket/zygote,类型为stream,权限660的socket。
    onrestart write /sys/android_power/request_state wake #onrestart是一个option,说明在zygote重启时需要执行的command
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks //创建子进程时,向/dev/cpuset/foreground/tasks 写入pid

xx.rc文件中的语法规则。其中有许多service启动,这些service通常不是普通的服务,文档里面的称呼是daemon(守护进程).
所谓守护进程就是这些服务进程会在系统初始化时启动,并一直运行于后台,直到系统关闭时终止。
32位的 zygote进程对应的二进制文件是 /system/bin/app_process
开启一个x86即32位虚拟机,可以看到
在这里插入图片描述
zygote最初的名字是app_process,他对应的源代码是

android_8.0\frameworks\base\cmds\app_process\app_main.cpp

zygote原理分析
Android Zygote介绍
Android 8.0 系统启动流程之zygote进程(八)

system_server进程:

负责启动和管理framework,包含AMS,PMS,WMS等服务。
不断循环处理binder消息。当和app交互的时候,app是客户端,SystemServer是服务端。它一直在监听创建新进程请求,如果有请求,则向Zygote发送请求。和Zygote交互的时候SystemServer是socket客户端,Zygote是socket服务端。SystemServer进程调用Process.start向Zygote进程发送 fork进程的参数,由Zygote进程fork进程

App进程:

不断循环处理Message消息
Zygote是什么
Android系统启动(一)开篇

猜你喜欢

转载自blog.csdn.net/w690333243/article/details/104812850