天天看点

Framework篇 - init.rc 与 ServiceManager 的启动和获取

Framework篇 - init.rc 与 ServiceManager 的启动和获取
本文源代码基于 Android 7.0。

目录:

  1. init.rc 和 init.c
  2. ServiceManager 的启动流程
  3. 获取 ServiceManager

1. init.rc 和 init.c

  • 1.1 init.rc
Linux 的重要特征之一就是一切都是以文件的形式存在的,例如,一个设备通常与一个或多个设备文件对应。这些与内核空间交互的文件都在用户空间,所以在 Linux 内核装载完,需要首先建立这些文件所在的目录。而完成这些工作的程序就是 init。Init 是一个命令行程序,其主要工作之一就是建立这些与内核空间交互的文件所在的目录。当 Linux 内核加载完后,要做的第一件事就是调用 init 程序。也就是说,init 是用户空间执行的第一个程序。

尽管 init 完成的工作不算很多,不过代码还是非常复杂的。Init 程序并不是由一个源代码文件组成的,而是由一组源代码文件的目标文件链接而成的。需要明白的是,init.rc 只是语法文件,并不是程序,真正的入口则是上面提到的 system/core/init/init.c。

init.rc 有两个,分别位于: 

  • ./system/core/rootdir/init.rc 
  • ./bootable/recovery/etc/init.rc 

这两个 init.rc 使用场景不一样,一个是刷机用到的,也就是进入 recorvery 模式,一个是正常启动用到的。

下面是 init.rc:

"【import <filename>一个init配置文件,扩展当前配置。】"
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.${ro.zygote}.rc
import /init.trace.rc

"【触发条件early-init,在early-init阶段调用以下行】"
on early-init
    # Set init and its forked children's oom_adj.
    write /proc/1/oom_score_adj -1000
    "【打开路径为<path>的一个文件,并写入一个或多个字符串】"
    # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
    write /sys/fs/selinux/checkreqprot 0

    # Set the security context for the init process.
    # This should occur before anything else (e.g. ueventd) is started.
    "【这段脚本的意思是init进程启动之后就马上调用函数setcon将自己的安全上下文设置为“u:r:init:s0”,即将init进程的domain指定为init。】"
    setcon u:r:init:s0

    # Set the security context of /adb_keys if present.
    "【恢复指定文件到file_contexts配置中指定的安全上线文环境】"
    restorecon /adb_keys

    "【执行start ueventd的命令。ueventd是一个service后面有定义】 "
    start ueventd

    "【mkdir <path> [mode] [owner] [group]   //创建一个目录<path>,可以选择性地指定mode、owner以及group。如果没有指定,默认的权限为755,并属于root用户和root组。】"
    # create mountpoints
    mkdir /mnt 0775 root system

on init
    "【设置系统时钟的基准,比如0代表GMT,即以格林尼治时间为准】"
    sysclktz 0

"【设置kernel日志等级】"
loglevel 6 ####
    write /proc/bootprof "INIT: on init start" ####

    "【symlink <target> <path>    //创建一个指向<path>的软连接<target>。】"
    # Backward compatibility
    symlink /system/etc /etc
    symlink /sys/kernel/debug /d

    # Right now vendor lives on the same filesystem as system,
    # but someday that may change.
    symlink /system/vendor /vendor

    "【创建一个目录<path>,可以选择性地指定mode、owner以及group。】"
    # Create cgroup mount point for cpu accounting
    mkdir /acct
    mount cgroup none /acct cpuacct
    mkdir /acct/uid

    "【mount <type> <device> <dir> [ <mountoption> ]   //在目录<dir>挂载指定的设备。<device> 可以是以 [email protected] 的形式指定一个mtd块设备。<mountoption>包括 ro、rw、remount、noatime、 ...】"
    # Create cgroup mount point for memory
    mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
    mkdir /sys/fs/cgroup/memory 0750 root system
    mount cgroup none /sys/fs/cgroup/memory memory
    write /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1
    "【chown <owner> <group> <path>   //改变文件的所有者和组。】"

    "【后面的一些行因为类似,就省略了】"
    .....

# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
    "【停止指定类别服务类下的所有已运行的服务】"
    class_stop charger
    "【触发一个事件,将该action排在某个action之后(用于Action排队)】"
    trigger late-init

# Load properties from /system/ + /factory after fs mount.
on load_all_props_action
    "【从/system,/vendor加载属性。默认包含在init.rc】"
    load_all_props

# Indicate to fw loaders that the relevant mounts are up.
on firmware_mounts_complete
    "【删除指定路径下的文件】"
    rm /dev/.booting

# Mount filesystems and start core system services.
on late-init
    "【触发一个事件。用于将一个action与另一个 action排列。】"
    trigger early-fs
    trigger fs
    trigger post-fs
    trigger post-fs-data

    # Load properties from /system/ + /factory after fs mount. Place
    # this in another action so that the load will be scheduled after the prior
    # issued fs triggers have completed.
    trigger load_all_props_action

    # Remove a file to wake up anything waiting for firmware.
    trigger firmware_mounts_complete

    trigger early-boot
    trigger boot


on post-fs
    ...
    "【一些创造目录,建立链接,更改权限的操作,这里省略】"

on post-fs-data
    ...
    "【一些创造目录,建立链接,更改权限的操作,这里省略】"

    "【恢复指定文件到file_contexts配置中指定的安全上线文环境】"
    restorecon /data/mediaserver

    "【将系统属性<name>的值设置为<value>,即以键值对的方式设置系统属性】"
    # Reload policy from /data/security if present.
    setprop selinux.reload_policy 1

    "【以递归的方式恢复指定目录到file_contexts配置中指定的安全上下文中】"
    # Set SELinux security contexts on upgrade or policy update.
    restorecon_recursive /data

    # If there is no fs-post-data action in the init.<device>.rc file, you
    # must uncomment this line, otherwise encrypted filesystems
    # won't work.
    # Set indication (checked by vold) that we have finished this action
    #setprop vold.post_fs_data_done 1

on boot
    "【初始化网络】"
    # basic network init
    ifup lo
    "【设置主机名为localhost】"
    hostname localhost
    "【设置域名localdomain】"
    domainname localdomain

    "【设置资源限制】"
    # set RLIMIT_NICE to allow priorities from 19 to -20
    setrlimit 13 40 40

    "【这里省略了一些chmod,chown,等操作,不多解释】"
   ...


    # Define default initial receive window size in segments.
    setprop net.tcp.default_init_rwnd 60

    "【重启core服务】"
    class_start core

on nonencrypted
    class_start main
    class_start late_start

on property:vold.decrypt=trigger_default_encryption
    start defaultcrypto

on property:vold.decrypt=trigger_encryption
    start surfaceflinger
    start encrypt

on property:sys.init_log_level=*
    loglevel ${sys.init_log_level}

on charger
    class_start charger

on property:vold.decrypt=trigger_reset_main
    class_reset main

on property:vold.decrypt=trigger_load_persist_props
    load_persist_props

on property:vold.decrypt=trigger_post_fs_data
    trigger post-fs-data

on property:vold.decrypt=trigger_restart_min_framework
    class_start main

on property:vold.decrypt=trigger_restart_framework
    class_start main
    class_start late_start

on property:vold.decrypt=trigger_shutdown_framework
    class_reset late_start
    class_reset main

on property:sys.powerctl=*
    powerctl ${sys.powerctl}

# system server cannot write to /proc/sys files,
# and chown/chmod does not work for /proc/sys/ entries.
# So proxy writes through init.
on property:sys.sysctl.extra_free_kbytes=*
    write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}

# "tcp_default_init_rwnd" Is too long!
on property:sys.sysctl.tcp_def_init_rwnd=*
    write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}

"【守护进程】"
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0

"【日志服务进程】"
service logd /system/bin/logd
    class core
    socket logd stream 0666 logd logd
    socket logdr seqpacket 0666 logd logd
    socket logdw dgram 0222 logd logd
    seclabel u:r:logd:s0

"【Healthd是android4.4之后提出来的一种中介模型,该模型向下监听来自底层的电池事件,向上传递电池数据信息给Framework层的BatteryService用以计算电池电量相关状态信息】"
service healthd /sbin/healthd
    class core
    critical
    seclabel u:r:healthd:s0

"【控制台进程】"
service console /system/bin/sh
    "【为当前service设定一个类别.相同类别的服务将会同时启动或者停止,默认类名是default】"
    class core
    "【服务需要一个控制台】"
    console
    "【服务不会自动启动,必须通过服务名显式启动】"
    disabled
    "【在执行此服务之前切换用户名,当前默认的是root.自Android M开始,即使它要求linux capabilities,也应该使用该选项.很明显,为了获得该功能,进程需要以root用户运行】"
    user shell
    seclabel u:r:shell:s0

on property:ro.debuggable=1
    start console

# adbd is controlled via property triggers in init.<platform>.usb.rc
service adbd /sbin/adbd --root_seclabel=u:r:su:s0
    class core
    "【创建一个unix域下的socket,其被命名/dev/socket/<name>. 并将其文件描述符fd返回给服务进程.其中,type必须为dgram,stream或者seqpacke,user和group默认是0.seclabel是该socket的SELLinux的安全上下文环境,默认是当前service的上下文环境,通过seclabel指定】"
    socket adbd stream 660 system system
    disabled
    seclabel u:r:adbd:s0

# adbd on at boot in emulator
on property:ro.kernel.qemu=1
    start adbd

"【内存管理服务,内存不够释放内存】"
service lmkd /system/bin/lmkd
    class core
    critical
    socket lmkd seqpacket 0660 system system

"【ServiceManager是一个守护进程,它维护着系统服务和客户端的binder通信。
在Android系统中用到最多的通信机制就是Binder,Binder主要由Client、Server、ServiceManager和Binder驱动程序组成。其中Client、Service和ServiceManager运行在用户空间,而Binder驱动程序运行在内核空间。核心组件就是Binder驱动程序了,而ServiceManager提供辅助管理的功能,无论是Client还是Service进行通信前首先要和ServiceManager取得联系。而ServiceManager是一个守护进程,负责管理Server并向Client提供查询Server的功能。】"
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    "【servicemanager 服务启动时会重启zygote服务】"
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm

"【Vold是Volume Daemon的缩写,它是Android平台中外部存储系统的管控中心,是管理和控制Android平台外部存储设备的后台进程】"
service vold /system/bin/vold
    class core
    socket vold stream 0660 root mount
    ioprio be 2

"【Netd是Android系统中专门负责网络管理和控制的后台daemon程序】"
service netd /system/bin/netd
    class main
    socket netd stream 0660 root system
    socket dnsproxyd stream 0660 root inet
    socket mdns stream 0660 root system
    socket fwmarkd stream 0660 root inet

"【debuggerd是一个daemon进程,在系统启动时随着init进程启动。主要负责将进程运行时的信息dump到文件或者控制台中】"
service debuggerd /system/bin/debuggerd
    class main

service debuggerd64 /system/bin/debuggerd64
    class main

"【Android RIL (Radio Interface Layer)提供了Telephony服务和Radio硬件之间的抽象层】"
# for using TK init.modem.rc rild-daemon setting
#service ril-daemon /system/bin/rild
#    class main
#    socket rild stream 660 root radio
#    socket rild-debug stream 660 radio system
#    user root
#    group radio cache inet misc audio log

"【提供系统 范围内的surface composer功能,它能够将各种应用 程序的2D、3D surface进行组合。】"
service surfaceflinger /system/bin/surfaceflinger
    class core
    user system
    group graphics drmrpc
    onrestart restart zygote

"【DRM可以直接访问DRM clients的硬件。DRM驱动用来处理DMA,内存管理,资源锁以及安全硬件访问。为了同时支持多个3D应用,3D图形卡硬件必须作为一个共享资源,因此需要锁来提供互斥访问。DMA传输和AGP接口用来发送图形操作的buffers到显卡硬件,因此要防止客户端越权访问显卡硬件。】"
#make sure drm server has rights to read and write sdcard ####
service drm /system/bin/drmserver
    class main
    user drm
    # group drm system inet drmrpc ####
    group drm system inet drmrpc sdcard_r ####

"【媒体服务,无需多说】"
service media /system/bin/mediaserver
    class main
    user root ####
#   google default ####
#   user media    ####
    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm media sdcard_r system net_bt_stack ####
#   google default ####
#   group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm ####

    ioprio rt 4

"【设备加密相关服务】"
# One shot invocation to deal with encrypted volume.
service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
    disabled
    "【当服务退出时,不重启该服务】"
    oneshot
    # vold will set vold.decrypt to trigger_restart_framework (default
    # encryption) or trigger_restart_min_framework (other encryption)

# One shot invocation to encrypt unencrypted volumes
service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
    disabled
    oneshot
    # vold will set vold.decrypt to trigger_restart_framework (default
    # encryption)

"【开机动画服务】"
service bootanim /system/bin/bootanimation
    class core
    user graphics
#    group graphics audio ####
    group graphics media audio ####
    disabled
    oneshot

"【在Android系统中,PackageManagerService用于管理系统中的所有安装包信息及应用程序的安装卸载,但是应用程序的安装与卸载并非PackageManagerService来完成,而是通过PackageManagerService来访问installd服务来执行程序包的安装与卸载的。】"
service installd /system/bin/installd
    class main
    socket installd stream 600 system system

service flash_recovery /system/bin/install-recovery.sh
    class main
    seclabel u:r:install_recovery:s0
    oneshot

"【vpn相关的服务】"
service racoon /system/bin/racoon
    class main
    socket racoon stream 600 system system
    # IKE uses UDP port 500. Racoon will setuid to vpn after binding the port.
    group vpn net_admin inet
    disabled
    oneshot

"【android中有mtpd命令可以连接vpn】"
service mtpd /system/bin/mtpd
    class main
    socket mtpd stream 600 system system
    user vpn
    group vpn net_admin inet net_raw
    disabled
    oneshot

service keystore /system/bin/keystore /data/misc/keystore
    class main
    user keystore
    group keystore drmrpc

"【可以用dumpstate 获取设备的各种信息】"
service dumpstate /system/bin/dumpstate -s
    class main
    socket dumpstate stream 0660 shell log
    disabled
    oneshot

"【mdnsd 是多播 DNS 和 DNS 服务发现的守护程序。】"
service mdnsd /system/bin/mdnsd
    class main
    user mdnsr
    group inet net_raw
    socket mdnsd stream 0660 mdnsr inet
    disabled
    oneshot

"【触发关机流程继续往下走】"
service pre-recovery /system/bin/uncrypt
    class main
    disabled
    "【当服务退出时,不重启该服务】"
    oneshot
           
  • 1.2 init.c
system/core/init/init.c

主要分析 main 方法:

int main( int argc, char **argv )
{
    #创 建一些linux根文件系统中的目录
    mkdir( "/dev", 0755 );
    mkdir( "/proc", 0755 );
    mkdir( "/sys", 0755 );

    mount( "tmpfs", "/dev", "tmpfs", 0, "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的 标准输入,标准输出,标准错误文件描述符定向到__null__,意味着没有输入和输出,它的输入和输出全部写入到Log中
    open_devnull_stdio();
    #初始化 log 写入init进 信息
    log_init();
    #读取并 且解析init.rc文件(这个文件在根目录下)
    parse_config_file( "/init.rc" );
    #取得硬件 为打印我们的设备名fs100
    get_hardware_name();
    snprintf( tmp, sizeof(tmp), "/init.%s.rc", hardware );
    #读取并 且解析硬件相关的init脚本文件,
    parse_config_file( tmp );
    #触发在init脚本文件中名字为early-init的action,并且执行其commands,其实是: on early-init
    action_for_each_trigger( "early-init", action_add_queue_tail );
    drain_action_queue();
    #初始化动态设备管理,设备文件有变化时反应给内核,后面具体解释
    device_fd = device_init(); # 初 始 化 设 备 管 理 务
    #加载启动动画,如果动画打开失败,则在屏幕上打印: A N D R O I D字样。
    if ( load_565rle_image( INIT_IMAGE_FILE ) )
    {
        fd = open( "/dev/tty0", O_WRONLY );
        if ( fd >= 0 )
        {
            const char *msg;
            msg = "\n"
                  "\n"
                  "\n"
                  879         "\n"
                  "\n"
                  "\n"
                  "\n" /* console is 40 cols x 30 lines */
                  "\n"
                  "\n"
                  "\n"
                  "\n"
                  "\n"
                  "\n"
                  "\n"
                  /* "             A N D R O I D ";开机动画 */
                  write( fd, msg, strlen( msg ) );
            close( fd );
        }
    }

    #触发 在init脚本文件中名字为init的action,并且执行其commands,其实是:on init
    action_for_each_trigger( "init", action_add_queue_tail );
    drain_action_queue();
    #启动系统属性服务: system property service
    property_set_fd = start_property_service();
    #创建socket用来处理孤儿进程信号
    if ( socketpair( AF_UNIX, SOCK_STREAM, 0, s ) == 0 )
    {
        signal_fd   = s[0];
        signal_recv_fd  = s[1];
        fcntl( s[0], F_SETFD, FD_CLOEXEC );
        fcntl( s[0], F_SETFL, O_NONBLOCK );
        fcntl( s[1], F_SETFD, FD_CLOEXEC );
        fcntl( s[1], F_SETFL, O_NONBLOCK );
    }
    #触发 在init脚本文件中名字为early-boot和boot的action,并且执行其commands,其实是:on early-boot和on boot
    action_for_each_trigger( "early-boot", action_add_queue_tail );
    action_for_each_trigger( "boot", action_add_queue_tail );
    drain_action_queue();
    #启动所有属性变化触发命令,其实是: on property:ro.xx.xx=xx
    queue_all_property_triggers();
    drain_action_queue();
    #进入 死循环()
    for (;; )
    {
    #启 动所有init脚本中声明的service,
    #如 :266 service servicemanager /system/bin/servicemanager
    #user system
    #critical
    #onrestart restart zygote
    #onrestart restart media
    restart_processes();
    #多路监听设备管理,子进程运行状态,属性服务
        nr = poll( ufds, fd_count, timeout );
        if ( nr <= 0 )
            continue;
        if ( ufds[2].revents == POLLIN )
        {
            read( signal_recv_fd, tmp, sizeof(tmp) );
            while ( !wait_for_one_process( 0 ) )
                ;
            continue;
        }

        if ( ufds[0].revents == POLLIN )
            handle_device_fd( device_fd );

        if ( ufds[1].revents == POLLIN )
            handle_property_set_fd( property_set_fd );
        if ( ufds[3].revents == POLLIN )
            handle_keychord( keychord_fd );
    }

    return(0);
}
           

2. ServiceManager 的启动流程

ServiceManager 是 Binder IPC 通信过程中的守护进程,本身也是一个 Binder 服务,但并没有采用 libbinder 中的多线程模型来与 Binder 驱动通信, 而是自行编写了 binder.c 直接和 Binder 驱动来通信,并且只有一个循环 binder_loop 来进行读取和处理事务,这样的好处是简单而高效。

ServiceManager 本身工作相对简单,其功能:查询和注册服务。对于 Binder IPC 通信过程中,其实更多的情形是 BpBinder 和BBinder 之间的通信, 比如 ActivityManagerProxy 和 ActivityManagerService 之间的通信等。

ServiceManager 是由 init 进程通过解析 init.rc 文件而创建的,其所对应的可执行程序 /system/bin/servicemanager, 所对应的源文件是 service_manager.c,进程名为 /system/bin/servicemanager。

  • 2.1 servicemanager.rc
native/cmds/servicemanager/servicemanager.rc

Android 7.0 中独立出了 servicemanager.rc: 

service servicemanager /system/bin/servicemanager
    class core
    user system
    group system readproc
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart audioserver
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart inputflinger
    onrestart restart drm
    onrestart restart cameraserver
    writepid /dev/cpuset/system-background/tasks
           
  • 2.2 service_manager.c 与 binder.c

native/cmds/servicemanager/service_manager.c

native/cmds/servicemanager/binder.c

看看 service_manager.c 的 main():

int main()
{
    // binder 状态
    struct binder_state *bs;
    // 第一步,打开binder驱动,申请128k字节大小的内存空间,会调用binder.c里面的binder_open函数
    bs = binder_open(128*1024);
    if (!bs) {
        ALOGE("failed to open binder driver\n");
        return -1;
    }
    // 成为上下文管理者
    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }
    // selinux权限是否使用
    selinux_enabled = is_selinux_enabled();
    sehandle = selinux_android_service_context_handle();
    selinux_status_open(true);

    if (selinux_enabled > 0) {
        if (sehandle == NULL) {
            ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
            // 无法获取sehandle
            abort();
        }

        if (getcon(&service_manager_context) != 0) {
            ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
            // 无法获取service_manager上下文
            abort();
        }
    }

    union selinux_callback cb;
    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
    cb.func_log = selinux_log_callback;
    selinux_set_callback(SELINUX_CB_LOG, cb);

    // 进入无限循环,处理client端发来的请求
    // 进入循环读写操作,由main()方法传递过来的参数func指向svcmgr_handler。
    binder_loop(bs, svcmgr_handler);

    return 0;
}
           

ServiceManager 的启动过程总结为:

  • 打开 binder 驱动:binderopen;
  • 注册成为 binder 服务的大管家:binderbecomecontextmanager;
  • 进入无限循环,处理 client 端发来的请求:binder_loop。

binderopen (位于 binder.c):

// binder状态结构
struct binder_state
{
    int fd; // dev/binder的文件描述符
    void *mapped; // 指向mmap的内存地址
    size_t mapsize; // 分配的内存大小,默认为128KB
};

// service_manager.c会调用binder.c里面的binder_open函数
// 打开binder驱动
struct binder_state *binder_open(size_t mapsize)
{
    // binder状态
    struct binder_state *bs;
    // binder版本
    struct binder_version vers;

    bs = malloc(sizeof(*bs));
    if (!bs) {
        errno = ENOMEM;
        return NULL;
    }
    // 通过系统调用陷入内核,打开Binder设备驱动
    // 打开/dev/binder,文件描述符
    bs->fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open device (%s)\n",
                strerror(errno));
        goto fail_open;
    }
    // 通过系统调用,ioctl获取binder版本信息
    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
        // 内核空间与用户空间的binder不是同一版本
        fprintf(stderr,
                "binder: kernel driver version (%d) differs from user space version (%d)\n",
                vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
        // goto 到fail_open代码块
        goto fail_open;
    }

    bs->mapsize = mapsize;
    // 通过系统调用,mmap内存映射,mmap必须是page的整数倍
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    if (bs->mapped == MAP_FAILED) {
        // binder设备内存无法映射
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }

    return bs;

fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return NULL;
}

// 关闭binder
void binder_close(struct binder_state *bs)
{
    munmap(bs->mapped, bs->mapsize);
    close(bs->fd);
    free(bs);
}
           

binder_become_context_manager (位于 binder.c):

// 成为上下文的管理者,整个系统中只有一个这样的管理者。 通过ioctl()方法经过系统调用,对应于Binder驱动层的binder_ioctl()方法.
int binder_become_context_manager(struct binder_state *bs)
{
    // 通过ioctl,传递BINDER_SET_CONTEXT_MGR指令
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
           

 binder_loop (位于 binder.c):

// 开启binder循环,监听客户端请求
void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    uint32_t readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;

    readbuf[0] = BC_ENTER_LOOPER;
     // 将BC_ENTER_LOOPER命令发送给binder驱动,让Service Manager进入循环
     // binder_write通过ioctl()将BC_ENTER_LOOPER命令发送给binder驱动,此时bwr只有write_buffer有数据,
     // 进入binder_thread_write()方法。 接下来进入for循环,执行ioctl(),此时bwr只有read_buffer有数据,
     // 那么进入binder_thread_read()方法。
    binder_write(bs, readbuf, sizeof(uint32_t));

    // 一个无限循环
    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;

        // 进入循环,不断地binder读写过程
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

        if (res < 0) {
            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }
        // 解析binder信息,会交由binder_handler(func)处理, parse里面有transaction各种函数
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        if (res == 0) {
            ALOGE("binder_loop: unexpected reply?!\n");
            break;
        }
        if (res < 0) {
            ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
            break;
        }
    }
}
           

binder_loop 中的 binder_parse (位于 binder.c): 

// for循环里的binder_parse
// 解析binder信息,此处参数ptr指向BC_ENTER_LOOPER,func指向svcmgr_handler。故有请求到来,则调用svcmgr_handler。
int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uintptr_t ptr, size_t size, binder_handler func)
{
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;

    while (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);
#if TRACE
        fprintf(stderr,"%s:\n", cmd_name(cmd));
#endif
        switch(cmd) {
        // 无操作,退出循环
        case BR_NOOP:
            break;
        // transaction完成
        case BR_TRANSACTION_COMPLETE:
            break;
        case BR_INCREFS:
        case BR_ACQUIRE:
        case BR_RELEASE:
        case BR_DECREFS:
#if TRACE
            fprintf(stderr,"  %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *)));
#endif
            ptr += sizeof(struct binder_ptr_cookie);
            break;
        // binder transaction消息
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            if ((end - ptr) < sizeof(*txn)) {
                ALOGE("parse: txn too small!\n");
                return -1;
            }
            binder_dump_txn(txn);
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;

                bio_init(&reply, rdata, sizeof(rdata), 4);
                // 从txn解析出binder_io信息
                bio_init_from_txn(&msg, txn);
                res = func(bs, txn, &msg, &reply);
                if (txn->flags & TF_ONE_WAY) {
                    binder_free_buffer(bs, txn->data.ptr.buffer);
                } else {
                    // binder发送回复
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
            }
            ptr += sizeof(*txn);
            break;
        }
        case BR_REPLY: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            if ((end - ptr) < sizeof(*txn)) {
                ALOGE("parse: reply too small!\n");
                return -1;
            }
            binder_dump_txn(txn);
            if (bio) {
                bio_init_from_txn(bio, txn);
                bio = 0;
            } else {
                /* todo FREE BUFFER */
            }
            ptr += sizeof(*txn);
            r = 0;
            break;
        }
        // binder死亡消息
        case BR_DEAD_BINDER: {
            struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;
            ptr += sizeof(binder_uintptr_t);
            death->func(bs, death->ptr);
            break;
        }
        case BR_FAILED_REPLY:
            r = -1;
            break;
        case BR_DEAD_REPLY:
            r = -1;
            break;
        default:
            ALOGE("parse: OOPS %d\n", cmd);
            return -1;
        }
    }

    return r;
}
           

解析 binder 信息,此处参数 ptr 指向 BC_ENTER_LOOPER,func 指向 svcmgr_handler。故有请求到来,则调用svcmgr_handler。svcmgr_handler 位于 service_manager.c:

// 该方法的功能:查询服务,注册服务,以及列举所有服务
int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;

    //ALOGI("target=%p code=%d pid=%d uid=%d\n",
    //      (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);

    if (txn->target.ptr != BINDER_SERVICE_MANAGER)
        return -1;

    if (txn->code == PING_TRANSACTION)
        return 0;

    // Equivalent to Parcel::enforceInterface(), reading the RPC
    // header with the strict mode policy mask and the interface name.
    // Note that we ignore the strict_policy and don't propagate it
    // further (since we do no outbound RPCs anyway).
    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);
    if (s == NULL) {
        return -1;
    }

    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        fprintf(stderr,"invalid id %s\n", str8(s, len));
        return -1;
    }

    if (sehandle && selinux_status_updated() > 0) {
        struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
        if (tmp_sehandle) {
            selabel_close(sehandle);
            sehandle = tmp_sehandle;
        }
    }

    switch(txn->code) {
    // 获取和检查服务
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        // 根据名称查找相应服务,s为服务名
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        // 当找到服务的handle, 则调用bio_put_ref(reply, handle),将handle封装到reply.
        bio_put_ref(reply, handle);
        return 0;

    // 注册服务
    case SVC_MGR_ADD_SERVICE:
        // 服务名
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        // 注册指定服务
        if (do_add_service(bs, s, len, handle, txn->sender_euid,
            allow_isolated, txn->sender_pid))
            return -1;
        break;
    // 获取服务列表
    case SVC_MGR_LIST_SERVICES: {
        uint32_t n = bio_get_uint32(msg);

        if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
            ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
                    txn->sender_euid);
            return -1;
        }
        si = svclist;
        while ((n-- > 0) && si)
            si = si->next;
        if (si) {
            bio_put_string16(reply, si->name);
            return 0;
        }
        return -1;
    }
    default:
        ALOGE("unknown code %d\n", txn->code);
        return -1;
    }

    bio_put_uint32(reply, 0);
    return 0;
}
           

可以看到包含注册服务和获取服务,关于 ServiceManager 如何注册和获取服务,将在下一篇文章中详细讲解。

ServiceManager 启动流程:
  • 打开 binder 驱动,并调用 mmap() 方法分配 128k 的内存映射空间:binder_open();
  • 通知 binder 驱动使其成为守护进程:binder_become_context_manager();
  • 验证 selinux 权限,判断进程是否有权注册或查看指定服务;
  • 进入循环状态,等待 Client 端的请求:binder_loop()。

注册服务的过程,根据服务名称,但同一个服务已注册,重新注册前会先移除之前的注册信息。

死亡通知:当 binder 所在进程死亡后,会调用 binder_release 方法,然后调用 binder_node_release,这个过程便会发出死亡通知的回调。

ServiceManager 最核心的两个功能为查询和注册服务:

  • 注册服务:记录服务名和 handle 信息,保存到 svclist 列表;
  • 查询服务:根据服务名查询相应的的 handle 信息。

3. 获取 ServiceManager

获取 ServiceManager 是通过 defaultServiceManager() 方法来完成,当进程注册服务 (addService) 或获取服务 (getService) 之前,都需要先调用 defaultServiceManager() 方法来获取 gDefaultServiceManager 对象。对于 gDefaultServiceManager 对象,如果存在则直接返回;如果不存在则创建该对象,创建过程包括调用 open() 打开 binder 驱动设备,利用 mmap() 映射内核的地址空间。

native/libs/binder/IServiceManager.cpp

native/libs/binder/ProcessState.cpp

native/libs/binder/BpBinder.cpp

native/libs/binder/Binder.cpp

// 命名空间 android
namespace android {
// 获取default ServiceManager
sp<IServiceManager> defaultServiceManager()
{
    // 如果已经存在,则直接返回
    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;

    {
        // 加锁
        AutoMutex _l(gDefaultServiceManagerLock);
        // 一个循环, 每次睡眠1秒,如果没有获取到,则继续等,因为获取时,可能ServiceManager还没有创建完
        while (gDefaultServiceManager == NULL) {
            // 用于获取ProcessState对象(也是单例模式),每个进程有且只有一个ProcessState对象,存在则直接返回,不存在则创建
            // 用于获取BpBinder对象,对于handle=0的BpBinder对象,存在则直接返回,不存在才创建
            // interface_cast用于获取BpServiceManager对象
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));
            if (gDefaultServiceManager == NULL)
                sleep(1);
        }
    }

    return gDefaultServiceManager;
}
// ...
}
           

获取 ServiceManager 对象采用单例模式,当 gDefaultServiceManager 存在,则直接返回,否则创建一个新对象。 

发现与一般的单例模式不太一样,里面多了一层 while 循环,这是 Google 在2013年1月 Todd Poynor 提交的修改。

当尝试创建或获取 ServiceManager 时,ServiceManager 可能尚未准备就绪,这时通过sleep 1 秒后,循环尝试获取直到成功。

native/libs/binder/ProcessState.cpp 的 self():

sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    // 实例化ProcessState
    gProcess = new ProcessState;
    return gProcess;
}
           

ProcessState::self():用于获取 ProcessState 对象 (也是单例模式),每个进程有且只有一个 ProcessState 对象,存在则直接返回,不存在则创建。

ProcessState 构造器:

// 初始化ProcessState
// ProcessState的单例模式的惟一性,因此一个进程只打开binder设备一次,其中ProcessState的成员变量mDriverFD记录binder驱动的fd,用于访问binder设备。
ProcessState::ProcessState()
    : mDriverFD(open_driver()) // 打开Binder驱动
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) // DEFAULT_MAX_BINDER_THREADS = 15,binder默认的最大可并发访问的线程数为16。
    , mStarvationStartTimeMs(0)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        // 采用内存映射函数mmap,给binder分配一块虚拟地址空间,用来接收事务
        // BINDER_VM_SIZE = (1*1024*1024) - (4096 *2), binder分配的默认内存大小为1M-8k。
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
            close(mDriverFD);
            mDriverFD = -1;
        }
    }

    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}
           

native/libs/binder/ProcessState.cpp 的 getContextObject():

// 获取handle=0的IBinder
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}
           

defaultServiceManager  等价于 new BpServiceManager(new BpBinder(0));

ProcessState::self() 主要工作:

  • 调用 open(),打开 /dev/binder 驱动设备;
  • 再利用 mmap(),创建大小为 1M-8K 的内存地址空间;
  • 设定当前进程最大的最大并发 Binder 线程个数为16;

BpServiceManager 巧妙将通信层与业务层逻辑合为一体,通过继承接口 IServiceManager 实现了接口中的业务逻辑函数;

通过成员变量 mRemote = new BpBinder(0) 进行 Binder 通信工作;

BpBinder 通过 handler 来指向所对应 BBinder,在整个 Binder 系统中 handle=0 代表 ServiceManager 所对应的 BBinder。

继续阅读