原生开机动画流程

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.csdn.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.csdn.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 函数设置动画结束标志。