android的开机动画是如何启动的

本文详细探讨了Android设备开机动画的启动流程,从SurfaceFlinger的readyToRun()函数开始,通过property_set()激活bootanim进程。接着,讲解了Android属性系统的工作原理,包括属性服务、consumer进程和setter进程如何通过Unix domain socket交互。最终,当init进程接收到启动bootanim的指令后,通过一系列步骤创建并执行bootanim服务。
摘要由CSDN通过智能技术生成

 在SurfaceFlinger::readyToRun()的最后启动开机动画

SurfaceFlinger::readyToRun()

{  ......

    // start boot animation
    property_set("ctl.start", "bootanim");

}

然后,init.rc里面记录的bootanim进程被创建,开机动画由这个进程放出来。

那么bootanim进程是如何被创建出来的呢?他是借助Android的属性系统(Android Property System)被创建的。

属性系统是android的一个重要特性。它作为一个服务运行,管理系统配置和状态。所有这些配置和状态都是属性。每个属性是一个键值对(key/value pair),其类型都是字符串。

属性系统的上层架构如下图所示:

图中有3个进程、一组永久属性文件和一块共享内存区域。共享内存区域是所有属性记录的存储所在。只有属性服务进程才可以写入共享内存区域,它负责从永久文件中加载属性记录并将它们保存在共享内存中。

         consumer进程将共享内存加载到其自身的虚拟地址空间并直接访问这些属性。setter进程同样将共享内存加载到其自身的虚拟地址空间,但其不能直接写该内存。当setter试图增加或者更新一个属性时,它将该属性通过unix domain socket发送至属性服务。属性服务代表setter进程将该属性写入共享内存和永久文件中。

属性服务运行于init进程中。init进程首先创建一个共享内存区域,并保存一个指向该区域的描述符fdinit进程将该区域通过使用了MAP_SHARED标志的mmap映射至它自身的虚拟地址空间,这样,任何对于该区域的更新对于所有进程都是可见的。fd和区域大小被存储在一个名为ANDROID_PROPERTY_WORKSPACE的变量中。任何其他进程,比如consumersetter将使用这个变量来获得fd和尺寸,这样它们就能mmap这个区域到它们自身的虚拟地址空间中。

下一步是启动属性服务。在这一步中,一个unix domain socket服务被创建。此socket的路径是/dev/socket/property_service,该路径对于其他客户端进程是熟知的。最后,init进程调用poll来等待该socket上的连接事件。

         在这里

SurfaceFlinger::readyToRun()

{  ......

    // start boot animation
    property_set("ctl.start", "bootanim");

}

然后调到system/core/libcutils/properties.c里面去

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

write(gPropFd, sendBuf, sizeof(sendBuf)) ; //写到Unix domain socket里面去

}

在system/core/init/init.c里面,init进程在等待unix domain socket,接到这个消息之后,就开始创建bootanim进程了

system/core/init/init.c

int main()

{

struct pollfd ufds[4];

 

if (!property_set_fd_init && get_property_set_fd() > 0) { //为property创建一个socket
            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;
        }

 

nr = poll(ufds, fd_count, timeout); //等待socket事件到来

for (i = 0; i < fd_count; i++) {
            if (ufds[i].revents == POLLIN) {
                if (ufds[i].fd == get_property_set_fd())  //处理property设置事件
                    handle_property_set_fd();
                else if (ufds[i].fd == get_keychord_fd())
                    handle_keychord();
                else if (ufds[i].fd == get_signal_fd())
                    handle_signal();
            }
        }

}

handle_property_set_fd()的实现在system/core/init/property_service.c

void handle_property_set_fd()
{

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

 switch(msg.cmd) {
    case PROP_MSG_SETPROP:
        msg.name[PROP_NAME_MAX-1] = 0;
        msg.value[PROP_VALUE_MAX-1] = 0;

        if(memcmp(msg.name,"ctl.",4) == 0) {
            if (check_control_perms(msg.value, cr.uid, cr.gid)) {
                handle_control_message((char*) msg.name + 4, (char*) msg.value);
            } else {
                ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n",
                        msg.name + 4, msg.value, cr.uid, cr.pid);
            }
        }

}

}

然后又掉init.c的handle_control_message()

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 {
        ERROR("unknown control msg '%s'\n", msg);
    }
}

我们这里是"ctl.start", 所以调msg_start(arg),它的实现也在init.c中

void msg_start(const char *name)

{

if (svc) {
        service_start(svc, args);
    }

}

 

void service_start(struct service *svc, const char *dynamic_args)
{

pid = fork();

execve(svc->args[0], (char**) svc->args, (char**) ENV) //至此,则bootanim进程被创建并开始执行

}

 

参考

http://blog.csdn.net/jackyu613/article/details/6136620

http://blog.csdn.net/kobeyxyx/article/details/6593976

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值