1.SurfaceFlinger启动
高版本sf由bp文件启动
framework/native/services/surfaceflinger/Android.bp: init_rc: ["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
1.1 初始化sf对象
上边没啥用,知道走到frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp 的main方法就可以了。以下只关注两件事儿就可以了
- 创建SF对象
- 调用SF的init() 和run()
int main(int, char**) {
// When SF is launched in its own process, limit the number of
// binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount(4);
IPCThreadState::self()->disableBackgroundScheduling(true);
// start the thread pool
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
// instantiate surfaceflinger 创建sf对象
sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
set_sched_policy(0, SP_FOREGROUND);
// Put most SurfaceFlinger threads in the system-background cpuset
// Keeps us from unnecessarily using big cores
// Do this after the binder thread pool init
if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM); // 这块看起来是cpu绑核的逻辑,没找到实现
// initialize before clients can connect
flinger->init(); /这块
// publish surface flinger
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
startDisplayService(); // dependency on SF getting registered above
// run surface flinger in this thread
flinger->run();// 还有这块
return 0;
}
1.2 StartPropertySetThread 设置service.bootanim.exit 和启动property_set("ctl.start", "bootanim");
接下来进入sf的实现,一坨和我们不太相关的代码。主要关注 mStartPropertySetThread,并调用了start()即可
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::init() {
initializeDisplays();
getFactory().createStartPropertySetThread(presentFenceReliable);
if (mStartPropertySetThread->Start() != NO_ERROR) {
ALOGE("Run StartPropertySetThread failed!");
}
}
接下来是StartPropertySetThread中的threadLoop方法,设置了我们要找的 property_set("service.bootanim.exit", "0") 以及通过ctl.start 启动bootanim
// frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp
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;
}
2.BootAnimation启动
framework/base/cmds/bootanimation/Android.bp: init_rc: ["bootanim.rc"],
// frameworks/base/cmds/bootanimation/bootanim.rc
service bootanim /system/bin/bootanimation
class core animation
user graphics // 用户组 graphics
group graphics audio
disabled //系统启动时,不会自动启动bootanimation
oneshot // 一次
ioprio rt 0
task_profiles MaxPerformance
用来启动应用程序bootanimation的服务是disable的,即init进程在启动的时候,不会主动将应用程序bootanimation启动起来。
2.1 bootanimation_main.cpp main()方法
我们首先关注main()方法
bootAnimationDisabled()用来检查系统属性“debug.sf.nobootnimaition”的值是否不等于0。
如果不等于0,就会启动一个Binder线程池,并且创建一个BootAnimation对象。这个Binder线程用于同SurfaceFlinger服务通信。
//frameworks/base/cmds/bootanimation/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)
#ifdef BOOTANIMATION_EXT
sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks(),true);
#else
sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
#endif
waitForSurfaceFlinger(); 这块在等sf服务起来 一般应该用不到
boot->run("BootAnimation", PRIORITY_DISPLAY);
ALOGV("Boot animation set up. Joining pool.");
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
2.2 BootAnimation.h 定义
接着看下BootAnimation的声明,具体定义可以看下注释,threadloop可以和前边联动
// frameworks/base/cmds/bootanimation/BootAnimation.h
class BootAnimation : public Thread, public IBinder::DeathRecipient
{
public:
BootAnimation();
virtual ~BootAnimation();
.......
private:
virtual bool threadLoop(); // 每个线程类都要实现的,在这里定义thread的执行内容。这个函数如果返回true,且没有调用requestExit(),则该函数会再次执行;如果返回false,则threadloop中的内容仅仅执行一次,线程就会退出。
virtual status_t readyToRun(); //Thread执行前的初始化工作
virtual void onFirstRef(); //该函数在强引用sp新增引用计数時调用,就是当有sp包装的类初始化的时候调用
virtual void binderDied(const wp<IBinder>& who); //当对象死掉或者其他情况导致该Binder结束时,就会回调binderDied()方法;
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();
};
onFirstRef这个留意
BootAnimation类间接地继承RefBase类,并重写了RefBase类的onFirstRef,当一个BootAnimation对象第一次被智能指针引用时,这个BootAnimation对象的成员函数onFirstRef就会被调用。
// frameworks/base/cmds/bootanimation/BootAnimation.cpp
mSession = new SurfaceComposerClient();
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
//通过调用linkToComposerDeath来注册SurfaceFlinger服务的死亡接收通知,这样当SurfaceFlinger服务意外死亡时,BootAnimation类就可以得到通知
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
}
mSession的类型为SurfaceComposerClient,是用来和SurfaceFlinger执行Binder进程间通信的,它是在BootAnimation类的构造函数中创建的。
BootAnimation类继承了Thread类,当BootAnimation类的成员函数onFirstRef调用了父类Thread的成员函数run之后,系统就会创建一个线程,这个线程在第一次运行之前,会调用BootAnimation类的成员函数readyToRun来执行一些初始化工作,后面再调用BootAnimation类的成员函数threadLoop来显示开机画面
2.3 BootAnimation.cpp threadloop() 播放动画
接下来看下threadloop(),主要判断了zip文件是否存在。不存在就用logo,存在就用bootanimation.zip threadLoop()函数如果返回值为false,则该函数中的内容只会执行一次;如果返回true,则会不停的执行。这里返回false,因此只会执行一次。
//frameworks/base/cmds/bootanimation/BootAnimation.cpp
bool BootAnimation::threadLoop() {
bool result;
// We have no bootanimation file, so we use the stock android logo
// animation.
if (mZipFileName.isEmpty()) {
result = android(); // 原生logo
} else {
result = movie(); //开机动画
}
return result;
}
主要看下movie()
bool BootAnimation::movie() {
if (mAnimation == nullptr) {
mAnimation = loadAnimation(mZipFileName);
}
playAnimation(*mAnimation);
releaseAnimation(mAnimation);
mAnimation = nullptr;
return false;
}
playAnimation(*mAnimation),这里主要关注checkExit() 在android()默认logo的时候也会有check
bool BootAnimation::playAnimation(const Animation& animation) {
if (!mShuttingDown) {
checkExit();
}
return true;
}
首先调用property_get获取属性EXIT_PROP_NAME的值,如果为1,则调用requestExit()要求退出当前线程,该函数是异步的
static const char EXIT_PROP_NAME[] = "service.bootanim.exit"
void BootAnimation::checkExit() {
// Allow surface flinger to gracefully request shutdown
char value[PROPERTY_VALUE_MAX];
property_get(EXIT_PROP_NAME, value, "0");
int exitnow = atoi(value);
if (exitnow) {
ALOGD("%sAnimationShownTiming exit animation time: %" PRId64 "ms",
mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
requestExit();
mCallbacks->shutdown();
}
}
动画执行时通过调用exitPending()检测,该函数判断requestExit()是否被调用过,如果调用过则返回true,否则为false。
当属性"service.bootanim.exit"值被设为"1"时,android()就会调用requestExit(),exitPending()返回值为true。于是循环就会退出,开机动画就会结束。
//system/core/libutils/Thread.cpp
void Thread::requestExit()
{
Mutex::Autolock _l(mLock);
//这里将mExitPending 赋值为true
mExitPending = true;
}
bool Thread::exitPending() const
{
Mutex::Autolock _l(mLock);
return mExitPending;
}
3.停止动画 WMS#performEnableScreen
最终service.bootanim.exit = 1是在WMS中设置的。 大概有以下几种情况调用performEnableScreen
1.正常启动
- ActivityStackSupervisor 的activityIdleInternal()开始
- checkFinishBootingLocked()
- ActivityTaskManagerService#postFinishBooting()
- WMS#enableScreenAfterBoot
2.PKMS启动 “正在优化xxx”这个弹窗的时候
3.factorytest以及AMS中uihandler一些error的情况
4.PhoneWindowManager windowdrawn 和windowstate变化的一些情况。
以上会有一些判断是否走到方法中,具体没有通过trace确认。后边甩张图/
private void performEnableScreen() {
synchronized (mGlobalLock) {
if (!mBootAnimationStopped) {
SystemProperties.set("service.bootanim.exit", "1");
mBootAnimationStopped = true;
}
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
data, null, 0);
data.recycle();
}
} catch (RemoteException ex) {
ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");
}
}
通过binder到native层
//frameworks/native/include/gui/ISurfaceComposer.h
class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {
public:
enum {
// Note: BOOT_FINISHED must remain this value, it is called from
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
...
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0);
};
//frameworks/native/libs/gui/ISurfaceComposer.cpp
case BOOT_FINISHED: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
return NO_ERROR;
最终来到sf中,停止再次设置,这里没想清楚二次set的作用
//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::bootFinished() {
property_set("service.bootanim.exit", "1");
}
4.总结
开机动画主要是以下三部分
1.surfaceflinger启动,在init方法中,调用StartPropertySetThread#theadloop(),设置两个prop。 property_set("service.bootanim.exit", "0")设置标志位property_set("ctl.start", "bootanim")启动bootanim进程
2.bootanima启动,也是在BootAnimation.cpp threadloop()中,播放动画,并在checkExit()检查对应的prop是否为1。如果是1则退出
3.开机启动当activityIdleInternal()的时候调用到WMS performEnableScreen()设置service.bootanim.exit为1。以及通过binder通知sf在设置一遍。
最后如果有人看到的话,还是希望各位多看书,少写文章。我这是最近研究开机时间,碰上了为了以后面试吹牛比。
掘金这个每次发布之前选标签的设计真沙比。