bootanimation frameworks/base/cmds/bootanimation/
surfaceflinger frameworks/native/services/surfaceflinger/
init system/core/init/
内核起来后会启动第一个进程,即init进程。
init进程会根据init.rc配置启动surfaceflinger进程
surfaceflinger代码路径中有surfaceflinger.rc
surfaceflinger进程便启动了,跟着就会跑进程的main()函数。
顺便说一句bootanimation里面也有一个bootanim.rc文件,但是里面有个disabled,因此init.rc执行时,不会启动bootanimation进程,什么时候启动请看后文
frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
int main(int, char**) {
startHidlServices();
signal(SIGPIPE, SIG_IGN);
// 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();
setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
set_sched_policy(0, SP_FOREGROUND);
// Put most SurfaceFlinger threads in the system-background cpuset
// Keeps us from unnecessarily using big cores
// Do this after the binder thread pool init
if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);
// initialize before clients can connect
flinger->init();
// publish surface flinger
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
// publish GpuService
sp<GpuService> gpuservice = new GpuService();
sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
struct sched_param param = {0};
param.sched_priority = 2;
if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) {
ALOGE("Couldn't set SCHED_FIFO");
}
// run surface flinger in this thread
flinger->run();
return 0;
}
这段代码的核心部分,首先new一个SurfaceFlinger实例 sp
(这个SurfaceFlinger是#include "SurfaceFlinger.h"
,正真的实现是在SurfaceFlinger.cpp中),初始化flinger->init();
(SurfaceFlinger.cpp中的init方法),然后注册到service manager里sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
,最后在这个线程中运行SurfaceFlingerflinger->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 H/W...");
ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
......
// 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) {
ALOGE("Run StartPropertySetThread failed!");
}
ALOGV("Done initializing");
}
初始化graphics之后,创建StartPropertySetThread对象,mStartPropertySetThread->Start()
启动设置bootanimation的属性线程,下面我们继续看看StartPropertySetThread做了什么
frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp
#include
#include "StartPropertySetThread.h"
namespace android {
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("service.bootanim.exit", "0");
// Start BootAnimation if not started
property_set("ctl.start", "bootanim");
// Exit immediately
return false;
}
} // namespace android
之前我们提到过看开机动画的bootanim.rc文件可以看到,其默认是disable的,也就是说,开机动画进程,默认是不会自启动的,需要有其他地方(即StartPropertySetThread)来触发而通过此处的ctl.start属性,能够触发bootanim进程,从而开始显示开机动画
从代码中可以看出StartPropertySetThread主要设置了开机动画相关的关键属性。property_set("service.bootanim.exit", "0")
设置service.bootanim.exit 为0,该属性值决定开机动画是否退出,然后通过property_set("ctl.start", "bootanim")
启动bootanim service。
为什么设置一个属性bootanim进程就会启动了呢?
当系统属性发生改变时,init进程就会接收到一个系统属性变化通知,这个通知最终是由在init进程中的函数handle_property_set_fd来处理。下面我们来看看init的main方法
system/core/init/init.cpp
int main(int argc, char** argv) {
......
property_init();
......
signal_handler_init();
property_load_boot_defaults();
export_oem_lock_status();
start_property_service();
set_usb_controller();
......
return 0;
}
这个方法中property_init()
对属性服务进行初始化,然后start_property_service()
启动属性的service。
system/core/init/property_service.cpp
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);
}
listen(property_set_fd, 8);
register_epoll_handler(property_set_fd, handle_property_set_fd);
}
在init进程中创建了一个CreateSocket用于跨进程通信,并且使用listen(property_set_fd, 8)
监听,
register_epoll_handler(property_set_fd, handle_property_set_fd)
使用epoll机制来轮询事件,其中一个事件是系统属性值被修改。得到该事件后,会执行handle_property_set_fd()。
简而言之,以我们的开机动画为例,假如有用进程对之前提到的设置动画的属性感兴趣就接受并处理。
handle_property_set_fd方法仍在property_service.cpp中
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;
}
case PROP_MSG_SETPROP2: {
std::string name;
std::string value;
if (!socket.RecvString(&name, &timeout_ms) ||
!socket.RecvString(&value, &timeout_ms)) {
PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
socket.SendUint32(PROP_ERROR_READ_DATA);
return;
}
handle_property_set(socket, name, value, false);
break;
}
default:
LOG(ERROR) << "sys_prop: invalid command " << cmd;
socket.SendUint32(PROP_ERROR_INVALID_CMD);
break;
}
}
这些case都执行了handle_property_set
方法,继续跟踪该方法。
该方法同样在property_service.cpp中
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());
if (!legacy_protocol) {
socket.SendUint32(PROP_SUCCESS);
}
} else {
LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
<< " service ctl [" << value << "]"
<< " uid:" << cr.uid
<< " gid:" << cr.gid
<< " pid:" << cr.pid;
if (!legacy_protocol) {
socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
}
}
} else {
......
}
freecon(source_ctx);
}
android::base::StartsWith(name, "ctl.")
从这里我们可以看出是在匹配条件,前面动画设置的属性是property_set("ctl.start", "bootanim")
,正好匹配。 该函数会进一步执行handle_control_message(name.c_str() + 4, value.c_str())
,启动开机动画会传入的参数name.c_str() + 4=start,value.c_str()=bootanim。
继续看这个方法做了什么。
/system/core/init/init.cpp
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 << "'";
}
}
前面调用handle_control_message(name.c_str() + 4, value.c_str())
,传递实参是start,bootanim,即对应这个方法中的形参msg,name
ServiceManager::GetInstance().FindServiceByName(name)
找到对应的Service* 对象,从service_list中查询要启动的服务是否有存在,若存在,返回服务的相关信息。因为init.rc中有bootanimation的定义,因此在init进程执行parse_config()时,会将该服务添加到service_list中。这里的name是bootanim如果找到了该服务,就调用start启动服务,首先会执行bootanimation_main.cpp中的main方法。