总体流程
涉及代码路径
bootanimation frameworks/base/cmds/bootanimation/ surfaceflinger frameworks/native/services/surfaceflinger/ init system/core/init/
流程详细分析
注:新的框架代码中的有些方法名可能统一改为了驼峰法,但是大体流程相同
1.init进程启动
内核起来后会启动第一个进程,即init进程。
init进程会根据init.rc配置启动surfaceflinger进程
surfaceflinger代码路径中有surfaceflinger.rc
surfaceflinger进程便启动了,跟着就会跑进程的main()函数。
顺便说一句bootanimation里面也有一个bootanim.rc文件,但是里面有个disabled,因此init.rc执行时,不会启动bootanimation进程,什么时候启动请看后文
2.SurfaceFlinger进程启动
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> flinger = new SurfaceFlinger();(这个SurfaceFlinger是#include "SurfaceFlinger.h",正真的实现是在SurfaceFlinger.cpp中),初始化flinger->init();(SurfaceFlinger.cpp中的init方法),然后注册到service manager里sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);,最后在这个线程中运行SurfaceFlingerflinger->run();
2.SurfaceFlinger初始化和启动StartPropertySetThread线程
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做了什么
3.StartPropertySetThread线程执行和设置动画属性
frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp
#include <cutils/properties.h>
#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。
4.通知init进程启动bootanim服务
为什么设置一个属性bootanim进程就会启动了呢? 当系统属性发生改变时,init进程就会接收到一个系统属性变化通知,这个通知最终是由在init进程中的函数handle_property_set_fd来处理。下面我们来看看init的main方法
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。
start_property_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()
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方法,继续跟踪该方法。
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。
继续看这个方法做了什么。
handle_control_message()
/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方法。
5.bootanimation的实现
执行bootanimation的main方法
/frameworks/base/cmds/bootanimation/bootanimation_main.cpp
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;
}
bootAnimationDisabled()用于判断开机动画是否被禁止,若未被禁止即noBootAnimation值为false(一般都为false,后面介绍bootAnimationDisabled方法),则走到条件中。
这个里面主要进行启动线程池,用于初始化binder线程,用于surfaceflinger通信。等待SurfaceFlinger起来后,创建BootAnimation对象
frameworks/base/cmds/bootanimation/BootAnimationUtil.cpp
bool bootAnimationDisabled() {
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.nobootanimation", value, "0");
if (atoi(value) > 0) {
return true;
}
property_get("ro.boot.quiescent", value, "0");
return atoi(value) > 0;
}
属性值debug.sf.nobootanimation和ro.boot.quiescent决定开机动画是否禁止,从代码中可以看到,两个属性的值默认为0,atoi(value) > 0即0>0为return false,因此前面main方法中变量noBootAnimation的值为false
创建BootAnimation对象
/frameworks/base/cmds/bootanimation/BootAnimation.cpp
BootAnimation::BootAnimation(sp<Callbacks> callbacks)
: Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
mTimeFormat12Hour(false), mTimeCheckThread(NULL), mCallbacks(callbacks) {
mSession = new SurfaceComposerClient();
std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
if (powerCtl.empty()) {
mShuttingDown = false;
} else {
mShuttingDown = true;
}
}
在构造方法中,创建SurfaceComposerClient用于与SurfaceFlinger跨进程通信。获取了一个用于判断开关机状态的属性sys.powerctl
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
run("BootAnimation", PRIORITY_DISPLAY);
}
}
sp<BootAnimation> boot = new BootAnimation(new AudioAnimationCallbacks());前面创建BootAnimation对象时是sp(智能指针,强指针)方式创建,onFirstRef()属于其父类RefBase,该函数在强引用sp新增引用计数时,第一次强引用会自动调用此函数。因此创建BootAnimation对象时除了会调用自身构造方法以外,还会调用onFirstRef()。
这里执行一个run方法,是调用了Thread的run方法,因为BootAnimation.h文件中发现BootAnimation继承了Thread
/frameworks/base/cmds/bootanimation/BootAnimation.h
class BootAnimation : public Thread, public IBinder::DeathRecipient {...}
system/core/libutils/Threads.cpp
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
...
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,//创建线程
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
....
}
在run方法中创建了_threadLoop线程
int Thread::_threadLoop(void* user)
{
....
do {
bool result;
if (first) {
first = false;
self->mStatus = self->readyToRun();//被bootanimation重写
result = (self->mStatus == NO_ERROR);
if (result && !self->exitPending()) {
...
result = self->threadLoop();//被bootanimation重写
}
} else {
result = self->threadLoop();
}
...
return 0;
}
从代码流程上可以看出先执行readyToRun(),再执行threadLoop(),其中这两个方法均被bootanimation重写
readyToRun()函数实现
/frameworks/base/cmds/bootanimation/BootAnimation.cpp
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
ISurfaceComposer::eDisplayIdMain));
DisplayInfo dinfo;
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
if (status)
return -1;
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
SurfaceComposerClient::closeGlobalTransaction();
sp<Surface> s = control->getSurface();
//上面的代码简而言之,就是获取了一个画布,用于在屏幕上绘制内容
// initialize opengl and egl
const EGLint attribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 0,
EGL_NONE
};
EGLint w, h;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
surface = eglCreateWindowSurface(display, config, s.get(), NULL);
context = eglCreateContext(display, config, NULL, NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
return NO_INIT;
mDisplay = display;
mContext = context;
mSurface = surface;
mWidth = w;
mHeight = h;
mFlingerSurfaceControl = control;
mFlingerSurface = s;
//以上内容均为opengl初始化
// If the device has encryption turned on or is in process
// of being encrypted we show the encrypted boot animation.
char decrypt[PROPERTY_VALUE_MAX];
property_get("vold.decrypt", decrypt, "");
bool encryptedAnimation = atoi(decrypt) != 0 ||
!strcmp("trigger_restart_min_framework", decrypt);
if (!mShuttingDown && encryptedAnimation &&
(access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
return NO_ERROR;
}
static const char* bootFiles[] = {OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE};
static const char* shutdownFiles[] =
{OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE};
//通过开关机状态判断使用哪个动画文件
//mShuttingDown变量,见Bootanimation构造方法
//bootFiles开机文件,shutdownFiles关机文件
for (const char* f : (!mShuttingDown ? bootFiles : shutdownFiles)) {
if (access(f, R_OK) == 0) { //判断文件是否存在
mZipFileName = f; //存在则赋值,使用此路径动画
return NO_ERROR;
}
}
return NO_ERROR;
}
//开机动画路径
static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
//默认动画路径(开机和关机动画文件没有时,使用)
static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
//关机动画路径
static const char OEM_SHUTDOWNANIMATION_FILE[] = "/oem/media/shutdownanimation.zip";
static const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";
通过修改路径中的文件来自定义开机动画
threadLoop()函数实现
/frameworks/base/cmds/bootanimation/BootAnimation.cpp
bool BootAnimation::threadLoop()
{
bool r;
// We have no bootanimation file, so we use the stock android logo
// animation.
if (mZipFileName.isEmpty()) {
r = android();
} else {
r = movie();
}
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
mFlingerSurface.clear();
mFlingerSurfaceControl.clear();
eglTerminate(mDisplay);
eglReleaseThread();
IPCThreadState::self()->stopProcess();
return r;
}
如果mZipFileName 为空,则执行android(),即显示默认的Android动画;不为空,则执行movie(),即显示自定义动画。
android()
bool BootAnimation::android()
{
ALOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
elapsedRealtime());
initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
mCallbacks->init({});
// clear screen
......
do {
......
checkExit();
} while (!exitPending());
glDeleteTextures(1, &mAndroid[0].name);
glDeleteTextures(1, &mAndroid[1].name);
return false;
}
movie()
bool BootAnimation::movie()
{
Animation* animation = loadAnimation(mZipFileName);
......
// Check if npot textures are supported
......
// Blend required to draw time on top of animation frames.
......
playAnimation(*animation);
......
releaseAnimation(animation);
......
}
bool BootAnimation::playAnimation(const Animation& animation)
{
const size_t pcount = animation.parts.size();
nsecs_t frameDuration = s2ns(1) / animation.fps;
const int animationX = (mWidth - animation.width) / 2;
const int animationY = (mHeight - animation.height) / 2;
ALOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
elapsedRealtime());
for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size();
glBindTexture(GL_TEXTURE_2D, 0);
// Handle animation package
if (part.animation != NULL) {
playAnimation(*part.animation);
if (exitPending())
break;
continue; //to next part
}
for (int r=0 ; !part.count || r<part.count ; r++) {
// Exit any non playuntil complete parts immediately
......
for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
......
checkExit();
}
usleep(part.pause * ns2us(frameDuration));
// For infinite parts, we've now played them at least once, so perhaps exit
if(exitPending() && !part.count)
break;
}
}
// Free textures created for looping parts now that the animation is done.
......
return true;
}
movie()调用了playAnimation方法,该方法调用了checkExit方法。 无论是android()还是movie(),都会调用checkExit(),这里我们主要关注一下checkExit(),该方法用于检测是否退出动画
检测是否退出动画
void BootAnimation::checkExit() {
// Allow surface flinger to gracefully request shutdown
char value[PROPERTY_VALUE_MAX];
property_get(EXIT_PROP_NAME, value, "0");
int exitnow = atoi(value);
if (exitnow) {
requestExit();
mCallbacks->shutdown();
}
}
获取EXIT_PROP_NAME属性值,根据属性值判断当前是否退出动画。EXIT_PROP_NAME对应的属性就是service.bootanim.exit
static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
前面我们讲StartPropertySetThread::threadLoop()方法时,里面曾有property_set("service.bootanim.exit", "0"),即设置属性service.bootanim.exit值为0。从判断条件if (exitnow)可以看出,属性service.bootanim.exit值为0时,不退出,即非0时退出。
关于这个requestExit() 和exitPending()可以参考blog.csdn.net/llping2011/… 大致意思就是mExitPendding = true 这个变量值由Thread类的requestExit函数设置,即调用requestExit() ,则exitPending()就会返回true.
通过查找代码,我们发现在WindowManagerService.java和SurfaceFlinger.cpp中有设置service.bootanim.exit值为1,退出动画。
注:surfaceflinger.cpp应用是android原生的;SurfaceFlinger_hwc1.cpp这个应该是不同平台自己定义的。有了解这块的朋友可以在评论区补充一下。
6.开机动画结束流程
优先看下java代码 /frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private void performEnableScreen() {
synchronized(mWindowMap) {
if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
+ " mForceDisplayEnabled=" + mForceDisplayEnabled
+ " mShowingBootMessages=" + mShowingBootMessages
+ " mSystemBooted=" + mSystemBooted
+ " mOnlyCore=" + mOnlyCore,
new RuntimeException("here").fillInStackTrace());
......
if (!mBootAnimationStopped) {
Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
// stop boot animation
// formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation.
SystemProperties.set("service.bootanim.exit", "1");
mBootAnimationStopped = true;
}
......
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
data, null, 0);
data.recycle();
}
} catch (RemoteException ex) {
Slog.e(TAG_WM, "Boot completed: SurfaceFlinger is dead!");
}
}
......
}
这里可以直接打印堆栈进行跟踪performEnableScreen(),找到其调用源头。
这里先简述一下流程,有时间在补充
首先进入idle,然后跨进程调用到AMS中,执行了postFinishBooting,在调用到WMS中的performEnableScreen,此时会判断条件if (!mBootAnimationStopped),然后执行SystemProperties.set("service.bootanim.exit", "1");,即设置动画退出。
在代码中还有一句IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger")这里是跨进程通信,
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
data, null, 0);
跨进程调用到SurfaceFlinger,通过FIRST_CALL_TRANSACTION,找到对应的是SurfaceFlinger.cpp的status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)这个方法。
最终会在SurfaceFlinger执行prop的设置,也就是我们之前在SurfaceFlinger.cpp文件中看到的property_set("service.bootanim.exit", "1")。
详细流程可以参考:
blog.csdn.net/ahaochina/a…
blog.csdn.net/xlnaan/arti…