admin管理员组文章数量:1625849
Android7
源码目录:frameworks/base/cmds/bootanimation/
bootanimation 源码分析:
一. 从 bootanimation_main.cpp 开始
创建 bootanimation 线程
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");
if (!noBootAnimation) {
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object
sp<BootAnimation> boot = new BootAnimation();
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
二. BootAnimation.cpp 流程分析
创建 BootAnimation 对象
BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true) {
mSession = new SurfaceComposerClient();
}
readyToRun 创建 surface 为渲染图像做准备
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;
// create the native surface 创建 surface,
// 创建的详细过程参考 《深入理解Surface系统 》
// https://blog.csdn/innost/article/details/47208337
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
SurfaceComposerClient::closeGlobalTransaction();
sp<Surface> s = control->getSurface();
// initialize opengl and egl 初始化 openGL
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;
// If the device has encryption turned on or is in process
// of being encrypted we show the encrypted boot animation.
char decrypt[PROPERTY_VALUE_MAX];
property_get("vold.decrypt", decrypt, "");
bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
// 选择待解压播放文件 mZipFileName
if (encryptedAnimation && (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
}
else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) {
mZipFileName = OEM_BOOTANIMATION_FILE;
}
else if (access(USER_BOOTANIMATION_FILE, R_OK) == 0) {
ALOGE("FILE PATH userdefine");
mZipFileName = USER_BOOTANIMATION_FILE;
}else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) {
ALOGE("FILE PATH system media");
mZipFileName = SYSTEM_BOOTANIMATION_FILE;
}
return NO_ERROR;
}
播放画面线程 threadLoop 调用 movie 函数
bool BootAnimation::threadLoop()
{
bool r;
// We have no bootanimation file, so we use the stock android logo
// animation.
//HISILICON add begin
//fastplay_stop: stop fastplay when bootanimation show
char buffer[PROPERTY_VALUE_MAX] = {0};
bool fastplayExists = hasFastplay();
HiSysManagerClient sysclient;
if (fastplayExists) {
property_get("persist.sys.fastplay.fullyplay", buffer, "false");
//stop fastplay & hold its last frame
if (!strcasecmp("true", buffer)) {
String8 device = String8("/proc/msp/mce");
String8 value = String8("stop count 1");
HIADP_MCE_Exit();
} else {
String8 device = String8("/proc/msp/mce");
String8 value = String8("stop time 0");
HIADP_MCE_Exit();
}
}
//support for cmcc
char cmcc[PROPERTY_VALUE_MAX] = {0};
property_get("ro.product.target", cmcc, "false");
// 根据 ro.product.target 属性值,选择播放源和播放方式
if(!strcasecmp("shcmcc", cmcc)){
if(access(USER_BOOTVIDEOANIMATION_FILE,R_OK)==0){
r = videoBootAnimation();
}else if (access(USER_BOOTANIMATION_FILE, R_OK) == 0) {
r = movie(String8(USER_BOOTANIMATION_FILE));
}else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) {
r = movie(String8(SYSTEM_BOOTANIMATION_FILE));
}else {
r = android();
}
//support video play in bootanimation
}else if (videoExist()) {
r = playVideo();
//HISILICON add end
} else if (mZipFileName.isEmpty()) {
r = android();
} else {
// 解压播放 mZipFileName
r = movie(mZipFileName);
}
函数 movie 调用 playAnimation 播放动画
bool BootAnimation::movie(const String8 ZipFileName)
{
// 解压 ZipFileName
Animation* animation = loadAnimation(ZipFileName);
if (animation == NULL)
return false;
// Blend required to draw time on top of animation frames.
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 clockTextureInitialized = false;
if (mClockEnabled) {
clockTextureInitialized = (initTexture(&mClock, mAssets, "images/clock64.png") == NO_ERROR);
mClockEnabled = clockTextureInitialized;
}
// 播放动画
playAnimation(*animation);
releaseAnimation(animation);
if (clockTextureInitialized) {
glDeleteTextures(1, &mClock.name);
}
return false;
}
播放动画 playAnimation 函数
bool BootAnimation::playAnimation(const Animation& animation)
{
const size_t pcount = animation.parts.size();
const int xc = (mWidth - animation.width) / 2;
const int yc = ((mHeight - animation.height) / 2);
nsecs_t frameDuration = s2ns(1) / animation.fps;
Region clearReg(Rect(mWidth, mHeight));
clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
// 读取对应的图片,调用 OpenGL 播放动画
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);
// Handle animation package
if (part.animation != NULL) {
playAnimation(*part.animation);
if (exitPending())
break;
continue; //to next part
}
// 根据解析的 part 进行循环,播放图片
for (int r=0 ; !part.count || r<part.count ; r++) {
// Exit any non playuntil complete parts immediately
if(exitPending() && !part.playUntilComplete)
break;
// only play audio file the first time we animate the part
if (r == 0 && mAudioPlayer != NULL && part.audioFile) {
mAudioPlayer->playFile(part.audioFile); // 播放音乐
}
glClearColor(
part.backgroundColor[0],
part.backgroundColor[1],
part.backgroundColor[2],
1.0f);
// 该循环中调用 OpenGL 函数绘制图形
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);
}
initTexture(frame);
}
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);
}
// specify the y center as ceiling((mHeight - animation.height) / 2)
// which is equivalent to mHeight - (yc + animation.height)
glDrawTexiOES(xc, mHeight - (yc + animation.height),
0, animation.width, animation.height);
if (mClockEnabled && part.clockPosY >= 0) {
drawTime(mClock, part.clockPosY);
}
eglSwapBuffers(mDisplay, mSurface);
nsecs_t now = systemTime();
nsecs_t delay = frameDuration - (now - lastFrame);
//ALOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));
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();
}
int loopTimes = part.pause * ns2us(frameDuration)/200000;
// 两个part之间的时间间隔
for(int i = 0 ;i<loopTimes;i++){
checkExit(); // 检查是否退出动画
usleep(200000);
if(exitPending()&& !part.playUntilComplete){
break;
}
}
// For infinite parts, we've now played them at least once, so perhaps exit
if(exitPending() && !part.count)
break;
}
// free the textures for this part
if (part.count != 1) {
for (size_t j=0 ; j<fcount ; j++) {
const Animation::Frame& frame(part.frames[j]);
glDeleteTextures(1, &frame.tid);
}
}
}
return true;
}
三. 制作 bootanimation
- 在电脑上新建文件夹命名为 bootanimation
- 进入 bootanimation 新建两个文件夹并命名: part0、part1 ,一个 txt 文件:desc.txt
- part0 文件夹里存放图片格式为 png
- part1 文件夹存放一张图片格式为 png
- desc.txt 文件的内容
- 压缩 bootanimation 文件夹,选择 zip 格式,压缩方式:存储
- 用 adb 命令把 bootanimation.zip 拷贝到 /system/media/ 目录
adb remount adb push bootanimation.zip /system/media/ ## 播放动画的两种方法 adb reboot # 重启设备,自动运行开机动画 ## 或者 adb shell $ setprop ctl.start bootanim # 播放开机动画 $ setprop ctl.stop bootanim # 停止开机动画
本文标签: 动画bootanimation
版权声明:本文标题:BootAnimation 开机动画 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dongtai/1728935132a1180575.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论