Init属性服务

系统属性服务

属性梳理

来源和读取时机

  1. 来源:内核参数

ro.kernel.*   代表有qemu内核参数才会设置(在虚拟机中)

ro.boot.*     1.内核设备树相关的设备属性,从 /proc/cmdline 的androidboot.* 中来

2.内部变量export_kernel_boot_props()中有个默认值表,当内核所给出的属性如ro.boot.serialno没有值时,那么ro.serialno的默认值将是表中给出的

  1. 来源:属性文件

ctl.* 一般用于IPC,如ctl.bootanim 开机动画,这种不会在读取/property_contexts 后,加入到 contexts集合中(控制消息不持久化记录,通过ctl.action=servername 的servername用ServiceManager::GetInstance().FindServiceByName(servername)找到对应的Service* 对象,然后根据action是 start stop restart 分别调用Service* 对应的函数)

PROP_PATH_* 的5个地方的 多个.prop 文件,这5个地方的多个属性文件主要分为3类。

1. PROP_PATH_RAMDISK_DEFAULT 在属性服务初始化的时候加载,

2. property_service_init_action() 打开属性服务,读取 PROP_PATH_SYSTEM_BUILD,PROP_PATH_SYSTEM_DEFAULT

3. 还有用户的 持久化属性PROP_PATH_LOCAL_OVERRIDE (可以通过 init.rc 中定义的 on property:vold.decrypt=trigger_load_persist_props load_persist_props   这个action来触发该类属性文件的读取)

Persist.* 需要持久化记录的,记录文件在PROP_PATH_LOCAL_OVERRIDE =  /data/property/属性名,  例如:  persist.sys.usb.config  , persist.sys.timezone 时区设置

  1. 来源:.rc文件中的action调用setprop命令设置

在init.rc 中的 on boot 里定义了setprop sys.usb.state $sys.usb.config 等

  1. 来源: 其他程序调用setprop

Init进程的set_init_properties_action() 中设置了一些 ro.* 的只读属性

system—properties属性服务的规则

只有1个写入者,多个读取者

Prop_area.count 永远不会减小值

一旦分配完成,prop_info 的name不会改变

一旦分配完成,prop_info 的offset不会改变

关于读取值相关的步骤:

  1. Serial = pi->serial
  2. if SERIAL_DIRTY(serial),wait*,然后执行第1步
  3. Memcpy(local, pi->value, SERIAL_VALUE_LEN(serial) + 1)
  4. If pi->serial != serial , 执行第2步

关于写入值的步骤:

  1. Pi->serial = pi->serial | 1
  2. Memcpy(pi->value, local_value, value_len)
  3. Pi->serial = (value_len << 24) | ((pi->serial + 1) & 0xffffff)

Property_set_impl()的实现

Selinux.reload_policy 等特殊的值不允许重复设置为1

__system_property_find(name) 找到 prop_info *的指针地址

get_prop_area_for_name(name)

list_find(prefixes,…)遍历匹配给定name的prefix_node 的指针,没有就返回null,然后访问context属性,然后访问pa方法获得 prop_area*,也就是在/dev/__propertes__/xxxx 中在tmpfs文件系统里映射到RAM的那块文件的内存地址。然后调用prop_area->find(name),内部实际上调用了find_property()

find_property() 从整个root_node() 的一个 trie(字典/二叉树混合结构)中查找属性,数据类型是prop_area,这个树的内存地址在data_,返回时被强制转换为 struct prop_bt*

如果已存在,那么用 __system_property_update() 更新值(本质是memcpy value 到 pi->value),否则用 __system_property_add() 添加新的

查找某个属性值的过程:key char *name -> __system_property_find(name) ->                                              prop_info*

get_prop_area_for_name(name) ->                                                prop_area.find(name)

list_find(prefixes,…) -> prefix_node -> prefix_node.context  ->  context_node.pa()

经历的数据结构变迁:

key == char -> prefix_node -> context_node -> prop_area -> prop_info -> prop_info.value == char == value

__system_property_add()

prop_area* get_prop_area_for_name()   * ?

context_node::open()

map_prop_area()

如何新增的?

Init管理service

关于服务的状态有这几种情况

66#define SVC_DISABLED    0x01  /* do not autostart with class */

67#define SVC_ONESHOT     0x02  /* do not restart on exit */

68#define SVC_RUNNING     0x04  /* currently active */

69#define SVC_RESTARTING  0x08  /* waiting to restart */

70#define SVC_CONSOLE     0x10  /* requires console */

71#define SVC_CRITICAL    0x20  /* will reboot into recovery if keeps crashing */

72#define SVC_RESET       0x40  /* Use when stopping a process, but not disabling

73                                 so it can be restarted with its class */

74#define SVC_RC_DISABLED 0x80  /* Remember if the disabled flag was set in the rc script */

可以用位域组合

运行状态标记 SVC_RUNNING

这些状态flag 在 .rc 文件中 一个service可以通过对应的OPTION 来设置

服务所指定的program什么时候被调用?

等于是 service_start() 函数什么时候执行,服务什么时候被启动?

从状态常量中,看出有一些启动方式

  1. 通过class自动启动(在某个action被触发时,如果定义了calss_start [class分组名称] 这条命令,则会对该组内所有符合条件的service进行启动)
  2. 某些 trigger触发action(如init.c中代码里固定的trigger,或某个.rc中的某个action下定义的start命令也可以触发),然后通过命令 start启动服务
  3. 在退出时自动(由init)重启(通过init接受到signal,设置service的运行状态, init最后死循环中检测需要重启的服务)
  4. 通过属性服务的控制命令 ctl.start/stop/restart 来启动服务,最后进入init中的msg_start()(命令可能由zygote进程通过命令socket接受后,并通过/bin/start可执行文件发出)

服务执行的本质是init调用fork后子进程execv服务指定的可执行文件

一个服务启动前的准备工作:

  1. 清除service对象的 (SVC_DISABLED|SVC_RESTARTING|SVC_RESET) 标志
  2. time_started = 0,重置运行时长
  3. 如果需要console则打开/dev/console 并dup 到 0,1,2
  4. Fork()

子进程:

  1. 属性初始化 properties_inited(),init_property_area(); 重新读取 PROP_PATH_RAMDISK_DEFAULT 的属性
  2. 设置服务用 setenv 设置的环境变量
  3. 创建服务用 socket 设置的域socket (socket <name> <type> <perm> [ <user> [ <group> ] ])
  4. 如果需要console 则设置 setsid() 设置session 和 group id ,让当前进程成为单独的一个会话,作为这个会话的前台进程,单独接受这个console的io
  5. Setpgid(0,getpid()) 设置当前进程的 pgid为当前pid,与init进程的进程组独立开来
  6. 将服务用 gid 设置的参数,用gid(参数) 设置,然后 group,uid。。。
  7. execve() ,执行指定镜像

Calss 的类别主要定义有core,main。。。

Core 和 main主要是在 on boot时启动

Core有 ueventd,adbd,servicemanager等

Main有netd,zygote,bootanimation,installd,keystore等

Default一般用在recover上

其他的初始化

keychord_init

遍历每个service 调用 add_service_keycodes(),问每个服务是否有使用多点触摸的要求,有的话就把 svc->keychord 加入到 keychords 列表中

然后打开/dev/keychord 一次性写入 keychords 配置信息

Console本质是把 /dev/consle 的fd 作为fork后的service的 STDOUT(0) STDIN(1) STDERR(2)

接下来分析几个主要的服务

Servicemanager

Zygote

Zygote – System_server(和Servicemanager有什么关系)

几个主要进程的启动顺序和角色 (还有主要函数)

看图:

 

android 启动流程 相关2 init进程 属性服务的更多相关文章

  1. android 启动流程 相关 杂项记录

    Android原生流程 Init进程 主要流程及分支梳理 ueventd_main()watchdogd_main()主要流程a) 公共部分 增加PATH 环境变量初始化内核日志,打开/dev/kms ...

  2. 内核启动流程3--Busybox的init进程

    Busybox是用来制作文件系统的一个工具集,可以用来替换GNU fileutils shellutils等工具集,它为各种小型的或者嵌入式系统提供了比较完全的工具集. 它提供的核心程序中包括了用户空 ...

  3. Android 启动流程分析

    原文:https://www.jianshu.com/p/a5532ecc8377 作者曾经在高通的Android性能组工作,主要工作是优化Android Application的启动时间. APP基 ...

  4. 深入浅出 - Android系统移植与平台开发(四)- Android启动流程

    作者:唐老师,华清远见嵌入式学院讲师. 一.Android init进程启动 还是从Linux的启动开始吧.Linux被bootloader加载到了内存之后,开始运行,在初始化完 Linux运行环境之 ...

  5. Tiny4412 Android 启动流程

    Android系统的启动主要包括三个阶段: ①BootLoader启动 ②Linux Kernel启动 ③Android系统启动 前面我们大致分析了前面两个步骤,即u-boot和内核的启动流程(内核启 ...

  6. Android启动流程

    Android是一个基于Linux的开源操作系统.x86(x86是一系列的基于intel 8086 CPU的计算机微处理器指令集架构)是linux内核部署最常见的系统.然而,所有的Android设备都 ...

  7. android 启动流程

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha adb shell 后  用 ps 命令 回车 可以看到 运行的进程. 如下结果: ct ...

  8. Android N 的开机启动流程概述

    原地址:https://blog.csdn.net/h655370/article/details/77727554 图片展示了Android的五层架构,从上到下依次是:应用层,应用框架层,库层,运行 ...

  9. Android解析ActivityManagerService(一)AMS启动流程和AMS家族

    前言 此前在Android系统启动流程.应用进程以及深入四大组件这三个系列文章中,都提及到了AMS,但都没有系统的来讲解它,本文就以AMS为主来进行讲解,其中会有一些知识点与这些系列文章有所重合,这里 ...

随机推荐

  1. 【JS】285- 拆解 JavaScript 中的异步模式

    JavaScript 中有很多种异步编程的方式.callback.promise.generator.async await 甚至 RxJS.我最初接触不同的异步模式时,曾想当然的觉得 promise ...

  2. 国内加速git下载速度

    主要是配置hosts文件 151.101.72.133 assets-cdn.github.com151.101.73.194 github.global.ssl.fastly.net192.30.2 ...

  3. 开启html元素的编辑模式contenteditable="true"

    开启html元素的编辑模式contenteditable="true"

  4. 双重检查锁单例模式为什么要用volatile关键字?

    前言 从Java内存模型出发,结合并发编程中的原子性.可见性.有序性三个角度分析volatile所起的作用,并从汇编角度大致说了volatile的原理,说明了该关键字的应用场景:在这补充一点,分析下v ...

  5. NodeJS4-8静态资源服务器实战_构建cli工具

    Cli(command-line interface),中文是 命令行界面,简单来说就是可以通过命令行快速生成自己的项目模板等功能(比较熟悉的是vue-cli脚手架这些),把上述写的包做成Cli工具. ...

  6. 牛客国庆集训派对Day1 L New Game!(堆优化dijkstra+建图)

    链接:https://ac.nowcoder.com/acm/contest/201/L来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 1048576K,其他语言2097 ...

  7. return之为什么能够终止函数,代码演练

    ''' return 有终止函数的作用,下面通过执行到return x 以后, 就结束了程序的下一步执行,所以就没有往下面走,所以终端上也就只能 看到打印结果100,看不到打印呢 ''' def se ...

  8. MySql全文检索使用详解

    实际项目中经常会有一个字段存储多个值用逗号分隔的场景,当分开查询的时候,使用模糊查询会非常影响效率.mysql提供了全文检索函数可以有效解决这一问题: 1.数据结构 ID CODE MSG 1 111 ...

  9. 一起学MyBatis之入门篇(2)

    概述 本文主要讲解MyBatis中类型转换的功能,其实在MyBatis中,提供了默认的数据类型之间的转换,但只是基本数据类型的转换,如果跨类型进行转换,则需要自定义转换类,如java中是boolean ...

  10. git到GitHub的操作和遇到的一些问题

    一.新建完项目后执行git git status //查看状态,任何时候都可以用 1. git init //初始化文件夹,并创建.git本地仓库(.git默认隐藏) 2. git add . //把 ...