Kernel logo到Bootanimaiton显示之源码分析
2018-02-12 09:42
615 查看
Kernel logo到Bootanimaiton显示之源码分析问题的引入:在9010项目中发现一个问题:从kernel logo到bootanimaiton开机动画,中间会存在一个黑屏的时间,或长或短。长时间显示像是死机,短时间即类似界面间的跳转(优化后)。原因在于当Bootanimation绘画之前会有一个清屏的动作,具体的解决思路及方法在mediatek上有相关的,这里先分析一下这两个阶段的源码。首先明确一点,开机logo图片的显示是在初始化kernel时(用户态);开机动画确切的来说是在SystemServer进程启动本地服务SurfaceFlinger时显示的,属于内核态。用户态与内核态之间通过系统调用层Syscall切换,实质上是一种软中断手段。 注:所有源码基于3710项目可能涉及到几处源码的path:1、init.rc:/system/core/rootdir/init.rc2、init.c:/system/core/init/init.cpp3、Bootanimation相关文件:/frameworks/base/cmds/bootanimation/...一、开机log的显示过程(初始化kernel时)1、在3710的/system/core/init/init.c下有这么一段源码: // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev... am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done"); // ... so that we can start queuing up actions that require stuff from /dev. ... am.QueueBuiltinAction(console_init_action, "console_init"); 说明:上述注释的大意就是等待冷启动(按下电源键开机)完成后,队列里的action会排队等待被执行,action是从启动脚本init.rc中解析得到的。当某个action需要被执行的时候,它会被添加到Queue列表中,以便init进程可以执行。我们知道,init进程最终会陷入一个无限的循环中,因此上述被添加到队列中的"console_init_action"会在init的循环过程中被执行。其中的“console_init_action”就是用来显示开机log的。 2、console_init_action的函数源码: static int console_init_action(...){ std::string console = property_get("ro.boot.console"); if (!console.empty()) { console_name = "/dev/" + console; } int fd = open(console_name.c_str(), O_RDWR | O_CLOEXEC); if (fd >= 0) have_console = 1;#ifdef MTK_INIT else ERROR("console_init: can't open %s\n", console_name.c_str());#endif close(fd); fd = open("/dev/tty0", O_WRONLY | O_CLOEXEC); if (fd >= 0) { const char *msg; msg = "\n" ... " A N D R O I D "; write(fd, msg, strlen(msg)); close(fd); } return 0;} 说明:上述源代码的大意就是如果能够打开设备文件/dev/console,即fd>=0的时候,那么就证明系统支持访问控制台。它以文本的方式来显示第二个开机log,即向控制台(/dev/tty0)输出“ANDROID”这7个字符。 二、开机动画的显示过程 init进程
100a5
Zygote进程 systemServer进程 Android系统在启动SystemServer进程时,通过两个阶段来启动系统所有服务,在第一阶段启动本地服务,SurfaceFlinger,SensorService等,在第二阶段则启动一系列的Java服务。 android开机动画是在启动SurfaceFlinger服务时启动的。 流程图大致如下所示: 3710中SurfaceFlinger.cpp的path:/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp1、SurfaceFlinger.cpp部分源码: void SurfaceFlinger::startBootAnim() {#ifdef MTK_AOSP_ENHANCEMENT // dynamic disable/enable boot animation checkEnableBootAnim();#else // start boot animation property_set("service.bootanim.exit", "0"); property_set("ctl.start", "bootanim");//设置ctl.start=bootanim#endif} 说明:上述源码的大意是将系统属性“ctl.start”的值设置为“bootanim”,表示要将应用程序bootanimation启动起来,以便可以显示开机动画。 2、进入system/core/init/init.c的handle_control_message()中: void handle_control_message(const std::string& msg, const std::string& name) { Service* svc = ServiceManager::GetInstance().FindServiceByName(name); if (svc == nullptr) { ERROR("no such service '%s'\n", name.c_str()); return; } if (msg == "start") { svc->Start(); } else if (msg == "stop") { svc->Stop(); } else if (msg == "restart") { svc->Restart(); } else { ERROR("unknown control msg '%s'\n", msg.c_str()); }}说明: “start”表示要启动某一个服务,而“stop”表示要停止某一个服务,它们是分别通过函数msg_start和msg_stop来实现的。由于当前发生变化的系统属性是以“start”来结尾的,因此,接下来就会调用函数msg_start来启动一个名称为“bootanim”的服务。 参数name的值等于“bootanim”,它用来描述一个服务名称。这个函数首先调用函数service_find_by_name来找到名称等于“bootanim”的服务的信息,这些信息保存在一个service结构体svc中,接着再调用另外一个函数来将对应的应用程序启动起来。 3、应用程序入口函数main是实现在frameworks/base/cmds/bootanimation_main.cpp中的。源代码如下所示: int main(int argc, char** argv){//sp智能指针被引用,当一个对象被智能指针引用的时候,调用这个对象对象的成员函数OnFirstRef()函数。 if (!noBootAnimation) { sp<ProcessState> proc(ProcessState::self()); ProcessState::self()->startThreadPool();/* M: use our construction method, because we support shut down animation @{ // create the boot animation object sp<BootAnimation> boot = new BootAnimation();@} */ ...} 4、BootAnimation的OnFirstRef()函数: void BootAnimation::onFirstRef() { status_t err = mSession->linkToComposerDeath(this); ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err)); if (err == NO_ERROR) { run("BootAnimation", PRIORITY_DISPLAY); }} 调用父类Thread的run()方法,会创建出一个子线程。这个线程在第一次运行之前,会调用BootAnimation类的成员函数readyToRun来执行一些初始化工作,后面再调用BootAnimation类的成员函数threadLoop来显示第三个开机画面。 bool BootAnimation::threadLoop(){ bool r; // We have no bootanimation file, so we use the stock android logo // animation. sp<MediaPlayer> mediaplayer; const char* resourcePath = initAudioPath(); status_t mediastatus = NO_ERROR; if (resourcePath != NULL) { ... mediastatus = mediaplayer->setDataSource(NULL, resourcePath, NULL); if (mediastatus == NO_ERROR) { if ((mZip == NULL)&&(mZipFileName.isEmpty())) { r = android(); //如果没有动画的压缩包,显示android字样,否则显示动画 } else { if (!bETC1Movie) { ALOGD("threadLoop() movie()"); r = movie(); //显示bootaniamtion.zip动画 } else { ALOGD("threadLoop() ETC1movie()"); r = ETC1movie(); } } //显示完成动画,关闭开机铃声 if (resourcePath != NULL) { if (mediastatus == NO_ERROR) { ALOGD("mediaplayer was stareted successfully, now it is going to be stoped"); mediaplayer->stop(); mediaplayer->disconnect(); mediaplayer.clear(); } } ... return r;}至此,logo动画、开机动画的显示过程就分析到这里。
100a5
Zygote进程 systemServer进程 Android系统在启动SystemServer进程时,通过两个阶段来启动系统所有服务,在第一阶段启动本地服务,SurfaceFlinger,SensorService等,在第二阶段则启动一系列的Java服务。 android开机动画是在启动SurfaceFlinger服务时启动的。 流程图大致如下所示: 3710中SurfaceFlinger.cpp的path:/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp1、SurfaceFlinger.cpp部分源码: void SurfaceFlinger::startBootAnim() {#ifdef MTK_AOSP_ENHANCEMENT // dynamic disable/enable boot animation checkEnableBootAnim();#else // start boot animation property_set("service.bootanim.exit", "0"); property_set("ctl.start", "bootanim");//设置ctl.start=bootanim#endif} 说明:上述源码的大意是将系统属性“ctl.start”的值设置为“bootanim”,表示要将应用程序bootanimation启动起来,以便可以显示开机动画。 2、进入system/core/init/init.c的handle_control_message()中: void handle_control_message(const std::string& msg, const std::string& name) { Service* svc = ServiceManager::GetInstance().FindServiceByName(name); if (svc == nullptr) { ERROR("no such service '%s'\n", name.c_str()); return; } if (msg == "start") { svc->Start(); } else if (msg == "stop") { svc->Stop(); } else if (msg == "restart") { svc->Restart(); } else { ERROR("unknown control msg '%s'\n", msg.c_str()); }}说明: “start”表示要启动某一个服务,而“stop”表示要停止某一个服务,它们是分别通过函数msg_start和msg_stop来实现的。由于当前发生变化的系统属性是以“start”来结尾的,因此,接下来就会调用函数msg_start来启动一个名称为“bootanim”的服务。 参数name的值等于“bootanim”,它用来描述一个服务名称。这个函数首先调用函数service_find_by_name来找到名称等于“bootanim”的服务的信息,这些信息保存在一个service结构体svc中,接着再调用另外一个函数来将对应的应用程序启动起来。 3、应用程序入口函数main是实现在frameworks/base/cmds/bootanimation_main.cpp中的。源代码如下所示: int main(int argc, char** argv){//sp智能指针被引用,当一个对象被智能指针引用的时候,调用这个对象对象的成员函数OnFirstRef()函数。 if (!noBootAnimation) { sp<ProcessState> proc(ProcessState::self()); ProcessState::self()->startThreadPool();/* M: use our construction method, because we support shut down animation @{ // create the boot animation object sp<BootAnimation> boot = new BootAnimation();@} */ ...} 4、BootAnimation的OnFirstRef()函数: void BootAnimation::onFirstRef() { status_t err = mSession->linkToComposerDeath(this); ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err)); if (err == NO_ERROR) { run("BootAnimation", PRIORITY_DISPLAY); }} 调用父类Thread的run()方法,会创建出一个子线程。这个线程在第一次运行之前,会调用BootAnimation类的成员函数readyToRun来执行一些初始化工作,后面再调用BootAnimation类的成员函数threadLoop来显示第三个开机画面。 bool BootAnimation::threadLoop(){ bool r; // We have no bootanimation file, so we use the stock android logo // animation. sp<MediaPlayer> mediaplayer; const char* resourcePath = initAudioPath(); status_t mediastatus = NO_ERROR; if (resourcePath != NULL) { ... mediastatus = mediaplayer->setDataSource(NULL, resourcePath, NULL); if (mediastatus == NO_ERROR) { if ((mZip == NULL)&&(mZipFileName.isEmpty())) { r = android(); //如果没有动画的压缩包,显示android字样,否则显示动画 } else { if (!bETC1Movie) { ALOGD("threadLoop() movie()"); r = movie(); //显示bootaniamtion.zip动画 } else { ALOGD("threadLoop() ETC1movie()"); r = ETC1movie(); } } //显示完成动画,关闭开机铃声 if (resourcePath != NULL) { if (mediastatus == NO_ERROR) { ALOGD("mediaplayer was stareted successfully, now it is going to be stoped"); mediaplayer->stop(); mediaplayer->disconnect(); mediaplayer.clear(); } } ... return r;}至此,logo动画、开机动画的显示过程就分析到这里。
相关文章推荐
- s5pv210 uboot 源码分析 笔记版 转载请注明出处---crosskernel@gmail.com
- 第二人生的源码分析(11)地面显示的实现
- Android4.0中判断WIFI P2P选项是否显示的源码分析
- mini2440 nboot 源码分析+TOC框架图
- 决定从头开始分析u-boot-1.1.4源码(二)
- u-boot-2010.06 源码分析<3>--第二阶段
- 高通平台android kernel 开机logo显示和传统linux一样
- S5PV210-uboot源码分析-第二阶段
- linux 3.6 启动源码分析(二) start_kernel
- U-boot源码简要分析(二)
- s3c-u-boot-1.1.6源码分析
- 第二人生的源码分析(九十)LLScrollListCtrl实现列表显示
- 第二人生的源码分析(九十四)LLTextBox类实现文本显示
- 第二人生的源码分析(九十六)LLMenuItemGL实现菜单的显示
- Java分布式跟踪系统Zipkin(六):Brave源码分析-Brave和SpringBoot整合
- uboot 源码分析(2)uboot 环境变量实现简析
- 第二人生的源码分析(九十八)LLIconCtrl实现图标按钮显示
- Ti-am335x-uboot-2015.07移植LCD显示logo功能
- am3359 u-boot显示logo
- linux-kernel 3.5.3Tcp系统调用,源码分析6-bind系统调用