(1)前述
Android系统在启动的过程中,最多可以出现四个画面,每一个画面都用来描述一个不同的启动阶段。
- Linux uboot显示(静态)
- Linux 内核的启动画面(静态)
- init 进程的启动画面(静态)
- BootAnimation启动动画(动态)
无论是哪一个画面,它们都是在一个称为帧缓冲区(frame buffer,简称fb)的硬件设备上进行渲染的。接下来,我们就单独分析BootAnimation是如何开始显示的。
(2)BootAnimation启动阶段
(A)bootanimation启动概述
开机动画是由应用程序bootanimation来负责显示的,先看一下其rc文件。
//frameworks/base/cmds/bootanimation/bootanim.rc
service bootanim /system/bin/bootanimation
class core animation
user graphics
group graphics audio
disabled //系统启动时,不会自动启动bootanimation
oneshot //只启动一次
ioprio rt 0
task_profiles MaxPerformance
应用程序bootanimation的用户和用户组名称分别被设置为graphics。注意, 用来启动应用程序bootanimation的服务是disable的,即init进程在启动的时候,不会主动将应用程序bootanimation启动起来。
SurfaceFlinger 服务启动的过程中会修改系统属性"ctl.start"的值以通知init进程启动bootanim来显示开机动画。当系统关键服务启动完毕后会由AMS通知SurfaceFlinger修改系统属性"ctl.stop"来通知init进程停止执行bootanim关闭动画。
(B)SurfaceFlinger如何启动bootAnimation
首先来看一下surfaceflinger.rc文件
//frameworks/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger
class core animation
user system
group graphics drmrpc readproc
capabilities SYS_NICE
onrestart restart zygote
task_profiles HighPerformance
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
socket pdx/system/vr/display/manager stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
socket pdx/system/vr/display/vsync stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
SurfaceFlinger服务的入口在下面的main_surfaceflinger.cpp中,我们查看它的main函数。
//frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
int main(int, char**) {
// When SF is launched in its own process, limit the number of
// binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount(4);
// start the thread pool
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
// instantiate surfaceflinger
sp<SurfaceFlinger> flinger = new SurfaceFlinger();
// initialize before clients can connect
flinger->init(); //我们主要看这里
// run in this thread
flinger->run();
return 0;
}
主要工作就是新建一个SurfaceFlinger对象,然后调用其中的init函数,最后调用run函数。
//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
sp<StartPropertySetThread> mStartPropertySetThread;
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
Mutex::Autolock _l(mStateLock);
//...
if (mStartPropertySetThread->Start() != NO_ERROR) {
ALOGE("Run StartPropertySetThread failed!");
}
ALOGV("Done initializing");
}
//frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp
status_t StartPropertySetThread::Start() {
return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
}
bool StartPropertySetThread::threadLoop() {
// Set property service.sf.present_timestamp, consumer need check its readiness
property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
// Clear BootAnimation exit flag
property_set("service.bootanim.exit", "0");
// Start BootAnimation if not started
property_set("ctl.start", "bootanim");
// Exit immediately
return false;
}
这里将系统属性"service.bootanim.exit"设置为"0",并将"ctl.start"设置为"bootanim"。
当系统属性发生改变时,init进程就会接收到一个系统属性变化通知,这个通知最终是由在init进程中的函数handle_property_set_fd来处理的,具体中间流程是如何运行的,可以参考另外一篇文章Android系统设置属性详解。
(C)bootAnimation启动
从前面的内容可以知道,名称等于"bootanim"的服务所对应的应用程序为/system/bin/bootanimation,应用程序入口函数的实现在frameworks/base/cmds/bootanimation/Bootanimation_main.cpp中。
//frameworks/base/cmds/bootanimation/bootanimation_main.cpp
int main()
{
bool noBootAnimation = bootAnimationDisabled();
ALOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {
//启动一个Binder线程池
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object (may take up to 200ms for 2MB zip)
sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
waitForSurfaceFlinger();
boot->run("BootAnimation", PRIORITY_DISPLAY);
ALOGV("Boot animation set up. Joining pool.");
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
bool bootAnimationDisabled() {
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.nobootanimation", value, "0");
if (atoi(value) > 0) {
return true;
}
property_get("ro.boot.quiescent", value, "0");
return atoi(value) > 0;
}
首先检查系统属性“debug.sf.nobootnimaition”的值是否不等于0。如果不等于的话,那么接下来就会启动一个Binder线程池,并且创建一个BootAnimation对象。这个Binder线程用于同SurfaceFlinger服务通信。
接着我们看看BootAnimation类的声明:
//frameworks/base/cmds/bootanimation/BootAnimation.h
class BootAnimation : public Thread, public IBinder::DeathRecipient
{
public:
BootAnimation();
virtual ~BootAnimation();
.......
private:
virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
virtual void binderDied(const wp<IBinder>& who);
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
status_t initTexture(const Animation::Frame& frame);
bool android();
bool movie();
Animation* loadAnimation(const String8&);
bool playAnimation(const Animation&);
void releaseAnimation(Animation*) const;
bool parseAnimationDesc(Animation&);
bool preloadZip(Animation &animation);
void findBootAnimationFile();
bool findBootAnimationFileInternal(const std::vector<std::string>& files);
bool preloadAnimation();
void checkExit();
};
BootAnimation类继承了Thread类和IBinder::DeathRecipient类,其中几个重要的函数说明如下:
- onFirstRef()—— 属于其父类RefBase,该函数在强引用sp新增引用计数時调用,就是当有sp包装的类初始化的时候调用;
- binderDied() ——当对象死掉或者其他情况导致该Binder结束时,就会回调binderDied()方法;
- readyToRun() ——Thread执行前的初始化工作;
- threadLoop() ——每个线程类都要实现的,在这里定义thread的执行内容。这个函数如果返回true,且没有调用requestExit(),则该函数会再次执行;如果返回false,则threadloop中的内容仅仅执行一次,线程就会退出。
其他函数简述如下:
- android()——显示系统默认的开机画面;
- movie()——显示用户自定义的开机动画;
- loadAnimation(const String8&)——加载动画;
- playAnimation(const Animation&)——播放动画;
- checkExit()——检查是否退出动画;
BootAnimation类间接地继承了RefBase类,并且重写了RefBase类的成员函数onFirstRef,当一个BootAnimation对象第一次被智能指针引用时,这个BootAnimation对象的成员函数onFirstRef就会被调用。
mSession = new SurfaceComposerClient();
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
}
mSession是BootAnimation类的一个成员变量,它的类型为SurfaceComposerClient,是用来和SurfaceFlinger执行Binder进程间通信的,它是在BootAnimation类的构造函数中创建的。
由于BootAnimation类引用了SurfaceFlinger服务,当SurfaceFlinger服务意外死亡时,BootAnimation类就需要得到通知,这是通过调用成员变量mSession的成员函数linkToComposerDeath来注册SurfaceFlinger服务的死亡接收通知来实现的。
BootAnimation类继承了Thread类,当BootAnimation类的成员函数onFirstRef调用了父类Thread的成员函数run之后,系统就会创建一个线程,这个线程在第一次运行之前,会调用BootAnimation类的成员函数readyToRun来执行一些初始化工作,后面再调用BootAnimation类的成员函数threadLoop来显示开机画面。