Android系统在启动过程中,最多可以出现三个画面。第一个开机画面是在内核启动的过程中出现,是一个静态的画面;第二个画面是在init进程启动的过程中出现的,也是一个静态的画面;第三个画面是在系统服务启动的过程中出现 ,是一个动态的画面。这三个画面都是在一个被称为帧缓冲区(frame buffer,简称fb)的硬件设备上进行渲染的。本文主要分析第三个启动画面的流程。
在Android层动画的流程图:
先由init启动SurfaceFlinger进程,对图形系统进行初始化,再由SurfaceFlinger进程启动BootAnimation 进程显示动画。动画由一个 while 循环播放,在播放循环里调用 checkExit ()检查一个系统标志,判断是否应该结束动画。由此可见,动画的显示流程较为简单,但动画的结束流程相对复杂,其中经历了Launcher、ActivityManagerService、SurfaceFlinger……等层层调用传递消息,最终在SurfaceFlinger.bootFinished()设置动画的结束标志。下面来具体分析整个从显示到结束的流程。
首先从init进程开始,init进程是linux内核启动后启动的第一个进程,init 会解析init.rc 文件,启动其中声明的服务。关于动画部分,在init.rc文件中有这样的配置:
service surfaceflinger /system/bin/surfaceflinger
class main
user system
group graphics drmrpc
onrestart restart zygote
init进程会启动surfaceflinger服务,入口源文件为/frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp:
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/resource.h>
#include <cutils/sched_policy.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include "GpuService.h"
#include "SurfaceFlinger.h"
using namespace android;
int main(int, char**) {
signal(SIGPIPE, SIG_IGN);
// 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
//创建了一个SurfaceFlinger对象flinger
sp<SurfaceFlinger> flinger = new SurfaceFlinger();
setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
set_sched_policy(0, SP_FOREGROUND);
#ifdef ENABLE_CPUSETS
// Put most SurfaceFlinger threads in the system-background cpuset
// Keeps us from unnecessarily using big cores
// Do this after the binder thread pool init
set_cpuset_policy(0, SP_SYSTEM);
#endif
// initialize before clients can connect
//初始化
flinger->init();
// publish surface flinger
//加入ServiceManager中进行管理,最后启动服务
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
// publish GpuService
sp<GpuService> gpuservice = new GpuService();
sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
// run surface flinger in this thread
flinger->run();
return 0;
}
在上面的源文件中创建了一个SurfaceFlinger对象flinger,然后调用flinger->init()进行初始化,再将其加入ServiceManager中进行管理,最后启动服务。
我们来看一下frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp中的init()初始化函数:
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);
// 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();
// start boot animation
//调用startBootAnim()开始动画显示
startBootAnim();
ALOGV("Done initializing");
}
init()函数主要是对屏幕显示窗口进行初始化工作。在最后调用了startBootAnim(),我们来看一下SurfaceFlinger.cpp中的startBootAnim()函数:
void SurfaceFlinger::startBootAnim() {
// start boot animation
property_set("service.bootanim.exit", "0");
property_set("ctl.start", "bootanim");
}
其中先将”service.bootanim.exit”标志为 0,这个标志用于在bootanim进程中检测开机动画是否结束,然后通过发”ctl.start”请求给init进程,启动”bootanim”服务。
这里需要注意的是,开机动画进程在init.rc中注册过了,但是在解析init.rc文件时并没有直接启动,而是由SurfaceFlinger服务来启动。这是因为init.rc 虽然注册了bootanimation服务,但是被disabled了。所以在解析init.rc文件时,bootanimation并没有被直接启动。
service bootanim /system/bin/bootanimation
class main
user root
group graphics
disabled
oneshot
由SurfaceFlinger启动的原因是开机动画必须得有显示窗口,而这个显示窗口则是由SurfaceFlinger提供的,所以必须得在SurfaceFlinger初始化完成之后,才开始显示开机动画。
下面转到bootanimation,入口文件为 frameworks/base/cmds/bootanimation/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;
}
启动了一个线程池。BootAnimation对象在显示第三个开机画面的过程中,需要与SurfaceFlinger服务通信,因此bootanimation就需要启动一个Binder线程池。
这里的BootAnimation类(frameworks\base\cmds\bootanimation\BootAnimation.cpp)间接地继承了RefBase类,并且重写了RefBase类的成员函数onFirstRef():
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
run("BootAnimation", PRIORITY_DISPLAY);
}
}
因此,当一个BootAnimation对象boot第一次被智能指针引用的时,对象的成员函数onFirstRef()会被调用。
此外BootAnimation类继承了Thread类(\system\core\libutils\Threads.cpp):
BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true) {
mSession = new SurfaceComposerClient();
}
Thread 类有个run() 函数,在run()函数中会调用_threadLoop()函数,而_threadLoop函数又调用了readyToRun和threadLoop两个函数:
do {
bool result;
if (first) {
first = false;
self->mStatus = self->readyToRun();
result = (self->mStatus == NO_ERROR);
if (result && !self->exitPending()) {
// Binder threads (and maybe others) rely on threadLoop
// running at least once after a successful ::readyToRun()
// (unless, of course, the thread has already been asked to exit
// at that point).
// This is because threads are essentially used like this:
// (new ThreadSubclass())->run();
// The caller therefore does not retain a strong reference to
// the thread and the thread would simply disappear after the
// successful ::readyToRun() call instead of entering the
// threadLoop at least once.
result = self->threadLoop();
}
} else {
result = self->threadLoop();
}
BootAnimation类重写了readyToRun和threadLoop这两个函数:
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
sp dtoken(SurfaceComposerClient::getBuiltInDisplay(
ISurfaceComposer::eDisplayIdMain));
DisplayInfo dinfo;
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
if (status)
return -1;
// create the native surface
// 初始化opengl和绘图表面surface
sp control = session()->createSurface(String8("BootAnimation"),
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
SurfaceComposerClient::closeGlobalTransaction();
sp s = control->getSurface();
// initialize opengl and egl
const EGLint attribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 0,
EGL_NONE
};
EGLint w, h;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
surface = eglCreateWindowSurface(display, config, s.get(), NULL);
context = eglCreateContext(display, config, NULL, NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
return NO_INIT;
mDisplay = display;
mContext = context;
mSurface = surface;
mWidth = w;
mHeight = h;
mFlingerSurfaceControl = control;
mFlingerSurface = s;
// If the device has encryption turned on or is in process
// of being encrypted we show the encrypted boot animation.
char decrypt[PROPERTY_VALUE_MAX];
property_get("vold.decrypt", decrypt, "");
bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
// 判断是否有开机动画文件 bootanimation.zip 存在
if (encryptedAnimation && (access(getAnimationFileName(IMG_ENC), R_OK) == 0)) {
mZipFileName = getAnimationFileName(IMG_ENC);
}
else if (access(getAnimationFileName(IMG_OEM), R_OK) == 0) {
mZipFileName = getAnimationFileName(IMG_OEM);
}
else if (access(getAnimationFileName(IMG_SYS), R_OK) == 0) {
mZipFileName = getAnimationFileName(IMG_SYS);
}
return NO_ERROR;
}
bool BootAnimation::threadLoop()
{
bool r;
// We have no bootanimation file, so we use the stock android logo
// animation.
if (mZipFileName.isEmpty()) {
r = android();
} else {
r = movie();
}
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
mFlingerSurface.clear();
mFlingerSurfaceControl.clear();
eglTerminate(mDisplay);
IPCThreadState::self()->stopProcess();
return r;
}
readyToRun() 主要是对opengl工作环境进行初始化,判断用户自定义的开机动画文件是否存在,保存结果到mZipFileName 成员变量中。threadLoop 就开始真正的播放动画了,当mZipFileName是空时,则播放Android系统默认的开机动画,否则播放用户自定义的开机动画 。自定义的开机动画是由文件USER_BOOTANIMATION_FILE或者文件SYSTEM_BOOTANIMATION_FILE来描述的。只要其中的一个文件存在,那么开机画面就会使用用户自定义的开机动画。
android() 播放的是系统原生动画,“android”字样加上不断移动的光影效果。movie() 则是读取bootanimation.zip 中的帧动画,一张一张的轮播,形成动画效果。下面来分析下这Android系统动画函数android(),它还是存在于BootAnimation.cpp文件中:
//播放系统原生动画
bool BootAnimation::android()
{
initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
// clear screen
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mDisplay, mSurface);
glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
const GLint xc = (mWidth - mAndroid[0].w) / 2;
const GLint yc = (mHeight - mAndroid[0].h) / 2;
const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
updateRect.height());
// Blend state
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
const nsecs_t startTime = systemTime();
do {
nsecs_t now = systemTime();
double time = now - startTime;
float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
GLint x = xc - offset;
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);
glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
if (res == EGL_FALSE)
break;
// 12fps: don't animate too fast to preserve CPU
const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
if (sleepTime > 0)
usleep(sleepTime);
checkExit();
} while (!exitPending());
glDeleteTextures(1, &mAndroid[0].name);
glDeleteTextures(1, &mAndroid[1].name);
return false;
}
使用一个while循环去绘图,并在循环中调用 checkExit()判断是否应该结束动画。
checkExit()也存在于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();
if (mAudioPlayer != NULL) {
mAudioPlayer->requestExit();
}
}
}
检测到 “service.bootanim.exit” 的值被修改成非 0 之后,就调用 requestExit() 结束动画。
requestExit() 函数是父类 Thread 中定义的,在Threads.cpp文件中:
void Thread::requestExit()
{
Mutex::Autolock _l(mLock);
mExitPending = true;
}
bool Thread::exitPending() const
{
Mutex::Autolock _l(mLock);
return mExitPending;
}
设置了一个标志位 mExitPending = true,表明准备退出线程。while (!exitPending()) 循环条件就变为 false了,退出动画线程。movie() 的流程也是类似。
下面我们来看看”service.bootanim.exit”。经过分析可知在\frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp文件中将这个标志设置为了 “1”:
void SurfaceFlinger::bootFinished()
{
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mBootFinished = true;
// wait patiently for the window manager death
const String16 name("window");
sp window(defaultServiceManager()->getService(name));
if (window != 0) {
window->linkToDeath(static_cast(this));
}
// 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.
//将service.bootanim.exit的值设置为1
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)));
}
在frameworks\native\libs\gui\ISurfaceComposer.cpp中调用了bootFinished():
status_t BnSurfaceComposer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
……
case BOOT_FINISHED: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
return NO_ERROR;
}
……
}
}
现在来探究是谁发送了BOOT_FINISHED 消息给SurfaceFlinger 服务,查看代码发现,在\frameworks\native\include\gui\ISurfaceComposer.h中有定义BOOT_FINISHED:
class BnSurfaceComposer: public BnInterface {
……
public:
enum {
// Note: BOOT_FINISHED must remain this value, it is called from
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
……
}
……
}
发现在\services\core\java\com\android\server\wm\WindowManagerService.java中有发送 IBinder::FIRST_CALL_TRANSACTION 消息,并注释说是 BOOT_FINISHED :
public 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();
}
……
}
获取 SurfaceFlinger 服务,发送了 IBinder.FIRST_CALL_TRANSACTION 消息。
在WindowManagerService.java中的enableScreenAfterBoot()是开机流程中的服务:
public void enableScreenAfterBoot() {
synchronized(mWindowMap) {
if (DEBUG_BOOT) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.i(TAG_WM, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled
+ " mForceDisplayEnabled=" + mForceDisplayEnabled
+ " mShowingBootMessages=" + mShowingBootMessages
+ " mSystemBooted=" + mSystemBooted, here);
}
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();
}
在frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java又调用了 ActivityManagerService.enableScreenAfterBoot() :
final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
Configuration config) {
...
if (enableScreen) {
mService.enableScreenAfterBoot();
}
...
}
在WindowManagerService.java中调用了ActivityStackSupervisor.activityIdleInternalLocked():
@Override
public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
ActivityRecord r =
mStackSupervisor.activityIdleInternalLocked(token, false, config);
if (stopProfiling) {
if ((mProfileProc == r.app) && (mProfileFd != null)) {
try {
mProfileFd.close();
} catch (IOException e) {
}
clearProfilerLocked();
}
}
}
}
Binder.restoreCallingIdentity(origId);
}
而在ActivityThread 中又调用了ActivityManagerService.activityIdle():
private class Idler implements MessageQueue.IdleHandler {
@Override
public final boolean queueIdle() {
...
if (a.activity != null && !a.activity.mFinished) {
try {
am.activityIdle(a.token, a.createdConfig, stopProfiling);
a.createdConfig = null;
} catch (RemoteException ex) {
// Ignore
}
}
...
}
ActivityThread 类就是android应用程序的主线程。这个 Idler 类是在 handleResumeActivity 被注册到主线程 ActivityThread 中的:
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
boolean reallyResume) {
...
if (!r.onlyLocalRequest) {
r.nextIdle = mNewActivities;
mNewActivities = r;
if (localLOGV) Slog.v(
TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
}
r.onlyLocalRequest = false;
// Tell the activity manager we have resumed.
if (reallyResume) {
try {
ActivityManagerNative.getDefault().activityResumed(token);
} catch (RemoteException ex) {
}
}
...
}
也就是说一个Activity 在Resume的时候会注册一个空闲处理函数到主线程,主线程空闲的时候就会调用这个函数。
那么开机动画结束和Activity的启动有什么关系呢?我们可以理解为Android系统启动完成后,就会启动Launcher中的主Activity,一旦Launcher的Activity启动完成之后,如果没有用户操作,就会进入空闲状态,ActivityThread就会调用注册的IdleHandler。然后层层转发调用,最终调用SurfaceFlinger去终止开机动画。
上面的分析是从下往上分析的,下面再从顶向下理一遍:
我们可以在各个方法调用点加Log来进行调试。