介绍

开机动画,BootAnimation,就是Android手机开机郭晨各种以一个展示给用户的界面,实际是一个多个帧组成的动画,在界面上进行一帧一帧的播放,形成开机动画的效果。

本文针对Android5.1源码分析BootAnimation


源码分析

1. 文件产生

Android平台的开机动画由system/bin下的bootanimation文件完成,而这个文件产生于

frameworks/base/cmds/bootanimation/Android.mk

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_SRC_FILES:= \
bootanimation_main.cpp \
AudioPlayer.cpp \
BootAnimation.cpp LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_C_INCLUDES += external/tinyalsa/include LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
libandroidfw \
libutils \
libbinder \
libui \
libskia \
libEGL \
libGLESv1_CM \
libgui \
libtinyalsa LOCAL_MODULE:= bootanimation ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif
include $(BUILD_EXECUTABLE)

编译结果为bootanimation的bin文件,所以,在有足够权限的前提下,在adb shell下执行bootanimation也是可以看到对应的开机动画效果的。

2. 启动开机动画

开机动画是以bin文件的形式存在于手机系统中,开机过程中通过init.rc定义

system/core/rootdir/init.rc

service bootanim /system/bin/bootanimation
class core
user graphics
group graphics audio
disabled//定义了disable,在开机过程中不会自动的启动
oneshot

这里不会启动,那么在哪里启动? 由于开机动画对SurfaceFlinger有依赖,所以应该是在SurfaceFlinger启动之后再开始执行,看一下源码。

SurfaceFlinger的启动在init.rc文件中

service surfaceflinger /system/bin/surfaceflinger
class core
user system
group graphics drmrpc
onrestart restart zygote

与SurfaceFlinger相关的源码存在于

frameworks\native\services\surfaceflinger

入口

frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

#if defined(HAVE_PTHREADS)
#include <sys/resource.h>
#endif #include <cutils/sched_policy.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include "SurfaceFlinger.h" using namespace android; int main(int, char**) {
// 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
sp<SurfaceFlinger> flinger = new SurfaceFlinger(); #if defined(HAVE_PTHREADS)
setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
#endif
set_sched_policy(0, SP_FOREGROUND); // initialize before clients can connect
flinger->init();//开机动画在这里执行,接着往下看 // publish surface flinger
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false); // run in this thread
flinger->run(); return 0;
}

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
....
// start boot animation
startBootAnim();
}

接着执行startBootAnim();

void SurfaceFlinger::startBootAnim() {
// start boot animation
property_set("service.bootanim.exit", "0");
property_set("ctl.start", "bootanim");
}

这里采用的是通过property_set中”ctl.start”的方式执行bootanim,这里是通过设置属性值的方式来启动的,属性值的设置采用的是C/S模式,socket连接,这里不详述,大致说下,这行代码会执行到

system/core/init/property_service.c

void handle_property_set_fd()
{
......
switch(msg.cmd) {
case PROP_MSG_SETPROP:
......
//这里很关键
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)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
}
//这里很关键
} else {
if (check_perms(msg.name, source_ctx)) {
property_set((char*) msg.name, (char*) msg.value);
} else {
ERROR("sys_prop: permission denied uid:%d name:%s\n",
cr.uid, msg.name);
} // 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:
close(s);
break;
}
}

接下来执行到

system/core/init/init.c

void handle_control_message(const char *msg, const char *arg)
{
if (!strcmp(msg,"start")) {
msg_start(arg);//就是这条路
} else if (!strcmp(msg,"stop")) {
msg_stop(arg);
} else if (!strcmp(msg,"restart")) {
msg_restart(arg);
} else {
ERROR("unknown control msg '%s'\n", msg);
}
}

接着往下执行->

static void msg_start(const char *name)
{
struct service *svc = NULL;
char *tmp = NULL;
char *args = NULL; if (!strchr(name, ':'))
svc = service_find_by_name(name);
else {
tmp = strdup(name);
if (tmp) {
args = strchr(tmp, ':');
*args = '\0';
args++; svc = service_find_by_name(tmp);
}
} if (svc) {
service_start(svc, args);
} else {
ERROR("no such service '%s'\n", name);
}
if (tmp)
free(tmp);
}

这里找到“bootanim”然后执行service_start函数,这里就是启动bootanim的地方。

<Android Framework 之路>BootAnimation(1)的更多相关文章

  1. <Android Framework 之路>BootAnimation(2)

    前言 上一篇主要讲解了BootAnimation是从何而来,如何启动,从开机,到SurfaceFlinger服务起来,然后到执行开机动画,如果要深入的看里面的代码,是需要花一定的时间的,我们旨在了解大 ...

  2. <Android Framework 之路> N版本 Framework Camera的一些改动

    前言 Android N版本最近发布,Nougat是否好吃,不得而知,慢慢看下~ 感谢AndroidXref这个网站,给开发者提供了大量的便捷~以后学习Android就靠它了. N版本上Framewo ...

  3. <Android Framework 之路>Android5.1 Camera Framework(三)

    上一次讲解了一下startPreview过程,主要是为了画出一条大致的从上到下的线条,今天我们看一下Camera在Framework的sendCommand和dataCallback,这部分属于衔接过 ...

  4. <Android Framework 之路>Android5.1 Camera Framework(一)

    Android5.0 Camera Framework 简介 CameraService启动 CameraService是在MediaServer启动过程中进行的 main_mediaserver.c ...

  5. <Android Framework 之路>多线程

    多线程编程 JAVA多线程方式 1. 继承Thread线程,实现run方法 2. 实现Runnable接口 JAVA单继承性,当我们想将一个已经继承了其他类的子类放到Thread中时,单继承的局限就体 ...

  6. <Android Framework 之路>Android5.1 MediaScanner

    前言 MediaScanner是Android系统中针对媒体文件的扫描过程,将储存空间中的媒体文件通过扫描的方式遍历并存储在数据库中,然后通过MediaProvider提供接口使用,在Android多 ...

  7. <Android Framework 之路>Android5.1 Camera Framework(四)——框架总结

    前言 从之前的几篇文件,可以基本弄清楚 Camera从APK,经过framework的衔接,与HAL层进行交互,最终通过驱动完成Camera的一些动作. Camera层次分析 APP层 Framewo ...

  8. <Android Framework 之路>Android5.1 Camera Framework(二)

    上一次讲解了一下CameraService的启动过程,今天梳理一下Camera预览的过程 StartPreview过程 首先,我们还是从应用层的使用入手 Camera.java (packages\a ...

  9. Android Framework 简介

    Android Framework 简介 简介 之前的研究太偏向应用层功能实现了,很多原理不了解没有详记,结果被很多公司技术人员鄙视了,为了减少自己的短板,重新复习了一遍C++.java.Androi ...

随机推荐

  1. git 常用口令

    版本管理 svn git   cd d 切换目录 cd www cd git git clone 一个地址 git status 获取修改的内容 git add * 上传修改的内容 git commi ...

  2. String字符串补位

    String类的format()方法用于创建格式化的字符串以及连接多个字符串对象.熟悉C语言的读者应该记得C语言的sprintf()方法,两者有类似之处.format()方法有两种重载形式. l    ...

  3. JAVA数据结构--优先队列(堆实现)

    优先队列(堆)的定义 堆(英语:Heap)是计算机科学中一类特殊的数据结构的统称.堆通常是一个可以被看做一棵树的数组对象.在队列中,调度程序反复提取队列中第一个作业并运行,因为实际情况中某些时间较短的 ...

  4. centos崩溃后如何修复

    首先看能不能进单用户模式,能进去,就用mount -o remount,rw / 重置成可写的. 不能进单用户模式,就进入光盘救援模式,进去挂载了系统,这时候通常是必要的动态静态库出了问题,先应该做的 ...

  5. iview tree 之如何获取已勾选的节点

    1.记得添加 ref 2.用 this.$refs.tree.getCheckNodes()

  6. 使用Jmeter进行http接口性能测试(转载)

    在进行网页或应用程序后台接口开发时,一般要及时测试开发的接口能否正确接收和返回数据,对于单次测试,Postman插件是个不错的Http请求模拟工具. 但是Postman只能模拟单客户端的单次请求,而对 ...

  7. 008-PageBean类模板

    1 PageBean模板一 package ${enclosing_package}; import java.util.ArrayList; import java.util.List; publi ...

  8. python中函数参数传递的几种方法

    转自  http://www.douban.com/note/13413855/ Python中函数参数的传递是通过“赋值”来传递的.但这条规则只回答了函数参数传递的“战略问题”,并没有回答“战术问题 ...

  9. c#随便写写 数据层和表现层,队列执行

    base.xxx() 调用父类的方法

  10. TCP/IP协议簇分层详解---转

    http://blog.csdn.net/hankscpp/article/details/8611229 一. TCP/IP 和 ISO/OSI ISO/OSI模型,即开放式通信系统互联参考模型(O ...