本文轉(zhuǎn)載自:Android之系統(tǒng)屬性(SystemProperties)
1.簡(jiǎn)介
??系統(tǒng)屬性是系統(tǒng)中具有特殊含義的鍵值對(duì)數(shù)據(jù)骏啰,我們?cè)陂_(kāi)發(fā)過(guò)程中有時(shí)需要使用系統(tǒng)屬性溉旋,例如獲取系統(tǒng)軟件版本恐锣,獲取設(shè)備名名稱(chēng)等,有時(shí)也需要設(shè)置自定義屬性役衡。系統(tǒng)屬性具有全局性的特點(diǎn),存取方便。
2.獲取和設(shè)置
2.1 架構(gòu)
2.2 使用終端
//獲取系統(tǒng)屬性值
getprop my.prop.test
//設(shè)置系統(tǒng)屬性值
setprop my.prop.test
//監(jiān)聽(tīng)系統(tǒng)屬性變化
watchprops my.prop.test
2.3 Java代碼中
??在Android源碼中的android.os下有一個(gè)隱藏類(lèi):SystemProperties蘑志,通過(guò)SystemProperties.set及SystemProperties.get可以設(shè)置和獲取系統(tǒng)屬性。Systemproperties部分源碼如下:
// frameworks\base\core\java\android\os\SystemProperties.java
...
public class SystemProperties {
...
//獲取屬性key的值贬派,如果沒(méi)有該屬性則返回默認(rèn)值def
@SystemApi
public static String get(@NonNull String key, @Nullable String def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get(key, def);
}
...
//設(shè)置屬性key的值為val
@SystemApi
public static void set(@NonNull String key, @Nullable String val) {
if (val != null && !val.startsWith("ro.") && val.length() > PROP_VALUE_MAX) {
throw new IllegalArgumentException("value of system property '" + key
+ "' is longer than " + PROP_VALUE_MAX + " characters: " + val);
}
if (TRACK_KEY_ACCESS) onKeyAccess(key);
native_set(key, val);
}
....
}
但是該類(lèi)的接口也不是對(duì)外開(kāi)放的急但,需要通過(guò)反射的方式來(lái)使用。下面是一個(gè)SystemProperties工具類(lèi):
public class SystemProperties {
private final static String TAG = "SystemProperties";
public static String get(String key) {
Class<?> SysProp = null;
Method method = null;
String value = null;
try {
SysProp = Class.forName("android.os.SystemProperties");
method = SysProp.getMethod("get", String.class);
value = (String) method.invoke(null, key);
Log.i(TAG, "value:" + value);
} catch (Exception e) {
Log.e(TAG,"read SystemProperties error",e);
}
return value;
}
public static String get(String key, String defaultValue) {
Class<?> SysProp = null;
Method method = null;
String value = null;
try {
SysProp = Class.forName("android.os.SystemProperties");
method = SysProp.getMethod("get", String.class, String.class);
value = (String) method.invoke(null, key, defaultValue);
} catch (Exception e) {
Log.e(TAG,"read SystemProperties error",e);
}
return value;
}
public static int getInt(String key, int defaultValue) {
Class<?> SysProp = null;
Method method = null;
int value = 0;
try {
SysProp = Class.forName("android.os.SystemProperties");
method = SysProp.getMethod("getInt", String.class, int.class);
value = (Integer) method.invoke(null, key, defaultValue);
} catch (Exception e) {
Log.e(TAG,"read SystemProperties error",e);
}
return value;
}
public static long getLong(String key, long defaultValue) {
Class<?> SysProp = null;
Method method = null;
long value = 0;
try {
SysProp = Class.forName("android.os.SystemProperties");
method = SysProp.getMethod("getLong", String.class, long.class);
value = (Long) method.invoke(null, key, defaultValue);
} catch (Exception e) {
Log.e(TAG,"read SystemProperties error",e);
}
return value;
}
public static boolean getBoolean(String key, boolean defaultValue) {
Class<?> SysProp = null;
Method method = null;
boolean value = false;
try {
SysProp = Class.forName("android.os.SystemProperties");
method = SysProp.getMethod("getBoolean", String.class, boolean.class);
value = (Boolean) method.invoke(null, key, defaultValue);
} catch (Exception e) {
Log.e(TAG,"read SystemProperties error",e);
}
return value;
}
public static void set(String key, String value) {
Class<?> SysProp = null;
Method method = null;
try {
SysProp = Class.forName("android.os.SystemProperties");
method = SysProp.getMethod("set", String.class, String.class);
method.invoke(null, key, value);
} catch (Exception e) {
Log.e(TAG,"read SystemProperties error",e);
}
}
public static void addChangeCallback(Runnable runnable) {
Class<?> SysProp = null;
Method method = null;
try {
SysProp = Class.forName("android.os.SystemProperties");
method = SysProp.getMethod("addChangeCallback", Runnable.class);
method.invoke(null, runnable);
} catch (Exception e) {
Log.e(TAG,"read SystemProperties error",e);
}
}
}
下面以ActivityManagerService為例搞乏,列舉源碼中使用prop的例子:
// frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
final void finishBooting() {
...
//設(shè)置開(kāi)機(jī)完成標(biāo)志屬性sys.boot_completed
SystemProperties.set("sys.boot_completed", "1");
}
...
private static void maybePruneOldTraces(File tracesDir) {
...
//獲取tombstoned.max_anr_count屬性值
final int max = SystemProperties.getInt("tombstoned.max_anr_count", 64);
}
2.4 C++代碼中
??下面以MPEG4Writer.cpp為例波桩,列舉源碼中使用prop的例子:
// frameworks\av\media\libstagefright\MPEG4Writer.cpp
#include <cutils/properties.h>
...
void MPEG4Writer::addDeviceMeta() {
...
if (property_get("ro.build.version.release", val, NULL)
...
if (property_get("ro.product.model", val, NULL)
...
}
在C++代碼中使用prop需要:
include <cutils/properties.h>;
Android.mk或Android.bp或Makefile中需要鏈接libcutils庫(kù)请敦。
// frameworks\av\media\libstagefright\Android.bp
shared_libs: [
...
"libcutils",
...
properties.h源碼在:system/core/libcutils/include/cutils/properties.h
int property_get(const char* key, char* value, const char* default_value);
int property_set(const char *key, const char *value);
int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
3.特殊屬性
3.1 ro只讀屬性
??ro即read only這類(lèi)屬性通常是系統(tǒng)默認(rèn)屬性镐躲,在系統(tǒng)編譯或初始化時(shí)設(shè)置的。
$ getprop ro.vendor.build.version.release
10
$ setprop ro.vendor.build.version.release 9
setprop: failed to set property 'ro.vendor.build.version.release' to '9'
3.2 persist持久屬性
??設(shè)置persist開(kāi)頭的屬性冬三,斷電后仍能保存匀油,值寫(xiě)入data/property/persistent_properties。
$ getprop persist.hello.test //屬性為空
$ setprop persist.hello.test abc //設(shè)置屬性persist.hello.test值為abc
$ getprop persist.hello.test abc //屬性get正常
abc
$reboot //重啟設(shè)備
$ getprop persist.hello.test //屬性為abc
abc
3.3 ctl 控制屬性
setprop ctl.start xxx //啟動(dòng)某服務(wù)
setprop ctl.stop xxx //關(guān)閉某服務(wù)
setprop ctl.restart xxx //重啟某服務(wù)
3.4 sys.powerctl屬性
??sys.powerctl屬性可控制設(shè)備重啟關(guān)機(jī)勾笆。
setprop sys.powerctl shutdown //設(shè)備關(guān)機(jī)
setprop sys.powerctl reboot //設(shè)備重啟
3.5 普通屬性
??設(shè)置其他格式開(kāi)頭的屬性敌蚜,斷電后不能保存。
$ getprop hello.test //屬性為空
$ setprop hello.test 123//設(shè)置屬性persist.hello.test值為abc
$ getprop hello.test 123//屬性get正常
123
$reboot //重啟設(shè)備
$ getprop hello.test //屬性為空
3.6 添加系統(tǒng)默認(rèn)屬性
??系統(tǒng)開(kāi)機(jī)時(shí)會(huì)加載 *.prop屬性配置文件中的屬性窝爪,因此開(kāi)機(jī)后就有了默認(rèn)屬性弛车。init進(jìn)程中property_load_boot_defaults(load_debug_prop)函數(shù)分析。
// system\core\init\property_service.cpp
void property_load_boot_defaults(bool load_debug_prop) {
std::map<std::string, std::string> properties;
//加載屬性build.prop蒲每、default.prop至properties
if (!load_properties_from_file("/system/etc/prop.default", nullptr, &properties)) {
// Try recovery path
if (!load_properties_from_file("/prop.default", nullptr, &properties)) {
// Try legacy path
load_properties_from_file("/default.prop", nullptr, &properties);
}
}
load_properties_from_file("/system/build.prop", nullptr, &properties);
load_properties_from_file("/vendor/default.prop", nullptr, &properties);
load_properties_from_file("/vendor/build.prop", nullptr, &properties);
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
} else {
load_properties_from_file("/odm/default.prop", nullptr, &properties);
load_properties_from_file("/odm/build.prop", nullptr, &properties);
}
load_properties_from_file("/product/build.prop", nullptr, &properties);
load_properties_from_file("/product_services/build.prop", nullptr, &properties);
load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
...
//將properties中屬性通過(guò)PropertySet存入屬性屬性
for (const auto& [name, value] : properties) {
std::string error;
if (PropertySet(name, value, &error) != PROP_SUCCESS) {
LOG(ERROR) << "Could not set '" << name << "' to '" << value
<< "' while loading .prop files" << error;
}
}
property_initialize_ro_product_props();//初始化ro_product前綴的只讀屬性
property_derive_build_props();//初始化編譯相關(guān)屬性
update_sys_usb_config();//設(shè)置persist.sys.usb.config屬性纷跛,用于控制USB調(diào)試和文件傳輸功能
}
從上面代碼可以看出從多個(gè)屬性文件.prop中將系統(tǒng)屬性加載至properties變量,再通過(guò)PropertySet()將properties添加到系統(tǒng)中邀杏,并初始化只讀贫奠、編譯、usb相關(guān)屬性值望蜡。在PropertySet()中是通過(guò)Socket與屬性服務(wù)進(jìn)行通信唤崭,將props存儲(chǔ)共享內(nèi)存。
??下面舉一個(gè)在device/google/marlin/system.prop中添加系統(tǒng)屬性的例子:
# 添加自己的系統(tǒng)默認(rèn)屬性
persist.hello.world=hello
注意:這里添加的屬性前綴必須是在system/sepolicy/private/property_contexts中被定義過(guò)的脖律,否則無(wú)效谢肾。make android后在out/target/product/xxx/system/build.prop 或out/target/product/xxx/vendor/build.prop可找到添加的屬性persist.hello.world,則說(shuō)明基本添加成功小泉。
4.添加定制的*.prop
??涉及的代碼路徑匯總?cè)缦拢?/p>
device/qcom/qssi/hello.prop
device/qcom/qssi/qssi.mk
device/qcom/sepolicy/generic/private/property_contexts
system/core/rootdir/init.rc
system/core/init/property_service.cpp
為了方便統(tǒng)一管理定制化屬性芦疏,有時(shí)會(huì)將定制化屬性都寫(xiě)在定制的.prop文件中冕杠,下面以添加hello.prop為例說(shuō)明添加過(guò)程。
4.1 device下添加hello.prop
// device/qcom/qssi/hello.prop
#
# system.prop for qssi
#
ro.hello.year=2022 //添加ro屬性
persist.hello.month=07 //添加persist屬性
hello.day=25 //添加hello屬性
ro.product.model=HelloWorld //定制系統(tǒng)已有ro.product.model屬性
4.2 配置預(yù)置路徑
??修改device下的device.mk來(lái)指定hello.prop的預(yù)置路徑device/qcom/qssi/qssi.mk酸茴。
#將hello.prop預(yù)置到system/hello.prop
PRODUCT_COPY_FILES += \
device/qcom/qssi/hello.prop:system/hello.prop
4.3 SELinux權(quán)限配置
??hello.開(kāi)頭的屬性是新添加的配置分预,需要在配置對(duì)應(yīng)的SELinux規(guī)則,否則無(wú)效薪捍,配置方法如下:device/qcom/sepolicy/generic/private/property_contexts噪舀。
hello. u:object_r:system_prop:s0
4.4 配置hello.prop權(quán)限
??此步驟可省略,若未配置讀寫(xiě)權(quán)限飘诗,默認(rèn)system/prop為644這里配置與system/build.prop相同的600權(quán)限 system/core/rootdir/init.rc。
on fs
chmod 0600 /system/hello.prop
4.5 加載hello.prop
??僅僅將hello.prop預(yù)置到system/hello.prop還不夠界逛,系統(tǒng)啟動(dòng)時(shí)需要load hello.prop才能使其生效system/core/init/property_service.cpp昆稿。
load_properties_from_file("/system/build.prop", nullptr, &properties);
load_properties_from_file("/vendor/default.prop", nullptr, &properties);
load_properties_from_file("/vendor/build.prop", nullptr, &properties);
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
} else {
load_properties_from_file("/odm/default.prop", nullptr, &properties);
load_properties_from_file("/odm/build.prop", nullptr, &properties);
}
load_properties_from_file("/product/build.prop", nullptr, &properties);
load_properties_from_file("/product_services/build.prop", nullptr, &properties);
load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
//load 預(yù)置的hello.prop 周伦,最后load保證其配置屬性?xún)?yōu)先級(jí)更高
load_properties_from_file("/system/hello.prop", nullptr, &properties);
4.6 驗(yàn)證
??Android全編譯后正常情況可找到生成的out/target/product/qssi/system/hello.prop镜悉,檢查其內(nèi)容應(yīng)與device/qcom/qssi/hello.prop內(nèi)容保持一致捕犬。