天天看点

Android System Property分析(2):property_service

    property_service是在init中启动的,

int main(int argc, char **argv){
    property_init();
    property_load_boot_defaults(); // 加载"/default.prop"
    queue_builtin_action(property_service_init_action, "property_service_init");
    // ...
           
void property_init(void){
    init_property_area(); // 开始初始化property内存和workspace
}
static int init_property_area(void) {
    if (property_area_inited)
        return -1;

    if(__system_property_area_init()) // 映射一块内存
        return -1;

    if(init_workspace(&pa_workspace, 0)) // 初始化workspace
        return -1;

    fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);

    property_area_inited = 1; // 初始化完成标记
    return 0;
}
int __system_property_area_init(){
    return map_prop_area_rw();
}
static int map_prop_area_rw(){
    prop_area *pa;
    int fd;
    int ret;

    /* dev is a tmpfs that we can use to carve a shared workspace
     * out of, so let's do that...
     */
    fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC |  // 打开/dev/__properties__临时设备
            O_EXCL, 0444);
    if (fd < 0) {
        if (errno == EACCES) {
            /* for consistency with the case where the process has already
             * mapped the page in and segfaults when trying to write to it
             */
            abort();
        }
        return -1;
    }

    ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
    if (ret < 0)
        goto out;

    if (ftruncate(fd, PA_SIZE) < 0) // 改变大小为128k
        goto out;

    pa_size = PA_SIZE;
    pa_data_size = pa_size - sizeof(prop_area);
    compat_mode = false;
    // 映射出一块内存
    pa = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(pa == MAP_FAILED)
        goto out;

    memset(pa, 0, pa_size);
    pa->magic = PROP_AREA_MAGIC;
    pa->version = PROP_AREA_VERSION;
    /* reserve root node */
    pa->bytes_used = sizeof(prop_bt);

    /* plug into the lib property services */
    __system_property_area__ = pa;  // __system_property_area__全局变量

    close(fd);
    return 0;
}
           
static int init_workspace(workspace *w, size_t size){
    void *data;
    int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW); // 只读工作区间pa_workspace
    if (fd < 0)
        return -1;

    w->size = size;
    w->fd = fd;
    return 0;
}
           

初始化property内存,工作区间完成。

下面开始启动property_service:

static int property_service_init_action(int nargs, char **args){
    start_property_service(); // 开始启动property_service
    return 0;
}
void start_property_service(void){
    int fd;
    // 依次加载系统属性文件"/system/build.prop", "/system/default.prop"
    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
    load_override_properties(); // 如果存在"/data/local.prop",则会覆盖已有属性
    /* Read persistent properties after all default values have been loaded. */
    load_persistent_properties(); // 加载persistent属性,读取/data/property/目录

    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0); // 创建socket
    if(fd < 0) return;
    fcntl(fd, F_SETFD, FD_CLOEXEC);
    fcntl(fd, F_SETFL, O_NONBLOCK);

    listen(fd, 8);  // 进入监听
    property_set_fd = fd;
}
           

加载属性文件:

static void load_properties_from_file(const char *fn){
    char *data;
    unsigned sz;

    data = read_file(fn, &sz);

    if(data != 0) {
        load_properties(data); // 读取属性文件后,调用property_set设置属性值
        free(data);
    }
}
           

persist开头的属性会做特殊处理,设置时除了设置属性,还会写到/data/property目录下,需要设置后重启还能生效的属性需要以persist方式保存。例如:art和dvm切换,persist.sys.dalvik.vm.lib

// 加载persistent属性
load_persistent_properties
// 设置persistent属性
int property_set(const char *name, const char *value){
     if (persistent_properties_loaded &&
            strncmp("persist.", name, strlen("persist.")) == 0) {
            char bootmode[PROP_VALUE_MAX];
            ret = property_get("ro.bootmode", bootmode);
            if (ret <= 0 || (strcmp(bootmode, "charger") != 0))         //do not write prop while charger mode
        /*
         * 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); // 写persistent属性到/data/property
    }
    return 0;
}
           

到这里,property_service就启动了。