原生开机动画流程
1.开机动画启动流程图
2.init进程启动surfaceflinger进程:
frameworks/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger
class core
...
frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
new一个SurfaceFlinger实例,然后init,然后run
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
.....
mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable);
创建StartPropertySetThread对象,启动 mStartPropertySetThread线程
if (mStartPropertySetThread->Start() != NO_ERROR) {
ALOGE("Run StartPropertySetThread failed!");
}
}
frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp
在 StartPropertySetThread线程的threadLoop()方法中会拉起开机动画进程
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");//修改开机动画退出标记,bootanimation线程会周期检查这个属性,值为1时退出
// Start BootAnimation if not started
property_set("ctl.start", "bootanim");//通过ctl.start启动bootanim进程
// Exit immediately
return false;
}
通过property_set("ctl.start", "bootanim");是如何启动bootanim进程呢?
系统属性分为两种类型,一种是普通类型的系统属性,另一种是控制类型的系统属性(属性名称以“ctl.”开头)。控制类型的系统属性在发生变化时,会触发init进程执行一个命令,而普通类型的系统属性就不具有这个特性。
从前面的调用过程可以知道,当前发生变化的系统属性的名称为“ctl.start”,它的值被设置为“bootanim”。由于这是一个控制类型的系统属性,因此,在通过了权限检查之后,另外一个函数handle_control_message就会被调用,以便可以执行一个名称为“bootanim”的命令。
通过property_set("ctl.start", "bootanim")写属性后,会走到
system/core/init/property_service.cpp
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
const std::string& source_context, const ucred& cr, std::string* error) {
if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
return ret;
}
if (StartsWith(name, "ctl.")) {
HandleControlMessage(name.c_str() + 4, value, cr.pid);
return PROP_SUCCESS;
}
然后会调用system/core/init/init.cpp的HandleControlMessage(name.c_str() + 4, value, cr.pid); 方法:
system/core/init/init.cpp
void HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) {
....
Service* svc = nullptr;
switch (function.target) {
case ControlTarget::SERVICE:
svc = ServiceList::GetInstance().FindService(name);//找到要启动的服务
break;
case ControlTarget::INTERFACE:
svc = ServiceList::GetInstance().FindInterface(name);
break;
default:
LOG(ERROR) << "Invalid function target from static map key '" << msg << "': "
<< static_cast<std::underlying_type<ControlTarget>::type>(function.target);
return;
}
....
if (auto result = function.action(svc); !result) {//这里就会调用 get_control_message_map
LOG(ERROR) << "Could not ctl." << msg << " for '" << name << "': " << result.error();
}
}
继续往下走会调用 DoControlStart或者DoControlStop
static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
// clang-format off
static const std::map<std::string, ControlMessageFunction> control_message_functions = {
….
{"start", {ControlTarget::SERVICE, DoControlStart}},
{"stop", {ControlTarget::SERVICE, DoControlStop}},
…..
};
// clang-format on
return control_message_functions;
}
控制类型的系统属性的名称是以"ctl."开头,并且是以“start”或者“stop”结尾的,其中,“start”表示要启动某一个服务,而“stop”表示要停止某一个服务,它们是最终分别通过函数DoControlStart 和DoControlStop 来实现的。由于当前发生变化的系统属性是以“start”来结尾的,因此,接下来就会调用函数DoControlStart来启动一个名称为“bootanim”的服务。如下所示:
static Result<Success> DoControlStart(Service* service) {
return service->Start();//ctl.start属性写值后最终调用启动服务
}
static Result<Success> DoControlStop(Service* service) {
service->Stop();//ctl.stop属性写值后最终调用结束服务
return Success();
}
参数name的值等于“bootanim”,它用来描述一个服务名称。这个函数首先调用函数ServiceList::GetInstance().FindService(name)来找到名称等于“bootanim”的服务的信息,这些信息保存在一个service结构体svc中,接着再调用另外一个函数 unction.action(svc)来将对应的应用程序启动起来
3.bootanim进程启动
frameworks/base/cmds/bootanimation/bootanim.rc:
service bootanim /system/bin/bootanimation
class core
...
disabled //此修饰词代表默认不启动,条件触发后启动
oneshot //此修饰词代表只启动一次,启动失败则不会自动重启
接下来看bootanimation的实现:
frameworks/base/cmds/bootanimation/bootanimation_main.cpp
int main()
{
sp<BootAnimation> boot = new BootAnimation();//创建BootAnimation实例
IPCThreadState::self()->joinThreadPool();//binder线程池,与surfaceflinger通信用的
}
return 0;
}
frameworks/base/cmds/bootanimation/BootAnimation.cpp
BootAnimation间接地继承了RefBase类,并且重写了RefBase类的成员函数onFirstRef():
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);// mSession其实是与SurfaceFlinger通信的binder对象,注册binderDeath监听,一旦发生binderDeath之后会走 BootAnimation::binderDied()
if (err == NO_ERROR) {
preloadAnimation();//加载开机动画资源文件
}
}
void BootAnimation::binderDied(const wp<IBinder>&)
{
// woah, surfaceflinger died!
SLOGD("SurfaceFlinger died, exiting...");
// calling requestExit() is not enough here because the Surface code
// might be blocked on a condition variable that will never be updated.
kill( getpid(), SIGKILL );//杀死bootanim进程
requestExit();//结束开机动画
}
接着看preloadAnimation();加载资源
bool BootAnimation::preloadAnimation() {
findBootAnimationFile();//这个方法最终主要是初始化 mZipFileName
if (!mZipFileName.isEmpty()) {
mAnimation = loadAnimation(mZipFileName);//解析资源
return (mAnimation != nullptr);
}
return false;
}
BootAnimation类重写了readyToRun和threadLoop这两个函数;
readyToRun() 主要是对opengl工作环境进行初始化,初始化EGL环境,为送图做准备工作.
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
DisplayInfo dinfo;
status_t status = session()->getDisplayInfo(0, &dinfo);//通过SurfaceFlinger获取屏幕相关信息,session()方法拿到的其实就是mSession, 通过getDisplayInfo()拿到屏幕尺寸等信息后存入 dinfo中,后续会用 dinfo中的信息创建Surface图层.
if (status)
return -1;
// create the native surface
sp<SurfaceControl> control = session()->createSurface(
getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);//此处就是使用mSession创建SurfaceControl
session()->openTransaction();
control->setLayer(0x40000000);
session()->closeTransaction();
sp<Surface> s = control->getSurface();//创建送图的Surface
// 初始化EGL库,EGL是连接OpenGL 与Android显示设备的库.
const EGLint attribs[] = {
EGL_DEPTH_SIZE, 0,
EGL_NONE
};
EGLint w, h, dummy;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
//调用eglGetDisplay
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
EGLUtils::selectConfigForNativeWindow(display, attribs, s.get(), &config);
//调用eglCreateWindowSurface将Surface s转换为本地窗口
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;
}
上面关于egl初始化及使用,这个流程是固定的套路,无论时java层调用还是cpp里面调用,都是这个套路.可参考如下blog:
https://blog.****.net/net_168/article/details/84566667
https://www.jianshu.com/p/ce3496ab9e02
BootAnimation类的成员函数session用来返回BootAnimation类的成员变量mSession所描述的一个SurfaceComposerClient对象。通过调用SurfaceComposerClient对象mSession的成员函数createSurface可以获得一个SurfaceControl对象control。
SurfaceComposerClient类的成员函数createSurface首先调用内部的Binder代理对象mClient来请求SurfaceFlinger返回一个类型为SurfaceLayer的Binder代理对象,接着再使用这个Binder代理对象来创建一个SurfaceControl对象。创建出来的SurfaceControl对象的成员变量mSurface就指向了从SurfaceFlinger返回来的类型为SurfaceLayer的Binder代理对象。有了这个Binder代理对象之后,SurfaceControl对象就可以和SurfaceFlinger服务通信了。
调用SurfaceControl对象control的成员函数getSurface会返回一个Surface对象s。这个Surface对象s内部也有一个类型为SurfaceLayer的Binder代理对象mSurface,这个Binder代理对象与前面所创建的SurfaceControl对象control的内部的Binder代理对象mSurface引用的是同一个SurfaceLayer对象。这样,Surface对象s也可以通过其内部的Binder代理对象mSurface来和SurfaceFlinger服务通信。
Surface类继承了ANativeWindow类。ANativeWindow类是连接OpenGL和Android窗口系统的桥梁,即OpenGL需要通过ANativeWindow类来间接地操作Android窗口系统。这种桥梁关系是通过EGL库来建立的,所有以egl为前缀的函数名均为EGL库提供的接口。
为了能够在OpenGL和Android窗口系统之间的建立一个桥梁,我们需要一个EGLDisplay对象display,一个EGLConfig对象config,一个EGLSurface对象surface,以及一个EGLContext对象context,其中,EGLDisplay对象display用来描述一个EGL显示屏,EGLConfig对象config用来描述一个EGL帧缓冲区配置参数,EGLSurface对象surface用来描述一个EGL绘图表面,EGLContext对象context用来描述一个EGL绘图上下文(状态),它们是分别通过调用egl库函数eglGetDisplay、EGLUtils::selectConfigForNativeWindow、eglCreateWindowSurface和eglCreateContext来获得的。注意,EGLConfig对象config、EGLSurface对象surface和EGLContext对象context都是用来描述EGLDisplay对象display的。有了这些对象之后,就可以调用函数eglMakeCurrent来设置当前EGL库所使用的绘图表面以及绘图上下文。
还有另外一个地方需要注意的是,每一个EGLSurface对象surface有一个关联的ANativeWindow对象。这个ANativeWindow对象是通过函数eglCreateWindowSurface的第三个参数来指定的。在我们这个场景中,这个ANativeWindow对象正好对应于前面所创建的 Surface对象s。每当OpenGL需要绘图的时候,它就会找到前面所设置的绘图表面,即EGLSurface对象surface。有了EGLSurface对象surface之后,就可以找到与它关联的ANativeWindow对象,即Surface对象s。有了Surface对象s之后,就可以通过其内部的Binder代理对象mSurface来请求SurfaceFlinger服务返回帧缓冲区硬件设备的一个图形访问接口。这样,OpenGL最终就可以将要绘制的图形渲染到帧缓冲区硬件设备中去,即显示在实际屏幕上。屏幕的大小,即宽度和高度,可以通过函数eglQuerySurface来获得
threadLoop 就开始真正的播放动画了,当mZipFileName是空时,则播放Android系统默认的开机动画,否则播放用户自定义的开机动画。
bool BootAnimation::threadLoop()
{
if (mZipFileName.isEmpty()) {
r = android();// 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);
eglReleaseThread();
//显示完成之后,就会销毁前面所创建的EGLContext对象mContext、EGLSurface对象mSurface,以及EGLDisplay对象mDisplay等。
}
android() 播放的是系统原生动画,“android”字样加上不断移动的光影效果。
movie() 则是读取bootanimation.zip 中的帧动画,一张一张的轮播,形成动画效果。
movie()方法中会调用playAnimation(const Animation& animation)方法送图.
bool BootAnimation::movie()
{
if (mAnimation == nullptr) {
mAnimation = loadAnimation(mZipFileName);//解压 mZipFileName文件,把文件信息存入 mAnimation
}
for (const Animation::Part& part : mAnimation->parts) {//解析part0,part文件内容
if (part.animation != nullptr) {
mCallbacks->init(part.animation->parts);
}
}
...
playAnimation(*mAnimation);//调用播放
}
查看playAnimation(*mAnimation),会拿到 mAnimation的图片,还有desc.txt中定义的图片分辨率,帧率等信息,依次播放part0,part1中图片,合成Surface,然后调用eglSwapBuffers(mDisplay, mSurface);动图给显示设备.
播放过程的详细介绍:https://blog.****.net/luoshengyang/article/details/7691321,讲的非常详细.
后在循环中调用 checkExit()判断是否应该结束动画:
void BootAnimation::checkExit() {
// Allow surface flinger to gracefully request shutdown
char value[PROPERTY_VALUE_MAX];
property_get(EXIT_PROP_NAME, value, "0");//EXIT_PROP_NAME为service.bootanim.exit
int exitnow = atoi(value);//service.bootanim.exit为非0
if (exitnow) {
requestExit();//调用父类 Thread的函数退出动画
}
}
下面我们来看看”service.bootanim.exit”,设置其为1的地方在:
frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp
void SurfaceFlinger::bootFinished()
{
// 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");//设置标志位为1
}
在frameworks\native\libs\gui\ISurfaceComposer.cpp中调用了bootFinished:
...
case BOOT_FINISHED: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
return NO_ERROR;
}
接下来看是谁发送了BOOT_FINISHED 消息给SurfaceFlinger 服务,查看代码发现,在frameworks\native\include\gui\ISurfaceComposer.h中有定义BOOT_FINISHED
然后发现在\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();
……
}
即SystemServer调用startOtherServices时,启动了WindowManagerService,后WMS获取了SurfaceFlinger 服务,发送了 IBinder.FIRST_CALL_TRANSACTION 消息。 大致流程可以理解为Android系统启动完成后,就会启动Launcher中的主Activity,一旦Launcher的Activity启动完成之后,如果没有用户操作,就会进入空闲状态,ActivityThread就会调用注册的IdleHandler。然后层层转发调用,最终调用SurfaceFlinger去终止开机动画,终止动画流程可概括为:
1>Launcher启动,注册一个Idler空闲处理器到ActivityThread中;
2>Launcher主线程空闲的时候就会调用Idler。queueIdle()方法;
3>Idler.queueIdle() 通过Binder通信调用了ActivityManagerService.activityIdle()方法
4>调用ActivityStackSupervisor.activityIdleInternalLocked()方法;
5>调用ActivityManagerService.enableScreenAfterBoot()方法;
6>调用WindowManagerService.enableScreenAfterBoot()方法;
7>调用WindowManagerService.performEnableScreen()方法;
8>performEnableScreen 通过Binder通信发送 BOOT_FINISHED 消息给 ISurfaceComposer
9>调用ISurfaceComposer 收到 BOOT_FINISHED 消息后调用SurfaceFlinger::bootFinished 函数设置动画结束标志。