开机动画位置:device\xxx\common\logo\bootanimation\bootanimation.zip
desc.txt用于描述动画如何显示
文件格式如下:
WIDTH HEIGHT FPS
//WIDTH 图片宽度(px)
//HEIGHT 图片高度(px)
//FPS:每秒帧数
TYPE COUNT PAUSE PATH
//TYPE:动画类型,p:如果系统启动完毕,会中断播放。默认;c:一直播放完毕,无论系统有没启动完毕
//COUNT:播放次数,0-无限循环
//PAUSE:本组播放完毕后,停留的帧数。
第一行的三个数字分别表示开机动画在屏幕中的显示宽度、高度以及帧速(fps)。
剩余的每一行都用来描述一个动画片断,这些行必须要以指定字符开头,后面紧跟着两个数字以及一个文件目录路径名称。第一个数字表示一个片断的循环显示次数,如果它的值等于0,那么就表示无限循环地显示该动画片断。第二个数字表示每一个片断在两次循环显示之间的时间间隔。这个时间间隔是以一个帧的时间为单位的。文件目录下面保存的是一系列png文件,这些png文件会被依次显示在屏幕中
动画的Start和stop控制:
动画的开始与结束是由属性控制的,由/system/bin/surfaceflinger来控制,然后相关的动画处理程序为/system/bin/bootanimation,在init.rc中指定。
bootanimation 需要 由property_set(“ctl.start”, “bootanim”);来启动进程,
由property_set(“ctl.stop”, “bootanim”);来关掉进程。
”service.bootanim.exit”:这个属性在bootanimation进程里会周期检查,=1时就退出动画,=0表示要播放动画。
主要过程:SurfaceFlinger 服务启动的过程中会修改系统属性"ctl.start"的值,以通知init进程启动bootanim来显示开机动画。当系统关键服务启动完毕后,由AMS通知SurfaceFlinger修改系统属性"ctl.stop"来通知init进程停止执行bootanim关闭动画。
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
surfaceflinger
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的启动时机
在高版本的Android上,如AndroidP,surfaceflinger进程并不是直接在init.rc文件中启动的,而是通过Android.bp文件去包含启动surfaceflinger.rc文件,然后在该文件中再去启动surfaceflinger:
frameworks\native\services\surfaceflinger\Android.bp
cc_binary {
name: "surfaceflinger",
defaults: ["libsurfaceflinger_binary"],
init_rc: ["surfaceflinger.rc"],
srcs: [
":surfaceflinger_binary_sources",
// Note: SurfaceFlingerFactory is not in the filegroup so that it
// can be easily replaced.
"SurfaceFlingerFactory.cpp",
],
shared_libs: [
"libSurfaceFlingerProp",
],
logtags: ["EventLog/EventLogTags.logtags"],
}
surfaceflinger启动了,就会跑到它的main函数:
SurfaceFlinger服务的入口在main_surfaceflinger.cpp中
frameworks\native\services\surfaceflinger\main_surfaceflinger.cpp
int main(int, char**) {
signal(SIGPIPE, SIG_IGN);
hardware::configureRpcThreadpool(1 /* maxThreads */,
false /* callerWillJoin */);
startGraphicsAllocatorService();
// 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 = 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);
// 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
if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
ALOGW("Couldn't set to SCHED_FIFO: %s", strerror(errno));
}
// run surface flinger in this thread
flinger->run();
return 0;
}
frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp
init方法中 start mStartPropertySetThread
const bool presentFenceReliable =
!getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE);
mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable);
if (mStartPropertySetThread->Start() != NO_ERROR) {
ALOGE("Run StartPropertySetThread failed!");
}
ALOGV("Done initializing");
frameworks\native\services\surfaceflinger\SurfaceFlingerDefaultFactory.cpp
sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
bool timestampPropertyValue) {
return new StartPropertySetThread(timestampPropertyValue);
}
frameworks\native\services\surfaceflinger\StartPropertySetThread.cpp
#include <cutils/properties.h>
#include "StartPropertySetThread.h"
namespace android {
StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue):
Thread(false), mTimestampPropertyValue(timestampPropertyValue) {}
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】并采用【ctl.start】的方式启动开机动画:
在这之后,开机动画就会启动,由bootanimation进程实现具体动画播放
bootAnimation的启动
名称等于"bootanim"的服务所对应的应用程序为/system/bin/bootanimation,应用程序入口函数的实现在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)
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;
}
首先检查系统属性“debug.sf.nobootnimaition”的值是否等于0。如果不等于的话,那么接下来就会启动一个Binder线程池,并且创建一个BootAnimation对象。这个Binder线程用于同SurfaceFlinger服务通信。
frameworks\base\cmds\bootanimation\BootAnimation.cpp
BootAnimation类间接地继承了RefBase类,并且重写了RefBase类的成员函数onFirstRef,因此,当一个BootAnimation对象第一次被智能指针引用的时,这个BootAnimation对象的成员函数onFirstRef就会被调用。其中几个重要的函数说明如下:
onFirstRef()—— 属于其父类RefBase,该函数在强引用sp新增引用计数時调用,就是当有sp包装的类初始化的时候调用;
binderDied() ——当对象死掉或者其他情况导致该Binder结束时,就会回调binderDied()方法;
readyToRun() ——Thread执行前的初始化工作;
threadLoop() ——每个线程类都要实现的,在这里定义thread的执行内容。这个函数如果返回true,且没有调用requestExit(),则该函数会再次执行;如果返回false,则threadloop中的内容仅仅执行一次,线程就会退出。
其他函数简述如下:android()——显示系统默认的开机画面;
movie()——显示用户自定义的开机动画;
loadAnimation(const String8&)——加载动画;
playAnimation(const Animation&)——播放动画;
checkExit()——检查是否退出动画;
void BootAnimation::onFirstRef() {
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());
}
}
mSession是BootAnimation类的一个成员变量,它的类型为SurfaceComposerClient,是用来和SurfaceFlinger执行Binder进程间通信的,它是在BootAnimation类的构造函数中创建的
mSession = new SurfaceComposerClient();
由于BootAnimation类引用了SurfaceFlinger服务,因此,当SurfaceFlinger服务意外死亡时,BootAnimation类就需要得到通知,这是通过调用成员变量mSession的成员函数linkToComposerDeath来注册SurfaceFlinger服务的死亡接收通知来实现的。
BootAnimation类继承了Thread类,因此,当bootanimation_main.cpp调用了Thread的成员函数run之后,系统就会创建一个线程,这个线程在第一次运行之前,会调用BootAnimation类的成员函数readyToRun来执行一些初始化工作,后面再调用BootAnimation类的成员函数threadLoop来显示第三个开机画面。
bool BootAnimation::threadLoop() {
bool result;
// We have no bootanimation file, so we use the stock android logo
// animation.
if (mZipFileName.isEmpty()) {
result = android();
} else {
result = movie();
}
mCallbacks->shutdown();
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
mFlingerSurface.clear();
mFlingerSurfaceControl.clear();
eglTerminate(mDisplay);
eglReleaseThread();
IPCThreadState::self()->stopProcess();
return result;
}
如果mZipFileName不为空,那么接下来就会调用BootAnimation类的成员函数android来显示系统默认的开机动画,否则的话,就会调用BootAnimation类的成员函数movie来显示用户自定义的开机动画
bool BootAnimation::findBootAnimationFileInternal(const std::vector<std::string> &files) {
for (const std::string& f : files) {
if (access(f.c_str(), R_OK) == 0) {
mZipFileName = f.c_str();
return true;
}
}
return false;
}
bootanim的关闭
init启动zygote进程之后,由zygote孵化出了system_server,然后system_server启动了各种各种的系统所需的服务,其中就有AMS,AMS启动并ready后,会执行startHomeActivityLocked:
void SurfaceFlinger::bootFinished()
{
if (mBootFinished == true) {
ALOGE("Extra call to bootFinished");
return;
}
mBootFinished = true;
if (mStartPropertySetThread->join() != NO_ERROR) {
ALOGE("Join StartPropertySetThread failed!");
}
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mFrameTracer->initialize();
mTimeStats->onBootFinished();
// wait patiently for the window manager death
const String16 name("window");
mWindowManager = defaultServiceManager()->getService(name);
if (mWindowManager != 0) {
mWindowManager->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
if (mVrFlinger) {
mVrFlinger->OnBootFinished();
}
// stop boot animation
// formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation.
property_set("service.bootanim.exit", "1");
const int LOGTAG_SF_STOP_BOOTANIM = 60110;
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
sp<IBinder> input(defaultServiceManager()->getService(String16("inputflinger")));
static_cast<void>(schedule([=] {
if (input == nullptr) {
ALOGE("Failed to link to input service");
} else {
mInputFlinger = interface_cast<IInputFlinger>(input);
}
readPersistentProperties();
mPowerAdvisor.onBootFinished();
mBootStage = BootStage::FINISHED;
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
enableRefreshRateOverlay(true);
}
}));
}
AMS在systemReady后会启动launcher
if (bootingSystemUser) {
t.traceBegin("startHomeOnAllDisplays");
mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
t.traceEnd();
}
frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerInternal.java
public abstract boolean startHomeOnAllDisplays(int userId, String reason);
frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java
final class LocalService extends ActivityTaskManagerInternal {
@Override
public boolean startHomeOnAllDisplays(int userId, String reason) {
synchronized (mGlobalLock) {
return mRootWindowContainer.startHomeOnAllDisplays(userId, reason);
}
}
frameworks\base\services\core\java\com\android\server\wm\RootWindowContainer.java
boolean startHomeOnAllDisplays(int userId, String reason) {
boolean homeStarted = false;
for (int i = getChildCount() - 1; i >= 0; i--) {
final int displayId = getChildAt(i).mDisplayId;
homeStarted |= startHomeOnDisplay(userId, reason, displayId);
}
return homeStarted;
}
void startHomeOnEmptyDisplays(String reason) {
for (int i = getChildCount() - 1; i >= 0; i--) {
final DisplayContent display = getChildAt(i);
for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
if (taskDisplayArea.topRunningActivity() == null) {
startHomeOnTaskDisplayArea(mCurrentUser, reason, taskDisplayArea,
false /* allowInstrumenting */, false /* fromHomeKey */);
}
}
}
}
boolean startHomeOnDisplay(int userId, String reason, int displayId) {
return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */,
false /* fromHomeKey */);
}
boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,
boolean fromHomeKey) {
// Fallback to top focused display or default display if the displayId is invalid.
if (displayId == INVALID_DISPLAY) {
final ActivityStack stack = getTopDisplayFocusedStack();
displayId = stack != null ? stack.getDisplayId() : DEFAULT_DISPLAY;
}
final DisplayContent display = getDisplayContent(displayId);
boolean result = false;
for (int tcNdx = display.getTaskDisplayAreaCount() - 1; tcNdx >= 0; --tcNdx) {
final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tcNdx);
result |= startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
allowInstrumenting, fromHomeKey);
}
return result;
}
frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java
void postFinishBooting(boolean finishBooting, boolean enableScreen) {
mH.post(() -> {
if (finishBooting) {
mAmInternal.finishBooting();
}
if (enableScreen) {
mInternal.enableScreenAfterBoot(isBooted());
}
});
}
@Override
public void enableScreenAfterBoot(boolean booted) {
synchronized (mGlobalLock) {
writeBootProgressEnableScreen(SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
updateEventDispatchingLocked(booted);
}
}
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
public void enableScreenAfterBoot() {
synchronized (mGlobalLock) {
ProtoLog.i(WM_DEBUG_BOOT, "enableScreenAfterBoot: mDisplayEnabled=%b "
+ "mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. "
+ "%s",
mDisplayEnabled, mForceDisplayEnabled, mShowingBootMessages, mSystemBooted,
new RuntimeException("here").fillInStackTrace());
if (mSystemBooted) {
return;
}
mSystemBooted = true;
hideBootMessagesLocked();
// If the screen still doesn't come up after 30 seconds, give
// up and turn it on.
mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000);
}
mPolicy.systemBooted();
performEnableScreen();
}
enableScreenAfterBoot()经过多次调用就会执行WMS的performEnableScreen()方法,在此方法中我们就可以看到surfaceflinger的身影了,通过transact调用发送BOOT_FINISHED的消息给surfaceflinger。
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
private void performEnableScreen() {
...
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
Slog.i(TAG_WM, "******* 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) {
Slog.e(TAG_WM, "Boot completed: SurfaceFlinger is dead!");
}
...
}
frameworks\native\libs\gui\include\gui\ISurfaceComposer.h
class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {
public:
enum ISurfaceComposerTag {
// Note: BOOT_FINISHED must remain this value, it is called from
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
WMS最终通过binder调用,经过ISurfaceComposer处理,最终通知SurfaceFlinger关闭开机动画。
frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp
void SurfaceFlinger::bootFinished()
{
if (mStartPropertySetThread->join() != NO_ERROR) {
ALOGE("Join StartPropertySetThread failed!");
}
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
// wait patiently for the window manager death
const String16 name("window");
sp<IBinder> window(defaultServiceManager()->getService(name));
if (window != 0) {
window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
if (mVrFlinger) {
mVrFlinger->OnBootFinished();
}
// stop boot animation
// formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation.
property_set("service.bootanim.exit", "1");
const int LOGTAG_SF_STOP_BOOTANIM = 60110;
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
sp<LambdaMessage> readProperties = new LambdaMessage([&]() {
readPersistentProperties();
});
postMessageAsync(readProperties);
}
至此开机动画结束。
frameworks\base\cmds\bootanimation\BootAnimation.cpp
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) {
requestExit();
}
}
requestExit(); kill掉bootanime进程
system\core\libutils\Threads.cpp
void Thread::requestExit()
{
Mutex::Autolock _l(mLock);
mExitPending = true;
}
至此bootanime进程死亡。