前面的一篇文章讲了如何启动bootanimation,这里假设bootanimation已经启动了。
bootanimation模块路径 frameworks/base/cmds/bootanimation
还是先看bootanimation的入口,还是main入口:
/* bootanimation_main.cpp */
int main()
{
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
bool noBootAnimation = bootAnimationDisabled();
ALOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object (may take up to 200ms for 2MB zip)
// 这里new BootAnimation
sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
waitForSurfaceFlinger(); // 等待surfaceflinger,毕竟bootanimation的绘制要依赖它
// BootAnimation 继承自 Thread 类,因此BootAnimation可以直接run
boot->run("BootAnimation", PRIORITY_DISPLAY);
ALOGV("Boot animation set up. Joining pool.");
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
概念补充:
Binder 机制:Android 跨进程通信的核心,ProcessState/IPCThreadState 是 Binder 框架的核心类,启动线程池是为了处理 SurfaceFlinger 等服务的 IPC 调用。IPC 是 Inter-Process Communication 的缩写,中文称为 “进程间通信”
sp 指针:Android 的强引用智能指针(Strong Pointer),用于管理对象的生命周期,避免内存泄漏。
这里当通过
new创建BootAnimation对象并赋值给sp<BootAnimation>智能指针时,onFirstRef()方法会被调用,onFirstRef()的作用是在对象第一次被强引用(sp)持有时执行初始化逻辑。
/* BootAnimation.cpp */
// BootAnimation 继承自 Thread 类,因此BootAnimation可以直接run
class BootAnimation : public Thread, public IBinder::DeathRecipient
// new的时候先执行构造函数,随后执行onFirstRef
BootAnimation::BootAnimation(sp<Callbacks> callbacks)
: Thread(false), mLooper(new Looper(false)), mClockEnabled(true), mTimeIsAccurate(false),
mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) {
...
}
// 执行完构造函数后,再执行onFirstRef
void BootAnimation::onFirstRef() {
ATRACE_CALL();
status_t err = mSession->linkToComposerDeath(this);
SLOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
// Load the animation content -- this can be slow (eg 200ms)
// called before waitForSurfaceFlinger() in main() to avoid wait
ALOGD("%sAnimationPreloadTiming start time: %" PRId64 "ms",
mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
preloadAnimation(); // 预加载开机动画资源
ALOGD("%sAnimationPreloadStopTiming start time: %" PRId64 "ms",
mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
}
}
bool BootAnimation::preloadAnimation() {
ATRACE_CALL();
findBootAnimationFile(); // 这里
if (!mZipFileName.empty()) {
mAnimation = loadAnimation(mZipFileName);
return (mAnimation != nullptr);
}
return false;
}
// 开机动画存放路径
static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
void BootAnimation::findBootAnimationFile() {
// 从 bootFiles 列表中搜索
static const std::vector<std::string> bootFiles = {
APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : OEM_BOOTANIMATION_FILE,
PRODUCT_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE
};
...
if (android::base::GetBoolProperty("sys.init.userspace_reboot.in_progress", false)) {
findBootAnimationFileInternal(userspaceRebootFiles);
} else if (mShuttingDown) {
findBootAnimationFileInternal(shutdownFiles);
} else {
findBootAnimationFileInternal(bootFiles); // 这里,查找开机动画资源
}
}
// 查找开机动画资源,存在就赋值给mZipFileName,返回true,否则返回false
bool BootAnimation::findBootAnimationFileInternal(const std::vector<std::string> &files) {
ATRACE_CALL();
for (const std::string& f : files) {
if (access(f.c_str(), R_OK) == 0) {
mZipFileName = f.c_str();
return true;
}
}
return false;
}
等到在bootanimation_main.cpp中执行boot->run("BootAnimation", PRIORITY_DISPLAY)时,会执行readyToRun()和threadLoop(),这两个是Thread 基类的函数,这里重写了。readyToRun() 先执行,threadLoop() 后执行。
readyToRun(): 线程进入循环之前,会先调用一次这个方法。
至于readyToRun和threadLoop的先后执行顺序,可以看system/core/libutils/Threads.cpp的定义:
/* system/core/libutils/Threads.cpp */
Thread::run --> Thread::_threadLoop ,在_threadLoop中是先执行了readyToRun(),后执行threadLoop()
/* BootAnimation.cpp */
// 作用是 准备显示资源、创建渲染环境、初始化 OpenGL/EGL 环境
status_t BootAnimation::readyToRun() {
...
}
bool BootAnimation::threadLoop() {
ATRACE_CALL();
bool result;
initShaders();
// We have no bootanimation file, so we use the stock android logo
// animation.
if (mZipFileName.empty()) { //如果路径不存在,即没有内置自己的动画,就用安卓自己的开机动画
ALOGD("No animation file");
result = android();
} else {
result = movie();
}
...
}
bool BootAnimation::android() {
......
do {
不停的绘制开机动画
.....
checkExit(); // 检查是否结束动画的绘制
} while (!exitPending());
glDeleteTextures(1, &mAndroid[0].name);
glDeleteTextures(1, &mAndroid[1].name);
return false;
}
static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
void BootAnimation::checkExit() {
ATRACE_CALL();
// Allow surface flinger to gracefully request shutdown
char value[PROPERTY_VALUE_MAX];
property_get(EXIT_PROP_NAME, value, "0"); // 使用 property_get() 从系统属性服务中获取值,存储到 value
int exitnow = atoi(value);
if (exitnow) { // 如果是1就退出
requestExit();
}
}
因此,开机动画是否退出的关键是属性service.bootanim.exit,是1就退出,0的话就继续。属性service.bootanim.exit在之前surfaceflinger启动的时候见过,当时给这个属性赋值为0了。
通过在framework中执行grep "service.bootanim.exit" ./ -rn可知,有SurfaceFlinger.cpp和WindowManagerService.java这两个地方将service.bootanim.exit设置为1了。