Android系统开发进阶-BootAnimation添加视频播放功能

对于手机用户来说,开机动画接触得比较少,因为用户可能一年也不会关开机一次。但对于 TV 设备跟盒子的用户来说,开机动画就是家常便饭了,每天都要开关机。反正都是要等待开机,看 Android logo 是看,看广告也是看,所以各厂商也就利用这个来顺便赚个广告费。Android 系统默认的开机动画只支持图片形式的动画,是不支持 mp4 等视频类型的,但我们的广告又是以视频为主的。所以我们需要给 BootAnimation 增加播放视频的功能,下面我们就来演示一下怎么实现这个功能。

1. BootAnimation 类添加 video 播放函数

BootAnimation.h

1
2
3
4
5
bool android();
bool movie();
//qiushao patch add start
bool video();
//qiushao patch add end

BootAnimation.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//qiushao patch add start
#include <media/mediaplayer.h>
#include <media/IMediaHTTPService.h>
//qiushao patch add start

//qiushao patch add start
const char *videoPath = "/system/media/bootvideo.mp4";
bool BootAnimation::video() {
const float MAX_FPS = 60.0f;
const float CHECK_DELAY = ns2us(s2ns(1) / MAX_FPS);
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(mDisplay, mSurface);
sp<MediaPlayer> mp = new MediaPlayer();
mp->reset();
mp->setDataSource(NULL, videoPath, NULL);
mp->setVideoSurfaceTexture(mFlingerSurface->getIGraphicBufferProducer());
mp->prepare();
mp->start();
//设置音量
mp->setVolume(1.0, 1.0);

//等Launcher启动完成
while(true) {
if(exitPending()) {
break;
}
usleep(CHECK_DELAY);
checkExit();
}

//等开机视频播放完成
while (mp->isPlaying()) {
usleep(200000);
}
ALOGD("bootvideo play finish");

mp->stop();
mp->disconnect();
mp.clear();
return true;
}
//qiushao patch add end
bool BootAnimation::threadLoop()
{
//qiushao patch modify start
if (access(videoPath, R_OK) == 0) {
video();
} else if (!mZipFileName.isEmpty()) {
movie();
} else {
android();
}
//qiushao patch modify end
...
}

2. 添加依赖

因为我们要用到 MediaPlayer, 所以需要添加 libmedia 依赖:
Android.bp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cc_library_shared {
name: "libbootanimation",
defaults: ["bootanimation_defaults"],

srcs: ["BootAnimation.cpp"],

shared_libs: [
"libui",
"libhwui",
"libEGL",
"libGLESv1_CM",
"libgui",
"libtinyalsa",
//qiushao patch add start
"libmedia",
//qiushao patch add end
],

product_variables: {
product_is_iot: {
init_rc: ["iot/bootanim_iot.rc"],
},
},
}

3. selinux 设置

selinux 的配置都是在执行后,看报什么错误,就加什么权限,最后需要给 bootanim 服务和 mediaserver 服务添加权限,直接看 diff 吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
qiushao@qiushao-pc:~/source/android-10/system/sepolicy$ git diff .
diff --git a/prebuilts/api/29.0/public/bootanim.te b/prebuilts/api/29.0/public/bootanim.te
index e8cb98bbc..0b1ffd3ee 100644
--- a/prebuilts/api/29.0/public/bootanim.te
+++ b/prebuilts/api/29.0/public/bootanim.te
@@ -8,6 +8,7 @@ hal_client_domain(bootanim, hal_graphics_composer)

binder_use(bootanim)
binder_call(bootanim, surfaceflinger)
+binder_call(bootanim, mediaserver)
binder_call(bootanim, audioserver)

hwbinder_use(bootanim)
@@ -23,6 +24,7 @@ allow bootanim audio_device:chr_file rw_file_perms;

allow bootanim audioserver_service:service_manager find;
allow bootanim surfaceflinger_service:service_manager find;
+allow bootanim mediaserver_service:service_manager find;

# Allow access to ion memory allocation device
allow bootanim ion_device:chr_file rw_file_perms;
diff --git a/prebuilts/api/29.0/public/mediaserver.te b/prebuilts/api/29.0/public/mediaserver.te
index 70d0a55b2..5a9d8fef0 100644
--- a/prebuilts/api/29.0/public/mediaserver.te
+++ b/prebuilts/api/29.0/public/mediaserver.te
@@ -24,6 +24,7 @@ userdebug_or_eng(`
binder_use(mediaserver)
binder_call(mediaserver, binderservicedomain)
binder_call(mediaserver, appdomain)
+binder_call(mediaserver, bootanim)
binder_service(mediaserver)

allow mediaserver media_data_file:dir create_dir_perms;
diff --git a/public/bootanim.te b/public/bootanim.te
index e8cb98bbc..0b1ffd3ee 100644
--- a/public/bootanim.te
+++ b/public/bootanim.te
@@ -8,6 +8,7 @@ hal_client_domain(bootanim, hal_graphics_composer)

binder_use(bootanim)
binder_call(bootanim, surfaceflinger)
+binder_call(bootanim, mediaserver)
binder_call(bootanim, audioserver)

hwbinder_use(bootanim)
@@ -23,6 +24,7 @@ allow bootanim audio_device:chr_file rw_file_perms;

allow bootanim audioserver_service:service_manager find;
allow bootanim surfaceflinger_service:service_manager find;
+allow bootanim mediaserver_service:service_manager find;

# Allow access to ion memory allocation device
allow bootanim ion_device:chr_file rw_file_perms;
diff --git a/public/mediaserver.te b/public/mediaserver.te
index 70d0a55b2..5a9d8fef0 100644
--- a/public/mediaserver.te
+++ b/public/mediaserver.te
@@ -24,6 +24,7 @@ userdebug_or_eng(`
binder_use(mediaserver)
binder_call(mediaserver, binderservicedomain)
binder_call(mediaserver, appdomain)
+binder_call(mediaserver, bootanim)
binder_service(mediaserver)

allow mediaserver media_data_file:dir create_dir_perms;
qiushao@qiushao-pc:~/source/android-10/system/sepolicy$

4. bootvideo 预置

我们把 bootvideo.mp4 视频文件放到 device/qiushao/pure/bootvideo.mp4, 我测试用的 bootvideo.mp4
然后在 pure.mk 中添加以下配置:

1
PRODUCT_COPY_FILES += device/qiushao/pure/bootvideo.mp4:system/media/bootvideo.mp4

5. 编译验证

以上就完成了 BootAnimation 播放视频的功能,其实也很简单,就是调用一下 MediaPlayer 的 c++ 接口而已。音量设置也是可以的。
我们编译验证一下,图像声音都是正常的。