Bootanimation 定制及原理剖析

一、bootanimtion服务

1.1 init阶段bootanimation服务配置

从Android 7.0开始,谷歌将bootnimation服务从init.rc中分离出来,单独存放在frameworks/base/cmds/bootanimation/目录下bootanim.rc文件中:

1
2
3
4
5
6
7
service bootanim /system/bin/bootanimation
class core
user graphics
group graphics audio
disabled //init启动时不会启动bootanimation服务
oneshot
writepid /dev/stune/top-app/tasks

bootanimation服务的用户和用户组分别为graphic和graphics audio。需要关注的disabled,即在init启动阶段该服务是不会启动的。oneshot表示该服务只启动一次。

1.2 surfaceflinger服务调用bootnimation

当SurfaceFlinger服务启动时,它会通过修改系统属性ctl.start的值来通知init进程启动bootanimation服务。

早期的版本中,SurfaceFlinger服务是在SystemServer服务中启动的;Android 5.0之后变为init.rc脚本中控制其在init阶段启动。Android 7.0之后谷歌又将其独立为surfaceflinger.rc文件,存放在frameworks/native/services/surfaceflinger/目录下:

1
2
3
4
5
6
service surfaceflinger /system/bin/surfaceflinger
class core
user system
group graphics drmrpc readproc
onrestart restart zygote
writepid /dev/stune/foreground/tasks

接下来看看SurfaceFlinger的入口文件main_surfaceflinger.cpp:

1
2
3
4
5
6
7
8
9
10
11
int main(int, char**) {
......
sp<SurfaceFlinger> flinger = DisplayUtils::getInstance()->getSFInstance();
......
// 我们这里只关注init方法
flinger->init();
......
// 在该线程中运行surface flinger
flinger->run();
return 0;
}

main函数主要任务就是:先新建SurfaceFlinger对象,然后调用init方法,接着调用run方法。

在SurfaceFlinger.cpp的init方法中,创建一系列事件线程后,调用startBootAnim方法启动动画。

1
2
3
4
5
6
7
8
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
......
// 启动boot animation
startBootAnim();
ALOGV("Done initializing");
}

在startBootAnim函数中,将service.bootanim.exit属性置为0,将ctl.start属性置为bootanim。

1
2
3
4
5
void SurfaceFlinger::startBootAnim() {
// start boot animation
property_set("service.bootanim.exit", "0");
property_set("ctl.start", "bootanim");
}

1.3 init进程处理属性变化

下面来看init.cpp的main函数:

1
2
3
4
5
6
7
int main(int argc, char** argv) {
......
// 启动系统属性服务
start_property_service();
......
return 0;
}

接着看property_service.cpp的start_property_service方法,调用register_epoll_handler函数监听属性变化。当属性值变化时,调用handle_property_set_fd

1
2
3
4
5
6
7
8
9
10
void start_property_service() {
property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
0666, 0, 0, NULL);
if (property_set_fd == -1) {
ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
exit(1);
}
listen(property_set_fd, 8);
register_epoll_handler(property_set_fd, handle_property_set_fd);
}
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
static void handle_property_set_fd()
{
// 通过socket接收系统属性变化事件
prop_msg msg;
int s;
int r;
struct ucred cr;
struct sockaddr_un addr;
socklen_t addr_size = sizeof(addr);
socklen_t cr_size = sizeof(cr);
char * source_ctx = NULL;
struct pollfd ufds[1];
const int timeout_ms = 2 * 1000;
int nr;
// 接收TCP连接
if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
return;
}
// 取出socket中内容
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
ERROR("Unable to receive socket options\n");
return;
}
ufds[0].fd = s;
ufds[0].events = POLLIN;
ufds[0].revents = 0;
// 轮询客户端事件
nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
// 轮询事件超时
if (nr == 0) {
ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);
close(s);
return;
// 等待错误
} else if (nr < 0) {
ERROR("sys_prop: error waiting for uid=%d to send property message: %s\n", cr.uid, strerror(errno));
close(s);
return;
}
// 接收socket主体数据
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
if(r != sizeof(prop_msg)) {
ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n",
r, sizeof(prop_msg), strerror(errno));
close(s);
return;
}
// 判断接收条件
switch(msg.cmd) {
// 系统属性变化
case PROP_MSG_SETPROP:
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
// 检查属性值是否合法
if (!is_legal_property_name(msg.name, strlen(msg.name))) {
ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
close(s);
return;
}
getpeercon(s, &source_ctx);
// 判断是否是ctl开头的属性,是则调用handle_control_message方法
if(memcmp(msg.name,"ctl.",4) == 0) {
close(s);
if (check_control_mac_perms(msg.value, source_ctx, &cr)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
}
} else {
if (check_mac_perms(msg.name, source_ctx, &cr)) {
property_set((char*) msg.name, (char*) msg.value);
} else {
ERROR("sys_prop: permission denied uid:%d name:%s\n",
cr.uid, msg.name);
}
close(s);
}
freecon(source_ctx);
break;
default:
close(s);
break;
}
}

调用handle_control_message方法启动bootanima服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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());
}
}

二、 开机动画启动

2.1 开机动画显示流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main()
{
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.nobootanimation", value, "0");
int noBootAnimation = atoi(value);
ALOGI_IF(noBootAnimation, "boot animation disabled");
// 检查属性debug.sf.nobootanimation是否不等于0
if (!noBootAnimation) {
// 启动一个binder线程池
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// 创建boot animation对象
sp<BootAnimation> boot = new BootAnimation();
IPCThreadState::self()->joinThreadPool();
}
return 0;
}

接下来看看BootAnimation.h中的声明:

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
class BootAnimation : public Thread, public IBinder::DeathRecipient
{
public:
BootAnimation();
virtual ~BootAnimation();
sp<SurfaceComposerClient> session() const;
private:
// 每个线程类都要实现的,这个函数如果返回true,且没有requestExist()没有被调用,则该函数会再次执行;如果返回false,则threadloop中的内容仅仅执行一次,线程就会退出。
virtual bool threadLoop();
// Thread执行前的初始化工作;
virtual status_t readyToRun();
// 属于其父类RefBase,该函数在强引用sp新增引用计数时调用,即有sp包装的类初始化时调用;
virtual void onFirstRef();
// 当对象死了或其他情况导致该Binder结束时,就会回调binderDied()方法;
virtual void binderDied(const wp<IBinder>& who);
......
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
status_t initTexture(FileMap* map, int* width, int* height);
status_t initFont(Font* font, const char* fallback);
// 显示系统默认的开机画面;
bool android();
// 显示用户自定义的开机动画。
bool movie();
......
};

接下来看看BootAnimation.cpp中各函数的具体实现:
BootAnimation间接继承自RefBase类,并重写了其onFirstRef方法,所以智能指针第一次调用BootAnimation时即先调用onFirstRef方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void BootAnimation::onFirstRef() {
// 注册SurfaceFlinger服务的死亡接收通知
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
run("BootAnimation", PRIORITY_DISPLAY);
}
}

BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
mTimeFormat12Hour(false), mTimeCheckThread(NULL) {
// 用于同Surfaceflinger进行Binder进程间通信
mSession = new SurfaceComposerClient();
mSystemBoot = !property_get_bool(BOOT_COMPLETED_PROP_NAME, 0);
}

当onFirstRef调用了父类的run方法后,系统会创建一个新线程,该线程执行前会先调用readyToRun方法执行一系列初始化操作:

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
// 检查显示屏信息
sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
ISurfaceComposer::eDisplayIdMain));
DisplayInfo dinfo;
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
if (status)
return -1;
// 获得一个SurfaceControl对象control
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
SurfaceComposerClient::closeGlobalTransaction();
// control的成员函数会返回一个Surface对象
sp<Surface> s = control->getSurface();
// 初始化OPENEGL和EGL
const EGLint attribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 0,
EGL_NONE
};
EGLint w, h;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
surface = eglCreateWindowSurface(display, config, s.get(), NULL);
context = eglCreateContext(display, config, NULL, NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
return NO_INIT;
mDisplay = display;
mContext = context;
mSurface = surface;
mWidth = w;
mHeight = h;
mFlingerSurfaceControl = control;
mFlingerSurface = s;
// 如果开启加密,则显示加密动画
char decrypt[PROPERTY_VALUE_MAX];
property_get("vold.decrypt", decrypt, "");
bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
// 选择对应目录下动画文件
// 加密动画
if (encryptedAnimation && (access(getAnimationFileName(IMG_ENC), R_OK) == 0)) {
mZipFileName = getAnimationFileName(IMG_ENC);
}
// OEM动画
else if (access(getAnimationFileName(IMG_OEM), R_OK) == 0) {
mZipFileName = getAnimationFileName(IMG_OEM);
}
// 系统动画
else if (access(getAnimationFileName(IMG_SYS), R_OK) == 0) {
mZipFileName = getAnimationFileName(IMG_SYS);
}
return NO_ERROR;
}

const char *BootAnimation::getAnimationFileName(ImageID image)
{
const char *fileName[3] = { OEM_BOOTANIMATION_FILE,
SYSTEM_BOOTANIMATION_FILE,
SYSTEM_ENCRYPTED_BOOTANIMATION_FILE };
if (Environment::isSupported()) {
Environment* environment = new Environment();
const char* animFile = environment->getMediaFile(
Environment::ANIMATION_TYPE, Environment::BOOT_STATUS);
ALOGE("Get Carrier Animation type: %d,status:%d", Environment::ANIMATION_TYPE,Environment::BOOT_STATUS);
if (animFile != NULL && strcmp(animFile, "") != 0) {
return animFile;
}else{
ALOGD("Get Carrier Animation file: %s failed", animFile);
}
delete environment;
}else{
ALOGE("Get Carrier Animation file,since it's not support carrier");
}

return fileName[image];
}

调用threadLoop方法显示动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bool BootAnimation::threadLoop()
{
bool r;
// 判断动画文件是否存在,存在则调用自定义动画,否则调用系统默认动画
if (mZipFileName.isEmpty()) {
r = android();
} else {
r = movie();
}
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
mFlingerSurface.clear();
mFlingerSurfaceControl.clear();
eglTerminate(mDisplay);
IPCThreadState::self()->stopProcess();
return r;
}

2.2 系统默认动画配置

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
bool BootAnimation::android()
{
// 读取开机动画默认图片frameworks/base/core/res/assets/images
// android字样图标
initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
// 闪光图片
initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
// 清理屏幕
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mDisplay, mSurface);
glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// 动画在屏幕显示位置
const GLint xc = (mWidth - mAndroid[0].w) / 2;
const GLint yc = (mHeight - mAndroid[0].h) / 2;
const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
updateRect.height());
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
const nsecs_t startTime = systemTime();
do {
nsecs_t now = systemTime();
double time = now - startTime;
float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
GLint x = xc - offset;
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
// 绘制闪光图片
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);
glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
glEnable(GL_BLEND);
// 绘制android字样图片
glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
if (res == EGL_FALSE)
break;
const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
if (sleepTime > 0)
usleep(sleepTime);
// 判断是否退出
checkExit();
} while (!exitPending());
glDeleteTextures(1, &mAndroid[0].name);
glDeleteTextures(1, &mAndroid[1].name);
return false;
}

void BootAnimation::checkExit() {
char value[PROPERTY_VALUE_MAX];
property_get(EXIT_PROP_NAME, value, "0");
int exitnow = atoi(value);
// 判断service.bootanim.exit属性,若为1则请求退出线程
if (exitnow) {
requestExit();
}
}

2.3 自定义动画配置

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
bool BootAnimation::movie()
{
// 加载动画文件
Animation* animation = loadAnimation(mZipFileName);
if (animation == NULL)
return false;
bool anyPartHasClock = false;
for (size_t i=0; i < animation->parts.size(); i++) {
if(validClock(animation->parts[i])) {
anyPartHasClock = true;
break;
}
}
if (!anyPartHasClock) {
mClockEnabled = false;
}
mUseNpotTextures = false;
String8 gl_extensions;
const char* exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if (!exts) {
glGetError();
} else {
gl_extensions.setTo(exts);
if ((gl_extensions.find("GL_ARB_texture_non_power_of_two") != -1) ||
(gl_extensions.find("GL_OES_texture_npot") != -1)) {
mUseNpotTextures = true;
}
}
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// 清理屏幕
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
bool clockFontInitialized = false;
if (mClockEnabled) {
clockFontInitialized =
(initFont(&animation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR);
mClockEnabled = clockFontInitialized;
}
if (mClockEnabled && !updateIsTimeAccurate()) {
mTimeCheckThread = new TimeCheckThread(this);
mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
}
// 播放动画
playAnimation(*animation);
if (mTimeCheckThread != NULL) {
mTimeCheckThread->requestExit();
mTimeCheckThread = NULL;
}
// 释放动画
releaseAnimation(animation);
if (clockFontInitialized) {
glDeleteTextures(1, &animation->clockFont.texture.name);
}
return false;
}

loadAnimation方法加载动画

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
BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn)
{
if (mLoadedFiles.indexOf(fn) >= 0) {
ALOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
fn.string());
return NULL;
}
ZipFileRO *zip = ZipFileRO::open(fn);
if (zip == NULL) {
ALOGE("Failed to open animation zip \"%s\": %s",
fn.string(), strerror(errno));
return NULL;
}
Animation *animation = new Animation;
animation->fileName = fn;
animation->zip = zip;
animation->clockFont.map = nullptr;
mLoadedFiles.add(animation->fileName);
// 解析动画文件
parseAnimationDesc(*animation);
if (!preloadZip(*animation)) {
return NULL;
}
mLoadedFiles.remove(fn);
return animation;
}

parseAnimationDesc方法解析desc文件,确定动画大小速度等信息。

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
bool BootAnimation::parseAnimationDesc(Animation& animation)
{
String8 desString;
// 读取desc.txt内容
if (!readFile(animation.zip, "desc.txt", desString)) {
return false;
}
char const* s = desString.string();
// 解析desc.txt文件
for (;;) {
const char* endl = strstr(s, "\n");
if (endl == NULL) break;
String8 line(s, endl - s);
const char* l = line.string();
int fps = 0;
int width = 0;
int height = 0;
int count = 0;
int pause = 0;
char path[ANIM_ENTRY_NAME_MAX];
// 默认黑色
char color[7] = "000000";
char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
char clockPos2[TEXT_POS_LEN_MAX + 1] = "";

char pathType;
if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
animation.width = width;
animation.height = height;
animation.fps = fps;
} else if (sscanf(l, " %c %d %d %s #%6s %16s %16s",
&pathType, &count, &pause, path, color, clockPos1, clockPos2) >= 4) {
Animation::Part part;
part.playUntilComplete = pathType == 'c';
part.count = count;
part.pause = pause;
part.path = path;
part.audioData = NULL;
part.animation = NULL;
if (!parseColor(color, part.backgroundColor)) {
ALOGE("> invalid color '#%s'", color);
part.backgroundColor[0] = 0.0f;
part.backgroundColor[1] = 0.0f;
part.backgroundColor[2] = 0.0f;
}
parsePosition(clockPos1, clockPos2, &part.clockPosX, &part.clockPosY);
animation.parts.add(part);
}
else if (strcmp(l, "$SYSTEM") == 0) {
Animation::Part part;
part.playUntilComplete = false;
part.count = 1;
part.pause = 0;
part.audioData = NULL;
part.animation = loadAnimation(String8(SYSTEM_BOOTANIMATION_FILE));
if (part.animation != NULL)
animation.parts.add(part);
}
s = ++endl;
}
return true;
}

preloadZip处理片段信息

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
bool BootAnimation::preloadZip(Animation& animation)
{
// 读取zip文件
const size_t pcount = animation.parts.size();
void *cookie = NULL;
ZipFileRO* zip = animation.zip;
if (!zip->startIteration(&cookie)) {
return false;
}
Animation::Part* partWithAudio = NULL;
ZipEntryRO entry;
char name[ANIM_ENTRY_NAME_MAX];
// 循环遍历每个文件
while ((entry = zip->nextEntry(cookie)) != NULL) {
const int foundEntryName = zip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
ALOGE("Error fetching entry file name");
continue;
}
const String8 entryName(name);
const String8 path(entryName.getPathDir());
const String8 leaf(entryName.getPathLeaf());
if (leaf.size() > 0) {
if (entryName == CLOCK_FONT_ZIP_NAME) {
FileMap* map = zip->createEntryFileMap(entry);
if (map) {
animation.clockFont.map = map;
}
continue;
}
for (size_t j = 0; j < pcount; j++) {
if (path == animation.parts[j].path) {
uint16_t method;
// 支持png格式文件
if (zip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
if (method == ZipFileRO::kCompressStored) {
FileMap* map = zip->createEntryFileMap(entry);
if (map) {
Animation::Part& part(animation.parts.editItemAt(j));
if (leaf == "audio.wav") {
// 一个片段最多只能包含一个audio文件
part.audioData = (uint8_t *)map->getDataPtr();
part.audioLength = map->getDataLength();
partWithAudio = &part;
} else if (leaf == "trim.txt") {
part.trimData.setTo((char const*)map->getDataPtr(),
map->getDataLength());
} else {
Animation::Frame frame;
frame.name = leaf;
frame.map = map;
frame.trimWidth = animation.width;
frame.trimHeight = animation.height;
frame.trimX = 0;
frame.trimY = 0;
part.frames.add(frame);
}
}
} else {
ALOGE("bootanimation.zip is compressed; must be only stored");
}
}
}
}
}
}
// 如果存在trimData,则覆盖默认值
for (Animation::Part& part : animation.parts) {
const char* trimDataStr = part.trimData.string();
for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) {
const char* endl = strstr(trimDataStr, "\n");
if (endl == NULL) {
break;
}
String8 line(trimDataStr, endl - trimDataStr);
const char* lineStr = line.string();
trimDataStr = ++endl;
int width = 0, height = 0, x = 0, y = 0;
if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) {
Animation::Frame& frame(part.frames.editItemAt(frameIdx));
frame.trimWidth = width;
frame.trimHeight = height;
frame.trimX = x;
frame.trimY = y;
} else {
ALOGE("Error parsing trim.txt, line: %s", lineStr);
break;
}
}
}
// 如果动画文件中有铃声则创建并初始化audioplay
if (partWithAudio != NULL) {
ALOGD("found audio.wav, creating playback engine");
if (!audioplay::create(partWithAudio->audioData, partWithAudio->audioLength)) {
return false;
}
}
zip->endIteration(cookie);
return true;
}

playAnimation方法播放动画

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
bool BootAnimation::playAnimation(const Animation& animation)
{
const size_t pcount = animation.parts.size();
nsecs_t frameDuration = s2ns(1) / animation.fps;
const int animationX = (mWidth - animation.width) / 2;
const int animationY = (mHeight - animation.height) / 2;
// 显示每个动画片段
for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size();
glBindTexture(GL_TEXTURE_2D, 0);
if (part.animation != NULL) {
playAnimation(*part.animation);
if (exitPending())
break;
continue;
}
// 循环显示动画片段
for (int r=0 ; !part.count || r<part.count ; r++) {
if(exitPending() && !part.playUntilComplete)
break;
if (r == 0 && part.audioData && playSoundsAllowed()) {
ALOGD("playing clip for part%d, size=%d", (int) i, part.audioLength);
audioplay::playClip(part.audioData, part.audioLength);
}
glClearColor(
part.backgroundColor[0],
part.backgroundColor[1],
part.backgroundColor[2],
1.0f);
// 显示每个片段对应的png文件
for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
const Animation::Frame& frame(part.frames[j]);
nsecs_t lastFrame = systemTime();
if (r > 0) {
glBindTexture(GL_TEXTURE_2D, frame.tid);
} else {
if (part.count != 1) {
glGenTextures(1, &frame.tid);
glBindTexture(GL_TEXTURE_2D, frame.tid);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
int w, h;
initTexture(frame.map, &w, &h);
}
const int xc = animationX + frame.trimX;
const int yc = animationY + frame.trimY;
Region clearReg(Rect(mWidth, mHeight));
clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
if (!clearReg.isEmpty()) {
Region::const_iterator head(clearReg.begin());
Region::const_iterator tail(clearReg.end());
glEnable(GL_SCISSOR_TEST);
while (head != tail) {
const Rect& r2(*head++);
glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
glClear(GL_COLOR_BUFFER_BIT);
}
glDisable(GL_SCISSOR_TEST);
}
glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight),
0, frame.trimWidth, frame.trimHeight);
if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
}
eglSwapBuffers(mDisplay, mSurface);
nsecs_t now = systemTime();
nsecs_t delay = frameDuration - (now - lastFrame);
lastFrame = now;
if (delay > 0) {
struct timespec spec;
spec.tv_sec = (now + delay) / 1000000000;
spec.tv_nsec = (now + delay) % 1000000000;
int err;
do {
err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
} while (err<0 && errno == EINTR);
}
checkExit();
}
usleep(part.pause * ns2us(frameDuration));
if(exitPending() && !part.count)
break;
}

}
for (const Animation::Part& part : animation.parts) {
if (part.count != 1) {
const size_t fcount = part.frames.size();
for (size_t j = 0; j < fcount; j++) {
const Animation::Frame& frame(part.frames[j]);
glDeleteTextures(1, &frame.tid);
}
}
}
audioplay::setPlaying(false);
audioplay::destroy();
return true;
}

releaseAnimation方法释放动画

1
2
3
4
5
6
7
8
9
10
11
void BootAnimation::releaseAnimation(Animation* animation) const
{
for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
e = animation->parts.end(); it != e; ++it) {
if (it->animation)
releaseAnimation(it->animation);
}
if (animation->zip)
delete animation->zip;
delete animation;
}

当SystemServer进程中关键服务都起来后,就会将Launcher启动起来,待Launcher启动后会发送idle通知给ActivityManagerService,进而传递给SurfaceFlinger,然后将service.bootanim.exit属性置为0,即退出动画播放。