property_set的整体过程--以reboot和bootanim为例

前记

         最近看到surfaceflinger在初始化结束后会通过property_set的方式启动开机动画,这种情形很像之前reboot命令中看见的,因此按照之前的分析来分析bootanim,但是发现分析错误,后来深入去了解,才发现我之前分析错了,因此写下这份文档纠正自己的错误,以便以后的学习。

1. Property_set的整个过程

 我先纠正一下reboot命令的分析,reboot的源码比较简单,在system/core/reboot/reboot.c中:

ret = property_set(ANDROID_RB_PROPERTY,property_val);

         reboot是通过property_set的方式触发propertychange事件,然后才会去真正执行reboot操作。而之前分析错误的原因主要就是property_set的定位出错。


 利用SourceInsight进行代码搜索,可以发现有两个地方定义了property_set,分析是在system/core/libcutils/properties.c和system/core/init/property_service.c。当时由于主观臆想定位出错了,现在分析一下如何正确地定位是在哪个源文件实现:

         Reboot目录下的Android.mk中是如下定义的:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= reboot.c

LOCAL_SHARED_LIBRARIES:= libcutils        

LOCAL_MODULE:= reboot

include $(BUILD_EXECUTABLE)

         reboot只包含了libcutils这个动态库,因此property_set就应该是在这里所实现的。而从这个库的名字就可以猜测其是在system/core/libcutils中,我们验证一下;

         从system/core/libcutils/Android.mk中可以看到,property_set就是该目录下的properties.c中定义的。


         在properties.c中有三个property_set的定义:

#ifdef HAVE_LIBC_SYSTEM_PROPERTIES        /*如果有定义libc,也就是bionic*/

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

{

    return__system_property_set(key, value);

}

#elif defined(HAVE_SYSTEM_PROPERTY_SERVER)     /*如果定义了property_server*/

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

{

    charsendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];

    charrecvBuf[1];

    intresult = -1;

   //ALOGV("PROPERTY SET [%s]: [%s]\n", key, value);

   pthread_once(&gInitOnce, init);

    if(gPropFd < 0)

       return -1;

    if(strlen(key) >= PROPERTY_KEY_MAX) return -1;

    if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;

   memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind

   sendBuf[0] = (char) kSystemPropertySet;

   strcpy(sendBuf+1, key);

   strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);

pthread_mutex_lock(&gPropertyFdLock);

/*通过socket -- /tmp/android-sysprop */

    if(write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)){

       pthread_mutex_unlock(&gPropertyFdLock);

       return -1;

    }

    if(read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {

       pthread_mutex_unlock(&gPropertyFdLock);

       return -1;

    }

   pthread_mutex_unlock(&gPropertyFdLock);

    if(recvBuf[0] != 1)

       return -1;

    return0;

}

#else

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

{

    charename[PROPERTY_KEY_MAX + 6];

    char*p;

    intlen;

    int r;

   if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;

    len =strlen(key);

    if(len>= PROPERTY_KEY_MAX) return -1;

   memcpy(ename, "PROP_", 5);

    memcpy(ename+ 5, key, len + 1);

mutex_lock(&env_lock);

/*通过env*/

#ifdef HAVE_MS_C_RUNTIME

    {

       char  temp[256];

       snprintf( temp, sizeof(temp), "%s=%s", ename, value);

       putenv(temp);

        r= 0;

    }

#else   

    r =setenv(ename, value, 1);

#endif   

   mutex_unlock(&env_lock);

    returnr;

}

#endif

         Property_set在Libcutils中有三种方式,可以通过配置进行选择,而通过grep可以知道使用的是libc的方式:

./build/core/combo/include/arch/linux-arm/AndroidConfig.h:249:#defineHAVE_LIBC_SYSTEM_PROPERTIES 1

         __system_property_set是在bionic/libc/bionic/system_properties.c中定义的:

int __system_property_set(const char *key, constchar *value)

{

    int err;

   prop_msg msg;

    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;

   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;

    }

    return0;

}

static int send_prop_msg(prop_msg *msg)

{

    structpollfd pollfds[1];

    structsockaddr_un addr;

   socklen_t alen;

    size_tnamelen;

    int s;

    int r;

    intresult = -1;

    s =socket(AF_LOCAL, SOCK_STREAM, 0);

    if(s< 0) {

       return result;

    }

   memset(&addr, 0, sizeof(addr));

namelen= strlen(property_service_socket);

/*

PROP_SERVICE_NAME=property_server

staticconst char property_service_socket[] = "/dev/socket/"PROP_SERVICE_NAME;

*/

   strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);

    addr.sun_family = AF_LOCAL;

    alen =namelen + offsetof(struct sockaddr_un, sun_path) + 1;

   if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen))< 0) {

       close(s);

       return result;

    }

    r =TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));

    if(r== sizeof(prop_msg)) {

       pollfds[0].fd = s;

       pollfds[0].events = 0;

        r= TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));

        if(r == 1 && (pollfds[0].revents & POLLHUP) != 0) {

           result = 0;

        }else {

           result = 0;

        }

    }

   close(s);

    returnresult;

}

         也就是说,propert_set最终会通过socket(IPC)来通知server处理,那必然会有一个server在接收数据进行处理,而这个server在init进程中:

<system/core/init/init.c>

queue_builtin_action(property_service_init_action,"property_service_init");

static intproperty_service_init_action(int nargs, char **args)

{

    start_property_service();

    return 0;

}

voidstart_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 alldefault values have been loaded. */

load_persistent_properties();

/*创建socket接收数据*/

    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;

}

<main>

for(;;) {

        int nr, i, timeout = -1;

        execute_one_command();

        restart_processes();

        if (!property_set_fd_init &&get_property_set_fd() > 0) {

            ufds[fd_count].fd =get_property_set_fd();   /*监听property_set_fd*/

            ufds[fd_count].events = POLLIN;

            ufds[fd_count].revents = 0;

            fd_count++;

            property_set_fd_init = 1;

        }

        if (!signal_fd_init &&get_signal_fd() > 0) {

            ufds[fd_count].fd =get_signal_fd();

            ufds[fd_count].events = POLLIN;

            ufds[fd_count].revents = 0;

            fd_count++;

            signal_fd_init = 1;

        }

        if (!keychord_fd_init &&get_keychord_fd() > 0) {

            ufds[fd_count].fd =get_keychord_fd();

            ufds[fd_count].events = POLLIN;

            ufds[fd_count].revents = 0;

            fd_count++;

            keychord_fd_init = 1;

        }

        if (process_needs_restart) {

            timeout = (process_needs_restart -gettime()) * 1000;

            if (timeout < 0)

                timeout = 0;

        }

        if (!action_queue_empty() ||cur_action)

            timeout = 0;

#ifBOOTCHART

        if (bootchart_count > 0) {

            if (timeout < 0 || timeout >BOOTCHART_POLLING_MS)

                timeout = BOOTCHART_POLLING_MS;

            if (bootchart_step() < 0 ||--bootchart_count == 0) {

                bootchart_finish();

                bootchart_count = 0;

            }

        }

#endif

        nr = poll(ufds, fd_count, timeout);

        if (nr <= 0)

            continue;

        for (i = 0; i < fd_count; i++) {

            if (ufds[i].revents == POLLIN) {

                if (ufds[i].fd ==get_property_set_fd())   /*如果property_set_fd有POLLIN事件*/

                    handle_property_set_fd();

                else if (ufds[i].fd ==get_keychord_fd())

                    handle_keychord();

                else if (ufds[i].fd ==get_signal_fd())

                    handle_signal();

            }

        }

}

<property_service.c>

voidhandle_property_set_fd()

{

    prop_msg msg;

    int s;

    int r;

    int res;

    struct ucred cr;

    struct sockaddr_un addr;

    socklen_t addr_size = sizeof(addr);

    socklen_t cr_size = sizeof(cr);

char * source_ctx = NULL;

/*接收property_set的数据*/

    if ((s = accept(property_set_fd, (structsockaddr *) &addr, &addr_size)) < 0) {

        return;

    }

    /* Check socket options here */

    if (getsockopt(s, SOL_SOCKET, SO_PEERCRED,&cr, &cr_size) < 0) {

        close(s);

        ERROR("Unable to receive socketoptions\n");

        return;

    }

    r = TEMP_FAILURE_RETRY(recv(s, &msg,sizeof(msg), 0));

    if(r != sizeof(prop_msg)) {

        close(s);

        return;

    }

    switch(msg.cmd) {

    case PROP_MSG_SETPROP:

       msg.name[PROP_NAME_MAX-1] = 0;

        msg.value[PROP_VALUE_MAX-1] = 0;

        /*校验property是否合法的属性*/

        if (!is_legal_property_name(msg.name,strlen(msg.name))) {

            ERROR("sys_prop: illegalproperty name. Got: \"%s\"\n", msg.name);

            close(s);

            return;

        }

        getpeercon(s, &source_ctx);

        /*如果是带有”ctl.”开头的属性,是具有控制操作的,另作处理,这就是bootanim的处理过程*/

        if(memcmp(msg.name,"ctl.",4)== 0) {

            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)) {

             /*当初定位错误就是在这里,分析reboot的时候直接跳到这一步*/

                property_set((char*)msg.name, (char*) msg.value);

            } else {

            }

            close(s);

        }

        freecon(source_ctx);

        break;

    default:

        close(s);

        break;

    }

}

1.1 reboot的处理

对于reboot的处理,就是第二分支,调用了property_set来进行处理,而这个property_set与在reboot.c中调用的property_set并不是同一个,这个后者是在libc定义的,前者是在property_service中定义的。

<system/core/init/property_service.c>

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

{

   prop_info *pi;

    intret;

    size_tnamelen = strlen(name);

    size_tvaluelen = 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);   /*更新到property的内存区域中*/

    } else{

       ret = __system_property_add(name, namelen, value, valuelen);  /*新增一个属性*/

        if(ret < 0) {

           ERROR("Failed to set '%s'='%s'\n", name, value);

           return ret;

        }

    }

    /* Ifname starts with "net." treat as a DNS property. */

    if(strncmp("net.", name, strlen("net.")) == 0)  {

        if(strcmp("net.change", name) == 0) {

           return 0;

        }

       property_set("net.change", name);

    } elseif (persistent_properties_loaded &&

           strncmp("persist.", name, strlen("persist.")) == 0){

       write_persistent_property(name, value);

    } elseif (strcmp("selinux.reload_policy", name) == 0 &&

              strcmp("1", value) == 0) {

       selinux_reload_policy();

    }

    property_changed(name, value);

    #ifdefAW_BOOSTUP_ENABLE

    aw_boost_up_perf(name,value);

    #endif

    return0;

}

void property_changed(const char *name, constchar *value)

{

    if(property_triggers_enabled)

       queue_property_triggers(name, value);

}

void queue_property_triggers(const char *name,const char *value)

{

    structlistnode *node;

structaction *act;

/*遍历所有注册的action*/

   list_for_each(node, &action_list) {

       act = node_to_item(node, struct action, alist);

        /*匹配带有property的action,直到与property_set的属性相同的action,然后执行相应操作*/

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

                     !strcmp(test + name_length+ 1, "*"))) {

               action_add_queue_tail(act);   /*添加到action队列中,等待init进程执行*/

           }

        }

    }

}

         Reboot的propert_set对应的命令是:

#define ANDROID_RB_PROPERTY"sys.powerctl"

         Init.rc中对应的sys.powerctlaction是如下定义的:

on property:sys.powerctl=*

   powerctl ${sys.powerctl}

         无论powerctl为何值,都会执行{powerctl${sys.powerctl}}这个操作,powerctl对应的函数在keyword.h中有定义—do_powerctl,这里就不进行分析了。

1.2 bootanim的处理

Bootanim对应于第一个分支,我们可以看看surfaceflinger是如何启动bootanim的:

void SurfaceFlinger::startBootAnim() {

    //start boot animation

   property_set("service.bootanim.exit", "0");

    property_set("ctl.start","bootanim");   /*主要是这一个操作*/

}

<init.rc>

service bootanim /system/bin/bootanimation

    classmain

    usersystem

    groupsystem

    disabled      /*init.rcbootanimdisable的,因为需要等待surfaceflinger的初始化完成*/

   oneshot

         当startBootAnim()后,就可以运行开机动画了。我们看一下property_service是如何实现的:

void handle_control_message(const char *msg,const char *arg)

{

    if(!strcmp(msg,"start")) {   /*ctl后带的是start*/

        msg_start(arg);

    } elseif (!strcmp(msg,"stop")) {

       msg_stop(arg);

    } elseif (!strcmp(msg,"restart")) {

       msg_restart(arg);

    } else{

       ERROR("unknown control msg '%s'\n", msg);

    }

}

static void msg_start(const char *name)

{

    structservice *svc = NULL;

    char*tmp = NULL;

    char*args = NULL;

 

    if(!strchr(name, ':'))

       svc = service_find_by_name(name);

    else {

       tmp = strdup(name);

        if(tmp) {

           args = strchr(tmp, ':');

           *args = '\0';

           args++;

           svc = service_find_by_name(tmp);

        }

    }

    if(svc) {

        service_start(svc, args);

    } else{

       ERROR("no such service '%s'\n", name);

    }

    if(tmp)

       free(tmp);

}

         Property_service在收到ctl族的property后,先去找到这个service,然后启动它。

struct service *service_find_by_name(const char*name)

{

    structlistnode *node;

structservice *svc;

/*service_list 就是保存了init.rc中使用service声明的action,bootanim就是一个service*/

   list_for_each(node, &service_list) {

       svc = node_to_item(node, struct service, slist);

        if(!strcmp(svc->name, name)) {

           return svc;

        }

    }

    return0;

}

         Service_start比较复杂,就不展开说明了,其实主要就是解析init.rc的配置,通过fork创建一个新进程,然后加载其elf文件运行。

         Property_set的整个过程就是如此简单,不过当初的武断差点走了歪路,不过现在已经搞清楚整个过程了。




 


  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值