一张图讲明白Property初始化过程

535 阅读5分钟

一、背景

在ARD11的移植过程中有同学,例如Camera模块,遇到了一些Property导致的问题,例如:

  • 有些属性值不是预期的值
  • 有些属性的值在Selinux打开和关闭的时候读取的值不一样
  • 有些属性值在代码里面有很多个设置不知道最终哪一个生效

众所周知,Property是Android系统中用途最广泛的机制之一,底层和上层都会用到,Property使用方便功能强大,全面系统的讲述Property也要花很大的篇幅,网上有大量的资源可以查看。本文不涉及Property的其他功能,仅仅针对前几天遇到的实际问题,仅仅局限在内置属性的初始化这个过程进行详细阐述。

二、Property初始化

2.1 Property的存储机制

Android系统中所有的Property是用map容器来存储的,map内部就是一颗红黑树(一种非严格意义上的平衡二叉树),所以这个存储机制很好的实现了Property的overide机制。只需要按照优先级从低到高依次加载属性文件就可以保证最后的结果是最高优先级的值。

在Android系统中,代码里面设置的所有的属性值,最终都会编译到一些文件中,然后保存在不同的文件中,在开机执行init进程中完成属性值的初始化。

2.2 Property的初始化流程

图中的给出的就是Darwin ARD11的所有内置属性的加载过程和属性值的代码产生过程。

加载过程就是按照优先级的从低到高的过程,即如果同一个属性的值在多个属性文件中存在,那最终生效的就是最后加载的那个文件里面的值,如果同一个属性的值在同一个属性文件出现多次则有效的是最后出现的那个值。

属性文件优先级:

/system/etc/prop.default < /system/build.prop < /system_ext/build.prop < /vendor/default.prop < /vendor/build.prop < /odm/etc/build.prop < /product/build.prop

属性值代码来源:

每一个属性文件中包含的属性值的是在编译过程中动态生成的,来源有编译脚本文件,指定的属性文件,Makefile里面编译变量的值。例如:

/system/build.prop文件中的属性值来源有如下几种:

  1. /build/make/tools/buildinfo_common.sh生成每个分区的build信息
  2. /build/make/tools/buildinfo.sh生成一些编译相关的动态的值如时间,版本等
  3. /device/qcom/qssi/system.prop高通预制的一些通用属性值
  4. /device/qcom/darwin_common/system.prop我司预制的一些属性值
  5. ADDITIONAL_BUILD_PROPERTIES编译变量里面添加的一些属性值

2.3 一个Property的赋值过程

下面按照上节属性的赋值原则,以vendor.camera.aux.packagelist为例看一下代码中一个实际的属性的赋值过程,这个属性在代码里面有多次赋值,我们看一下赋值的过程

  1. device/qcom/qssi/system.prop

vendor.camera.aux.packagelist=org.codeaurora.snapcam,com.android.camera2,com.qualcomm.qti.qmmi

---初始设置值,编译后位于/system/build.prop

  1. device/qcom/darwin_common/system.prop

vendor.camera.aux.packagelist=org.codeaurora.snapcam

---值被更新,编译后位于/system/build.prop

  1. vendor/smartisan/config/common_full_phone.mk

PRODUCT_PROPERTY_OVERRIDES += \

vendor.camera.aux.packagelist=org.codeaurora.snapcam,com.smartisan.factorytest,com.android.camera2

---再次更新,编译后位于/vendor/build.prop

整个的属性值的更新过程是在init进程中完成的,因此最终vendor.camera.aux.packagelist的值就应该是org.codeaurora.snapcam,com.smartisan.factorytest,com.android.camera2

2.4 Selinux对Property的赋值影响

在ARD11的移植过程中出现了Selinux打开和关闭,属性值不一样的情况,例如上例中在Selinux关闭的时候vendor.camera.aux.packagelist=org.codeaurora.snapcam,com.smartisan.factorytest,com.android.camera2

而在Selinux打开的时候

vendor.camera.aux.packagelist=org.codeaurora.snapcam

这是什么原因呢?原来从ARD10开始,Google对init进程的Selinux权限进行收紧,引入了vendor_init进程,用来执行vendor分区的属性加载和rc文件处理。所以需要给vendor_init添加对vendor.camera.aux.packagelist的设置权限。因为vendor.camera.aux.packagelist的selinux标签是vendor_persist_camera_prop,因此添加如下规则。

set_prop(vendor_init, vendor_persist_camera_prop)

这样在Selinux开和关的情况下,vendor.camera.aux.packagelist的值就都是

vendor.camera.aux.packagelist=org.codeaurora.snapcam,com.smartisan.factorytest,com.android.camera2

三、Property的修改规则

理解了Property的加载优先级和Selinux的规则,Property的添加和修改规则就很容易很灵活了。不过除非必须,我们没有必要刻意的给自己创造困难,目前Darwin里面除了编译自动生成的属性,odm和product里面并没有设置其他属性,因此放到vendor分区的属性值基本上就是最终的值了。简单来讲就是如下的原则

  1. 要添加修改到system分区的属性可以

    1. 修改device/qcom/darwin_common/system.prop
    2. 如果赋值根据编译变量变化,则在mk文件中使用编译变量ADDITIONAL_BUILD_PROPERTIES += ro.XXX=YYY
  2. 要添加修改到vendor分区的属性可以

    1. 在mk文件中使用编译变量

PRODUCT_PROPERTY_OVERRIDES += ro.XXX=YYY

  1. 如果需要在vendor_init.te里面添加Selinux规则set_prop(vendor_init, ZZZ)

四、FAQ

4.1 设置属性缺少Selinux权限是否有AVC Log?

因为设置Property的操作非常靠前,在Selinux的完整初始化以前,因此没有AVC的打印,并且在Linux的初始化阶段对打印输出的Log量有控制,打印太频繁了Log就不会输出了。所以之前属性设置出问题也始终无法找到任何出错记录。现在我已经在Userdebug版本里面,把这部分的打印给做了延迟处理,保证设置属性出错会有如下格式的打印,如果再有类似属性设置的问题,可以先查找一下kernel Log。

[ 26.294941] (3)[ 1|init ] init: Do not have permissions to set 'ro.product.cuptsm' to 'SMARTISAN|ESE|01|02' in property file '/vendor/build.prop': SELinux permission check failed

4.2 如何查看一个Property的Selinux标签?

getprop -Z XXXX,例如

darwin:/ # getprop -Z ro.product.cuptsm

u:object_r:default_prop:s0 ---这类属性无法通过selinux检查的,需要给这个属性添加一个标签

darwin:/ # getprop -Z vendor.camera.aux.packagelist

u:object_r:vendor_persist_camera_prop:s0