3.1 BootAnimation 结构
源码路径:frameworks/base/cmds/bootanimation
├── Android.mk
├── audioplay.cpp
├── audioplay.h
├── BootAnimation.cpp
├── BootAnimation.h
├── bootanimation_main.cpp
├── bootanim.rc
└── FORMAT.md
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
bootanimation_main.cpp \ #入口在这里
audioplay.cpp \
BootAnimation.cpp #主要方法
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
LOCAL_C_INCLUDES += \
external/tinyalsa/include \
frameworks/wilhelm/include
LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
libandroidfw \
libutils \
libbinder \
libui \
libskia \
libEGL \
libGLESv1_CM \
libgui \
libOpenSLES \
libtinyalsa
LOCAL_MODULE:= bootanimation
LOCAL_INIT_RC := bootanim.rc
ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif
include $(BUILD_EXECUTABLE) #编译为可执行程序
运行入口在bootanimation_main.cpp
int main()
{
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.nobootanimation", value, "0");
int noBootAnimation = atoi(value);
ALOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {
sp proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object
sp boot = new BootAnimation();
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
sp
ProcessState::self()->startThreadPool(); 启动binder主线程,可以与binder Service通讯。还可以有其他binder线程,这些线程并不是由动画进程启动,是由binder驱动间接创建启动。
IPCThreadState::self()->joinThreadPool(); 使线程进入循环,等待消息,处理数据,完成与binder驱动数据处理。相当于Bp(代理)作用。
3.2 BootAnimation 的启动
BootAnimation 并未在init.rc中配置为开机自启动,那么它到底是如何启动?
3.2.1 再回到SurfaceFlinger初始化过程来看,
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
{ // Autolock scope
Mutex::Autolock _l(mStateLock);
// initialize EGL for the default display
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(mEGLDisplay, NULL, NULL);
// start the EventThread
sp vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
vsyncPhaseOffsetNs, true, "app");
mEventThread = new EventThread(vsyncSrc, *this);
sp sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
sfVsyncPhaseOffsetNs, true, "sf");
mSFEventThread = new EventThread(sfVsyncSrc, *this);
mEventQueue.setEventThread(mSFEventThread);
// set SFEventThread to SCHED_FIFO to minimize jitter
struct sched_param param = {0};
param.sched_priority = 2;
if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
}
// Get a RenderEngine for the given display / config (can't fail)
mRenderEngine = RenderEngine::create(mEGLDisplay,
HAL_PIXEL_FORMAT_RGBA_8888);
}
// Drop the state lock while we initialize the hardware composer. We drop
// the lock because on creation, it will call back into SurfaceFlinger to
// initialize the primary display.
mHwc = new HWComposer(this);
mHwc->setEventHandler(static_cast(this));
Mutex::Autolock _l(mStateLock);
// retrieve the EGL context that was selected/created
mEGLContext = mRenderEngine->getEGLContext();
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
// make the GLContext current so that we can create textures when creating
// Layers (which may happens before we render something)
getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
// initialize our drawing state
mDrawingState = mCurrentState;
// set initial conditions (e.g. unblank default device)
initializeDisplays();
mRenderEngine->primeCache();
// start boot animation
startBootAnim();//这里启动动画进程
ALOGV("Done initializing");
}
可以看到SurfaceFlinger::init()启动动画进程,在之前还有很多初始化工作。
可以判断出这些初始化工作与动画显示关系很大。
// initialize EGL for the default display
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(mEGLDisplay, NULL, NULL);
EGL可以理解为Open GL与本地窗口的中间件,为Open GL传递上下文、绘图目标、Buffer等配置属性等。这样Open GL可以做到平台无关化。
mEGLDisplay 即 EGLDisplay实例,表示系统显示ID。
EGL_DEFAULT_DISPLAY表示获取默认显示。
eglInitialize(),后两个参数表示传递版本号,这里忽略版本号。
// start the EventThread
sp
vsyncPhaseOffsetNs, true, "app");
mEventThread = new EventThread(vsyncSrc, *this);
sp
sfVsyncPhaseOffsetNs, true, "sf");
mSFEventThread = new EventThread(sfVsyncSrc, *this);
mEventQueue.setEventThread(mSFEventThread);
vsyncSrc 用于应用监控Vsync信号,sfVsyncSrc内部监控Vsync信号。
Vsync保证CPU
和GPU
运行的时间在一个周期内,目的是消除Jank
。
如何做到监听Vsync信号
DispSyncSource
class DispSyncSource : public VSyncSource, private DispSync::Callback {
public:
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
const char* name) :
mName(name),
mValue(0),
mTraceVsync(traceVsync),
mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
mVsyncEventLabel(String8::format("VSYNC-%s", name)),
mDispSync(dispSync),
mCallbackMutex(),
mCallback(),
mVsyncMutex(),
mPhaseOffset(phaseOffset),
mEnabled(false) {}
virtual ~DispSyncSource() {}
virtual void setVSyncEnabled(bool enable) {//使能接口,可以关闭Vsync
Mutex::Autolock lock(mVsyncMutex);
if (enable) {
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast(this));
if (err != NO_ERROR) {
ALOGE("error registering vsync callback: %s (%d)",
strerror(-err), err);
}
//ATRACE_INT(mVsyncOnLabel.string(), 1);
} else {
status_t err = mDispSync->removeEventListener(
static_cast(this));
if (err != NO_ERROR) {
ALOGE("error unregistering vsync callback: %s (%d)",
strerror(-err), err);
}
//ATRACE_INT(mVsyncOnLabel.string(), 0);
}
mEnabled = enable;
}
//....
private:
virtual void onDispSyncEvent(nsecs_t when) {//检测到vsync信号到来
sp callback;
{
Mutex::Autolock lock(mCallbackMutex);
callback = mCallback;
if (mTraceVsync) {
mValue = (mValue + 1) % 2;
ATRACE_INT(mVsyncEventLabel.string(), mValue);
}
}
if (callback != NULL) {
callback->onVSyncEvent(when);//具体怎么做,在callback里定义
}
}
//...
};
总体的作用是利用Vsync信号即时间定时,Vsync可以由硬件产生也可以由软件模拟。在规定时间到后,刷新界面。
mRenderEngine = RenderEngine::create(mEGLDisplay,HAL_PIXEL_FORMAT_RGBA_8888);//建立渲染引擎
3.2.2 下面介绍 SurfaceFlinger init() 最后一部分代码
// Drop the state lock while we initialize the hardware composer. We drop
// the lock because on creation, it will call back into SurfaceFlinger to
// initialize the primary display.
mHwc = new HWComposer(this);//硬件图层合成器对象
mHwc->setEventHandler(static_cast(this));
Mutex::Autolock _l(mStateLock);
// retrieve the EGL context that was selected/created
mEGLContext = mRenderEngine->getEGLContext();
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
// make the GLContext current so that we can create textures when creating
// Layers (which may happens before we render something)
getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
// initialize our drawing state
mDrawingState = mCurrentState;
// set initial conditions (e.g. unblank default device)
initializeDisplays();
mRenderEngine->primeCache();
// start boot animation
startBootAnim();
ALOGV("Done initializing");
HWComposer 有两个作用
1.由硬件图层合成器提供Vsync信号
2.针对所有的surface(各个需要显示的界面)会有对应的Layer,HWC将对可以合成的(overlay)图层将交给HWC HAL层处理。根据SOC的差异,HWC HAL会使用GPU 2D core 或者GPU 3D core。最终数据写入Display Framebuffer,完成显示。HWC不能处理的图层,将使用EGL处理即直接交给GPU处理。
总体流程是根据硬件特性,图层合成由硬件图层合成器或者GPU处理。
回到代码:
mHwc = new HWComposer(this);//硬件图层合成器对象
mHwc->setEventHandler(static_cast
// retrieve the EGL context that was selected/created
mEGLContext = mRenderEngine->getEGLContext();//GEL 上下文
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
// make the GLContext current so that we can create textures when creating
// Layers (which may happens before we render something)
getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);//绑定上下文和Surface
//此线程用于控制Vsync使能开关,入口在EventControlThread::setVsyncEnabled(bool enabled)
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
可以看下线程的具体实现:frameworks/native/services/surfaceflinger$ vim EventControlThread.cpp
bool EventControlThread::threadLoop() {
Mutex::Autolock lock(mMutex);
bool vsyncEnabled = mVsyncEnabled;
#ifdef USE_HWC2
mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled);
#else
mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC,
mVsyncEnabled);
#endif
while (true) {
status_t err = mCond.wait(mMutex);
if (err != NO_ERROR) {
ALOGE("error waiting for new events: %s (%d)",
strerror(-err), err);
return false;
}
if (vsyncEnabled != mVsyncEnabled) {
#ifdef USE_HWC2
mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled);
#else
mFlinger->eventControl(HWC_DISPLAY_PRIMARY,
SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled);
#endif
vsyncEnabled = mVsyncEnabled;
}
}
return false;
}
// initialize our drawing state
mDrawingState = mCurrentState;
// set initial conditions (e.g. unblank default device)
initializeDisplays();
void SurfaceFlinger::initializeDisplays() {
class MessageScreenInitialized : public MessageBase {
SurfaceFlinger* flinger;
public:
MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
virtual bool handler() {
flinger->onInitializeDisplays();
return true;
}
};
sp msg = new MessageScreenInitialized(this);
postMessageAsync(msg); // we may be called from main thread, use async message
}
经过消息处理,最终还是会回到SurfaceFlinger::onInitializeDisplays
void SurfaceFlinger::onInitializeDisplays() {
// reset screen orientation and use primary layer stack
Vector state;
Vector displays;
DisplayState d;
d.what = DisplayState::eDisplayProjectionChanged |
DisplayState::eLayerStackChanged;
d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
d.layerStack = 0;
d.orientation = DisplayState::eOrientationDefault;
d.frame.makeInvalid();
d.viewport.makeInvalid();
d.width = 0;
d.height = 0;
displays.add(d);
setTransactionState(state, displays, 0);
setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
}
Display还原,重置屏幕方向并使用主层堆栈。
mRenderEngine->primeCache();//着色器缓存进行初始化
// start boot animation
startBootAnim();//开始启动动画
至此SurfaceFlinger已完成动画包括界面显示的初始化工作,总体上是使能Vsync、初始化HWC HAL、初始化EGL。
SurfaceFlinger属于服务端,动画是客户端,客户端必然会与服务端通讯才能完成画面的显示。