|
遇到一個Bug,需要熟悉這個流程,自己不太熟悉Java,只能在網(wǎng)上狂搜資料,總算搞清楚整個流程了,沒想到方向偏了,記錄下來,方便以后復(fù)習(xí)。
以下僅為參考,應(yīng)以實(shí)際代碼分析。
一、Android bootanim 啟動過程:
1、bootanim 服務(wù)在 init.rc 文件里面有描述:
service bootanim /system/bin/bootanimation
class main
user graphics
group graphics
disabled // <---- 一開始要 disable ,原因如下
oneshot
2、初始化surfaceflinger服務(wù)
開機(jī)動畫依賴于 Android 系統(tǒng)的 surface 管理服務(wù),要等待 surfaceflinger
服務(wù)完成后才能顯示開機(jī)動畫。用以下方式啟動開機(jī)動畫
service.bootanim.exit = 0
ctl.start = bootanim
3、當(dāng)System_server啟動系統(tǒng)HomeUI(Launcher)的時候關(guān)閉bootanim
service.bootanim.exit = 1
二、bootanim 啟動框架:
init進(jìn)程 --- surfaceflingerService --> new SurfaceFlinger() --> flinger->init() --> startBootAnim() --> start bootanimation
surfaceflingerService:主要是初始化顯示部分,管理顯示的分層,為顯示開機(jī)動畫做準(zhǔn)備
init進(jìn)程 --- Zygote --> System_service --> ActivityManagerService --> startHomeActivityLocked --> bootFinished --> WindowManagerService
Zygote:主要是創(chuàng)建 java 層所有的服務(wù)和應(yīng)用
System_service:啟動 android java 層所有服務(wù)
ActivityManagerService:用于管理我們的應(yīng)用,最后會調(diào)用 startHomeActivityLocked,從而啟動 系統(tǒng)HomeUI(Launcher)
bootFinished:停止 bootanim 服務(wù),關(guān)閉開機(jī)動畫
三、bootanim 工作流程:
new BootAnimation() --> readyToRun() --> 創(chuàng)建 surface 初始化 opengles --> surfaceflinger Service
readyToRun() --> threadLoop() --> android()/movie() <--> 循環(huán)對圖像處理 --> surfaceflinger Service <--> exit()
android()/movie() : 顯示的內(nèi)容不一樣,兩種顯示方式
四、啟動與關(guān)閉動畫的代碼流程分析,bootanim 服務(wù)一旦被啟動就會刷新開機(jī)動畫
new BootAnimation() --> BootAnimation::BootAnimation() : Thread(false) -->void BootAnimation::onFirstRef()
--> status_t BootAnimation::readyToRun() --> mZip.open(bootanimation.zip) --> bool BootAnimation::threadLoop()
--> bool BootAnimation::movie() --> void BootAnimation::checkExit() --> void Thread::requestExit() --> 退出
android/frameworks/base/cmds/bootanimation/bootanimation_main.cpp
int main(int argc, char** argv)
{
#if defined(HAVE_PTHREADS)
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
#endif
char value[PROPERTY_VALUE_MAX];
// debug.sf.nobootanimation 是否等于 0
property_get("debug.sf.nobootanimation", value, "0");
int noBootAnimation = atoi(value);
ALOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {// 不等于 0 才創(chuàng)建 Binder線程池
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();// <--- 線程池
// create the boot animation object
// 創(chuàng)建這個對象,將會導(dǎo)致 BootAnimation::onFirstRef() 被調(diào)用
sp<BootAnimation> boot = new BootAnimation();// <--- 構(gòu)造函數(shù)被調(diào)用
boot->playBootMusic("/system/media/boot.wav");
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
這個函數(shù)首先檢查系統(tǒng)屬性“debug.sf.nobootnimaition”的值是否不等于0。如果不等于的話,那么接下來就會啟動一個Binder線程池,
并且創(chuàng)建一個BootAnimation對象。這個BootAnimation對象就是用來顯示第三個開機(jī)畫面的。由于BootAnimation對象在顯示第三個
開機(jī)畫面的過程中,需要與SurfaceFlinger服務(wù)通信,因此,應(yīng)用程序bootanimation就需要啟動一個Binder線程池。
BootAnimation類間接地繼承了RefBase類,并且重寫了RefBase類的成員函數(shù)onFirstRef,因此,當(dāng)一個BootAnimation對象第一次被
智能指針引用的時,這個BootAnimation對象的成員函數(shù)onFirstRef就會被調(diào)用。
android/frameworks/base/cmds/bootanimation/bootanimation.cpp
BootAnimation::BootAnimation() : Thread(false)
{
// mSession是BootAnimation類的一個成員變量,它的類型為SurfaceComposerClient,
// 是用來和SurfaceFlinger執(zhí)行Binder進(jìn)程間通信的,
mSession = new SurfaceComposerClient();
mPlayer = NULL;
mBootVideo = false;
if(access(USER_BOOTVIDEO_FILE, R_OK) == 0){
mBootVideo = true;
}
if(access(USER_BOOTMUSIC_FILE, R_OK) == 0){
mPlayer = new MediaPlayer();
}
}
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);// <---- 注冊 SurfaceFlinger 死亡通知
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
run("BootAnimation", PRIORITY_DISPLAY);// 會創(chuàng)建線程
}
}
BootAnimation類繼承了Thread類,因此,當(dāng)BootAnimation類的成員函數(shù)onFirstRef調(diào)用了父類Thread的成員函數(shù)run之后,系統(tǒng)就會創(chuàng)建一個
線程,這個線程在第一次運(yùn)行之前,會調(diào)用BootAnimation類的成員函數(shù)readyToRun來執(zhí)行一些初始化工作,后面再調(diào)用BootAnimation類的成員
函數(shù) threadLoop 來顯示第三個開機(jī)畫面。
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
ISurfaceComposer::eDisplayIdMain));
DisplayInfo dinfo;
// 通過與 Surface 拿到顯示的層
// SurfaceComposerClient 是 surflinger 的客戶端
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
if (status)
return -1;
// create the native surface
// 設(shè)置寬、高、以及顯示的格式
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();
if(mBootVideo)
{
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->checkService(String16("media.player"));
if (binder != 0)
break;
ALOGD("media player not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
mPlayer = new MediaPlayer();
if(mPlayer == NULL)
{
ALOGE("MediaPlayer is null!");
return BAD_VALUE;
}
//mMediaPlayerControl = mp;
mPlayer->setDataSource(USER_BOOTVIDEO_FILE, NULL);
Parcel* _parcel = new Parcel;
mPlayer->setParameter(100, *_parcel);
mPlayer->setVideoSurfaceTexture(s->getSurfaceTexture());
mPlayer->prepare();
mPlayer->start();
while(1)
{
sleep(1000);
}
}
else
{// EGL 初始化代碼
// 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, dummy;
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;
mAndroidAnimation = true;
// 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);
// 打開開機(jī)動畫文件
//#define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"
//#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
//#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
if ((encryptedAnimation &&
(access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
(mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
(mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
(mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
mAndroidAnimation = false;// <--- 會調(diào)用 move() 方法去刷新我們的界面
}
//add to start play music
//this->startBootMusic();
}
return NO_ERROR;
}
/* 刷開機(jī)動畫的線程 */
bool BootAnimation::threadLoop()
{
if(!mBootVideo)
{
bool r;
if (mAndroidAnimation) {// <--- 這里來決定使用哪種顯示方式
r = android(); // <--- 這種就是那個 android 鏤空動畫 該函數(shù)解析并刷新
} else {
r = movie(); // 這個就是顯示我們的開機(jī)動畫
}
// 動畫顯示完之后做清理工作操作
// No need to force exit anymore
property_set(EXIT_PROP_NAME, "0");
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
mFlingerSurface.clear();
mFlingerSurfaceControl.clear();
eglTerminate(mDisplay);
IPCThreadState::self()->stopProcess();
return r;
}
else
{
return true;
}
}
/* 刷新UI的方法 */
bool BootAnimation::movie()
{
ZipFileRO& zip(mZip);
size_t numEntries = zip.getNumEntries();
ZipEntryRO desc = zip.findEntryByName("desc.txt");
FileMap* descMap = zip.createEntryFileMap(desc);
ALOGE_IF(!descMap, "descMap is null");
if (!descMap) {
return false;
}
String8 desString((char const*)descMap->getDataPtr(),
descMap->getDataLength());
char const* s = desString.string();
Animation animation;
// Parse the description file
for (;;) {
const char* endl = strstr(s, "\n");
if (!endl) break;
String8 line(s, endl - s);
const char* l = line.string();
int fps, width, height, count, pause;
char path[256];
char pathType;
// 解析配置文件
if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
//LOGD("> w=%d, h=%d, fps=%d", width, height, fps);
animation.width = width;
animation.height = height;
animation.fps = fps;
}
else if (sscanf(l, " %c %d %d %s", &pathType, &count, &pause, path) == 4) {
//LOGD("> type=%c, count=%d, pause=%d, path=%s", pathType, count, pause, path);
Animation::Part part;
part.playUntilComplete = pathType == 'c';
part.count = count;
part.pause = pause;
part.path = path;
animation.parts.add(part);
}
s = ++endl;
}
// read all the data structures
// 開始獲取圖片的信息,全部加載過來
const size_t pcount = animation.parts.size();
for (size_t i=0 ; i<numEntries ; i++) {
char name[256];
ZipEntryRO entry = zip.findEntryByIndex(i);
if (zip.getEntryFileName(entry, name, 256) == 0) {
const String8 entryName(name);
const String8 path(entryName.getPathDir());
const String8 leaf(entryName.getPathLeaf());
if (leaf.size() > 0) {
for (int j=0 ; j<pcount ; j++) {
if (path == animation.parts[j].path) {
int method;
// supports only stored png files
if (zip.getEntryInfo(entry, &method, 0, 0, 0, 0, 0)) {
if (method == ZipFileRO::kCompressStored) {
FileMap* map = zip.createEntryFileMap(entry);
if (map) {
Animation::Frame frame;
frame.name = leaf;
frame.map = map;
Animation::Part& part(animation.parts.editItemAt(j));
part.frames.add(frame);
}
}
}
}
}
}
}
}
// clear screen
// 清空一下屏幕
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mDisplay, mSurface);
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
const int xc = (mWidth - animation.width) / 2;
const int yc = ((mHeight - animation.height) / 2);
nsecs_t lastFrame = systemTime();
nsecs_t frameDuration = s2ns(1) / animation.fps;
Region clearReg(Rect(mWidth, mHeight));
clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
// 不斷刷新動畫,讓動畫動起來
for (int i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[ i]);
const size_t fcount = part.frames.size();
glBindTexture(GL_TEXTURE_2D, 0);
for (int r=0 ; !part.count || r<part.count ; r++) {
// Exit any non playuntil complete parts immediately
if(exitPending() && !part.playUntilComplete)
break;
for (int j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
const Animation::Frame& frame(part.frames[j]);
nsecs_t lastFrame = systemTime();
if (r > 0) {
glBindTexture(GL_TEXTURE_2D, frame.tid);
} else {
if (part.count != 1) {
glGenTextures(1, &frame.tid);
glBindTexture(GL_TEXTURE_2D, frame.tid);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
initTexture(
frame.map->getDataPtr(),
frame.map->getDataLength());
}
if (!clearReg.isEmpty()) {
Region::const_iterator head(clearReg.begin());
Region::const_iterator tail(clearReg.end());
glEnable(GL_SCISSOR_TEST);
while (head != tail) {
const Rect& r(*head++);
glScissor(r.left, mHeight - r.bottom,
r.width(), r.height());
glClear(GL_COLOR_BUFFER_BIT);
}
glDisable(GL_SCISSOR_TEST);
}
glDrawTexiOES(xc, yc, 0, animation.width, animation.height);
eglSwapBuffers(mDisplay, mSurface);
nsecs_t now = systemTime();
nsecs_t delay = frameDuration - (now - lastFrame);
//ALOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));
lastFrame = now;
if (delay > 0) {
struct timespec spec;
spec.tv_sec = (now + delay) / 1000000000;
spec.tv_nsec = (now + delay) % 1000000000;
int err;
do {
err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
} while (err<0 && errno == EINTR);
}
// 這里來檢查是否退出該動畫,原理是通過檢查 service.bootanim.exit 是否為1
// 為 1 則設(shè)置 mExitPending 為 ture ,讓 exitPending() 返回為 true
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; // 退出刷新動畫的循環(huán)
/*
bool Thread::exitPending() const
{
Mutex::Autolock _l(mLock);
return mExitPending;
}
*/
}
// free the textures for this part
if (part.count != 1) {
for (int j=0 ; j<fcount ; j++) {
const Animation::Frame& frame(part.frames[j]);
glDeleteTextures(1, &frame.tid);
}
}
}
//add to stop boot music
this->stopBootMusic();
return false;
}
/* 檢查是否退出該動畫 */
void BootAnimation::checkExit() {
// Allow surface flinger to gracefully request shutdown
char value[PROPERTY_VALUE_MAX];
// #define EXIT_PROP_NAME "service.bootanim.exit"
// 檢查 service.bootanim.exit 是否為 1 為 1 則退出
property_get(EXIT_PROP_NAME, value, "0");
int exitnow = atoi(value);
if (exitnow) {
requestExit(); // 請求退出
}
}
/* 會設(shè)置 mExitPending 為 true */
void Thread::requestExit()
{
Mutex::Autolock _l(mLock);
mExitPending = true;
}
五、上述開機(jī)動畫流程和退出流程都已經(jīng)描述的很清楚,那什么時候啟動動畫,什么時候關(guān)閉動畫呢?(這個地方有些不太清晰)
從第一點(diǎn)就知道,啟動 startBootAnim 是由 SurfaceFlinger 負(fù)責(zé)。
Zygote進(jìn)程在啟動的過程中,會將System進(jìn)程啟動起來,
System進(jìn)程在啟動的過程中,會調(diào)用SurfaceFlinger類的靜態(tài)成員函數(shù)instantiate來啟動SurfaceFlinger服務(wù)。
status_t system_init() --> SurfaceFlinger::onFirstRef() --> status_t SurfaceFlinger::readyToRun()
--> void SurfaceFlinger::startBootAnim() --> void handle_property_set_fd() --> void handle_control_message(const char *msg, const char *arg)
--> static void msg_start(const char *name) --> 動畫啟動
android/frameworks/base/cmds/system_server/library/system_init.cpp
extern "C" status_t system_init()
{
ALOGI("Entered system_init()");
//...
char propBuf[PROPERTY_VALUE_MAX];
property_get("system_init.startsurfaceflinger", propBuf, "1");
if (strcmp(propBuf, "1") == 0) {
// Start the SurfaceFlinger
SurfaceFlinger::instantiate();// <--- 啟動 SurfaceFlinger 服務(wù)
}
//...
return NO_ERROR;
}
Sytem進(jìn)程在啟動SurfaceFlinger服務(wù)的過程中,首先會創(chuàng)建一個SurfaceFlinger實(shí)例,然后再將這個實(shí)例注冊到
Service Manager中去。在注冊的過程,前面創(chuàng)建的SurfaceFlinger實(shí)例會被一個sp指針引用,當(dāng)一個對象第一次被
智能指針引用的時候,這個對象的成員函數(shù)onFirstRef就會被調(diào)用。由于SurfaceFlinger重寫了父類RefBase的成員
函數(shù)onFirstRef,因此,在注冊SurfaceFlinger服務(wù)的過程中,將會調(diào)用SurfaceFlinger類的成員函數(shù)onFirstRef().
void SurfaceFlinger::onFirstRef()
{
mEventQueue.init(this);
run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
// Wait for the main thread to be done with its initialization
mReadyToRunBarrier.wait(); // 用于同步線程
}
SurfaceFlinger類繼承了Thread類,當(dāng)它的成員函數(shù)run被調(diào)用的時候,系統(tǒng)就會創(chuàng)建一個新的線程。這個線程在第
一次運(yùn)行之前,會調(diào)用SurfaceFlinger類的成員函數(shù)readyToRun來通知SurfaceFlinger,它準(zhǔn)備就緒了。當(dāng)這個線程
準(zhǔn)備就緒之后,它就會循環(huán)執(zhí)行SurfaceFlinger類的成員函數(shù)threadLoop,直到這個成員函數(shù)的返回值等于false為止。
status_t SurfaceFlinger::readyToRun() -> void SurfaceFlinger::startBootAnim()
status_t SurfaceFlinger::readyToRun()
{
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
// initialize EGL for the default display
// 初始化 EGL 獲取默認(rèn)的顯示設(shè)備
// 配置硬件方式
// ...
// We're now ready to accept clients...
mReadyToRunBarrier.open();
// set initial conditions (e.g. unblank default device)
initializeDisplays();
// start boot animation
startBootAnim();// <-- SurfaceFlinger 初始化完之后 啟動開機(jī)動畫
return NO_ERROR;
}
void SurfaceFlinger::startBootAnim() {
// start boot animation
ALOGD("******** void SurfaceFlinger::startBootAnim() ******** zfl");
property_set("service.bootanim.exit", "0");// <-------- 表示不退出
property_set("ctl.start", "bootanim");// <-------- 啟動 bootanim 服務(wù) 進(jìn)入刷開機(jī)動畫流程即第四步
}
通過修改系統(tǒng)屬性,init進(jìn)程就會接收到一個系統(tǒng)屬性變化通知,這個通知最終是由在init進(jìn)程中
的函數(shù)handle_property_set_fd來處理的。
android/system/core/init/property_service.c
/* 系統(tǒng)屬性發(fā)生變動,此函數(shù)被回調(diào) */
void handle_property_set_fd()
{
// ...
switch(msg.cmd) {
case PROP_MSG_SETPROP:
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
#ifdef HAVE_SELINUX
getpeercon(s, &source_ctx);
#endif
// 此處匹配 ctl. 屬性,然后操作(啟動、停止、重啟)它所要求啟動的訪問。
if(memcmp(msg.name,"ctl.",4) == 0) {
// Keep the old close-socket-early behavior when handling
// ctl.* properties.
close(s);
if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);// <-------- 調(diào)用這個函數(shù)去處理
} 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 {
// ...
}
// ...
}
}
/* 操作指定服務(wù) */
void handle_control_message(const char *msg, const char *arg)
{
if (!strcmp(msg,"start")) {
msg_start(arg);// <----- 在這里表示啟動一個服務(wù)
} else if (!strcmp(msg,"stop")) {
msg_stop(arg);// <----- 在這里表示停止一個服務(wù)
} else if (!strcmp(msg,"restart")) {// <----- 標(biāo)識重啟訪問
msg_stop(arg);
msg_start(arg);
} else {// <----- 其他參數(shù)無效
ERROR("unknown control msg '%s'\n", msg);
}
}
/* 啟動、停止、重啟指定服務(wù) */
static void msg_start(const char *name)
{
struct service *svc;
char *tmp = NULL;
char *args = NULL;
// 從 “bootanim” 的服務(wù)的信息
if (!strchr(name, ':'))
svc = service_find_by_name(name);
else {
tmp = strdup(name);
args = strchr(tmp, ':');
*args = '\0';
args++;
svc = service_find_by_name(tmp);
}
// 啟動該服務(wù)
if (svc) {
service_start(svc, args);
} else {
ERROR("no such service '%s'\n", name);
}
if (tmp)
free(tmp);
}
當(dāng)系統(tǒng)啟動了Home UI 時(即Launcher),就會通知 SurfaceFlinger , SurfaceFlinger 的bootFinished() 被調(diào)用。
因?yàn)樯婕暗搅硗庖粋知識點(diǎn),此處忽略了這部分細(xì)節(jié),
void SurfaceFlinger::bootFinished()
{
char srcPath[30]="/data/displaysetmode";
FILE *srcFp;
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mBootFinished = true;
// wait patiently for the window manager death
const String16 name("window");
sp<IBinder> window(defaultServiceManager()->getService(name));
if (window != 0) {
window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
// 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.
// <--- 這里設(shè)置 為 1,剛剛好符合第四步所描述的,void BootAnimation::checkExit()
property_set("service.bootanim.exit", "1");
char value[PROPERTY_VALUE_MAX];
if((srcFp = fopen(srcPath, "r")) == NULL){
ALOGE("#####cannot open file %s to read#####",srcPath);
}
else
{
char type[4] = "";
char format[4] = "";
int len1 = 4;
int len2 = 4;
fgets(type,len1,srcFp);
fgets(format,len2,srcFp);
int outtype = atoi(type);
int outformat = atoi(format);
ALOGD("####read file %s, outtype is %d, outformat is %d",srcPath,outtype,outformat);
if(outtype >= 0 && outformat >= 0){
setDisplayProp(DISPLAY_CMD_SETDISPPARA,0,outtype,outformat);
setDisplayProp(DISPLAY_CMD_SETDISPMODE,DISPLAY_MODE_SINGLE_VAR_FE,0,0);
}
fclose(srcFp);
}
}
|
|