介绍

开机动画,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. 比较 GET 与 POST

    post比get安全 get请求方法向url添加数据  全部用POST不是十分合理,最好先把请求按功能和场景分下类, 对数据请求频繁,数据不敏感且数据量在普通浏览器最小限定的2k范围内,这样的情况使用 ...

  2. JS 与 OC 交互

    WebView与JS的几种交互 IOS中 使用JavaScriptCore 实现OC与JS的交互 JavaScriptCore 使用

  3. git.exe 妙用

    1.如果 window 上的命令行,在进行编译的不好使 可以尝试在git 中运行 2.运行 python 脚本 ,保持脚本一直执行(尤其是中间出错) 可以做一个 sh 文件,然后在git 中运行 #! ...

  4. 搭建spring boot项目

    1.建立maven项目 点击finish,完成创建maven项目 在pom.xml文件中添加如下代码: <parent> <groupId>org.springframewor ...

  5. 51nod 1943 联通期望 题解【枚举】【二进制】【概率期望】【DP】

    集合统计类期望题目. 题目描述 在一片大海上有 \(n\) 个岛屿,规划建设 \(m\) 座桥,第i座桥的成本为 \(z_i\),但由于海怪的存在,第 \(i\) 座桥有 \(p_i\) 的概率不能建 ...

  6. C++标准库类模板(stack)和 队列(queue)

    在C++标准库(STL)中有栈和队列的类模板,因此可以直接使用 1.栈(stack):使用栈之前,要先包含头文件 : #include<stack> stack.push(elem); / ...

  7. 实现接口必须要加注解@Override吗

    不一定的,但是我们的编译器在查询我们重写的方法,方法名,参数,返回类型的时候,是能够根据注解来帮助我们判断方法重写的正确与否 所以我们有必要在编写过程中加上@Override,虽然我们的eclipse ...

  8. 更新Mac双系统多分区

    前言制作Mac USB系统安装盘安装Mac OS 10.12制作win10 USB系统安装盘安装win10windows多分区实现 前言 同事有一台mac pro,系统是mac os 10.9+win ...

  9. Python与C相互调用、编译

    因为最近学习Boost::python的缘故,想尝试下不同语言之间的相互编译. 参考资料:http://blog.csdn.net/joliny/article/details/2457197. 很吃 ...

  10. Delphi对Word的基本操作

    一.Delphi程序启动Word 采用CreateOleObjects的方法来启动Word,调用VBA代码,具体实现过程为: 首先使用GetActiveOleObject('Word.Applicat ...