对于android开机动画的启动和停止,在代码中是通过调用property_service.c中的property_set实现的,代码如下:

property_set(“ctl.start”, “bootanim”);

property_set(“ctl.stop”, “bootanim”);

当然也可以通过命令行来控制,命令如下:

#setprop ctl.start bootanim

#setprop ctl.stop bootanim

其实通过控制ctl.startctl.stop这两个属性,不仅仅可以控制开机动画,还可以控制init.rc文件中定义的各种service

ctl.xxx是怎么样实现start或者stop一个service的呢?

Androidinit进程在启动的过程当中会通过start_property_service函数创建一个属性服务的socket,这个socket描述符为/dev/socket/

property_service,系统中对属性的操作都会以请求的形式发给这个socket, start_property_service函数代码如下:

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;

}

那这些请求是在哪里被处理呢?也是在init进程当中。

Init进程启动的最后,会进入一个循环结构,代码如下:

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

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;

#if BOOTCHART

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

handle_property_set_fd();//处理对属性的控制请求

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

handle_keychord();

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

handle_signal();

}

}

}

这个循环体就一直在poll几个fd,其中有一个就是上面讲的属性服务的socket, handle_property_set_fd的代码如下:

void handle_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;

if ((s = accept(property_set_fd, (struct sockaddr *) &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 recieve socket options\n");

return;

}

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

if(r != sizeof(prop_msg)) {

ERROR("sys_prop: mis-match msg size recieved: %d expected: %d errno: %d\n",

r, sizeof(prop_msg), errno);

close(s);

return;

}

switch(msg.cmd) {

case PROP_MSG_SETPROP:

msg.name[PROP_NAME_MAX-1] = 0;

msg.value[PROP_VALUE_MAX-1] = 0;

#ifdef HAVE_SELINUX

getpeercon(s, &source_ctx);

#endif

//如果是对ctl.xxx属性的请求,则最后会调用init.c文件定义的service_start或者service_stop函数来运行或者停止一个service

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

}

// Note: bionic's property client code assumes that the

// property server will not close the socket until *AFTER*

// the property is written to memory.

close(s);

}

#ifdef HAVE_SELINUX

freecon(source_ctx);

#endif

break;

default:

close(s);

break;

}

}

这样通过设置ctl.start或者ctl.stop属性就可以达到启动或者停止service的目的。

更多相关文章

  1. Android中WebView和JavaScript通信
  2. Android(安卓)属性动画 源码解析 深入了解其内部实现
  3. Android中使用log4j
  4. Android自动化测试初探(二): Hierarchyviewer 捕获Element的实现原
  5. Android(安卓)之 CheckBox 详解
  6. 高通android10.0默认赋予第三方apk权限
  7. Android使用ViewPager实现左右滑动效果
  8. Android(安卓)/ iOS 静态代码扫描工具调研
  9. android开发之给LinearLayout增加点击效果

随机推荐

  1. android studio 导入工程慢
  2. Android Studio删除工程里面无用的代码和
  3. MVVMArchitecture,一款可配置的 MVVM 框架
  4. Android 微信分享,无需那么麻烦。
  5. android中的多线程基础问题
  6. Android(安卓)Data Binding
  7. 终于来了!耗时268天,7大模块、2983页58万字
  8. Android(安卓)MVP 实践 Dagger + activit
  9. Android Binder AIDL解析
  10. Android 个人开发者接入支付功能