android 开机动画和开机视频流程分析基于android4.4
16lz
2021-12-04
android 开机画面是由应用程序bootanimation来负责显示的,主要类BootAnimation.cpp直接继承于android中定义的一个Thread, 接地继承了RefBase类,并且重写了RefBase类的成员函数onFirstRef,因此,当一个BootAnimation对象第一次被引用的时,这个BootAnimation对象的成员函数onFirstRef就会被调用。 当应用程序启动时,是先从main开始,具体代码如下: sp boot = new BootAnimation(); //add video boot memset(value,0,sizeof(value)); property_get("service.bootvideo", value, "0"); gUseBootVideo = (atoi(value) == 1 ? true : false);
if(gUseBootVideo){ // boot->setBootVolume(); /* modify,bootanimation path */ /*before modify code(property_set("service.bootvideo", "2");)*/ if (access(USER_BOOTVIDEO_FILE, R_OK) == 0) { property_set("service.bootvideo", "2"); }else{ gUseBootVideo = false; } /*modify end */ } 如果access(USER_BOOTVIDEO_FILE, R_OK) == 0),即bootvideo文件存在则会执行property_set("service.bootvideo", "2"),则启动系统内的视频播放应用程序LibPlayer播放开机视频,同时gUseBootVideo =true代表bootanimation播放的是开机视频。否则播放开机动画。 所以当开机视频文件bootvideo存在时,应用程序bootanimation会做2件事情: 一:执行到sp boot = new BootAnimation();时会调用BootAnimation对象的成员函数onFirstRe,在onFirstRe里会执行线程的run方法,然后会调用动画的android或movie方法来显示动画(既然是为了播放开机视频,开机动画就没必要播放,后续在播放动画的方法中必须跳过GLES的绘图逻辑以免出现动画和视频同时出现的BUG)。 二:执行 到property_set("service.bootvideo", "2");时,则启动系统内的视频播放应用程序LibPlayer播放开机视频。
之前说到BootAnimation对象的成员函数onFirstRe执行后会经过一系列的调用最终执行到播放开机动画,具体流程如下: 1.在onFirstRe中调用 run("BootAnimation", PRIORITY_DISPLAY);创建线程 2.这个线程在第一次运行之前,会调用BootAnimation类的成员函数readyToRun来执行一些初始化工作,这里我们需要注意mAndroidAnimation这个bool,它是来决定后面的动画走的是原生android还是我们自定义的movie 3.调用BootAnimation类的成员函数htreadLoop来显示第开机动画,这里我们走的是movie。
具体的书写格式j及含义我就不多说了自行谷歌,但是需要大家注意的一点就是无论是什么样的 desc.txt 它的最后一行应该基本都是
由于我手上的代码并不是原生的android源码,而是项目code,所以关于画面显示的原理可能不太一样。我们的开机视频及开机动画是在Video层播放的,而launcher的显示是在OSD层,所以在视频和动画播放结束后需要将display_mode从Video层切换到OSD层,否则就算launcher正常启动了我们还是会看到屏幕一直卡在开机logo。 所以之前说的那2种出错的情况不能直接返回,而是需要按照正常流程那样在 SurfaceFlinger::bootFinished() 调用后进行一个setDisPlayMode操作,再返回。这样就可以避免屏幕一直卡在开机logo。 针对这些情况方法都是一样的:先调用用setDisPlayMode然后通过checkExit循环判断是否已接收到 bootFinished ,若接收到直接返回退出播放。例如: int switch_logo_flag = 0; while(!descMap&&!gUseBootVideo){ if(switch_logo_flag == 0){ property_set(RUNNING_PROP_NAME,"running"); switch_logo_flag=1; } checkExit(); if(exitPending()){ ALOGD("======tzr=====descMap is null ,return \n"); return false; } }
------------------------------------------------------------开机视频播放过程中出现黑屏------------------------------------------------------------------------ 如果视频长度超过10s, 在播放开机视频的10后就会出现屏幕一直黑屏,直到launcher显示出来。 根据log及之前的开机动画分析可知,开机视频的流程与开机动画相比就是增加了用libPlayer播放指定文件夹中的视频文件,而当开机的准备工作完成后会执行 SurfaceFlinger::bootFinished() 会设置service.bootanim.exit=1来通知应用程序bootanimation可以停止播放动画了,然后setDisplayMode以便让launcher显示出来。但是如果播放的是长度较长的视频,在接到 SurfaceFlinger 的通知后不能停止播放,必须在播放结束后才能执行setDisplayMode。 而播放10s后的黑屏问题就是因为恰好执行了执行 SurfaceFlinger::bootFinished() 然后bootanimation立即调用了setDisplayMode。既然问题的原因已经查明,修改的方法很简单,就是当接收到service.bootanim.exit=1时,不要立即setDisplayMode,而是要等到接收到开机视频播放完成的消息后再去设置。 接收和设置的代码全部在函数checkExit中: void BootAnimation::checkExit() { // Allow surface flinger to gracefully request shutdown char value[PROPERTY_VALUE_MAX]; property_get(EXIT_PROP_NAME, value, "0"); int exitnow = atoi(value); if(gUseBootVideo){ // 下面这个while循环就是为了判断是否已经执行了SurfaceFlinger::bootFinished(),如果是则退出循环执行下面的代码,否则就一直循环等待 do{ usleep(10*1000); memset(value,0,sizeof(value)); property_get(EXIT_PROP_NAME, value, "0"); exitnow = atoi(value); }while(!exitnow); }
if (exitnow) {
if(gUseBootVideo){ - property_set("service.bootvideo.exit", "1"); / /这里是修改前的代码,通过这个属性设置会执行set_display_mode.sh do{ memset(value,0,sizeof(value)); property_get("init.svc.bootvideo", value, "NULL"); / /这个属性init.svc.bootvideo=stopped代表视频播放结束了 }while(!strcmp(value,"running")); + property_set("service.bootvideo.exit", "1"); }
requestExit(); } }
这篇文章是之前很早写的基于android4.4版本,现在项目都已经基于android8.1了,代码架构也更改非常大,但是一些基础的地方还是相同的,还是发出来作为参考
if(gUseBootVideo){ // boot->setBootVolume(); /* modify,bootanimation path */ /*before modify code(property_set("service.bootvideo", "2");)*/ if (access(USER_BOOTVIDEO_FILE, R_OK) == 0) { property_set("service.bootvideo", "2"); }else{ gUseBootVideo = false; } /*modify end */ } 如果access(USER_BOOTVIDEO_FILE, R_OK) == 0),即bootvideo文件存在则会执行property_set("service.bootvideo", "2"),则启动系统内的视频播放应用程序LibPlayer播放开机视频,同时gUseBootVideo =true代表bootanimation播放的是开机视频。否则播放开机动画。 所以当开机视频文件bootvideo存在时,应用程序bootanimation会做2件事情: 一:执行到sp
之前说到BootAnimation对象的成员函数onFirstRe执行后会经过一系列的调用最终执行到播放开机动画,具体流程如下: 1.在onFirstRe中调用 run("BootAnimation", PRIORITY_DISPLAY);创建线程 2.这个线程在第一次运行之前,会调用BootAnimation类的成员函数readyToRun来执行一些初始化工作,这里我们需要注意mAndroidAnimation这个bool,它是来决定后面的动画走的是原生android还是我们自定义的movie 3.调用BootAnimation类的成员函数htreadLoop来显示第开机动画,这里我们走的是movie。
- bool BootAnimation::threadLoop()
- {
- bool r;
- if (mAndroidAnimation) {
- r = android();
- } else {
- r = movie();
- }
- .............
- return r;
- }
- 600 480 24
- p 1 0 part1
- p 0 10 part2
具体的书写格式j及含义我就不多说了自行谷歌,但是需要大家注意的一点就是无论是什么样的 desc.txt 它的最后一行应该基本都是
- p 0 xx xxxx
由于我手上的代码并不是原生的android源码,而是项目code,所以关于画面显示的原理可能不太一样。我们的开机视频及开机动画是在Video层播放的,而launcher的显示是在OSD层,所以在视频和动画播放结束后需要将display_mode从Video层切换到OSD层,否则就算launcher正常启动了我们还是会看到屏幕一直卡在开机logo。 所以之前说的那2种出错的情况不能直接返回,而是需要按照正常流程那样在 SurfaceFlinger::bootFinished() 调用后进行一个setDisPlayMode操作,再返回。这样就可以避免屏幕一直卡在开机logo。 针对这些情况方法都是一样的:先调用用setDisPlayMode然后通过checkExit循环判断是否已接收到 bootFinished ,若接收到直接返回退出播放。例如: int switch_logo_flag = 0; while(!descMap&&!gUseBootVideo){ if(switch_logo_flag == 0){ property_set(RUNNING_PROP_NAME,"running"); switch_logo_flag=1; } checkExit(); if(exitPending()){ ALOGD("======tzr=====descMap is null ,return \n"); return false; } }
------------------------------------------------------------开机视频播放过程中出现黑屏------------------------------------------------------------------------ 如果视频长度超过10s, 在播放开机视频的10后就会出现屏幕一直黑屏,直到launcher显示出来。 根据log及之前的开机动画分析可知,开机视频的流程与开机动画相比就是增加了用libPlayer播放指定文件夹中的视频文件,而当开机的准备工作完成后会执行 SurfaceFlinger::bootFinished() 会设置service.bootanim.exit=1来通知应用程序bootanimation可以停止播放动画了,然后setDisplayMode以便让launcher显示出来。但是如果播放的是长度较长的视频,在接到 SurfaceFlinger 的通知后不能停止播放,必须在播放结束后才能执行setDisplayMode。 而播放10s后的黑屏问题就是因为恰好执行了执行 SurfaceFlinger::bootFinished() 然后bootanimation立即调用了setDisplayMode。既然问题的原因已经查明,修改的方法很简单,就是当接收到service.bootanim.exit=1时,不要立即setDisplayMode,而是要等到接收到开机视频播放完成的消息后再去设置。 接收和设置的代码全部在函数checkExit中: void BootAnimation::checkExit() { // Allow surface flinger to gracefully request shutdown char value[PROPERTY_VALUE_MAX]; property_get(EXIT_PROP_NAME, value, "0"); int exitnow = atoi(value); if(gUseBootVideo){ // 下面这个while循环就是为了判断是否已经执行了SurfaceFlinger::bootFinished(),如果是则退出循环执行下面的代码,否则就一直循环等待 do{ usleep(10*1000); memset(value,0,sizeof(value)); property_get(EXIT_PROP_NAME, value, "0"); exitnow = atoi(value); }while(!exitnow); }
if (exitnow) {
if(gUseBootVideo){ - property_set("service.bootvideo.exit", "1"); / /这里是修改前的代码,通过这个属性设置会执行set_display_mode.sh do{ memset(value,0,sizeof(value)); property_get("init.svc.bootvideo", value, "NULL"); / /这个属性init.svc.bootvideo=stopped代表视频播放结束了 }while(!strcmp(value,"running")); + property_set("service.bootvideo.exit", "1"); }
requestExit(); } }
这篇文章是之前很早写的基于android4.4版本,现在项目都已经基于android8.1了,代码架构也更改非常大,但是一些基础的地方还是相同的,还是发出来作为参考
更多相关文章
- Android(安卓)Animation
- Android(安卓)之 使用MediaPlayer播放音频
- Android(安卓)动画系列之自定义补间动画
- 【Android(安卓)UI设计与开发】之动画(Animation)详解(一)
- Android(安卓)属性动画(Property Animation)介绍
- Android如何判断系统是不是首次开机
- Android中Animator & Animation比较
- Android手势识别ViewFlipper触摸动画
- Android应用实例之----基于Service与ContentProvider的音乐播放