Android系统的开机画面显示过程分析(8)

简介:
     3. 第三个开机画面的显示过程
        第三个开机画面是由应用程序bootanimation来负责显示的。应用程序bootanimation在启动脚本init.rc中被配置成了一个服务,如下所示:
  1. service bootanim /system/bin/bootanimation  
  2.     user graphics  
  3.     group graphics  
  4.     disabled  
  5.     oneshot  
       应用程序bootanimation的用户和用户组名称分别被设置为graphics。注意, 用来启动应用程序bootanimation的服务是disable的,即init进程在启动的时候,不会主动将应用程序bootanimation启动起来。当SurfaceFlinger服务启动的时候,它会通过修改系统属性ctl.start的值来通知init进程启动应用程序bootanimation,以便可以显示第三个开机画面,而当System进程将系统中的关键服务都启动起来之后,ActivityManagerService服务就会通知SurfaceFlinger服务来修改系统属性ctl.stop的值,以便可以通知init进程停止执行应用程序bootanimation,即停止显示第三个开机画面。接下来我们就分别分析第三个开机画面的显示过程和停止过程。
 
      从前面 Android系统进程Zygote启动过程的源代码分析 一文可以知道,Zygote进程在启动的过程中,会将System进程启动起来,而从前面 Android应用程序安装过程源代码分析一文 又可以知道,System进程在启动的过程(Step 3)中,会调用SurfaceFlinger类的静态成员函数instantiate来启动SurfaceFlinger服务。Sytem进程在启动SurfaceFlinger服务的过程中,首先会创建一个SurfaceFlinger实例,然后再将这个实例注册到Service Manager中去。在注册的过程,前面创建的SurfaceFlinger实例会被一个sp指针引用。从前面 Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析一文 可以知道,当一个对象第一次被智能指针引用的时候,这个对象的成员函数onFirstRef就会被调用。由于SurfaceFlinger重写了父类RefBase的成员函数onFirstRef,因此,在注册SurfaceFlinger服务的过程中,将会调用SurfaceFlinger类的成员函数onFirstRef。在调用的过程,就会创建一个线程来启动第三个开机画面。
       SurfaceFlinger类实现在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp 中,它的成员函数onFirstRef的实现如下所示:
  1. void SurfaceFlinger::onFirstRef()  
  2. {  
  3.     run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);  
  4.   
  5.     // Wait for the main thread to be done with its initialization  
  6.     mReadyToRunBarrier.wait();  
  7. }  
        SurfaceFlinger类继承了Thread类,当它的成员函数run被调用的时候,系统就会创建一个新的线程。这个线程在第一次运行之前,会调用SurfaceFlinger类的成员函数readyToRun来通知SurfaceFlinger,它准备就绪了。当这个线程准备就绪之后,它就会循环执行SurfaceFlinger类的成员函数threadLoop,直到这个成员函数的返回值等于false为止。
 
        注意,SurfaceFlinger类的成员函数onFirstRef是在System进程的主线程中调用的,它需要等待前面创建的线程准备就绪之后,再继续往前执行,这个通过调用SurfaceFlinger类的成员变量mReadytoRunBarrier所描述的一个Barrier对象的成员函数wait来实现的。每一个Barrier对象内问都封装了一个条件变量(Condition Variable),而条件变量是用来同步线程的。
        接下来,我们继续分析SurfaceFlinger类的成员函数readyToRun的实现,如下所示:
  1. status_t SurfaceFlinger::readyToRun()  
  2. {  
  3.     LOGI(   "SurfaceFlinger's main thread ready to run. "  
  4.             "Initializing graphics H/W...");  
  5.       
  6.     ......  
  7.   
  8.     mReadyToRunBarrier.open();  
  9.   
  10.     /* 
  11.      *  We're now ready to accept clients... 
  12.      */  
  13.   
  14.     // start boot animation  
  15.     property_set("ctl.start""bootanim");  
  16.   
  17.     return NO_ERROR;  
  18. }  

       前面创建的线程用作SurfaceFlinger的主线程。这个线程在启动的时候,会对设备主屏幕以及OpenGL库进行初始化。初始化完成之后,接着就会调用SurfaceFlinger类的成员变量mReadyToRunBarrier所描述的一个Barrier对象的成员函数open来唤醒System进程的主线程,以便它可以继续往前执行。最后,SurfaceFlinger类的成员函数readyToRun的成员函数会调用函数property_set来将系统属性“ctl.start”的值设置为“bootanim”,表示要将应用程序bootanimation启动起来,以便可以显示第三个开机画面。
 
       前面在介绍第二个开机画面的时候提到,当系统属性发生改变时,init进程就会接收到一个系统属性变化通知,这个通知最终是由在init进程中的函数handle_property_set_fd来处理的。
       函数handle_property_set_fd实现在文件system/core/init/property_service.c中,如下所示:
  1. void handle_property_set_fd()  
  2. {  
  3.     prop_msg msg;  
  4.     int s;  
  5.     int r;  
  6.     int res;  
  7.     struct ucred cr;  
  8.     struct sockaddr_un addr;  
  9.     socklen_t addr_size = sizeof(addr);  
  10.     socklen_t cr_size = sizeof(cr);  
  11.   
  12.     if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {  
  13.         return;  
  14.     }  
  15.   
  16.     /* Check socket options here */  
  17.     if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {  
  18.         close(s);  
  19.         ERROR("Unable to recieve socket options\n");  
  20.         return;  
  21.     }  
  22.   
  23.     r = recv(s, &msg, sizeof(msg), 0);  
  24.     close(s);  
  25.     if(r != sizeof(prop_msg)) {  
  26.         ERROR("sys_prop: mis-match msg size recieved: %d expected: %d\n",  
  27.               r, sizeof(prop_msg));  
  28.         return;  
  29.     }  
  30.   
  31.     switch(msg.cmd) {  
  32.     case PROP_MSG_SETPROP:  
  33.         msg.name[PROP_NAME_MAX-1] = 0;  
  34.         msg.value[PROP_VALUE_MAX-1] = 0;  
  35.   
  36.         if(memcmp(msg.name,"ctl.",4) == 0) {  
  37.             if (check_control_perms(msg.value, cr.uid, cr.gid)) {  
  38.                 handle_control_message((char*) msg.name + 4, (char*) msg.value);  
  39.             } else {  
  40.                 ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n",  
  41.                         msg.name + 4, msg.value, cr.uid, cr.pid);  
  42.             }  
  43.         } else {  
  44.             if (check_perms(msg.name, cr.uid, cr.gid)) {  
  45.                 property_set((char*) msg.name, (char*) msg.value);  
  46.             } else {  
  47.                 ERROR("sys_prop: permission denied uid:%d  name:%s\n",  
  48.                       cr.uid, msg.name);  
  49.             }  
  50.         }  
  51.         break;  
  52.   
  53.     default:  
  54.         break;  
  55.     }  
  56. }  

        init进程是通过一个socket来接收系统属性变化事件的。每一个系统属性变化事件的内容都是通过一个prop_msg对象来描述的。在prop_msg对象对,成员变量name用来描述发生变化的系统属性的名称,而成员变量value用来描述发生变化的系统属性的值。系统属性分为两种类型,一种是普通类型的系统属性,另一种是控制类型的系统属性(属性名称以“ctl.”开头)。控制类型的系统属性在发生变化时,会触发init进程执行一个命令,而普通类型的系统属性就不具有这个特性。注意,改变系统属性是需要权限,因此,函数handle_property_set_fd在处理一个系统属性变化事件之前,首先会检查修改系统属性的进程是否具有相应的权限,这是通过调用函数check_control_perms或者check_perms来实现的。
 
        从前面的调用过程可以知道,当前发生变化的系统属性的名称为“ctl.start”,它的值被设置为“bootanim”。由于这是一个控制类型的系统属性,因此,在通过了权限检查之后,另外一个函数handle_control_message就会被调用,以便可以执行一个名称为“bootanim”的命令。




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/967040,如需转载请自行联系原作者
目录
相关文章
|
16天前
|
搜索推荐 Android开发 iOS开发
探索安卓与iOS系统的用户界面设计哲学
现代移动操作系统的设计哲学不仅仅是技术的表现,更是用户体验与功能实现的结合。本文将深入分析安卓与iOS两大主流系统在用户界面设计方面的差异与共通之处,探讨它们背后的思维模式及其对用户体验的影响。 【7月更文挑战第11天】
|
22天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
【7月更文挑战第4天】在移动应用开发的广阔天地中,安卓和iOS两大平台各据一方,引领着技术潮流。本文将深入探讨这两个平台的开发环境,从编程语言、工具链到市场分布等多个维度进行比较。我们将揭示各自的优势与局限,并分析开发者如何在这两个不同的生态系统中做出选择。通过本文,读者将获得一个全面的视角,理解两大平台在开发实践中的差异性及其对项目成功的影响。
|
4天前
|
IDE 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔舞台上,安卓与iOS这两大操作系统各占半壁江山。它们在开发环境上的差异,不仅影响了开发者的编码体验,也在一定程度上塑造了应用生态的多样性。本文将深入探讨两者在开发工具、编程语言、用户界面设计以及市场分布等方面的不同特点,为即将踏入这一领域的开发者提供一盏明灯。
|
12天前
|
Android开发 Kotlin
kotlin开发安卓app,如何让布局自适应系统传统导航和全面屏导航
使用`navigationBarsPadding()`修饰符实现界面自适应,自动处理底部导航栏的内边距,再加上`.padding(bottom = 10.dp)`设定内容与屏幕底部的距离,以完成全面的布局适配。示例代码采用Kotlin。
57 15
|
5天前
|
IDE 开发工具 Android开发
安卓与iOS开发环境的差异性分析
在移动应用开发的广阔舞台上,安卓和iOS两大操作系统各据一方,引领着市场潮流。它们各自拥有独特的开发环境和工具集,为开发者提供了不同的挑战与机遇。本文旨在深入剖析这两个平台的开发环境,通过比较它们的编程语言、集成开发环境(IDE)、用户界面设计、以及系统架构等方面,揭示各自的优势与局限。我们将探讨如何基于这些差异来优化开发策略,并预测未来可能的发展趋势,以期为开发者在选择平台时提供有价值的参考。
|
5天前
|
API 开发工具 Android开发
安卓与iOS开发环境对比分析
移动操作系统的两大巨头,安卓和iOS,各自拥有独特的开发环境和工具。本文将深入探讨两者的开发环境差异,从编程语言、开发工具、用户界面设计、API支持以及生态系统五个维度进行比较分析。通过数据支撑和案例研究,揭示各自的优势和局限性,为开发者选择适合自己项目需求的平台提供参考依据。
13 1
|
8天前
|
Java Android开发 iOS开发
探索安卓与iOS开发的差异:平台特性与用户体验的对比分析
【7月更文挑战第19天】在移动开发的广阔天地中,安卓与iOS两大阵营各据一方,它们在开发环境、用户界面设计、性能优化等方面展现出独特的魅力与挑战。本文旨在深入探讨这两个平台在技术开发和用户体验上的根本差异,并分析这些差异如何影响开发者的策略和最终用户的选择。通过比较两者的编程语言、工具、框架以及设计理念,我们将揭示各自平台的优势与局限,为开发者提供实用的参考,并为消费者呈现一个更加清晰的平台选择视角。
|
11天前
|
开发工具 Android开发 Swift
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个操作系统的开发环境,从编程语言、开发工具到用户界面设计等多个维度进行比较。通过丰富的数据支持和案例研究,揭示了不同平台的优势与挑战,为开发者提供了宝贵的参考信息。
|
10天前
|
安全 开发工具 Android开发
安卓与iOS开发环境对比分析
本文通过深入探讨和比较安卓与iOS两大主流移动操作系统的开发环境,旨在为开发者提供一个全面的视角。我们将从开发工具、编程语言、用户界面设计、性能优化、安全性考量等多个维度进行细致分析,揭示各自平台的优势与挑战。通过统计数据支持的实证研究,本文将展示两个系统在实际应用中的技术差异及其对项目开发周期的影响,并基于市场数据评估各自的商业潜力。
15 1
|
14天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了两者的开发环境差异,从编程语言、工具框架到用户群体和市场份额进行了全面比较。通过数据支撑和案例分析,揭示了不同平台的优势与局限,旨在为开发者提供决策参考,同时预测未来发展趋势。