AndroidFramework学习视频(1)-BootAnimation开机动画启动流程源码分析课程答疑和新课信息:QQ交流:966916899 进⾏课程讨论
专题博客系列:
课前问题:
请问⼤家在android系统中要展⽰⼀个界⾯,不使⽤View⽅式还有没有其他⽅式?
.1 Android开机动画实现⽅式⽬前实现Android开机动画的⽅式主要是逐帧动画和OpenGL直接编程绘制动画。
1、逐帧动画
逐帧动画是⼀种常见的动画形式(Frame By Frame),其原理是在“连续的关键帧”中分解动画动作,也就是在时间轴的每帧上逐帧绘制不同的内容,使其连续播放⽽成动画。 因为逐帧动画的帧序列内容不⼀样,不但给制作增加了负担⽽且最终输出的⽂件量也很⼤,但它的优势也很明显:逐帧动画具有⾮常⼤的灵活性,⼏乎可以表现任何想表现的内容,⽽它类似与电影的播放模式,很适合于表演细腻的动画。逐帧动画是⼴泛流传的⼀种实现⽅法。实现原理是将⼀系列图⽚打包成bootanimation.zip放⼊/system/media/⽬录,系统将图⽚⼀帧⼀帧循环播放形成⼀个动画效果。理论上讲这种⽅法应该是可
以实现⼀切动画需求的,但是实践后你会发现当bootanimation.zip⼤于5M的时候,动画将有明显卡顿,⽂件越⼤动画越不流畅。所以细⼼的同学会发现⼿机上的开机动画⼤多都是只有中间⼀⼩部分在变化,⽽四周全是⿊⾊,这样做是为了使得可以采⽤100*50(甚⾄更⼩)分辨率的图⽚,这样100帧也才⼏M的⼤⼩。
2、OpenGL动画
OpenGL(英语:Open Graphics Library)是个定义了⼀个跨编程语⾔、跨平台的应⽤程序接⼝(API)的规范,它⽤于⽣成⼆维、三维图像。这个接⼝由近三百五⼗个不同的函数调⽤组成,⽤来从简单的图形⽐特绘制复杂的三维景象。
代码分析路径介绍:
bootanimation frameworks/base/cmds/bootanimation/
surfaceflinger frameworks/native/services/surfaceflinger/
init system/core/init/
启动流程详细分析:
内核起来后会启动第⼀个进程,即init进程。
init进程会根据配置启动surfaceflinger进程。
service surfaceflinger /system/bin/surfaceflinger
class main
user system
group graphics drmrpc
onrestart restart zygote
surfaceflinger进程便启动了,跟着就会跑进程的main()函数。
frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
int main(int argc,char** argv){
....
/
/ instantiate surfaceflinger
sp<SurfaceFlinger> flinger = new SurfaceFlinger();//创建surfaceflinger服务
....
flinger->init();
// publish surface flinger
sp<IServiceManager>sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);//注册到servicemanager⾥
// run in this thread
flinger->run();//运⾏
return0;
}
⾸先new⼀个SurfaceFlinger实例,然后init,然后run
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
// Do not call property_set on main thread which will be blocked by init
// Use StartPropertySetThread instead.
void SurfaceFlinger::init(){
ALOGI("SurfaceFlinger's main thread ready to run. "
"Initializing graphics ");
// Inform native graphics APIs whether the present timestamp is supported:
if(getHwComposer().hasCapability(
HWC2::Capability::PresentFenceIsNotReliable)){
mStartPropertySetThread =new StartPropertySetThread(false);
}else{
mStartPropertySetThread =new StartPropertySetThread(true);
}
if(mStartPropertySetThread->Start()!= NO_ERROR){//真正启动设置bootanimation的属性线程
ALOGE("Run StartPropertySetThread failed!");
}
ALOGV("Done initializing");
}
初始化graphics之后,mStartPropertySetThread()播放开机动画。//注意已经不是以前的startBootAnim⽅法StartPropertySetThread如下定义:
StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue):
Thread(false),mTimestampPropertyValue(timestampPropertyValue){}
status_t StartPropertySetThread::Start(){
return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
}
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("it","0");//关键属性
// Start BootAnimation if not started
property_set("ctl.start","bootanim");//关键属性
// Exit immediately
return false;
}
这样bootanim进程就会启动?凭什么设置了⼀个属性就启动了?那么下⾯我们来看,/system/core/init/init.cpp ,在看init进程的
init.cpp的main函数中:
int main(int argc,char** argv){
//省略
property_load_boot_defaults();
export_oem_lock_status();
start_property_service();//start_property_service
set_usb_controller();
}
下⾯来来看看start_property_service⽅法,在/system/core/init/property_service.cpp:
main函数中start_property_service(),在这个函数中注册⼀个epoll handle 的机制
register_epoll_handler():
void start_property_service(){
property_set("ro.property_service.version","2");
property_set_fd =create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,0666,0,0,NULL);
if(property_set_fd ==-1){
PLOG(ERROR)<<"start_property_service socket creation failed";
exit(1);
}
listen(property_set_fd,8);
register_epoll_handler(property_set_fd, handle_property_set_fd);
}
init进程会使⽤epoll机制来轮询事件,其中⼀个事件是系统属性值被修改。得到该事件后,会执⾏handle_property_set_fd(),代码如下:通过handle_property_set_fd():
static void handle_property_set_fd(){
//省略
switch(cmd){
case PROP_MSG_SETPROP:{
char prop_name[PROP_NAME_MAX];
char prop_value[PROP_VALUE_MAX];
if(!socket.RecvChars(prop_name, PROP_NAME_MAX,&timeout_ms)||
!socket.RecvChars(prop_value, PROP_VALUE_MAX,&timeout_ms)){
PLOG(ERROR)<<"sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
return;
}
prop_name[PROP_NAME_MAX-1]=0;
prop_value[PROP_VALUE_MAX-1]=0;
handle_property_set(socket, prop_value, prop_value, true);
android学习教程break;
}
该函数会进执⾏handle_property_set()
static void handle_property_set(SocketConnection& socket,
const std::string& name,
const std::string& value,
bool legacy_protocol){
//省略。。。。。。
handle_control_message(name.c_str()+4, value.c_str());
//省略。。。。。。。
}
该函数会进⼀步执⾏handle_control_message(),在/system/core/init/init.cpp,传⼊的参数msg.name=ctl.start,
msg.value=bootanim
void handle_control_message(const std::string& msg,const std::string& name){
Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
if(svc ==nullptr){
LOG(ERROR)<<"no such service '"<< name <<"'";
return;
}
if(msg =="start"){
svc->Start();
}else if(msg =="stop"){
svc->Stop();
}else if(msg =="restart"){
svc->Restart();
}else{
LOG(ERROR)<<"unknown control msg '"<< msg <<"'";
}
}
该函数⾸先调⽤FindServiceByName,从service_list中查询要启动的服务是否有存在,若存在,返回服务的相关信息。因为中有bootanimation的定义,因此在init进程执⾏parse_config()时,会将该服务添加到service_list中,所以bootanimation应⽤是存在的。然后,如果到了该服务,就调⽤service_start启动服务。
把it属性设为0,这个属性bootanimation进程⾥会周期检查,=1时就退出动画,这⾥=0表⽰要播放动画。
后⾯通过ctl.start的命令启动bootanimation进程,动画就开始播放了。
下⾯来到bootanimation的实现
frameworks/base/cmds/bootanimation/bootanimation_main.cpp
int main(int argc,char** argv)
{
sp<ProcessState>proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object
sp<BootAnimation> boot = new BootAnimation();//创建BootAnimation实例
IPCThreadState::self()->joinThreadPool();//binder线程池,与surfaceflinger通信⽤的。
}
return0;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论