Android Framework- 开机动画

206 阅读5分钟

开机动画的启动

在init.rc 中 会启动core组,Bootanim和surfaceFlinger 划归到了core

on boot
  # Start standard binderized HAL daemons
    class_start hal
​
    class_start core //启动划分到core组  

Bootanim.rc

//frameworks/base/cmds/bootanimation/bootanim.rc
​
service bootanim /system/bin/bootanimation
    class core animation
    user graphics
    group graphics audio
    disabled //禁止自启动 init 不会启动他
    oneshot//运行一次 
    ioprio rt 0
    task_profiles MaxPerformance

surfaceFlinger.rc

//frameworks/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    capabilities SYS_NICE
    onrestart restart zygote
    task_profiles HighPerformance
    socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
    socket pdx/system/vr/display/manager    stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
    socket pdx/system/vr/display/vsync      stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
​

init 会将 surfaceFlinger 启动起来 (如果sf不起来就没办法播放动画了)

//frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
int main(int, char**) {
  //省略。。。
   sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
   flinger->init();
    //将sf 加入到ServiceManager里面去
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
  
  //省略。。。
      flinger->run();
}

SurfaceFlinger

//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
  void SurfaceFlinger::init() {
    //省略
     if (mStartPropertySetThread->Start() != NO_ERROR) {
        ALOGE("Run StartPropertySetThread failed!");
    }
​
  }
  

StartPropertySetThread

//native/services/surfaceflinger/StartPropertySetThread.cpp
bool StartPropertySetThread::threadLoop() {
     
    property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
    //设置 开机动画属性
    property_set("service.bootanim.exit", "0");
    property_set("service.bootanim.progress", "0");
    // Start BootAnimation if not started
    property_set("ctl.start", "bootanim");
    // Exit immediately
    return false;
}
//这里的属性变化 会导致 init 进程接收到系统属性变化通知  然后启动bootanim //property_service.c
//https://blog.csdn.net/u010223349/article/details/8876232

进入动画相关

//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();
      
        // 构建启动BootAnimation
        sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
​
        waitForSurfaceFlinger();
   
        boot->run("BootAnimation", PRIORITY_DISPLAY);
​
        ALOGV("Boot animation set up. Joining pool.");
​
        IPCThreadState::self()->joinThreadPool();
    }
    return 0;
}

BootAnimation

初始化构建

//frameworks/base/cmds/bootanimation/BootAnimation.cpp
//继承了 IBinder::DeathRecipient  ::RefBase
/**
​
基本可以分为几步  构建 BootAnimation
1.链接sf  onFirstRef  
​
查找路径加载地址, findBootAnimationFile
加载动画路径,loadAnimation
解析出来压缩包中的动画基础属性 parseAnimationDesc
​
完成构建 BootAnimation
​
*/
​
​
​
//  Sp智能指针 RefBase 则在构建完成后会回调onFirstRefvoid BootAnimation::onFirstRef() {
  //链接sf
    status_t err = mSession->linkToComposerDeath(this);
    if (err == NO_ERROR) {
        preloadAnimation();//预加载动画
    }
}
​
bool BootAnimation::preloadAnimation() {
    //查找动画路径
    findBootAnimationFile();
    if (!mZipFileName.isEmpty()) {
       //查找到对应路径 开始加载动画 会构建一个 BootAnimation对象 然后开始加载
        mAnimation = loadAnimation(mZipFileName);
        return (mAnimation != nullptr);
    }
​
    return false;
}
​
​
​
//查找开机动画路径
void BootAnimation::findBootAnimationFile(){
  //构建 动画file 路径组 会挨个遍历该路径下有没有对应文件
  static const std::vector<std::string> bootFiles = {
        APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : PRODUCT_BOOTANIMATION_FILE,
        OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE
    };
  //省略 
   findBootAnimationFileInternal(bootFiles);//主要就是给   mZipFileName 赋值
}
​
​

开始动画

bool BootAnimation::threadLoop() {
  
    if (mZipFileName.isEmpty()) {
        result = android();//走android 默认的
    } else {
        result = movie();//设定
    }
}
​
//android 默认 会不断的进行扫光动画
bool BootAnimation::android() {
    //base/core/res/assets/images
   initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
    initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
  // 省略
   checkExit();
}
​
bool BootAnimation::movie() {
   //二次检查
    if (mAnimation == nullptr) {
        mAnimation = loadAnimation(mZipFileName);
    }
   playAnimation(*mAnimation);//该方法中也会调用 checkExit()
}
​
​
//检查是否要退出
void BootAnimation::checkExit() { 
   static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
    char value[PROPERTY_VALUE_MAX];
    property_get(EXIT_PROP_NAME, value, "0");//标识是否可以结束开机动画
    int exitnow = atoi(value);
    if (exitnow) {
        requestExit();
    }
}

动画结束

//native/services/surfaceflinger/SurfaceFlinger.cppvoid SurfaceFlinger::bootFinished() {
  //省略
   property_set("service.bootanim.exit", "1");
}

压缩文件的配置和注意事项

static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
/**
 压缩包一般是有desc.txt 文件 和part0到 partN
 
​
​
desc 文件基本如下
1080 360 60
c 1 0 part0 #ffee00 c c
c 0 0 part1 #ffee00 c c
c 1 0 part2 #ffee00 c c
c 1 1 part3 #ffee00 c c
c 1 0 part4 #ffee00 c c
​
基础格式是
TYPE +COUNT + PAUSE +PATH [#RGBHEX COLOR]
​
type  2种类型
  p 是可以打断
  c 是不能打断 一般都是写c
count  0 是无限循环 直到启动完成
pause  这个part 完成后停留几帧   0就直接干下一个 1就停留一帧的时间
path 就是文件夹目录
bacghex  可选项 背景色 一般不写  练习的时候可以测试下 要写成 rgb 模式
clock  坐标参数   c 就中间
图片配置就是从00001到0000号码你的图片结束。
  
文件包的放置位置
 第一种. 最简单方法直接在打出的包的 (目录)
out/target/product/redfin/system/media  
扔自己打好的 bootanimation
​
第二种 追加复制目录
device/google/redfin/aosp_redfin.mk 里面追加(aosp_redfin 是我的手机版本)
PRODUCT_COPY_FILES += \
    device/google/redfin/media/bootanimation.zip:system/media/bootanimation.zip
其实这样是过不去的,因为会报错
​
选择对应的vendor下 ,比如我的是redfin,新建 media (随便什么名字 )将 bootanimation.zip放进去
在mac 上要查看下 zip 包 要所有人都可读可写 不然解析不出来,
不然就下载专门的压缩工具,选择仅压缩
其实就是读的 自己的系统下的system/media 目录里面的压缩文件
和系统代码下的 system/meida 文件夹没啥关系。
​
在mac 下可能会报错  需要运行一下
 source build/envsetup.sh  之后 
   禁用  export DISABLE_ARTIFACT_PATH_REQUIREMENTS="true"
  
​
*/

文件包的放置位置

第一种. 最简单方法直接在打出的包的 (目录) out/target/product/redfin/system/media  扔自己打好的 bootanimation

第二种 追加复制目录

device/google/redfin/aosp_redfin.mk 里面追加(aosp_redfin 是我的手机版本) PRODUCT_COPY_FILES += \    device/google/redfin/media/bootanimation.zip:system/media/bootanimation.zip

其实这样是过不去的,因为会报错。 选择对应的vendor下 ,比如我的是redfin,新建 media (随便什么名字 ),将 bootanimation.zip放进去。

在我的主力机是mac, 要查看下 zip 包, 要所有人都可读可写 不然解析不出来。 不然就下载专门的压缩工具,选择仅压缩。 其实就是读的自己的系统下的system/media 目录里面的压缩文件 和系统代码下的 system/meida 文件夹没啥关系。

在mac 下可能会报错 需要运行一下, source build/envsetup.sh 之后 ,

禁用 export DISABLE_ARTIFACT_PATH_REQUIREMENTS="true"