介绍:Android开机动画是相对简单的逻辑,其中主要代码也不到两百行,但开机动画进程的启动用到了其他进程启动类似的逻辑。这里分析清楚了之后,后面其他进程启动就更加容易理解
1. surfaceflinger启动
为什么要先从surfaceflinger开始呢?
因为surfaceflinger是设备显示模块,而开机动画必定跟显示有关,所以先从surfaceflinger看是否有和开机启动有关的逻辑
启动进程应该都能知道从哪里启动,必定是***.rc文件中启动,这里是surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger
class core animation
user system
group graphics drmrpc readproc
capabilities SYS_NICE
onrestart restart --only-if-running zygote
task_profiles HighPerformance
surfacegflinger启动之后,必定要看surfaceflinger的main方法;在源码的这个路径下
frameworks\native\services\surfaceflinger\main_surfaceflinger.cpp
//删除了跟开机启动无关的代码,这里主要就是设置线程池,给surfaceflinger添加到ServiceManager;
//以及开始执行surfaceflinger相关代码 flinger->init();和flinger->run();
int main(int, char**) {
ProcessState::self()->setThreadPoolMaxThreadCount(4);
// start the thread pool
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
// initialize before clients can connect
flinger->init();
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
flinger->run();
return 0;
}
这里就是执行到frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp
先看init方法
//这里和开机有关的是StartPropertySetThread,相当于一个线程,这里开启的一个线程,并调用start方法
void SurfaceFlinger::init() {
if (getHwComposer().hasCapability(
HWC2::Capability::PresentFenceIsNotReliable)) {
mStartPropertySetThread = new StartPropertySetThread(false);
} else {
mStartPropertySetThread = new StartPropertySetThread(true);
}
if (mStartPropertySetThread->Start() != NO_ERROR) {
ALOGE("Run StartPropertySetThread failed!");
}
}
// \frameworks\native\services\surfaceflinger\StartPropertySetThread.cpp
//其头文件中,继承自Thread 也就是:class StartPropertySetThread : public Thread
//这里mStartPropertySetThread->Start()直接调用了线程的run方法,
// 这里开始后就会执行threadLoop方法,这个我们先记住,后面有空再分析下native的Thread类
status_t StartPropertySetThread::Start() {
return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
}
bool StartPropertySetThread::threadLoop() {
//这里设置了两个属性
property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
property_set("service.bootanim.exit", "0");
//设置了这个属性后,意味着开机动画就可以启动了
property_set("ctl.start", "bootanim");
return false;
}
为什么设置了service.bootanim.exit和ctl.start这两个属性后,开机动画就启动了呢?
这里先记录下,我们接着看
2. init进程
我们都知道,init进程是Android启动的第一个进程,比zygote还要早。 我们看下init进程里和开机动画相关的逻辑
// \system\core\init\init.cpp
int main(int argc, char** argv) {
//其他的逻辑先不看,我们先看下与开机启动动画相关的逻辑
start_property_service();
return 0;
}
// \system\core\init\property_service.cpp
//这里相当于创建了一个socket(用于跨进程通讯)
void start_property_service() {
property_set("ro.property_service.version", "2");
property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
false, 0666, 0, 0, nullptr, sehandle);
if (property_set_fd == -1) {
PLOG(ERROR) << "start_property_service socket creation failed";
exit(1);
}
//这里接收了其他进程的socket发来了消息,然后执行handle_property_set_fd这个方法
listen(property_set_fd, 8);
register_epoll_handler(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);
break;
}
}
}
static void handle_property_set(SocketConnection& socket,
const std::string& name,
const std::string& value,
bool legacy_protocol) {
if (android::base::StartsWith(name, "ctl.")) {
if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
//根据逻辑判断,会走到这里
handle_control_message(name.c_str() + 4, value.c_str());
}
}
}
// \system\core\init\init.cpp
void handle_control_message(const std::string& msg, const std::string& name) {
//这里就是开机动画相关的进程启动,就进入bootanimation进程
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 << "'";
}
}
3. bootanimation进程
// \frameworks\base\cmds\bootanimation\bootanimation_main.cpp
这里进入bootanimation进程后,就开始执行开机动画
int main()
{
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
bool noBootAnimation = bootAnimationDisabled();
ALOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
waitForSurfaceFlinger();
// create the boot animation object
sp<BootAnimation> boot = new BootAnimation(new AudioAnimationCallbacks());
ALOGV("Boot animation set up. Joining pool.");
IPCThreadState::self()->joinThreadPool();
}
ALOGV("Boot animation exit");
return 0;
}
到这里有点乱了,稍微整理一下
- 首先应该是init进程启动,
- 接着应该是surfaceflinger进程启动,
- init进程启动的时候为什么不直接启动bootanimation进程呢,因为开机动画需要surfaceflinger进程,所以要等surfaceflinger进程启动完成之后,才能启动bootanimation进程,并执行开机动画
- 所以init进程就有了一个socket,用于监听surfaceflinger进程传递过来的消息
- 也就是说surfaceflinger进程启动结束后,会发送给init进程一个消息,让init进程去启动开机动画
画一个图解释一下