Android 系統屬性-SystemProperties詳解***

  建立與修改android屬性用Systemproperties.set(name, value),獲取android屬性用Systemproperties.get(name),須要注意的是android屬性的名稱是有必定的格式要求的:java

  以下:1.前綴必須用system\core\init\property_service.c中定義的前綴。 2. 進行系統屬性設置的程序也必須有system或root權限,linux

  如何將android程序的權限提高到system權限?方法是這樣的:android

    一、在AndroidManifest.xml中,在manifest加入android:sharedUserId="android.uid.system"。shell

    二、在Android.mk中,將LOCAL_CERTIFICATE := XXX修改爲LOCAL_CERTIFICATE :=platformvim

  通過以上兩步就能夠把ap的權限提高到system權限了。windows

Android 的系統屬性包括兩部分:文件保存的持久屬性和每次開機導入的cache屬性。前者主要保存在下面幾個文件中:

bionic/libc/include/sys/_system_properties.h數組

1     #define PROP_SERVICE_NAME "property_service"
2     #define PROP_PATH_RAMDISK_DEFAULT  "/default.prop"
3     #define PROP_PATH_SYSTEM_BUILD     "/system/build.prop"
4     #define PROP_PATH_SYSTEM_DEFAULT   "/system/default.prop"
5     #define PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop"

後者則經過frameworks/base/core/java/android/os/SystemProperties.java的接口定義,架構

 1     private static native String native_get(String key);
 2     private static native String native_get(String key, String def);
 3     private static native void native_set(String key, String def);
 4     public static void set(String key, String val) {
 5         if (key.length() > PROP_NAME_MAX) {
 6             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
 7         }
 8         if (val != null && val.length() > PROP_VALUE_MAX) {
 9             throw new IllegalArgumentException("val.length > " +
10                 PROP_VALUE_MAX);
11         }
12         native_set(key, val);
13     }

該接口類在初始化運行環境中註冊對應的cpp接口android_os_SystemProperties.cpp,實際操做經過JNI調用的是cpp文件對應的接口:

frameworks/base/core/jni/AndroidRuntime.cppapp

1     namespace android {
2     extern int register_android_os_SystemProperties(JNIEnv *env);
3     }

frameworks/base/core/jni/android_os_SystemProperties.cppdom

 1     static void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ, jstring valJ)
 2     {
 3         int err;
 4         const char* key;
 5         const char* val;
 6         key = env->GetStringUTFChars(keyJ, NULL);
 7         if (valJ == NULL) {
 8             val = "";       /* NULL pointer not allowed here */
 9         } else {
10             val = env->GetStringUTFChars(valJ, NULL);
11         }
12         err = property_set(key, val);
13         env->ReleaseStringUTFChars(keyJ, key);        
14         if (valJ != NULL) {
15             env->ReleaseStringUTFChars(valJ, val);
16         }
17     }

設置key的value時,須要做鑑權,根據設置程序所在進程的fd獲知uid值,好比system server進程能夠設置net打頭的key,不能夠設置gsm打頭的key,相關的定義以下:

system/core/include/private/android_filesystem_config.h

1     #define AID_ROOT             0  /* traditional unix root user */
2     #define AID_SYSTEM        1000  /* system server */
3     #define AID_RADIO         1001  /* telephony subsystem, RIL */
4     #define AID_DHCP          1014  /* dhcp client */
5     #define AID_SHELL         2000  /* adb and debug shell user */
6     #define AID_CACHE         2001  /* cache access */
7     #define AID_APP          10000 /* first app user */

 

vim  ./system/core/init/property_service.c
struct {
    const char *prefix;
    unsigned int uid;
    unsigned int gid;
} property_perms[] = {
    { "net.rmnet0.",      AID_RADIO,    0 },
    { "net.gprs.",        AID_RADIO,    0 },
    { "net.ppp",          AID_RADIO,    0 },
    { "net.qmi",          AID_RADIO,    0 },
    { "net.lte",          AID_RADIO,    0 },
    { "net.cdma",         AID_RADIO,    0 },
    { "ril.",             AID_RADIO,    0 },
    { "gsm.",             AID_RADIO,    0 },
    { "persist.radio",    AID_RADIO,    0 },
    { "net.dns",          AID_RADIO,    0 },
    { "sys.usb.config",   AID_RADIO,    0 },
    { "net.",             AID_SYSTEM,   0 },
    { "dev.",             AID_SYSTEM,   0 },
    { "runtime.",         AID_SYSTEM,   0 },
    { "hw.",              AID_SYSTEM,   0 },
    { "sys.",             AID_SYSTEM,   0 },
    { "sys.powerctl",     AID_SHELL,    0 },
    { "service.",         AID_SYSTEM,   0 },
    { "wlan.",            AID_SYSTEM,   0 },
    { "bluetooth.",       AID_BLUETOOTH,   0 },
    { "dhcp.",            AID_SYSTEM,   0 },
    { "dhcp.",            AID_DHCP,     0 },
    //MStar Android Patch Begin
    { "dhcp.offer",       AID_NOBODY,     0 },
    //MStar Android Patch End
    { "debug.",           AID_SYSTEM,   0 },
    { "debug.",           AID_SHELL,    0 },
    { "log.",             AID_SHELL,    0 },
    { "service.adb.root", AID_SHELL,    0 },
    { "service.adb.tcp.port", AID_SHELL,    0 },
    { "persist.sys.",     AID_SYSTEM,   0 },
    { "persist.service.", AID_SYSTEM,   0 },
    { "persist.security.", AID_SYSTEM,   0 },
    { "persist.service.bdroid.", AID_BLUETOOTH,   0 },
    { "selinux."         , AID_SYSTEM,   0 },
    // MStar Android Patch Begin
    { "mstar.",           AID_SYSTEM,   0 },
    { "mstar.",           AID_MEDIA,    0 },
    { "http.",            AID_SYSTEM,   0 },
    { "mstar.media.",     AID_MEDIA,   0 },
    { "mstar.dvfs.",      AID_MEDIA,   0 },
    { "persist.bt.", AID_BLUETOOTH,   0 },
    { "mstar.",           AID_GRAPHICS, 0 },
    // MStar Android Patch End
    { NULL, 0, 0 }
}; 

在開機啓動後的init操做中,會執行一個loop循環,當檢測到有新的設置時,進入設置流程,鑑權失敗會提示相關的異常,如sys_prop: permission denied uid:1000  name:gsm.phone.id

system/core/init/init.c

 1     void property_changed(const char *name, const char *value)
 2     {
 3         if (property_triggers_enabled) {
 4             queue_property_triggers(name, value);
 5             drain_action_queue();
 6         }
 7     }
 8     int main(int argc, char **argv)
 9     {
10         parse_config_file("/init.rc");
11         qemu_init();
12         device_fd = device_init();
13         property_init();
14         fd = open(console_name, O_RDWR);
15         property_set_fd = start_property_service();
16         ufds[0].fd = device_fd;
17         ufds[0].events = POLLIN;
18         ufds[1].fd = property_set_fd;
19         ufds[1].events = POLLIN;
20         ufds[2].fd = signal_recv_fd;
21         ufds[2].events = POLLIN;
22         fd_count = 3;
23         for(;;) {
24             if (ufds[0].revents == POLLIN)
25                 handle_device_fd(device_fd);
26 
27             if (ufds[1].revents == POLLIN)
28                 handle_property_set_fd(property_set_fd);
29             if (ufds[3].revents == POLLIN)
30                 handle_keychord(keychord_fd);
31         }
32         return 0;
33     }

 

         屬性系統是android的一個重要特性。它做爲一個服務運行,管理系統配置和狀態。全部這些配置和狀態都是屬性。每一個屬性是一個鍵值對(key/value pair),其類型都是字符串。

         從功能上看,屬性與windows系統的註冊表很是類似。許多android應用程序和庫直接或者間接地依賴此特性,以決定它們的運行時行爲。例如,adbd進程查詢屬性服務已確認當前是否運行在模擬器環境中。另外一個例子是java.io.File.pathSpearator,其返回存儲於屬性服務中的值。

         屬性系統是如何工做的

         屬性系統的上層架構以下圖所示。

  

         圖中有3個進程、一組永久屬性文件和一塊共享內存區域。共享內存區域是全部屬性記錄的存儲所在。只有屬性服務進程才能夠寫入共享內存區域,它負責從永久文件中加載屬性記錄並將它們保存在共享內存中。

         consumer進程將共享內存加載到其自身的虛擬地址空間並直接訪問這些屬性。setter進程一樣將共享內存加載到其自身的虛擬地址空間,但其不能直接寫該內存。當setter試圖增長或者更新一個屬性時,它將該屬性經過unix domain socket發送至屬性服務。屬性服務表明setter進程將該屬性寫入共享內存和永久文件中。

         屬性服務運行於init進程中。init進程首先建立一個共享內存區域,並保存一個指向該區域的描述符fd。init進程將該區域經過使用了MAP_SHARED標誌的mmap映射至它自身的虛擬地址空間,這樣,任何對於該區域的更新對於全部進程都是可見的。fd和區域大小被存儲在一個名爲ANDROID_PROPERTY_WORKSPACE的變量中。任何其餘進程,好比consumer和setter將使用這個變量來得到fd和尺寸,這樣它們就能mmap這個區域到它們自身的虛擬地址空間中。該共享內存區域以下圖所示。

  

在這以後,init進程將從下列文件加載屬性:

/default.prop
/system/build.prop
/system/default.prop
/data/local.prop

 

下一步是啓動屬性服務。在這一步中,一個unix domain socket服務被建立。此socket的路徑是/dev/socket/property_service,該路徑對於其餘客戶端進程是熟知的。最後,init進程調用poll來等待該socket上的鏈接事件。

         在consumer一邊,當它初始化libc(bionic/libc/bionic/libc_common.c __libc_init_common 函數),它將從環境變量中返回fd和尺寸,並映射共享內存到其自身的地址空間(bionic/libc/bionic/system_properties.c __system_properties_init 函數)。在這以後,libcutils能夠想讀取普通內存那樣爲consumer讀取屬性。

         目前,屬性是不可以被刪除的。也就是說,一旦添加了一個屬性,它將不可以被刪除,其鍵也不可以被改變。

         如何讀取/設置屬性

         Android上有三種主要途徑來get/set屬性。

一、  native code

當編寫本地應用程序時,可使用property_get和property_set 這兩個API來讀取/設置屬性。要使用它們,咱們須要include cutils/properties.h,並連接libcutils庫。

二、  java code

在Java包(java.lang.System)中提供有System.getProperty和System.setProperty方法。但值得注意的是,儘管這兩個API在語義上等同native函數,但其將數據存儲於徹底不一樣的位置。實際上,dalvik VM使用一個哈希表來存儲這些屬性。因此,用這兩個API存儲的屬性是獨立的,不能存取native屬性,反之亦然。

然而Android有一個內部隱藏類(@hide,對SDK不可見)android.os.SystemProperties來操縱native屬性。其經過jni來存取native屬性庫。

三、  shell腳本

Android提供getprop和setprop命令行工具來獲取和更新屬性。其依賴libcutils實現。 

         補充:經過查看property_service.c,咱們能夠明確如下事實:

一、  屬性名不是隨意取的。在property_perms數組中定義了當前系統上可用的全部屬性的前綴,以及相對應的存取權限UID。對屬性的設置要知足權限要求,同時命名也要在這些定義的範圍內。

二、  PA_COUNT_MAX指定了系統(共享內存區域中)最多能存儲多少個屬性。

三、  PROP_NAME_MAX指定了一個屬性的key最大容許長度;PROP_VALUE_MAX則指定了value的最大容許長度。

此外,http://blog.csdn.net/tekkamanitachi/archive/2009/06/18/4280982.aspx 這篇文章翻譯了Android的官方文檔,從另外一個角度敘述了屬性系統,須要者請參看。

 

 

Android系統源碼中,存在大量的SystemProperties.get或SystemProperties.set,具體使用以下:

一、SystemProperties的使用
SystemProperties的使用很簡單,在SystemProperties.java中因此方法都是static,直接經過SystemProperties.get(String key)或SystemProperties.set(String key, String val)就能夠了,系統屬性都是以鍵值對的形式存在即name和value
須要注意的是對name和value的length是有限制的,name的最大長度是31,value最大長度是91,具體定義以下:

//frameworks/base/core/java/android/os/SystemProperties.java
public class SystemProperties
{
    public static final int PROP_NAME_MAX = 31;
    public static final int PROP_VALUE_MAX = 91;
    ...
    private static native String native_get(String key);
    private static native void native_set(String key, String def);
    /**
     * Get the value for the given key.
     * @return an empty string if the key isn't found
     * @throws IllegalArgumentException if the key exceeds 32 characters
     */
    public static String get(String key) {
        if (key.length() > PROP_NAME_MAX) {
            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
        }
        return native_get(key);
    }
    ...
    /**
     * Set the value for the given key.
     * @throws IllegalArgumentException if the key exceeds 32 characters
     * @throws IllegalArgumentException if the value exceeds 92 characters
     */
    public static void set(String key, String val) {
        if (key.length() > PROP_NAME_MAX) {
            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
        }
        if (val != null && val.length() > PROP_VALUE_MAX) {
            throw new IllegalArgumentException("val.length > " +
                PROP_VALUE_MAX);
        }
        native_set(key, val);
    }
    ...
}

在調用get或set時,都是經過調用native方法去操做的,開始原本想一筆帶過的,仍是看看native方法中的具體流程吧,若是不感興趣能夠直接看第三條

ps:在調用SystemProperties.set時所在的apk uid必須在system group,不然設置屬性會報錯,在manifest配置下行:

  android:sharedUserId="android.uid.system"


二、SystemProperties中方法具體實現
SystemProperties.java中全部native方法都是在android_os_SystemProperties.cpp裏實現,先來看看java中個方法是怎麼和cpp中方法對應起來的

//frameworks/base/core/jni/android_os_SystemProperties.cpp
static const JNINativeMethod method_table[] = {
    { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
      (void*) SystemProperties_getS },
    { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
      (void*) SystemProperties_getSS },
    { "native_get_int", "(Ljava/lang/String;I)I",
      (void*) SystemProperties_get_int },
    { "native_get_long", "(Ljava/lang/String;J)J",
      (void*) SystemProperties_get_long },
    { "native_get_boolean", "(Ljava/lang/String;Z)Z",
      (void*) SystemProperties_get_boolean },
    { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
      (void*) SystemProperties_set },
    { "native_add_change_callback", "()V",
      (void*) SystemProperties_add_change_callback },
};
 
int register_android_os_SystemProperties(JNIEnv *env)
{
    return RegisterMethodsOrDie(env, "android/os/SystemProperties", method_table,
                                NELEM(method_table));
}

register_android_os_SystemProperties方法是在AndroidRuntime.cpp中調用的,RegisterMethodsOrDie能夠簡單的理解爲把method_table數組裏的方法一一對應起來。在android_os_SystemProperties.cpp中能夠發現最終實現是不區分SystemProperties_get_int或 SystemProperties_getS,基本全部的方法都是調用property_get和property_set方法來實現的

property_get和property_set是在properties.c裏實現的,以下

//system/core/libcutils/properties.c
int property_get(const char *key, char *value, const char *default_value)
{
    int len;
 
    len = __system_property_get(key, value);
    if(len > 0) {
        return len;
    }
    if(default_value) {
        len = strlen(default_value);
        if (len >= PROPERTY_VALUE_MAX) {
            len = PROPERTY_VALUE_MAX - 1;
        }
        memcpy(value, default_value, len);
        value[len] = '\0';
    }
    return len;
}
int property_set(const char *key, const char *value)
{
    return __system_property_set(key, value);
}

進程啓動後數據已經將系統屬性數據讀取到相應的共享內存中,保存在全局變量__system_property_area__,具體操做在system_properties.cpp中

//bionic/libc/bionic/system_properties.cpp
int __system_property_get(const char *name, char *value)
{
    const prop_info *pi = __system_property_find(name);
 
    if (pi != 0) {
        //數據已經存儲在內存中__system_property_area__ 等待讀取完返回
        return __system_property_read(pi, 0, value);
    } else {
        value[0] = 0;
        return 0;
    }
}

設置屬性經過異步socket通訊,向property_service發送消息

int __system_property_set(const char *key, const char *value)
{
    if (key == 0) return -1;
    if (value == 0) value = "";
    if (strlen(key) >= PROP_NAME_MAX) return -1;
    if (strlen(value) >= PROP_VALUE_MAX) return -1;
 
    prop_msg msg;
    memset(&msg, 0, sizeof msg);
    msg.cmd = PROP_MSG_SETPROP;
    strlcpy(msg.name, key, sizeof msg.name);
    strlcpy(msg.value, value, sizeof msg.value);
 
    const int err = send_prop_msg(&msg);
    if (err < 0) {
        return err;
    }
 
    return 0;
}
static int send_prop_msg(const prop_msg *msg)
{   //sokcet 通訊 /dev/socket/property_service 
    const int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
    if (fd == -1) {
        return -1;
    }
    //static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
    const size_t namelen = strlen(property_service_socket);
    sockaddr_un addr;
    memset(&addr, 0, sizeof(addr));
    strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
    addr.sun_family = AF_LOCAL;
    socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
    if (TEMP_FAILURE_RETRY(connect(fd, reinterpret_cast<sockaddr*>(&addr), alen)) < 0) {
        close(fd);
        return -1;
    }
 
    const int num_bytes = TEMP_FAILURE_RETRY(send(fd, msg, sizeof(prop_msg), 0));
 
    ...
    close(fd);
    return result;
}

property_service是在init進程調用start_property_service啓動的,在property_service.cpp中

//system/core/init/property_service.cpp
void start_property_service() {
    //建立socket
    property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                    0666, 0, 0, NULL);
    if (property_set_fd == -1) {
        ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
        exit(1);
    }
   //監聽socket
    listen(property_set_fd, 8);
 
    register_epoll_handler(property_set_fd, handle_property_set_fd);
}

仍是在property_service.cpp的handle_property_set_fd()處理對應屬性

static void handle_property_set_fd()
{
    //等待創建通訊
    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
        return;
    }
 
    /獲取套接字相關信息 uid gid
    if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
        close(s);
        ERROR("Unable to receive socket options\n");
        return;
    }
    ...
    //接收屬性設置請求消息
    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
    //處理消息  
    switch(msg.cmd) {
    case PROP_MSG_SETPROP:
        msg.name[PROP_NAME_MAX-1] = 0;
        msg.value[PROP_VALUE_MAX-1] = 0;
        //檢查屬性名是否合法
        if (!is_legal_property_name(msg.name, strlen(msg.name))) {
            ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
            close(s);
            return;
        }
 
        getpeercon(s, &source_ctx);     
        //處理ctl.開頭消息
        if(memcmp(msg.name,"ctl.",4) == 0) {
            // Keep the old close-socket-early behavior when handling
            // ctl.* properties.
            close(s);
            //檢查權限,處理以ctl開頭的屬性
            if (check_control_mac_perms(msg.value, source_ctx, &cr)) {
                handle_control_message((char*) msg.name + 4, (char*) msg.value);
            } else {
                ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
                        msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
            }
        } else {
            //檢查權限,設置對應的屬性
            if (check_mac_perms(msg.name, source_ctx, &cr)) {
                property_set((char*) msg.name, (char*) msg.value);
            } else {
                ERROR("sys_prop: permission denied uid:%d  name:%s\n",
                      cr.uid, msg.name);
            }
            close(s);
        }
        ...
    }
}

不繼續看了,後面的坑還有不少,考慮到後面還有幾個方面沒講,簡單說下property_set最後是調用了property_set_impl實現的,有興趣的能夠繼續去跟蹤

三、系統屬性怎麼生成的
Android的build.prop文件是在Android編譯時刻收集的各類property(LCD density/語言/編譯時間, etc.),編譯完成以後,文件生成在out/target/product/<board>/system/目錄下,build.prop的生成是由make系統解析build/core/Makefile完成。
    3.1 Makefile中直接把$(TARGET_DEVICE_DIR)/system.prop的內容追加到build.prop中
    3.2 收集ADDITIONAL_BUILD_PROPERTIES中的屬性,追加到build.prop中
    3.3 ADDITIONAL_BUILD_PROPERTIES又會收集PRODUCT_PROPERTY_OVERRIDES中定義的屬性
在配置系統屬性時,若是是在*.prop文件中配置直接是在文件添加一行「persist.timed.enable=true」就行,但在*.mk配置時就須要加上PRODUCT_PROPERTY_OVERRIDES屬性,須要注意最後一個沒有「\」,下面提供了一個實例

PRODUCT_PROPERTY_OVERRIDES += \
    persist.timed.enable=true \
    persist.timed.enable=true \
    ... \
    key=value 

四、系統屬性類別和加載優先級

屬性名稱以「ro.」開頭,被視爲只讀屬性。一旦設置,屬性值不能改變。
屬性名稱以「persist.」開頭,當設置這個屬性時,其值也將寫入/data/property。
屬性名稱以「net.」開頭,當設置這個屬性時,「net.change」屬性將會自動設置,以加入到最後修改的屬性名。
(這是很巧妙的。 netresolve模塊的使用這個屬性來追蹤在net.*屬性上的任何變化。)
屬性「 ctrl.start 」和「 ctrl.stop 」是用來啓動和中止服務。每一項服務必須在init.rc中定義。系統啓動時,與init守護進程將解析init.rc和啓動屬性服務(此處在7.0上有改動,作了相關優化,後面會說到)。一旦收到設置「 ctrl.start 」屬性的請求,屬性服務將使用該屬性值做爲服務名找到該服務,啓動該服務。這項服務的啓動結果將會放入「 init.svc.<服務名>「屬性中。客戶端應用程序能夠輪詢那個屬性值,以肯定結果。
須要注意的一點是在Android7.0之後在mk文件中提供了一個編譯宏LOCAL_INIT_RC用於將服務相關的RC文件編譯到相應位置。這能確保服務定義和服務的可執行文件同時存在,避免了以前出現的服務對應的可執行程序不存在的問題。 
單一的init*.rc,被拆分,服務根據其二進制文件的位置(/system,/vendor,/odm)定義到對應分區的etc/init目錄中,每一個服務一個rc文件。與該服務相關的觸發器、操做等也定義在同一rc文件中。
在init執行mount_all指令掛載分區時,會加載這些目錄中的rc文件,並在適當的時機運行這些服務和操做,具體能夠參考system/core/init/readme.txt文件裏面有詳細的介紹。
系統屬性是在init.rc中加載的,具體啓動方式以下:

//system/core/rootdir/init.rc
on property:sys.boot_from_charger_mode=1
    trigger late-init
 
# Load properties from /system/ + /factory after fs mount.
on load_system_props_action
    load_system_props  #定義在property_service.cpp
 
on load_persist_props_action
    load_persist_props #定義在property_service.cpp
    start logd
    start logd-reinit
 
# Mount filesystems and start core system services.
on late-init
    # Load properties from /system/ + /factory after fs mount. Place
    # this in another action so that the load will be scheduled after the prior
    # issued fs triggers have completed.
    trigger load_system_props_action
 
    # Load persist properties and override properties (if enabled) from /data.
    trigger load_persist_props_action

當屬性值sys.boot_from_charger_mode爲1時,會觸發late-init,在late-init又會觸發load_system_props_action和load_persist_props_action,具體看看property_service.cpp這兩個方法對應幹啥了

//system/core/init/property_service.cpp
void load_system_props() {
    load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);//加載system/build.prop
    load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);//加載vendor/build.prop
    load_properties_from_file(PROP_PATH_FACTORY, "ro.*");//加載factory/factory.prop
    load_recovery_id_prop();//加載recovery相關prop
}
void load_persist_props(void) {
    load_override_properties();//若是"ro.debuggable"爲1加載data/local.prop裏的屬性
    /* Read persistent properties after all default values have been loaded. */
    load_persistent_properties();//加載/data/property裏的persistent properties 
}

當同一屬性在多個文件中都有配置,先加載的會被後加載的覆蓋。

 五、利用系統屬性動態設置程序中Log的開關android 動態控制logcat日誌開關,經過Log.isLoggable(TAG,level)方法動態控制,以FlashlightController類爲例 private static final String TAG = "FlashlightController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);利用adb命令設置屬性值來控制該日誌開關adb shell setprop log.tag.FlashlightController DEBUG 設置該TAG的輸出級別爲DEBUG,則 level爲DEBUG以上的都返回true須要注意的是經過adb shell setprop設置的屬性值每次重啓後都會恢復以前的值,log的級別以下:where <tag> is a log component tag (or * for all) and priority is:  V    Verbose (default for <tag>)  D    Debug (default for '*')  I    Info  W    Warn  E    Error  F    Fatal  S    Silent (suppress all output)也能夠將該屬性添加在data/local.prop屬性文件中,不一樣的是隻要存在local.prop,該手機重啓與否屬性值都存在,另外須要注意的是user版ro.debuggable=0,系統啓動時不會讀取/data/local.prop文件

相關文章
相關標籤/搜索