Property System of Android

Source: Internet
Author: User

I always wanted to study the property system of Android, but a recent project has come to an end, so I can start to study the relevant code.

According to my understanding, Android attributes are divided into two parts:

1. One part is system attributes, which are generally related to virtual machines,

Code Location

Dalvik/libcore/luni-kernel/src/main/Java/lang/system. Java

Dalvik/libcore/luni/src/main/Java/util/properties. Java

Dalvik/Vm/properties. c

Virtual machines have some default attributes, such as OS. Arch and Java. boot. Class. path, which are loaded only once.

Take the VNC attribute in settings. Java as an example.

        private DialogInterface.OnClickListener mVncDisableListener =  new DialogInterface.OnClickListener()        {            public void onClick(DialogInterface dialog, int whichButton)            {                System.setProperty("vncserver.enable", "0");                System.setProperty("vncserver.password", "");            }        };

Check the code of system. java.

    public static String setProperty(String prop, String value) {        if (prop.length() == 0) {            throw new IllegalArgumentException();        }        SecurityManager secMgr = System.getSecurityManager();        if (secMgr != null) {            secMgr.checkPermission(new PropertyPermission(prop, "write"));        }        return (String)internalGetProperties().setProperty(prop, value);    }

The write permission check will be performed on the thread before setting the attribute.

In the internalgetproperties method, the default attributes of the virtual machine are loaded.

    static Properties internalGetProperties() {        if (System.systemProperties == null) {            SystemProperties props = new SystemProperties();            props.preInit();            props.postInit();            System.systemProperties = props;        }        return systemProperties;    }

The systemproperties here is only an internal class, which is not the same as Android. OS. systemproperties.

class SystemProperties extends Properties {    // Dummy, just to make the compiler happy.    native void preInit();    native void postInit();}

It inherits properties. Two JNI interfaces are registered in Dalvik/Vm/native/java_lang_systemproperties.c. preinit calls the local dvmcreatedefaultproperties function, which loads the default attributes of the VM just mentioned.

static void Dalvik_java_lang_SystemProperties_preInit(const u4* args,    JValue* pResult){    dvmCreateDefaultProperties((Object*) args[0]);    RETURN_VOID();}

That is to say, system. setproperty is called to properties. setproperty,

    public Object setProperty(String name, String value) {        return put(name, value);    }

Properties is inherited from hashtable

public class Properties extends Hashtable<Object, Object>

In this way, the attribute setting action is completed. The obtained action is similar. Finally, the value is obtained from the hash table based on the key. The whole process is relatively simple.

We can see that this property system is only suitable for attributes that do not change, or that are rarely changed. If you want to trigger some practices after changing your property, such as init. the action in the RC Script requires another property system.

2. The rest are general attributes.

Its implementation principle is different from that of the hash table. It means that attributes are stored in a shared memory. The size of the shared memory is determined by the Environment Variable android_property_workspace.

Code Location:

Frameworks/base/CORE/Java/Android/OS/systemproperties. Java

Frameworks/base/CORE/JNI/android_ OS _systemproperties.cpp

System/CORE/init/property_service.c

Bionic/libc/bionic/system_properties.c

Attribute writing process:

Systemproperties. Java

    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);    }

Value only supports the string type, while get reloads values of various types.

These methods call JNI

    private static native String native_get(String key);    private static native String native_get(String key, String def);    private static native int native_get_int(String key, int def);    private static native long native_get_long(String key, long def);    private static native boolean native_get_boolean(String key, boolean def);    private static native void native_set(String key, String def);

These JNI are registered in frameworks/base/CORE/jniandroid_ OS _systemproperties.cpp.

static 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 },};

The systemproperties_set method is called to

int property_set(const char *name, const char *value)

The process in property_set is as follows:

Prime Minister, pass

    pi = (prop_info*) __system_property_find(name);

Find the corresponding key-value pair. prop_info is defined in Bionic/libc/include/sys/_ system_properties.h.

struct prop_area {    unsigned volatile count;    unsigned volatile serial;    unsigned magic;    unsigned version;    unsigned reserved[4];    unsigned toc[1];};#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)#define SERIAL_DIRTY(serial) ((serial) & 1)struct prop_info {    char name[PROP_NAME_MAX];    unsigned volatile serial;    char value[PROP_VALUE_MAX];};

Let's take a look at the implementation of _ system_property_find. This function is located in system_properties.c.

const prop_info *__system_property_find(const char *name){    prop_area *pa = __system_property_area__;    unsigned count = pa->count;        unsigned *toc = pa->toc;    unsigned len = strlen(name);       prop_info *pi;    while(count--) {        unsigned entry = *toc++;               if(TOC_NAME_LEN(entry) != len) continue;                pi = TOC_TO_INFO(pa, entry);           if(memcmp(name, pi->name, len)) continue;        return pi;    }      return 0;}

This function is used to find out the key-value pairs. Let's look at the definitions of toc_name_len and toc_to_info,

#define TOC_NAME_LEN(toc)       ((toc) >> 24)#define TOC_TO_INFO(area, toc)  ((prop_info*) (((char*) area) + ((toc) & 0xFFFFFF)))

Therefore, the top 8 bits of TOC store the length of the attribute name, and the lowest 24 bits store the address of the attribute key-value pair,

Let's look at _ system_property_area _. This is a global variable and is initialized in the _ system_properties_init function of system_properties.c.

This function reads android_property_workspace environment variables in the format of FD and size.

Then, MMAP is used to map the content in "FD" to "size" and assign it to _ system_property_area __.

If the matching is successful, check how property_set works.

 if(pi != 0) {        /* ro.* properties may NEVER be modified once set */        if(!strncmp(name, "ro.", 3)) return -1;        pa = __system_property_area__;        update_prop_info(pi, value, valuelen);        pa->serial++;        __futex_wake(&pa->serial, INT32_MAX);    }

Note that the modifier of PA-> serial ++ contains a volatile, which ensures that every modification to the attribute system can be processed.

See update_prop_info

static void update_prop_info(prop_info *pi, const char *value, unsigned len){    pi->serial = pi->serial | 1;    memcpy(pi->value, value, len + 1);    pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);    __futex_wake(π->serial, INT32_MAX);}

First, modify the serial number + 1 for the format, save the attribute value, and call _ futex_wake to trigger a system call. This is written in atomics_x86.c.

int __futex_wake(volatile void *ftx, int count){    int ret;    asm volatile (        "int $0x80;"        : "=a" (ret)        : "0" (FUTEX_SYSCALL),          "b" (ftx),          "c" (FUTEX_WAKE),          "d" (count)    );    return ret;}

What does it mean.

Next, the property_set statement is executed as follows:

property_changed(name, value);

Property_changed is defined in system/CORE/init. C.

void property_changed(const char *name, const char *value){    if (property_triggers_enabled) {        queue_property_triggers(name, value);        drain_action_queue();    }}

Property_triggers_enabled is set in the execution of the main function.

void queue_property_triggers(const char *name, const char *value){           struct listnode *node;    struct action *act;    list_for_each(node, &action_list) {        act = node_to_item(node, struct action, alist);        if (!strncmp(act->name, "property:", strlen("property:"))) {            const char *test = act->name + strlen("property:");            int name_length = strlen(name);                        if (!strncmp(name, test, name_length) &&                    test[name_length] == '=' &&                    !strcmp(test + name_length + 1, value)) {                action_add_queue_tail(act);            }        }    }}

This function indicates that all actions in action_list that care about this attribute are serialized into act. action_list should be generated when parsing the initialization script file.

void drain_action_queue(void){           struct listnode *node;    struct command *cmd;    struct action *act;    int ret;    while ((act = action_remove_queue_head())) {        INFO("processing action %p (%s)\n", act, act->name);        list_for_each(node, &act->commands) {            cmd = node_to_item(node, struct command, clist);            ret = cmd->func(cmd->nargs, cmd->args);            INFO("command '%s' r=%d\n", cmd->args[0], ret);        }    }}   

This function is used to trigger various callback functions.

Parsing the script file is completed by system/CORE/init/parser. C. The main function of init. C has the following statements:

    get_hardware_name();    snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);    parse_config_file(tmp);

In parser. C

    int parse_config_file(const char *fn){       char *data;    data = read_file(fn, 0);    if (!data) return -1;    parse_config(fn, data);    DUMP();    return 0;}

Parse_config_file reads and parses the script file.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.