android深入了解开机动画
开机动画的种类
1:View绘制
2:逐帧动画:比较主流的方式,一般动画的文件打包成 bootanimation.zip 存储到 /system/media/ 下。一般.zip文件 > 5M 就会有明显的卡顿,所以一般开机动画只有中间一块有图案,四周是黑色,这样可以采用更小分辨率的图片。
3:OpenGL:定义了跨平台语言,跨平台的应用接口API规范,用于生成二维、三维图像。
开机动画启动流程
- 代码路径介绍
- bootanimation: /frameworks/base/cmds/bootanimation/
- surfaceflinger: /frameworks/native/services/surfaceflinger/
- init: /system/core/init/
内核启动之后启动的第一个进程就是 init 进程,init进程会根据 init.rc 的配置启动 surfaceflinger 进程,在/frameworks/native/services/surfaceflinger/ 下有 surfaceflinger.rc 如下:
1 service surfaceflinger /system/bin/surfaceflinger
2 class core animation
3 user system
4 group graphics drmrpc readproc
5 onrestart restart zygote
6 writepid /dev/stune/foreground/tasks
而 bootanim.rc 配置了 disabled ,因此在 init 进程解析时不会启动 bootanimation 进程。
1 service bootanim /system/bin/bootanimation
2 class core animation
3 user graphics
4 group graphics audio
5 disabled
6 oneshot
7 writepid /dev/stune/top-app/tasks
- surfaceflinger 进程启动以后,执行了 main_surfaceflinger.cpp 的 main 方法。
71 int main(int, char**) {
// ..............
83 // start the thread pool
84 sp<ProcessState> ps(ProcessState::self());
85 ps->startThreadPool();
86
87 // instantiate surfaceflinger 创建 SurfaceFlinger 实例
88 sp<SurfaceFlinger> flinger = new SurfaceFlinger();
89
99 // 调用 flinger 的 init()
100 flinger->init();
101
102 // publish surface flinger 将 flinger 服务添加到 ServiceManager 中。
103 sp<IServiceManager> sm(defaultServiceManager());
104 sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
105 IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
106
107 // publish GpuService
108 sp<GpuService> gpuservice = new GpuService();
109 sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
110
119 // run surface flinger in this thread 执行了 run() 方法
120 flinger->run();
121
122 return 0;
123 }
main_surfaceflinger.cpp 的 main 方法。,创建了 SurfaceFlinger 实例,并执行了其 init() 和 run() 方法。在 init() 函数中,有如下相关代码
637 void SurfaceFlinger::init() {
724 if (getHwComposer().hasCapability(
725 HWC2::Capability::PresentFenceIsNotReliable)) {
726 mStartPropertySetThread = new StartPropertySetThread(false);
727 } else {
728 mStartPropertySetThread = new StartPropertySetThread(true);
729 }
731 if (mStartPropertySetThread->Start() != NO_ERROR) {
732 ALOGE("Run StartPropertySetThread failed!");
733 }
739 }
创建了一个 Thread 并且调用start() , 运行起来该线程以后看一看做了什么工作。接下来,看一下 StartPropertySetThread.cpp 的代码。
17#include <cutils/properties.h>
18#include "StartPropertySetThread.h"
19
20namespace android {
21
22StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue):
23 Thread(false), mTimestampPropertyValue(timestampPropertyValue) {
}
24
25status_t StartPropertySetThread::Start() {
26 return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
27}
28
29bool StartPropertySetThread::threadLoop() {
30 // Set property service.sf.present_timestamp, consumer need check its readiness
31 property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
32 // Clear BootAnimation exit flag 这个不是结束,就是设置初始状态
33 property_set("service.bootanim.exit", "0");
34 // Start BootAnimation if not started 开启 BootAnimation 进程
35 property_set("ctl.start", "bootanim");
36 // Exit immediately
37 return false;
38}
39
40} // namespace android
41
| property_set(“”, “”); 函数是Android框架中的一个函数,用于设置系统属性的值。系统属性是一种用于存储系统配置信息的键值对。property_set()函数的作用是将指定的属性名和属性值存储到系统属性中,并且进行后续动作和调整。
在之前提到的 /system/core/init/init.cpp 中,执行 main 函数有下面的代码
545 int main(int argc, char** argv) {
701 property_load_boot_defaults();
702 export_oem_lock_status();
703 start_property_service(); // 关键代码 启动监听 property 的服务
704 set_usb_controller();
790 }
start_property_service(); 调用的是 /system/core/init/property_service.cpp 下的 start_property_service () 函数如下:
840 void start_property_service() {
841 selinux_callback cb;
842 cb.func_audit = SelinuxAuditCallback;
843 selinux_set_callback(SELINUX_CB_AUDIT, cb);
844
845 property_set("ro.property_service.version", "2");
846 // 创建了 Socket 来进行跨进程通信。
847 property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
848 false, 0666, 0, 0, nullptr);
849 if (property_set_fd == -1) {
850 PLOG(FATAL) << "start_property_service socket creation failed";
851 }
852 // 监听 property_set_fd 这个 fd
853 listen(property_set_fd, 8);
854 // 通过 epoll 机智,来监听 property_set_fd 是否有消息过来,如果有消息进来就会回调 handle_property_set_fd 方法。
855 register_epoll_handler(property_set_fd, handle_property_set_fd);
856 }
857
858 }
上面讲述了,监听到 property_set 以后,会调用到 handle_property_set_fd 方法,接下来看看,设置了 property_set(“ctl.start”, “bootanim”); 后执行流程是怎么样的。
481 static void handle_property_set_fd() {
482
506
507 switch (cmd) {
508 case PROP_MSG_SETPROP: {
509 char prop_name[PROP_NAME_MAX];
510 char prop_value[PROP_VALUE_MAX];
521 const auto& cr = socket.cred();
522 std::string error;
// 主要代码
523 uint32_t result =
524 HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);
531 break;
532 }
533
534 case PROP_MSG_SETPROP2: {
535 std::string name;
536 std::string value;
546 uint32_t result = HandlePropertySet(name, value, socket.source_context(), cr, &error);
553 break;
554 }
555
556 default:
557 LOG(ERROR) << "sys_prop: invalid command " << cmd;
558 socket.SendUint32(PROP_ERROR_INVALID_CMD);
559 break;
560 }
561}
上述代码,调用时,我们是设置属性,最终会调用到 HandlePropertySet() 函数,
425// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.