介绍: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进程去启动开机动画
画一个图解释一下