久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6259|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

Android 4.2 開機(jī)動畫流程代碼解析

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:91350 發(fā)表于 2015-9-30 00:53 | 只看該作者 回帖獎勵 |倒序?yàn)g覽 |閱讀模式
     遇到一個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);
    }
}


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 亚洲日本一区二区 | 日韩视频一区在线观看 | 色资源在线视频 | 一区二区三区在线免费观看 | 欧美中文字幕一区二区三区亚洲 | 美女黄色在线观看 | 久久久久久天堂 | 完全免费在线视频 | 日本一区二区三区四区 | 欧美日韩一二三区 | 国产精品欧美一区二区三区 | 天天拍天天操 | 久草色视频 | 国产成人在线免费 | 久久久国产一区二区 | 欧美不卡一区二区三区 | 99色播| 午夜精品久久久 | 日本精品一区二区三区视频 | 色综合99 | 激情久久av一区av二区av三区 | 一级做a| 欧美日本在线 | 亚洲一区二区三区四区在线观看 | 久久99深爱久久99精品 | 亚洲一区二区三区四区五区午夜 | 成人免费日韩 | 精品入口麻豆88视频 | 午夜成人免费视频 | 国内自拍第一页 | 九九九视频在线 | 国产激情精品 | 日韩在线欧美 | 三级黄色片在线播放 | www日日日| 天天色影视综合 | 老妇激情毛片免费 | 亚洲一区成人 | 亚洲在线免费 | 精品国产区 | 色综合视频 |