android ctl属性的实现过程

本文详细解析了Android系统中如何通过属性服务控制开机动画的启动与停止,并深入介绍了init进程如何响应ctl.start和ctl.stop命令来启动或停止服务。

对于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的目的。

 

 

<think>嗯,用户遇到了一个错误信息:“Unable to set property 'ctl.interface_start' to 'android.hardware.radio@1.5::IRadio/slot1': error code: 0x20”。首先,我需要理解这个错误的上下文和可能的原因。 这个错误涉及到Android系统的属性设置,特别是与HAL(硬件抽象层)相关的服务启动问题。属性名称是“ctl.interface_start”,尝试设置的值为“android.hardware.radio@1.5::IRadio/slot1”,错误代码是0x20。根据Android系统的知识,ctl.interface_start通常用于启动HAL服务实例。错误代码0x20通常对应的是ENOSPC,也就是设备上没有足够的空间,但在这里可能代表其他含义,需要进一步确认。 接下来,我需要考虑可能的原因。首先,权限问题。Android系统服务可能需要特定的SELinux权限或root权限才能修改系统属性。如果当前进程没有足够的权限,设置属性会失败。其次,HAL接口版本是否正确。用户指定的HAL版本是radio@1.5,设备可能不支持该版本,或者对应的服务实现不存在。第三,属性名称是否正确,是否有拼写错误。第四,系统资源问题,如内存不足或服务管理器的限制,导致无法启动新服务。最后,系统兼容性问题,比如Android版本与HAL版本不匹配。 解决步骤方面,首先应该检查权限,确认是否有足够的权限设置系统属性,可能需要root权限或调整SELinux策略。其次,验证HAL版本是否可用,查看设备支持的radio HAL版本,可能需要检查vendor目录下的相关库文件。第三,确认属性名称正确,特别是接口名称和实例名称(slot1)是否正确。第四,查看系统日志,使用adb logcat获取更多错误信息,帮助定位问题。第五,检查资源限制,查看内存或进程数是否达到上限。最后,考虑系统兼容性,确认使用的HAL版本与当前Android版本兼容,可能需要降级或升级HAL版本。 此外,用户可能在尝试手动启动某个HAL服务时遇到此问题,比如在开发或调试过程中。需要确保操作符合Android的系统架构,并且所有依赖项都已正确配置。如果用户是开发者,可能需要检查HAL实现的正确性,以及manifest或VINTF配置是否正确声明了服务。如果是普通用户遇到此错误,可能是系统更新或应用兼容性问题,建议联系设备厂商获取支持。</think>这个错误提示通常出现在Android系统底层服务或硬件抽象层(HAL)的交互过程中。让我们逐步分析问题原因和可能的解决方案: **错误代码解析** - **错误码 0x20**:对应十六进制值换算为十进制是32,在Linux系统中表示 `ENOSPC`(No space left on device) - **但在此上下文中**更可能指向 `STATUS_NO_MEMORY` (Android特有错误码),表示资源分配失败 **关键要素分析** 1. **属性名**:`ctl.interface_start` - 用于控制HAL服务启动的系统属性 - 格式应为:`ctl.interface_start=<接口名>/<实例名>` 2. **目标值**:`android.hardware.radio@1.5::IRadio/slot1` - 涉及Radio接口1.5版 - 指定slot1实例 **可能原因** 1. **权限不足** - 需要`android.permission.ACCESS_SYSTEM_PROPERTIES`权限 - SELinux策略限制(常见于非root设备) 2. **HAL服务缺失** ```bash # 检查HAL实现是否存在 adb shell ls -l /vendor/lib64/hw/android.hardware.radio@1.5-impl.so ``` 3. **版本不兼容** - 设备可能仅支持较低版本(如radio@1.4) 4. **资源耗尽** - 内存泄漏导致无法创建新服务实例 - Binder线程池耗尽 **调试步骤** 1. 获取完整错误日志: ```bash adb logcat -b all | grep -E 'HIDL|Radio' ``` 2. 验证属性操作权限: ```bash adb shell getprop security.perf_harden # 返回1表示处于限制模式 ``` 3. 检查VINTF兼容性: ```xml <!-- 在device manifest中应包含 --> <hal format="hidl"> <name>android.hardware.radio</name> <transport>hwbinder</transport> <version>1.5</version> <interface> <name>IRadio</name> <instance>slot1</instance> </interface> </hal> ``` **解决方案** 1. **更新HAL实现** ```bash # 在设备端更新radio HAL adb push radio.vendor.so /vendor/lib64/hw/ ``` 2. **调整SELinux策略** ```te # 添加以下规则 allow system_server vendor_radio_hwservice:service_manager add; ``` 3. **释放系统资源** ```bash adb shell "stop; start" # 软重启Android框架 ``` 4. **降级HAL版本(临时方案)** ```bash setprop ctl.interface_start android.hardware.radio@1.4::IRadio/slot1 ``` **进阶诊断建议** 使用hidl-gen工具验证接口定义: ```bash hidl-gen -L check android.hardware.radio@1.5 ``` 如果问题持续存在,建议: 1. 检查内核日志:`dmesg | grep radio` 2. 验证Binder状态:`adb shell cat /proc/binder/stats` 3. 使用strace跟踪系统调用: ```bash adb shell strace -p $(pidof system_server) -e trace=openat ``` 该错误通常需要结合具体设备型号和Android版本进行针对性分析,建议联系设备厂商获取专属HAL实现更新。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值