Android系统10 RK3399 init进程启动(三十六) 属性property操作API

Posted 旗浩QH

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android系统10 RK3399 init进程启动(三十六) 属性property操作API相关的知识,希望对你有一定的参考价值。


 配套系列教学视频链接:

      ​​安卓系列教程之ROM系统开发-百问100ask​

说明

系统:android10.0

设备: FireFly RK3399 (ROC-RK3399-PC-PLUS)

前言

前面几篇文章介绍的属性基本框架和属性的基本概念, 在Android中,各种代码场景下都会对属性进行代码操作, 所以需要了解一下常见的C, C++,java中属性的各种API。


一, API调用层次

Android系统10

二, C语言客户端API

头文件在: system/core/include/cutils/properties.h

实现在: system/core/libcutils/properties.cpp

int8_t property_get_bool(const char *key, int8_t default_value);
int64_t property_get_int64(const char *key, int64_t default_value);
int property_get(const char* key, char* value, const char* default_value);
int32_t property_get_int32(const char *key, int32_t default_value);
int property_set(const char *key, const char *value);

 例子:

#include <cutils/properties.h> 
#include <log/log.h>
property_set("persist.sys.language", "zh");
property_get("persist.sys.language", propLang, "en");

三, C++客户端API

头文件声明在: system/core/base/include/android-base/properties.h

实现代: system/core/base/properties.cpp

namespace android 
namespace base
// 获取bool类型的属性值,如果属性为空或者不存在, 返回参数2的默认值
bool GetBoolProperty(const std::string& key, bool default_value);
template <typename T>
//获取int类型的属性值, 如果属性为空或不存在,并且不在最小值和最大值之间,返回参数2的默认值
T GetIntProperty(const std::string& key, T default_value, T min, T max);
//获取unsignd int类型的属性值,如果属性为空或不存在,并且不在0和最大值之间,返回参数2的默认值
template <typename T>
T GetUintProperty(const std::string& key, T default_value, T max);
// 获取默认类型( 字符串)属性值
std::string GetProperty(const std::string& key, const std::string& default_value);
//设置属性值
bool SetProperty(const std::string& key, const std::string& value);
#if defined(__BIONIC__)
// 等待属性的值变成预定值, relative_timeout参数设置超时时间, 成功返回true。
bool WaitForProperty(const std::string& key, const std::string& expected_value,
std::chrono::milliseconds relative_timeout = std::chrono::milliseconds::max());
#endif

 例子:

#include <android-base/properties.h>

std::string prop_val = android::base::GetProperty("sys.boot_completed", "");
if (!android::base::SetProperty("ctl.stop", "mpdecision"))
LOG(ERROR) << "setprop ctl.start mpdecision failed";

四, 服务端C++修改属性的实现API

C和C ++客户端的设置都是通过socket和服务端通信, 服务端中会实现对应的接口,一般我们开发的时候不需要关注这个, 想了解原理的话, 可以看看这部分代码:

在proerty_service端(init进程)在响应客户端修改属性值的时候,会使用如下API:

system/core/init/property_service.cpp

uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error)

因为只有设置属性才会调用到init进程中来,所以get相关接口就不是在这里实现了,另外在init进程中经常会用如下接口:

property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
该接口在init.cpp有如下定义:
uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;

 其实最终都会调用到PropertySet()去。而PropertySet()再会调用bionic相关API:

bionic/libc/bionic/system_property_api.cpp

修改属性会调用如下接口来完成:

//1, 根据属性名,获取到prop_info树叶指针
const prop_info* __system_property_find(const char* name)
//2, 更新prop_info树叶中属性的值,其实就是修改属性
int __system_property_update(prop_info* pi, const char* value, unsigned int len)
//3, 如果属性为系统中新增属性
int __system_property_add(const char* name, unsigned int namelen, const char* value,
unsigned int valuelen)

最后不管是客户端还是服务端, set和get都是通过一个类来实现:

bionic/libc/system_properties/system_properties.cpp

static SystemProperties system_properties;
int __system_property_get(const char* name, char* value)
return system_properties.Get(name, value);

int __system_property_update(prop_info* pi, const char* value, unsigned int len)
return system_properties.Update(pi, value, len);

 调用过程就是前面提到的: 

Android系统10

五, JAVA API

Android系统中提供类​​frameworks/base/core/java/android/os/​​​​SystemProperties.java​​来操作属性,需要注意的是,这些接口只针对系统APP, Android API从21后开始,不再支持普通APP直接支持通过SystemProperties.get/set方式来获取/设置系统属性。一般通过反射机制可以获取。但是Android11之后,又不允许使用反射机制了,所以很多时候会通过jni的方式来获取。

public class SystemProperties 
public static String get(@NonNull String key, @Nullable String def);
public static int getInt(@NonNull String key, int def);
public static long getLong(@NonNull String key, long def) ;
public static boolean getBoolean(@NonNull String key, boolean def);
public static void set(@NonNull String key, @Nullable String val);
public static void addChangeCallback(@NonNull Runnable callback);

 例子: 

import android.os.SystemProperties; 
SystemProperties.set("persist.sys.language", zone.getID());
String lang= SystemProperties.get("persist.sys.language");

Android系统提供的现成的key用来获取系统信息: android.os.Build类

frameworks/base/core/java/android/os/Build.java

Build.BOARD // 主板  

Build.CPU_ABI // cpu指令集  

Build.DEVICE // 设备参数  

Build.DISPLAY // 显示屏参数  

Build.FINGERPRINT // 硬件名称

该类就是系统获取好了系统属性,然后封装起来给应用使用: 

package android.os;
public class Build
/** The manufacturer of the product/hardware. */
public static final String MANUFACTURER = getString("ro.product.manufacturer");

/** The consumer-visible brand with which the product/hardware will be associated, if any. */
public static final String BRAND = getString("ro.product.brand");

/** The end-user-visible name for the end product. */
public static final String MODEL = getString("ro.product.model");

/** The system bootloader version number. */
public static final String BOOTLOADER = getString("ro.bootloader");

@UnsupportedAppUsage
private static String getString(String property)
return SystemProperties.get(property, UNKNOWN);


例子:

public static String getDeviceListing() 
return "Build.PRODUCT: " + Build.PRODUCT + "\\n" +
"Build.MANUFACTURER: " + Build.MANUFACTURER + "\\n" +
"Build.BRAND: " + Build.BRAND + "\\n" +
"Build.DEVICE: " + Build.DEVICE + "\\n" +
"Build.MODEL: " + Build.MODEL + "\\n" +
"Build.HARDWARE: " + Build.HARDWARE + "\\n" +
"Build.FINGERPRINT: " + Build.FINGERPRINT + "\\n" +
"Build.TAGS: " + Build.TAGS + "\\n"

 在应用开发中因为systemproperties的hide属性,所以无法直接访问到get和set函数。通过反射机制来获取get和set函数:

public static String getProperty(String key, String defaultValue) 
String value = defaultValue;
try
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class, String.class);
value = (String)(get.invoke(c, key, defaultValue));
catch (Exception e)
e.printStackTrace();
finally
return value;

六,总结

以上就是C, C++, JAVA各个语言中操作属性的相关API, 在开发中,我们掌握使用这些接口就足够了。

以上是关于Android系统10 RK3399 init进程启动(三十六) 属性property操作API的主要内容,如果未能解决你的问题,请参考以下文章

Android系统-Ubuntu21.04编译RK3399_android10问题汇总

Android系统-Ubuntu21.04编译RK3399_android10问题汇总

RK3399平台开发系列讲解(内核调试篇)9.19strace跟踪器的使用

RK3399平台开发系列讲解(进程调度篇)14.10什么是进程调度?

RK3399平台开发系列讲解(进程调度篇)14.10什么是进程调度?

RK3399平台开发系列讲解(进程调度篇)14.7Linux进程的调度