版本:Rev 0.6
文档内容拷贝自:
codebase_host/yunhal/opendoc/zh/user_guide/system_configurable.md
联系人: 王作省 (zuosheng.wzs@alibaba-inc.com
)注意:本文将尽可能将Syscap实现原理精简化,但因为有些细节必须讲清楚,所以篇幅会稍长。若读者优先关心如何实现本模块的参数化配置,建议直接跳到 <样例:powerd模块> 参考具体实现,再回过头来看原理的信息。
Syscap
是基于 parameter framework 实现,用于表征 YunOS 系统硬件能力和特性的组织形式,实现系统功能和特性的可配置化。Syscap主要将整体分为 HWCapability 和 OSCapability 两类,分别描述系统的硬件能力的配置和OS Framework的能力。期望能通过清晰的结构化形式,方便厂商和系统服务开发者们配置和访问系统各项属性,并将参数调优工作从代码逻辑的层面抽取出来,便于动态调整。
Syscap采用的XML结构化方式主要分为两部分,即为 Schema 和 Config 。其中,_Schema_ 相当于表述系统特性和模块能力的属性列表,包括 HWCapability 中描述系统各部分所有属性的汇总,也包括 OSCapability 中各个模块自有的多种属性,但它并不涉及每项属性默认的参数设定,这项工作主要在*Config* 中完成。在 Config 中可以根据平台需求,选择暴露 Schema 描述中的一部分属性,然后指定默认值形成Key-Value的对应关系。另外,根据参数数值的不同,可以明确指定其数据类型,比如整型,布尔型,浮点型或者字符串等类型,当然也可以添加 ArrayLength 字段使之增强为对应的类型数组,比如整型数组,浮点数组等。
续前文介绍,配置化文档存放于[codebase_host]/vendor/sprd/sc9832_n/syscap
文件夹里,结构组织如下表所示。在 syscap_entry.xml 文件中,指定了包含各 Schema 和 Config 文件的相对路径以及层次关系,在访问程序中作为解析所有关联配置文件的 唯一入口。系统里所有的 Schema 配置信息全部由 syscap_schemas.xml 文件展开,容易注意到 HWCapability 和 OSCapability 分别以两个不同的 Virtual Subsystem 形式存在;而所有的 Config 文件都将逐一包含在 syscap_configs.xml 中,然后分别在各自的ConfigurableDomain
域中按规则设定。
[syscap] └── syscap_entry.xml ├── syscap_schemas.xml ├── syscap_configs.xml ├── [hwcapability] │ ├── syscap_schemas_hw_all.xml │ └── syscap_configs_hw_all.xml └── [oscapability] ├── syscap_schemas_os_powerd.xml ├── syscap_configs_os_powerd.xml ├── syscap_schemas_os_audio.xml └── syscap_configs_os_audio.xml
有了这些描述文件,大家可能会一直有这样的疑问:到底如何访问到系统的每个属性呢?其实,系统的属性都以类似于文件系统路径的形式存在,比如Sensor模块是否支持light sensor,就可以用 /syscap/hw/sensor/LightSensorSupported
访问到。这里每一级路径对应于Schema中的各级描述,分别有/syscap/
(*SystemClass*), hw/
(*Subsystem*), sensor/
(*ComponentType*), LightSensorSupported
(*BooleanParameter*),并可以根据实际情况可以将 ComponentType 这级扩展成 1…N 级,形成层次化的描述。
接下来,我们再看看具体的实现:
SystemClass
,名字为syscap
Subsystem
,名字分别为os
和hw
,都将由各个硬件模块构成。其中Subsystem: hw
以SubsystemInclude
的方式被包含,实际定义在syscap_schemas_hw_all.xml文件里,主要用于覆盖系统里所有模块的hwcapability;Subsystem: os
则在直接定义后,将逐一包含系统多个模块的Schema
规则。另外,每个Subsystem
又包含:ComponentLibrary
和 InstanceDefinition
,此两者皆只能有一组,但是范围域包含的元素可以有多个。
ComponentLibrary
(等价的有ComponentTypeSet
)中可包含1个到多个ComponentType
,可理解为 属性组 的概念ComponentType
又可以包含多个 子属性组 ,以Component
标签表示;或者可以直接包含1到多个 属性 ,以BooleanParameter
, IntegerParameter
, EnumParameter
, FixedPointParameter
, StringParameter
等形式组织,在这些属性的描述中增加 ArrayLength
字段可使之支持数组形式的数据InstanceDefinition
域中可包含多个Component
用于 实例化 表示上述的ComponentType
,相当于文件系统中增加某个文件夹节点,如上例中的sensor
ConfigurableDomain
中指定名称描述并模块各自附带属性的描述,主要由Configurations
、ConfigurableElements
和Settings
三个必要部分组成:
Configurations
可以根据需求定义不同的策略,此处略过不做介绍,audio等带有复杂policy的模块可进一步研究ConfigurableElements
是三者中 最为关键 的描述,控制当前export出来的所有属性或者某级根节点。syscap_configs_hw_all.xml目前实现中给出的都是某级根节点,读者可以根据自己的需求暴露叶子节点或者某级根节点,只需保证与Settings
中的描述一致即可。Settings
是真正描述属性初始值的地方,简单来说,这里的所有属性都来自上方的 Configuration
和ConfigurableElement
,因而必须跟上方保持一致的名称。这里也要注意,若ConfigurableElement
中为某级根节点,那么需要增加ParameterBlock
域,否则直接定义具体的值即可。Syscap
对上述XML配置文件的访问是通过Parameter Framework
达成的。通过封装SyscapUtils
单例类和SysCapability
虚类,用户只需要知道属性对应的路径表述,就可以获取对应的设置值。相应的文件存放在:
# Header file: [codebase_host]/third_party/corefoundation/include/syscap/SysCapability.h # Souce Implementation file [codebase_host]/third_party/corefoundation/SysCapability.cpp # library generated STATIC LIBRARY: libsyscap.a
模块实现: 模块用户需要继承SysCapability
类,并且在yunos.mk包含 libsyscap.a
,然后在代码里可以用 SyscapUtils::getInstance().getSignedIntArray(key, retValue)
的方式就可以拿到之前在XML中定义的默认值,而通过set[XXX]
类型的接口也可以把数据写回。
通过上面的基本介绍,此时读者对整个*Syscap* 实现应该有了一定的了解。那么又该如何增加自己模块的描述和访问呢?下文将以powerd模块为例,演示操作。
参考实现:可以用
grep powerd *
的方式查看相关的改动
要实现powerd模块的参数可配置化,首先需梳理Powerd模块自身的逻辑,将需要暴露给厂商或者其他模块访问的参数提取出来,然后按照既定规则写入配置文件(因篇幅有限,省略大部分属性信息)。
syscap ├── hw │ └── powerd │ ├── ambientLuxLevels │ ├── ambientBacklightLevels │ └── LowPowerModeSupported └── os └── powerd ├── feature │ ├── AlwaysOnWhenPluggedSupported │? ├── ScreenSaverActiveOnSleep │ ├── ScreenSaverActiveOnDock │ └── wakeUpWhenPluggedOrUnplugged ├── constants │ └── ... ├── proximity │ └── ... ├── light │ └── ... ├── display │ └── ... ├── lowpowermode │ └── ... └── fusionsupport └── ...
第一步,增加schema描述:
hw
部分。在syscap_schemas_hw_all.xml中添加名为PowerdCapability
的属性组ComponentType
并定义各种属性、对应的类型以及是否数组,若是需给出数组长度;然后在<InstanceDefinition>
域中添加该Component
实例化之,最终会成为访问路径上的一级节点os
部分。新建syscap_schemas_os_powerd.xml,然后通过预定义的<xi:include />
包含在 syscap_schemas.xml 文件中Subsystem: os
下的<ComponentType>
域里。注意到,syscap_schemas_os_powerd.xml文件使用的是<ComponentTypeSet>
域,并且模块里的属性分门别类以<ComponentType>
逐项表示,最后全部汇总到PowerdCapability
中,然后在<InstanceDefinition>
中实例化。**其他的模块文件可以用类似的方式组织后添加。**第二步,增加config初始化值设定,同样分为两部分:
hw
部分。于syscap_configs_hw_all.xml文件中添加 /syscap/hw/powerd
的属性组配置项(ConfigurableElement),然后在<Settings>
中逐项添加各个属性的值。os
部分。添加新建文件syscap_configs_os_powerd.xml到总开关syscap_configs.xml之中。并且在内容上也依照上面介绍的,逐项添加Configuration、ConfigurableElement和Settings项,这里就不再赘述。至此,配置项的工作已经完成,其中涉及各项属性支持的格式、类型请参考FAQs。
继承SysCapability
类实现PowerdSysCapability
类,并且实现虚函数getModuleName
指定自己的模块名称powerd
,相当于注册powerd模块到系统之中。于loadConfigs
里完成系统初始化访问XML的能力,随后通过单例SyscapUtils
的接口达到访问各项属性的能力,并且将值可以缓存到本地,用于模块的交互。
注意:PowerdSysCapability
要根据模块自身的需求定义接口。
powerd的样例代码放在 [codebase_host]/third_party/corefoundation/test/syscaptest
,可以作为模块实现参数化配置调用的参考。
Syscap
支持的属性访问有**只读**, 读写, 持久性写入等三种方式。在当前结构化组织形式里,我们约定/syscap/hw/*
部分为*只读*,即通过setter
操作将返回false
。模块相关的/syscap/os/[module]/*
部分为*可读可写*,初始化阶段后内存中会建立一份副本,getter/setter
都将与该副本交互,而不会影响到ROM上原有的XML文件。若模块有*持久性写入*的需求,用于保存模块的critical配置,可以通过Solidify
接口实现。[codebase_host]/third_party/parameter-framework/schemas/Parameter.xsd
文件中的描述。