Android 系統(tǒng)屬性

本文轉(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)

系統(tǒng)屬性_01.png

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需要:

  1. include <cutils/properties.h>;

  2. 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)容保持一致捕犬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末唇跨,一起剝皮案震驚了整個(gè)濱河市贼陶,隨后出現(xiàn)的幾起案子蹂窖,更是在濱河造成了極大的恐慌欣福,老刑警劉巖绢片,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赞别,死亡現(xiàn)場(chǎng)離奇詭異畏陕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)仿滔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)惠毁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人崎页,你說(shuō)我怎么就攤上這事鞠绰。” “怎么了飒焦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵蜈膨,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我牺荠,道長(zhǎng)翁巍,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任志电,我火速辦了婚禮曙咽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挑辆。我一直安慰自己例朱,他們只是感情好孝情,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著洒嗤,像睡著了一般箫荡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上渔隶,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天羔挡,我揣著相機(jī)與錄音,去河邊找鬼间唉。 笑死绞灼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呈野。 我是一名探鬼主播低矮,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼被冒!你這毒婦竟也來(lái)了军掂?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤昨悼,失蹤者是張志新(化名)和其女友劉穎蝗锥,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體率触,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡终议,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了闲延。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痊剖。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖垒玲,靈堂內(nèi)的尸體忽然破棺而出陆馁,到底是詐尸還是另有隱情,我是刑警寧澤合愈,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布叮贩,位于F島的核電站,受9級(jí)特大地震影響佛析,放射性物質(zhì)發(fā)生泄漏益老。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一寸莫、第九天 我趴在偏房一處隱蔽的房頂上張望捺萌。 院中可真熱鬧,春花似錦膘茎、人聲如沸桃纯。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)态坦。三九已至盐数,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間伞梯,已是汗流浹背玫氢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谜诫,地道東北人漾峡。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像喻旷,于是被迫代替她去往敵國(guó)和親灰殴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345