• Android终端属性prop操作的底层实现

    setprop、getprop与watchprops
    服务器君一共花费 12.825 ms 进行了 2 次数据库查询,努力地为您提供了这个页面。
    广告很萌的

    接下来,看一下终端命令setprop、getprop、watchprops。

    在init.c文件中main函数中会调用start_property_service(),而它分别调用load_properties_from_file函数读取PROP_PATH_SYSTEM_BUILD(/system/build.prop)、PROP_PATH_SYSTEM_DEFAULT(/system/default.prop)和PROP_PATH_LOCAL_OVERRIDE(/data/local.prop)存放系统属性的文件并设置到系统属性。

    编译时由build/tool/buildinfo.sh文件写到文件build.prop,修改系统默认属性一般是改build/tool/buildinfo.sh文件。

    在android系统中,有一些初始化的配置文件,例如:

    • /init.rc
    • /default.prop
    • /system/build.prop

    文件里面里面配置了开机设置的系统属性值,这些属性值,可以通过getprop获取,setprop设置,它的格式如下:

    • getprop [key] 获取指定key的配置值,如果不带参数,只是getprop则是显示系统所有的配置值
    • setprop [key] [value] 设置指定key的属性值
    • watchprops 监听系统属性的变化,如果期间系统的属性发生变化则把变化的值显示出来

    其实这三个命令都是toolbox的子命令,如果有兴趣的可以看在android源码中看到其对应的源码:system/core/toolbox/

    toolbox命令主要完成扩展命令的执行,每一个扩展命令对应一个name_main函数,如ls命令,对应ls_main函数。同时,每一个扩展命令都由一个system/core/toolbox/目录下面的.c文件实现。toolbox.c会根据这个目录下面的.c文件生成tools.h头文件,并在system/core/toolbox/Android.mk文件中为每个命令生成指向toolbox的连接。toolbox的实现结构使它扩展一个命令很容易。

    假设现在我们自己想手工添加一个shell命令mycommand,只要在system/core/toolbox/目录下面新建一个mycommand.c文件,并在里面实现一个mycommand_main函数,然后在system/core/toolbox/Android.mk中添加mycommand.c即可。Android.mk会自动把它编译进toolbox程序,并在编译生成的Android系统/system/bin目录下为这个命令生成一个指向toolbox的连接。

    以setprop这个命令为例:在system/toolbox目录下会有个setprop.c这个文件, 源代码如下:

    #include <stdio.h>
    
    #include <cutils/properties.h>
    
    int setprop_main(int argc, char *argv[])
    {
        if(argc != 3) {
            fprintf(stderr,"usage: setprop <key> <value>\n");
            return 1;
        }
    
        if(property_set(argv[1], argv[2])){
            fprintf(stderr,"could not set property\n");
            return 1;
        }
    
        return 0;
    }
    

    不难分析出来,setprop这个命令是需要3个参数,一个命令本身,一个是prop name,一个是prop value,如果不是三个就会报错usage: setprop <key> <value>,在Android.mk中将这个命令import进去就ok了,最终编译会在system/bin下面生成对应的文件。

    而如果参数正确的话就会调用property_set这个函数,传入的值分别是prop name 和prop value。而这个函数定义是在system/core/init/下的property_service.c中。源代码如下:

    int property_set(const char *name, const char *value)
    {
        prop_info *pi;
        int ret;
    
        size_t namelen = strlen(name);
        size_t valuelen = strlen(value);
    
        if (!is_legal_property_name(name, namelen)) return -1;
        if (valuelen >= PROP_VALUE_MAX) return -1;
    
        pi = (prop_info*) __system_property_find(name);
    
        if(pi != 0) {
            /* ro.* properties may NEVER be modified once set */
            if(!strncmp(name, "ro.", 3)) return -1;
    
            __system_property_update(pi, value, valuelen);
        } else {
            ret = __system_property_add(name, namelen, value, valuelen);
            if (ret < 0) {
                ERROR("Failed to set '%s'='%s'\n", name, value);
                return ret;
            }
        }
        /* If name starts with "net." treat as a DNS property. */
        if (strncmp("net.", name, strlen("net.")) == 0)  {
            if (strcmp("net.change", name) == 0) {
                return 0;
            }
           /*
            * The 'net.change' property is a special property used track when any
            * 'net.*' property name is updated. It is _ONLY_ updated here. Its value
            * contains the last updated 'net.*' property.
            */
            property_set("net.change", name);
        } else if (persistent_properties_loaded &&
                strncmp("persist.", name, strlen("persist.")) == 0) {
            /*
             * Don't write properties to disk until after we have read all default properties
             * to prevent them from being overwritten by default values.
             */
            write_persistent_property(name, value);
        } else if (strcmp("selinux.reload_policy", name) == 0 &&
                   strcmp("1", value) == 0) {
            selinux_reload_policy();
        }
        property_changed(name, value);
        return 0;
    }
    

    这样setprop怎么实现就完全了解了。

    至于prop的存储,从bionic/libc/include/sys/_system_properties.h就可以看出来:

    #define PROP_PATH_RAMDISK_DEFAULT  "/default.prop"
    #define PROP_PATH_SYSTEM_BUILD     "/system/build.prop"
    #define PROP_PATH_SYSTEM_DEFAULT   "/system/default.prop"
    #define PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop"
    

    而通过上面code中write_persistent_property函数就可以知道一般persist.xx等prop是存储在/data/property下,具体code如下:

    static void write_persistent_property(const char *name, const char *value)  
    {  
        const char *tempPath = PERSISTENT_PROPERTY_DIR "/.temp";  
        char path[PATH_MAX];  
        int fd, length;  
      
        snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);  
      
        fd = open(tempPath, O_WRONLY|O_CREAT|O_TRUNC, 0600);  
        if (fd < 0) {  
            ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno);  
            return;  
        }  
        write(fd, value, strlen(value));  
        close(fd);  
      
        if (rename(tempPath, path)) {  
            unlink(tempPath);  
            ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path);  
        }  
    }
    

    一般的prop是暂时存放在内存中。

更多 推荐条目

Welcome to NowaMagic Academy!

现代魔法 推荐于 2013-02-27 10:23   

本章最新发布
随机专题
  1. [Python程序设计] Django数据库模型 6 个条目
  2. [PHP程序设计] htaccess 设置技巧 6 个条目
  3. [移动开发] Android Studio里的Gradle 3 个条目
  4. [软件工程与项目管理] 呈现器的布局与绘制 11 个条目
  5. [移动开发] Android根基概念Context 8 个条目
  6. [智力开发与知识管理] 信息的类型与结构 9 个条目
  7. [Python程序设计] Python Web部署的背景知识 9 个条目
  8. [PHP程序设计] PHP数组探索 4 个条目
  9. [软件工程与项目管理] 开始使用Git 3 个条目
  10. [Python程序设计] Django架构流程分析 7 个条目
  11. [软件工程与项目管理] 浏览器与CSS渲染技巧 2 个条目
  12. [移动开发] Android属性系统Property 9 个条目
窗口 -- [博客]