必威体育Betway必威体育官网
当前位置:首页 > IT技术

android开机动画bootanimation

时间:2019-07-23 00:41:07来源:IT技术作者:seo实验室小编阅读:94次「手机版」
 

开机动画下载

Android开机动画bootanimation

bootanim服务

源码:frameworks/base/cmds/bootanimation/bootanim.rc

service bootanim /system/bin/bootanimation

class core

user graphics

group graphics audio

disabled

oneshot

bootanim服务可执行程序是/system/bin/bootanimation,定义为core类型的核心服务,所有者是graphics,

组是graphics audio默认是disable的,即开机时不会自动启动,oneshot只启动一次,也就是该服务被异常

销毁也不会重启。

之所以设置为disable是因为bootanim服务是依赖于系统的显示服务的,只有当显示相关的服务起来后才能启动

也就是surfaceflinger服务起来后会拉起bootanim服务显示开机动画。

surfaceFlinger服务

源码:frameworks/native/services/surfaceflinger/surfaceflinger.rc

service surfaceflinger /system/bin/surfaceflinger

class core

user system

group graphics drmrpc readproc

onrestart restart zygote

writepid /sys/fs/cgroup/stune/foreground/tasks

surfaceFlinger是负责显示相关的服务,是非常核心的服务必须一直保持存活的

源码:frameworks/native/cmds/servicemanager/servicemanager.rc

service servicemanager /system/bin/servicemanager

class core

user system

group system readproc

critical

onrestart restart healthd

onrestart restart zygote

onrestart restart audiOServer

onrestart restart media

onrestart restart surfaceflinger

onrestart restart inputflinger

onrestart restart drm

onrestart restart cameraserver

writepid /dev/cpuset/system-background/tasks

init进程读取init.rc就会去解析服务,surfaceflinger也是定义的服务之一,调用 /system/bin/surfaceflinger

启动surfaceflinger服务,服务的入口是main函数,下面对surfaceflinger进行分析:

源码:frameworks/native/services/surfaceflinger

入口文件main_surfaceflinger.cpp

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); //binder服务池大小限制,最多同时4个线程

// start the thread pool

sp<ProcessState> ps(ProcessState::self());

ps->startThreadPool(); //启动线程池监听连接

// instantiate surfaceflinger

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

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.cpp

void SurfaceFlinger::init() {

...

// set initial conditions (e.g. unblank default device)

initializeDisplays(); //初始化显示设备

// start boot animation

startBootAnim(); //启动开机动画

}

void SurfaceFlinger::startBootAnim() {

#ifdef MTK_AOSP_ENHANCEMENT

// dynamic disable/enable boot animation

checkEnableBootAnim();

#else

// start boot animation

property_set("service.bootanim.exit", "0"); //为了防止这个属性被设为1,不管现在值怎样都设置为0

property_set("ctl.start", "bootanim"); //启动开机动画

#endif

}

下面分析init property service怎样将属性设置转为对应的动作

在init.cpp中

int main(int argc, char** argv) {

...

start_property_service(); //启动属性管理服务

...

}

start_property_service函数在property_service.cpp中定义:

start_property_service

void start_property_service() {

property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,

0666, 0, 0, NULL);

if (property_set_fd == -1) {

ERROR("start_property_service socket creation failed: %s\n", strerror(errno));

exit(1);

}

listen(property_set_fd, 8); //socket监听binder服务请求,处理相关属性设置动作

register_epoll_handler(property_set_fd, handle_property_set_fd); //epoll监听处理,处理回调函数是handle_property_set_fd

}

handle_property_set_fd

static void handle_property_set_fd()

{

...

switch(msg.cmd) {

...

if (!is_legal_property_name(msg.name, strlen(msg.name))) {

ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);

close(s);

return;

}

getpeercon(s, &source_ctx);

if(memcmp(msg.name,"ctl.",4) == 0) {

// Keep the old close-socket-early behavior when handling

// ctl.* properties.

close(s);

if (check_control_mac_perms(msg.value, source_ctx, &cr)) {

...

handle_control_message((char*) msg.name + 4, (char*) msg.value);

} else {

...

}

} else {

if (check_mac_perms(msg.name, source_ctx, &cr)) {

...

property_set((char*) msg.name, (char*) msg.value); //普通属性,只是做设置值处理

} else {

}

// Note: bionic's property client code assumes that the

// property server will not close the socket until *AFTER*

// the property is written to memory.

close(s);

}

freecon(source_ctx);

break;

default:

...

}

handle_control_message

void handle_control_message(const std::string& msg, const std::string& name) {

Service* svc = ServiceManager::Getinstance().FindServiceByName(name); //根据只有一个全局Service存储所有定义的服务,后面可以根据名字查找服务

if (svc == nullptr) {

ERROR("no such service '%s'\n", name.c_str());

return;

}

if (msg == "start") {

svc->Start(); //启动服务

} else if (msg == "stop") {

svc->Stop(); //停止服务

} else if (msg == "restart") {

svc->Restart(); //重启服务

} else {

ERROR("unknown control msg '%s'\n", msg.c_str());

}

}

ServiceManager

1.FindServiceByName

Service* ServiceManager::FindServiceByName(const std::string& name) const {

auto svc = std::find_if(services_.begin(), services_.end(),

[&name] (const std::unique_ptr<Service>& s) {

return name == s->name();

});

if (svc != services_.end()) {

return svc->get();

}

return nullptr;

}

ServiceManager.h中定义services_向量数组

std::vector<std::unique_ptr<Service>> services_;

2.Start

bool Service::Start() {

...

if (!seclabel_.empty()) {

scon = seclabel_;

} else {

...

rc = security_compute_create(mycon, fcon, string_to_security_class("process"),

&ret_scon);

...

if (rc == 0 && scon == mycon) {

ERROR("Service %s does not have a SElinux domain defined.\n", name_.c_str()); //selinux安全检查,在init.rc中定义了服务不能启动会提示这个错误

...

}

pid_t pid = fork();

if (pid == 0) {

std::vector<char*> strs;

for (const auto& s : args_) {

strs.push_back(const_cast<char*>(s.c_str()));

}

strs.push_back(nullptr);

if (execve(args_[0].c_str(), (char**) &strs[0], (char**) ENV) < 0) { //启动子进程执行服务程序

ERROR("cannot execve('%s'): %s\n", args_[0].c_str(), strerror(errno));

}

_exit(127);

}

NotifyStateChange("running");

}

NotifyStateChange

void Service::NotifyStateChange(const std::string& new_state) const {

if ((flags_ & SVC_EXEC) != 0) {

// 'exec' commands don't have properties tracking their state.

return;

}

std::string prop_name = Stringprintf("init.svc.%s", name_.c_str()); //init.svc.bootanim

if (prop_name.length() >= PROP_NAME_MAX) {

// If the property name would be too long, we can't set it.

ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n",

name_.c_str(), new_state.c_str());

return;

}

property_set(prop_name.c_str(), new_state.c_str());//设置init.svc.bootanim 为running

}

3. Stop

void Service::Stop() {

StopOrReset(SVC_DISABLED);

}

void Service::StopOrReset(int how) {

/* The service is still SVC_RUNNING until its process exits, but if it has

* already exited it shoudn't attempt a restart yet. */

flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);

if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {

/* Hrm, an illegal flag. Default to SVC_DISABLED */

how = SVC_DISABLED;

}

/* if the service has not yet started, prevent

* it from auto-starting with its class

*/

if (how == SVC_RESET) {

flags_ |= (flags_ & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET;

} else {

flags_ |= how;

}

if (pid_) {//如果服务进程已经启动才会有pid_

notice("Service '%s' is being killed...\n", name_.c_str());

kill(-pid_, SIGKILL); //杀死服务进程

NotifyStateChange("stopping"); //设置init.svc.bootanim 为stopping

} else {

NotifyStateChange("stopped");//设置init.svc.bootanim 为stopped

}

}

4.Restart

void Service::Restart() {

if (flags_ & SVC_RUNNING) {

/* Stop, wait, then start the service. */

StopOrReset(SVC_RESTART);

} else if (!(flags_ & SVC_RESTARTING)) {

/* Just start the service since it's not running. */

Start();

} /* else: Service is restarting anyways. */

}

经过上面分析,我们已经知道了开机init进程解析init.rc注册bootanim服务到surfaceFlinger服务启动startBootanim到属性服务如何将

属性转化为对应的动作即启动子进程执行 /system/bin/bootanimation整个过程,下面分析bootanimation程序是怎样启动动画的

bootanimation

源码:frameworks/base/cmds/bootanimation/

入口bootanimation_main.cpp

int main(int argc, char** argv)

{

setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);

char value[PROPERTY_VALUE_MAX];

property_get("debug.sf.nobootanimation", value, "0"); //调试状态可通过设置属性debug.sf.nobootanimation值为1禁止开机动画

int noBootAnimation = atoi(value);

ALOGI_IF(noBootAnimation, "boot animation disabled");

if (!noBootAnimation) {

sp<ProcessState> proc(ProcessState::self());

ProcessState::self()->startThreadPool();

bool setBoot = true;

bool setRotated = false;

bool sePaly = true;

if(argc > 1){

if(!strcmp(argv[1],"shut"))

setBoot = false;

}

if(argc > 2){

if(!strcmp(argv[2],"nomp3"))

sePaly = false;

}

if(argc > 3){

if(!strcmp(argv[3],"rotate"))

setRotated = true;

}

ALOGD("[BootAnimation %s %d]setBoot=%d,sePaly=%d,setRotated=%d",__FUNCTION__,__LINE__,setBoot,sePaly,setRotated);

char volume[PROPERTY_VALUE_MAX];

property_get("persist.sys.mute.state", volume, "-1"); //属性persist.sys.mute.state设置音量

int nVolume = -1;

nVolume = atoi(volume);

ALOGD("[BootAnimation %s %d]nVolume=%d",__FUNCTION__,__LINE__,nVolume);

if(nVolume == 0 || nVolume == 1 ){

sePaly = false;

}

ALOGD("before new BootAnimation...");

ALOGD("[BootAnimation %s %d]before new BootAnimation...",__FUNCTION__,__LINE__);

sp<BootAnimation> boot = new BootAnimation(setBoot,sePaly,setRotated); //智能指针sp,使用后自动释放

ALOGD("jointhreadPool...");

ALOGD("[BootAnimation %s %d]before joinThreadPool...",__FUNCTION__,__LINE__);

IPCThreadState::self()->joinThreadPool(); //等待开机动画线程结束

}

ALOGD("[BootAnimation %s %s %d]end",__FILE__,__FUNCTION__,__LINE__);

return 0;

}

BootAnimation

源码:BootAnimation.cpp

BootAnimation::BootAnimation(bool bSetBootOrShutDown, bool bSetPlayMP3,bool bSetRotated) : Thread(false), mZip(NULL)

{

ALOGD("[BootAnimation %s %d]",__FUNCTION__,__LINE__);

msession = new SurfacecomposerClient();

bBootOrShutDown = bSetBootOrShutDown;

bShutRotate = bSetRotated;

bPlayMP3 = bSetPlayMP3;

mProgram = 0;

bETC1Movie = false;

mBootVideoPlayType = BOOT_VIDEO_PLAY_FULL;

mBootVideoPlayState = MEDIA_NOP;

ALOGD("[BootAnimation %s %d]bBootOrShutDown=%d,bPlayMP3=%d,bShutRotate=%d",__FUNCTION__,__LINE__,bBootOrShutDown,bPlayMP3,bShutRotate);

}

在BootAnimation.h中,我们可以看到

class BootAnimation : public Thread, public IBinder::DeathRecipient

{

...

private:

virtual bool threadLoop();

virtual status_t readyToRun();

virtual void onFirstRef();

...

}

BootAnimation继承于Thread,而Thread继承RefBase类,并且BootAnimation覆写了onFirstRef,readyToRun,threadLoop函数,

结合智能指针知识,在创建对象BootAnimation时候会首先调用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); //这里会调用onFirstRef()函数

}

}

status_t BootAnimation::readyToRun() {

if (bBootOrShutDown) {

initBootanimationZip(); //开机动画

} else {

initShutanimationZip(); //关机动画

}

if ((mZip != NULL)&&!(mZipFileName.isEmpty())) {

ZipEntryRO desc = mZip->findEntryByName("desc.txt"); //desc.txt文件描述了如何播放动画,如图片目录,播放次数和播放帧率

uint16_t method;

mZip->getEntryInfo(desc, &method, NULL, NULL, NULL, NULL, NULL);

mZip->releaseEntry(desc);

if (method == ZipFileRO::kCompressStored) {

bETC1Movie = false;

} else {

bETC1Movie = true;

}

}

massets.addDefaultAssets();

sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(

ISurfaceComposer::eDisplayIdMain));

DisplayInfo dinfo;

status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);

... //下面主要初始化Surface相关的类

sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(

ISurfaceComposer::eDisplayIdMain));

DisplayInfo dinfo;

status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);

if (status)

return -1;

/// M: The tablet rotation maybe 90/270 degrees, so set the lcm config for tablet

SurfaceComposerClient::setDisplayProjection(dtoken, DisplayState::eOrientationDefault, Rect(dinfo.w, dinfo.h), Rect(dinfo.w, dinfo.h));

// create the native surface

sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"), //创建BootAnimation surface

dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);

SurfaceComposerClient::openGlobaltransaction();

control->setLayer(0x2000010);

SurfaceComposerClient::closeGlobalTransaction();

sp<Surface> s = control->getSurface();

...

/*opengl渲染相关初始化*/

EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

ALOGD("initialize opengl and egl");

EGLBoolean eglret = eglInitialize(display, 0, 0);

//下面是加密相关处理,部分厂家放在initBootanimationZip处理

}

#define GLOBAL_DEVICE_BOOTANIM_OPTR_NAME "persist.operator.optr"

#define REGIONAL_BOOTANIM_FILE_NAME "persist.bootanim.logopath"

void BootAnimation::initBootanimationZip() {

....

f (property_get(GLOBAL_DEVICE_BOOTANIM_OPTR_NAME, OPTR, NULL) > 0){ //获取bootanimation.zip文件的路径

for(int i=0;i<PATH_COUNT_USP;i++) {

strcpy(BootanimFileName,mResourcePath_gb[i]);

strcat(BootanimFileName,OPTR);

ALOGD("[BootAnimation %s %d]use operator = %s",__FUNCTION__,__LINE__,OPTR);

strcat(BootanimFileName,"/bootanimation.zip");

ALOGD("[BootAnimation %s %d]use the bootanimation zip path = %s",__FUNCTION__,__LINE__,BootanimFileName);

if ((access(BootanimFileName, R_OK) == 0) &&

((zipFile = ZipFileRO::open(BootanimFileName)) != NULL)){

mZip = zipFile;

mZipFileName = BootanimFileName;

break;

}

}

}

...

/*接下来对zip包进行解密*/

property_get("vold.decrypt", decrypt, "");

..

}

threadLoop

根据Thread的周期函数在调用完readyToRun函数后就会调用threadLoop()函数

bool BootAnimation::threadLoop()

{

bool r;

// We have no bootanimation file, so we use the stock android logo

// animation.

sp<mediaplayer> mediaplayer; //开机音乐设置,播放

const char* resourcePath = initAudioPath();

status_t mediastatus = NO_ERROR;

if (resourcePath != NULL) {

bPlayMP3 = true;

ALOGD("sound file path: %s", resourcePath);

mediaplayer = new MediaPlayer();

mediastatus = mediaplayer->setdatasource(NULL, resourcePath, NULL);

sp<BootVideoListener> listener = new BootVideoListener(this);

mediaplayer->setListener(listener);

if (mediastatus == NO_ERROR) {

ALOGD("mediaplayer is initialized");

Parcel* attributes = new Parcel();

attributes->writeInt32(AUDIO_USAGE_MEDIA); //usage

attributes->writeInt32(AUDIO_content_TYPE_MUSIC); //audio_content_type_t

attributes->writeInt32(AUDIO_SOURCE_DEFAULT); //audio_source_t

attributes->writeInt32(0); //audio_flags_mask_t

attributes->writeInt32(1); //kAudioAttributesMarshallTagFlattenTags of mediaplayerservice.cpp

attributes->writeString16(String16("BootAnimationAudioTrack")); // tags

mediaplayer->setparameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *attributes);

mediaplayer->setAudioStreamType(AUDIO_STREAM_MUSIC);

mediastatus = mediaplayer->prepare();

}

if (mediastatus == NO_ERROR) {

ALOGD("media player is prepared");

mediastatus = mediaplayer->start();

}

}else{

bPlayMP3 = false;

}

if ((mZip == NULL)&&(mZipFileName.isEmpty())) { //如果开机动画不存在的情况

r = android(); //加载原生的ANDROID开机图片

} else {

if (!bETC1Movie) {

ALOGD("threadLoop() movie()");

r = movie(); //解析动画,原生开机动画,ANDROID

} else {

ALOGD("threadLoop() ETC1movie()");

r = ETC1movie(); //解析动画,定制的开机动画,bootanimation.zip中desc.txt文件描述动画播放

}

}

if (resourcePath != NULL) {

if (mediastatus == NO_ERROR) {

ALOGD("mediaplayer was stareted successfully, now it is going to be stoped");

mediaplayer->stop();

mediaplayer->disconnect();

mediaplayer.clear();

}

}

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;

}

ETC1movie

先看个desc.txt例子

420 232 20

p 1 0 part0

p 0 10 part1

1355263

第一行表示420*232 20表示1秒播放多少帧(帧率)

第二行p表示动画,也有用c表示的,1表示播放1次,0表示这部分播完到下部分的时间间隔,part0表示播放的图片目录

第三行p(旧版本的)表示动画,也有用c表示(新版本),0表示无限循环播放,10表示两次播放两个part之间间隔的帧数是10,间隔时间是10*1/20秒,只作用于part1

bool BootAnimation::ETC1movie()

{

ZipEntryRO desc = mZip->findEntryByName("desc.txt"); //如果找不到desc.txt则无法播放动画

ALOGE_IF(!desc, "couldn't find desc.txt");

if (!desc) {

return false;

}

...

Animation animation;

// Parse the description file

for (;;) {

const char* endl = strstr(s, "\n");

if (!endl) break;

String8 line(s, endl - s);

const char* l = line.string();

int fps, width, height, count, pause;

char path[ANIM_ENTRY_NAME_MAX];

char color[7] = "000000"; // default to black if unspecified

char pathType;

if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) { //解析desc.txt第一行

ALOGD("> w=%d, h=%d, fps=%d", width, height, fps); // add log

animation.width = width;

animation.height = height;

animation.fps = fps;

}

else if (sscanf(l, "%c %d %d %s", &pathType, &count, &pause, path) == 4) {//解析desc.txt第一行后面的行

ALOGD("> type=%c, count=%d, pause=%d, path=%s", pathType, count, pause, path); // add log

Animation::Part part;

part.playUntilComplete = pathType == 'c';

part.count = count;

part.pause = pause;

part.path = path;

animation.parts.add(part);//添加值animation中

if (!parseColor(color, part.backgroundColor)) {

ALOGD("> invalid color '#%s'", color);

part.backgroundColor[0] = 0.0f;

part.backgroundColor[1] = 0.0f;

part.backgroundColor[2] = 0.0f;

}

}

s = ++endl;

}

/*读取对应的图片*/

ZipEntryRO entry;

char name[ANIM_ENTRY_NAME_MAX];

while ((entry = mZip->nextEntry(cookie)) != NULL) {

const int foundEntryName = mZip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);

if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {

ALOGE("Error fetching entry file name");

continue;

}

const String8 entryName(name);

const String8 path(entryName.getPathDir());

const String8 leaf(entryName.getPathLeaf());

if (leaf.size() > 0) {

for (size_t j=0 ; j<pcount ; j++) {

if (path == animation.parts[j].path) {

Animation::Frame frame;

frame.name = leaf;

// frame.map = map;

frame.fullPath = entryName;

Animation::Part& part(animation.parts.editItemAt(j));

part.frames.add(frame);

}

}

}

}

mZip->endIteration(cookie);

for (size_t i=0 ; i<pcount ; i++) {

const Animation::Part& part(animation.parts[i]);

const size_t fcount = part.frames.size();

ALOGD("[BootAnimation %s %d]i=%zu,i<pcount=%zu,r<part.count=%d,j<fcount=%zu",__FUNCTION__,__LINE__,i,pcount,part.count,fcount);

glBindTexture(GL_TEXTURE_2D, 0);

...

//下面真正开始播放动画

for (int r=0 ; !part.count || r<part.count ; r++) { //根据前面解析的part进行循环

// Exit any non playuntil complete parts immediately

if(exitPending() && !part.playUntilComplete) {

//ALOGD("[BootAnimation %s %d]part.playUntilComplete=%d", __FUNCTION__, __LINE__ ,part.playUntilComplete);

break;

}

glClearColor(

part.backgroundColor[0],

part.backgroundColor[1],

part.backgroundColor[2],

1.0f);

for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) { //每个part图片播放

const Animation::Frame& frame(part.frames[j]);

nsecs_t lastFrame = systemTime();

//ALOGD("[BootAnimation %s %d]i=%d,r=%d,j=%d,lastFrame=%lld(%lld ms),file=%s",__FUNCTION__,__LINE__,i,r,j,lastFrame,ns2ms(lastFrame),frame.name.string());

if (r > 0) {

glBindTexture(GL_TEXTURE_2D, frame.tid);

} else {

if (part.count != 1) {

glGenTextures(1, &frame.tid);

glBindTexture(GL_TEXTURE_2D, frame.tid);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

}

initTexture(frame.fullPath.string());

}

static GLfloat quadVertex[] = { -1.0f, 1.0f, 0.0f, // Position 0

0.0f, 0.0f, // TexCoord 0

-1.0f, -1.0f, 0.0f, // Position 1

0.0f, 1.0f, // TexCoord 1

1.0f, -1.0f, 0.0f, // Position 2

1.0f, 1.0f, // TexCoord 2

1.0f, 1.0f, 0.0f, // Position 3

1.0f, 0.0f // TexCoord 3

};

static GLushort quadIndex[] = { 0, 1, 2, 0, 2, 3 };

3, GL_FLOAT,

false, 5*sizeof(GL_FLOAT), quadVertex);

glVertexAttribPointer(mAttribTexCoord,

2, GL_FLOAT,

false, 5*sizeof(GL_FLOAT), &quadVertex[3]);

glEnableVertexAttribArray(mAttribPosition);

glEnableVertexAttribArray(mAttribTexCoord);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, quadIndex);

eglSwapBuffers(mDisplay, mSurface);

nsecs_t now = systemTime();

nsecs_t delay = frameDuration - (now - lastFrame);

//ALOGD("[BootAnimation %s %d]%lld,delay=%lld",__FUNCTION__,__LINE__,ns2ms(now - lastFrame), ns2ms(delay));

lastFrame = now;

if (delay > 0) {

struct timespec spec;

spec.tv_sec = (now + delay) / 1000000000;

spec.tv_nsec = (now + delay) % 1000000000;

int err;

do {

err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); //播放的帧率

} while (err<0 && errno == EINTR);

}

if(!bPlayMP3){

checkExit();

}else{

if(mBootVideoPlayState == MEDIA_PLAYBACK_COMPLETE || mBootVideoPlayState == MEDIA_ERROR) {

checkExit(); //检查是否需要退出动画

}

}

}

usleep(part.pause * ns2us(frameDuration));//两个part之间的时间间隔

// For infinite parts, we've now played them at least once, so perhaps exit

if(exitPending() && !part.count) {

ALOGD("[BootAnimation %s %d]break,exitPending()=%d,part.count=%d",__FUNCTION__,__LINE__,exitPending(),part.count);

break;

}

}

// free the textures for this part

if (part.count != 1) {

for (size_t j=0 ; j<fcount ; j++) {

const Animation::Frame& frame(part.frames[j]);

glDeleteTextures(1, &frame.tid);

ALOGD("[BootAnimation %s %d]del,part.count=%d,j=%zu,fcount=%zu",__FUNCTION__,__LINE__,part.count,j,fcount);

}

}

}

ALOGD("[BootAnimation %s %d]end",__FUNCTION__,__LINE__);

return false;

}

至此,开机动画启动过程解析完毕,接下来要进行的是停止开机动画的调用过程。

相关阅读

android向联系人中添加头像以及获得电话记录

Java代码 <pre name="code" class="java">ContentResolver cr = getContentResolver();Cursor cursor = cr.query(ContactsContr

Android中Adapter的notifyDataSetInvalidated()和noti

notifyDataSetChanged方法通过一个外部的方法控制如果适配器的内容改变时需要强制调用getView来刷新每个Item的内容。public void

Android 4.0设计规范(附全文翻译pdf)

在拜读和翻译了Android design设计指导后,对比Android 4.0与Android2.3及之前版本的app设计指导,总结了Android 4.0设计的10大改变:1

Android9.0,5.0,6.0,7.0,8.0新特性整理

   Android 9.0新特性 1、全面屏支持,Android P加入了对刘海屏的支持,谷歌称之为凹口屏幕(display with a cutout)。借助最新的提

android cts测试方法及步骤 Android gts测试方法与步

CTS 是一个兼容性性测试工具。是Android TV 的必备条件。 CTS 是一个自动化测试工具,其中包括两个主要软件组件: CTS tradefed 自动

分享到:

栏目导航

推荐阅读

热门阅读