开机动画位置: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进程死亡。