安卓系列教程之ROM系统开发-百问100ask
系统:Android10.0
设备: FireFly RK3399 (ROC-RK3399-PC-PLUS)
前面几篇文章介绍的属性基本框架和属性的基本概念, 在Android中,各种代码场景下都会对属性进行代码操作, 所以需要了解一下常见的C, C++,java中属性的各种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
#include
property_set("persist.sys.language", "zh");
property_get("persist.sys.language", propLang, "en");
头文件声明在: 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
//获取int类型的属性值, 如果属性为空或不存在,并且不在最小值和最大值之间,返回参数2的默认值
T GetIntProperty(const std::string& key, T default_value, T min, T max);
//获取unsignd int类型的属性值,如果属性为空或不存在,并且不在0和最大值之间,返回参数2的默认值
template
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
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和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系统中提供类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, 在开发中,我们掌握使用这些接口就足够了。