找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5678|回复: 0
打印 上一主题 下一主题
收起左侧

Android 4.2 开机动画流程代码解析

[复制链接]
跳转到指定楼层
楼主
ID:91350 发表于 2015-9-30 00:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
     遇到一个Bug,需要熟悉这个流程,自己不太熟悉Java,只能在网上狂搜资料,总算搞清楚整个流程了,没想到方向偏了,记录下来,方便以后复习。

以下仅为参考,应以实际代码分析。


一、Android bootanim 启动过程:
1、bootanim 服务在 init.rc 文件里面有描述:
service bootanim /system/bin/bootanimation
    class main
    user graphics
    group graphics
    disabled   // <---- 一开始要 disable ,原因如下
    oneshot

2、初始化surfaceflinger服务
开机动画依赖于 Android 系统的 surface 管理服务,要等待 surfaceflinger
服务完成后才能显示开机动画。用以下方式启动开机动画
service.bootanim.exit = 0
ctl.start = bootanim

3、当System_server启动系统HomeUI(Launcher)的时候关闭bootanim
service.bootanim.exit = 1

二、bootanim 启动框架:
init进程 --- surfaceflingerService --> new SurfaceFlinger() --> flinger->init() --> startBootAnim() --> start bootanimation
surfaceflingerService:主要是初始化显示部分,管理显示的分层,为显示开机动画做准备

init进程 --- Zygote --> System_service --> ActivityManagerService --> startHomeActivityLocked --> bootFinished --> WindowManagerService
Zygote:主要是创建 java 层所有的服务和应用
System_service:启动 android java 层所有服务
ActivityManagerService:用于管理我们的应用,最后会调用 startHomeActivityLocked,从而启动 系统HomeUI(Launcher)
bootFinished:停止 bootanim 服务,关闭开机动画

三、bootanim 工作流程:
new BootAnimation() --> readyToRun() --> 创建 surface 初始化 opengles --> surfaceflinger Service
readyToRun() --> threadLoop() --> android()/movie() <--> 循环对图像处理 --> surfaceflinger Service <--> exit()
android()/movie() : 显示的内容不一样,两种显示方式

四、启动与关闭动画的代码流程分析,bootanim 服务一旦被启动就会刷新开机动画
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 才创建 Binder线程池

        sp<ProcessState> proc(ProcessState::self());
        ProcessState::self()->startThreadPool();// <--- 线程池

        // create the boot animation object
// 创建这个对象,将会导致 BootAnimation::onFirstRef() 被调用
        sp<BootAnimation> boot = new BootAnimation();// <--- 构造函数被调用
        boot->playBootMusic("/system/media/boot.wav");
        IPCThreadState::self()->joinThreadPool();

    }
    return 0;
}
这个函数首先检查系统属性“debug.sf.nobootnimaition”的值是否不等于0。如果不等于的话,那么接下来就会启动一个Binder线程池,
并且创建一个BootAnimation对象。这个BootAnimation对象就是用来显示第三个开机画面的。由于BootAnimation对象在显示第三个
开机画面的过程中,需要与SurfaceFlinger服务通信,因此,应用程序bootanimation就需要启动一个Binder线程池。
BootAnimation类间接地继承了RefBase类,并且重写了RefBase类的成员函数onFirstRef,因此,当一个BootAnimation对象第一次被
智能指针引用的时,这个BootAnimation对象的成员函数onFirstRef就会被调用。

android/frameworks/base/cmds/bootanimation/bootanimation.cpp
BootAnimation::BootAnimation() : Thread(false)
{
   // mSession是BootAnimation类的一个成员变量,它的类型为SurfaceComposerClient,
   // 是用来和SurfaceFlinger执行Binder进程间通信的,
    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);// 会创建线程
    }
}
BootAnimation类继承了Thread类,因此,当BootAnimation类的成员函数onFirstRef调用了父类Thread的成员函数run之后,系统就会创建一个
线程,这个线程在第一次运行之前,会调用BootAnimation类的成员函数readyToRun来执行一些初始化工作,后面再调用BootAnimation类的成员
函数 threadLoop 来显示第三个开机画面。

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
    // 设置宽、高、以及显示的格式
    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);
// 打开开机动画文件
//#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;// <--- 会调用 move() 方法去刷新我们的界面
    }
   
    //add to start play music
    //this->startBootMusic();
}

    return NO_ERROR;
}
/* 刷开机动画的线程 */
bool BootAnimation::threadLoop()
{
if(!mBootVideo)
{
bool r;
    if (mAndroidAnimation) {// <--- 这里来决定使用哪种显示方式
        r = android(); // <--- 这种就是那个 android 镂空动画 该函数解析并刷新
    } else {
        r = movie(); // 这个就是显示我们的开机动画
    }

// 动画显示完之后做清理工作操作
    // 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 则设置 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; // 退出刷新动画的循环
/*
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(); // 请求退出
    }
}
/* 会设置 mExitPending 为 true */
void Thread::requestExit()
{
    Mutex::Autolock _l(mLock);
    mExitPending = true;
}

五、上述开机动画流程和退出流程都已经描述的很清楚,那什么时候启动动画,什么时候关闭动画呢?(这个地方有些不太清晰)
从第一点就知道,启动 startBootAnim 是由 SurfaceFlinger 负责。
Zygote进程在启动的过程中,会将System进程启动起来,
System进程在启动的过程中,会调用SurfaceFlinger类的静态成员函数instantiate来启动SurfaceFlinger服务。

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 服务
    }

//...

    return NO_ERROR;
}

Sytem进程在启动SurfaceFlinger服务的过程中,首先会创建一个SurfaceFlinger实例,然后再将这个实例注册到
Service Manager中去。在注册的过程,前面创建的SurfaceFlinger实例会被一个sp指针引用,当一个对象第一次被
智能指针引用的时候,这个对象的成员函数onFirstRef就会被调用。由于SurfaceFlinger重写了父类RefBase的成员
函数onFirstRef,因此,在注册SurfaceFlinger服务的过程中,将会调用SurfaceFlinger类的成员函数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类,当它的成员函数run被调用的时候,系统就会创建一个新的线程。这个线程在第
一次运行之前,会调用SurfaceFlinger类的成员函数readyToRun来通知SurfaceFlinger,它准备就绪了。当这个线程
准备就绪之后,它就会循环执行SurfaceFlinger类的成员函数threadLoop,直到这个成员函数的返回值等于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 获取默认的显示设备
// 配置硬件方式
   
// ...


    // We're now ready to accept clients...
    mReadyToRunBarrier.open();

    // set initial conditions (e.g. unblank default device)
    initializeDisplays();

    // start boot animation
    startBootAnim();// <-- SurfaceFlinger 初始化完之后 启动开机动画

    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 服务 进入刷开机动画流程即第四步
}

通过修改系统属性,init进程就会接收到一个系统属性变化通知,这个通知最终是由在init进程中
的函数handle_property_set_fd来处理的。

android/system/core/init/property_service.c
/* 系统属性发生变动,此函数被回调 */
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);// <--------  调用这个函数去处理
            } 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 {
// ...
        }
// ...
    }
}
/* 操作指定服务 */
void handle_control_message(const char *msg, const char *arg)
{
    if (!strcmp(msg,"start")) {
        msg_start(arg);// <----- 在这里表示启动一个服务
    } else if (!strcmp(msg,"stop")) {
        msg_stop(arg);// <----- 在这里表示停止一个服务
    } else if (!strcmp(msg,"restart")) {// <----- 标识重启访问
        msg_stop(arg);
        msg_start(arg);
    } else {// <----- 其他参数无效
        ERROR("unknown control msg '%s'\n", msg);
    }
}
/* 启动、停止、重启指定服务 */
static void msg_start(const char *name)
{
    struct service *svc;
    char *tmp = NULL;
    char *args = NULL;
// 从 “bootanim” 的服务的信息
    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);
    }
// 启动该服务
    if (svc) {
        service_start(svc, args);
    } else {
        ERROR("no such service '%s'\n", name);
    }
    if (tmp)
        free(tmp);
}

当系统启动了Home UI 时(即Launcher),就会通知 SurfaceFlinger , SurfaceFlinger 的bootFinished() 被调用。
因为涉及到另外一个知识点,此处忽略了这部分细节,
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.
// <--- 这里设置 为 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 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表