Android -- SystemProperties Application

Source: Internet
Author: User

1. Order

The previous article analyzed the generation of the system property file build. prop. Attributes are widely used in Android systems to record system settings or information exchange between processes. Properties are globally visible throughout the system. Each process can get/set attributes, which are mainly recorded in the java layer or c ++ layer, and the entire system_property operation process.


2. The source code for calling the java layer is located in/frameworks/base/core/java/android/OS/SystemProperties. java:

Get attributes:
  /**     * 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 attributes:
    /**     * 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);    }

Both call the local interface:
private static native String native_get(String key);private static native void native_set(String key, String def);


This interface class registers the corresponding cpp interface android_ OS _SystemProperties.cpp in the initialization runtime environment. The actual operation is to call the interface corresponding to the cpp file through JNI:

In/frameworks/base/core/jni/AndroidRuntime. cpp:

extern int register_android_os_SystemProperties(JNIEnv *env);


Jni in/frameworks/base/core/JNI/android_ 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 },    { "native_add_change_callback", "()V",      (void*) SystemProperties_add_change_callback },};

Take the set attribute as an Example, Call:

static void SystemProperties_set(JNIEnv *env, jobject clazz,                                      jstring keyJ, jstring valJ){    int err;    const char* key;    const char* val;    if (keyJ == NULL) {        jniThrowNullPointerException(env, "key must not be null.");        return ;    }    key = env->GetStringUTFChars(keyJ, NULL);    if (valJ == NULL) {        val = "";       /* NULL pointer not allowed here */    } else {        val = env->GetStringUTFChars(valJ, NULL);    }    err = property_set(key, val);    env->ReleaseStringUTFChars(keyJ, key);    if (valJ != NULL) {        env->ReleaseStringUTFChars(valJ, val);    }    if (err < 0) {        jniThrowException(env, "java/lang/RuntimeException",                          "failed to set system property");    }}

To/system/core/libcutils/properties. c Property_set (key, val). It is okay to understand the java layer here.


III. c ++ layer calls in/system/core/libcutils/properties. c:

int property_set(const char *key, const char *value){    return __system_property_set(key, value);}

To/bionic/libc/bionic/system_properties.c:
int __system_property_set(const char *key, const char *value){....    memset(&msg, 0, sizeof msg);    msg.cmd = PROP_MSG_SETPROP;    strlcpy(msg.name, key, sizeof msg.name);    strlcpy(msg.value, value, sizeof msg.value);    err = send_prop_msg(&msg);    if(err < 0) {        return err;    }    return 0;}

Communicate through a common TCP (SOCK_STREAM) socket.

static int send_prop_msg(prop_msg *msg){    struct pollfd pollfds[1];    struct sockaddr_un addr;    socklen_t alen;    size_t namelen;    int s;    int r;    int result = -1;    s = socket(AF_LOCAL, SOCK_STREAM, 0);    if(s < 0) {        return result;    }    memset(&addr, 0, sizeof(addr));    namelen = strlen(property_service_socket);...}

The above is used as a client to send messages to the service through socket.




4. Start the property_service Service

The property_service service is enabled when android is initialized at/system/core/init. c:


int main(int argc, char **argv){    int fd_count = 0;    struct pollfd ufds[4];...int property_set_fd_init = 0;... queue_builtin_action(property_service_init_action, "property_service_init");... if (!property_set_fd_init && get_property_set_fd() > 0) {            ufds[fd_count].fd = get_property_set_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            property_set_fd_init = 1;        }...  if (ufds[i].revents == POLLIN) {                if (ufds[i].fd == get_property_set_fd())                    handle_property_set_fd();...}

The init daemon allocates a shared memory area to store these attributes. And through _ libc_init (...) -- _ libc_init_common (...) -- _ system_properties_init ();

The _ system_properties_init () in/bionic/libc/bionic/system_properties.c initializes the shared memory of the property system.


The system property service property_service is started here, which is http://blog.csdn.net/jscese/article/details/17115395.


Call the start function from property_service_init_action to/system/core/init/property_service.c:

void start_property_service(void){    int fd;    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);    load_override_properties();    /* Read persistent properties after all default values have been loaded. */    load_persistent_properties();    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);    if(fd < 0) return;    fcntl(fd, F_SETFD, FD_CLOEXEC);    fcntl(fd, F_SETFL, O_NONBLOCK);    listen(fd, 8);    property_set_fd = fd;}

We can see that the system property file is loaded to the shared memory. The file is defined in/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"

Property Information is loaded in the above Order. The loaded attributes overwrite the previous attribute values (when the attribute names are the same ). After the above loading is complete, the last load is the resident attribute, Which is saved in the/data/property file.

A SOCK_STREAM socket is created and enters the listen listening status!

Property_service has been started!



5. property_service Service Message Processing

It is called when an event with property service is monitored in the init daemon:

void handle_property_set_fd(){    prop_msg msg;... if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {        return;    }... r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));... switch(msg.cmd) {    case PROP_MSG_SETPROP:...  if(memcmp(msg.name,"ctl.",4) == 0) {            // Keep the old close-socket-early behavior when handling            // ctl.* properties.            close(s);            if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {                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_perms(msg.name, cr.uid, cr.gid, source_ctx)) {                property_set((char*) msg.name, (char*) msg.value);            } else {                ERROR("sys_prop: permission denied uid:%d  name:%s\n",                      cr.uid, msg.name);            }...}

Receive socket request connections, receive attribute requests, and process information:

We can see that if the receivedThe information starts with "ctl ".Check_control_perms (msg. value, cr. uid, cr. gid, source_ctx)Authentication.

Here, the incoming message value, the uid and gid of the message sending process.

Here is the control permission array:

/* * White list of UID that are allowed to start/stop services. * Currently there are no user apps that require. */struct {    const char *service;    unsigned int uid;    unsigned int gid;} control_perms[] = {    { "dumpstate",AID_SHELL, AID_LOG },    { "ril-daemon",AID_RADIO, AID_RADIO },     {NULL, 0, 0 }};

Various permissions are defined in/system/core/include/private/android_filesystem_config.h:

#define AID_ROOT             0  /* traditional unix root user */#define AID_SYSTEM        1000  /* system server */#define AID_RADIO         1001  /* telephony subsystem, RIL */#define AID_BLUETOOTH     1002  /* bluetooth subsystem */#define AID_GRAPHICS      1003  /* graphics devices */


Execute:

void handle_control_message(const char *msg, const char *arg){    if (!strcmp(msg,"start")) {        msg_start(arg);    } else if (!strcmp(msg,"stop")) {        msg_stop(arg);    } else if (!strcmp(msg,"restart")) {        msg_stop(arg);        msg_start(arg);    } else {        ERROR("unknown control msg '%s'\n", msg);    }}

This is used to enable, disable, or restart the service!


Average message value Authentication check_perms (msg. name, cr. uid, cr. gid, source_ctx ).

General control permission array:

/* White list of permissions for setting property services. */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 },...};

If you have the permission, run the following command:

int property_set(const char *name, const char *value){... if(pi != 0) {        /* ro.* properties may NEVER be modified once set */        if(!strncmp(name, "ro.", 3))          return -1;... /* 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);#ifdef HAVE_SELINUX    } else if (strcmp("selinux.reload_policy", name) == 0 &&               strcmp("1", value) == 0) {        selinux_reload_policy();#endif    }    property_changed(name, value);    return 0;}

This property_set is the real execution function of the set attribute!


You can see whether"Ro"String. If the received message value, that is, the attribute value to be set starts with this value, it indicatesRead-OnlyCannot be changed.


If the shared memory contains update_prop_info (pi, value, valuelen); if not, it is saved to the memory.


If the property is"Net ."String. When this attribute is set,"Net. change"This attribute is automatically set, and its content is set to the last updated attribute name to record changes in the net. * attribute.


If the property is"Persist ."It is considered as a resident attribute. When modified, it will also be written/Data/propertyFile.


Last callProperty_changed (name, value)The notification attributes have changed and are updated. You do not need to call this method for the attributes available only at runtime unless they can be bound to data.


The property_service service has been thoroughly analyzed!



6. adb shell command

Adb shell getprop list all system attributes


Adb shell getprop | grep LCD list attributes containing the LCD


Adb shell setprop Modifies a specified system attribute.




It is not easy to write. For more information, see http://blog.csdn.net/jscese/article/details/18700903.




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.