• <Android Framework 之路>BootAnimation(1)


    介绍

    开机动画,BootAnimation,就是Android手机开机郭晨各种以一个展示给用户的界面,实际是一个多个帧组成的动画,在界面上进行一帧一帧的播放,形成开机动画的效果。

    本文针对Android5.1源码分析BootAnimation


    源码分析

    1. 文件产生

    Android平台的开机动画由system/bin下的bootanimation文件完成,而这个文件产生于
    frameworks/base/cmds/bootanimation/Android.mk

    LOCAL_PATH:= $(call my-dir)
    include $(CLEAR_VARS)
    
    LOCAL_SRC_FILES:= 
        bootanimation_main.cpp 
        AudioPlayer.cpp 
        BootAnimation.cpp
    
    LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
    
    LOCAL_C_INCLUDES += external/tinyalsa/include
    
    LOCAL_SHARED_LIBRARIES := 
        libcutils 
        liblog 
        libandroidfw 
        libutils 
        libbinder 
        libui 
        libskia 
        libEGL 
        libGLESv1_CM 
        libgui 
        libtinyalsa
    
    LOCAL_MODULE:= bootanimation
    
    ifdef TARGET_32_BIT_SURFACEFLINGER
    LOCAL_32_BIT_ONLY := true
    endif
    include $(BUILD_EXECUTABLE)

    编译结果为bootanimation的bin文件,所以,在有足够权限的前提下,在adb shell下执行bootanimation也是可以看到对应的开机动画效果的。

    2. 启动开机动画

    开机动画是以bin文件的形式存在于手机系统中,开机过程中通过init.rc定义
    system/core/rootdir/init.rc

    service bootanim /system/bin/bootanimation
        class core
        user graphics
        group graphics audio
        disabled//定义了disable,在开机过程中不会自动的启动
        oneshot

    这里不会启动,那么在哪里启动? 由于开机动画对SurfaceFlinger有依赖,所以应该是在SurfaceFlinger启动之后再开始执行,看一下源码。

    SurfaceFlinger的启动在init.rc文件中

    service surfaceflinger /system/bin/surfaceflinger
        class core
        user system
        group graphics drmrpc
        onrestart restart zygote

    与SurfaceFlinger相关的源码存在于
    frameworks ativeservicessurfaceflinger
    入口
    frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

    #if defined(HAVE_PTHREADS)
    #include <sys/resource.h>
    #endif
    
    #include <cutils/sched_policy.h>
    #include <binder/IServiceManager.h>
    #include <binder/IPCThreadState.h>
    #include <binder/ProcessState.h>
    #include <binder/IServiceManager.h>
    #include "SurfaceFlinger.h"
    
    using namespace android;
    
    int main(int, char**) {
        // 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();
    
    #if defined(HAVE_PTHREADS)
        setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
    #endif
        set_sched_policy(0, SP_FOREGROUND);
    
        // initialize before clients can connect
        flinger->init();//开机动画在这里执行,接着往下看
    
        // publish surface flinger
        sp<IServiceManager> sm(defaultServiceManager());
        sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
    
        // run in this thread
        flinger->run();
    
        return 0;
    }

    frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

    void SurfaceFlinger::init() {
        ALOGI(  "SurfaceFlinger's main thread ready to run. "
                "Initializing graphics H/W...");
        ....
        // start boot animation
        startBootAnim();
    }

    接着执行startBootAnim();

    void SurfaceFlinger::startBootAnim() {
        // start boot animation
        property_set("service.bootanim.exit", "0");
        property_set("ctl.start", "bootanim");
    }

    这里采用的是通过property_set中”ctl.start”的方式执行bootanim,这里是通过设置属性值的方式来启动的,属性值的设置采用的是C/S模式,socket连接,这里不详述,大致说下,这行代码会执行到

    system/core/init/property_service.c

    void handle_property_set_fd()
    {
        ......
        switch(msg.cmd) {
        case PROP_MSG_SETPROP:
            ......
            //这里很关键
            if(memcmp(msg.name,"ctl.",4) == 0) {
                // Keep the old close-socket-early behavior when handling
                // ctl.* properties.
                close(s);
                if (check_control_mac_perms(msg.value, 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
    ",
                            msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
                }
             //这里很关键
            } else {
                if (check_perms(msg.name, source_ctx)) {
                    property_set((char*) msg.name, (char*) msg.value);
                } else {
                    ERROR("sys_prop: permission denied uid:%d  name:%s
    ",
                          cr.uid, msg.name);
                }
    
                // Note: bionic's property client code assumes that the
                // property server will not close the socket until *AFTER*
                // the property is written to memory.
                close(s);
            }
            freecon(source_ctx);
            break;
    
        default:
            close(s);
            break;
        }
    }

    接下来执行到
    system/core/init/init.c

    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_restart(arg);
        } else {
            ERROR("unknown control msg '%s'
    ", msg);
        }
    }

    接着往下执行->

    static void msg_start(const char *name)
    {
        struct service *svc = NULL;
        char *tmp = NULL;
        char *args = NULL;
    
        if (!strchr(name, ':'))
            svc = service_find_by_name(name);
        else {
            tmp = strdup(name);
            if (tmp) {
                args = strchr(tmp, ':');
                *args = '';
                args++;
    
                svc = service_find_by_name(tmp);
            }
        }
    
        if (svc) {
            service_start(svc, args);
        } else {
            ERROR("no such service '%s'
    ", name);
        }
        if (tmp)
            free(tmp);
    }

    这里找到“bootanim”然后执行service_start函数,这里就是启动bootanim的地方。

  • 相关阅读:
    【牛客】找出单向链表中的一个节点,该节点到尾指针的距离为K
    【牛客】牛妹的礼物 (动态规划)
    【问题解决】Anaconda连不上服务器,"服务器正在启动,请稍等",报错信息:ImportError: cannot import name 'create_prompt_application'
    将一个数组的各元素插入到链表中,并以升序排列
    链式队列的相关操作
    循环队列的基本操作
    栈的相关操作
    双链表的基本操作
    单链表的相关操作
    顺序表的相关操作
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6467183.html
Copyright © 2020-2023  润新知