开机关机动画工作流程

一,开机画面切换过程

(1) Linux 系统启动,出现Linux小企鹅画面(由内核实现)。
 
(2) Android平台启动初始化,出现"A N D R I O D"文字字样画面。
 
(3) Android平台上层图形系统启动,出现含闪动的ANDROID字样的动画图片(start)。
 

二,(2)和(3)启动运行的过程

     (1) Android 系统启动后,init.c中main()调用load_565rle_p_w_picpath()函数读取/initlogo.rle(一张565 rle压缩的位图),如果读取成功,则在/dev/graphics/fb0显示Logo图片;如果读取失败,则将/dev/tty0设为TEXT模式,并打开/dev/tty0,输出文本“A N D R I O D”字样。E8,E9已经将此部分会直接路过,E8直接注释此过程
相应代码如下:
 
  
  1. static int console_init_action(int nargs, char **args) 
  2.     int fd; 
  3.     char tmp[PROP_VALUE_MAX]; 
  4.  
  5.     if (console[0]) { 
  6.         snprintf(tmp, sizeof(tmp), "/dev/%s", console); 
  7.         console_name = strdup(tmp); 
  8.     } 
  9.     fd = open(console_name, O_RDWR); 
  10.     if (fd >= 0) 
  11.         have_console = 1; 
  12.     close(fd); 
  13. /*  
  14. //查看init.h文件 
  15. //#define INIT_IMAGE_FILE   "/initlogo.rle" 
  16. //ADB SHELL查看根目录没有此张图片 
  17. //加载initlogo.rle文件 
  18.  
  19. if( load_rle_p_w_picpath(INIT_IMAGE_FILE) ) {
  20. //此时fd 是/dev/tty0对应的是输出端口 
  21. //tty1表示输入端口,tty2貌似表示错误信息 
  22.  
  23.         fd = open("/dev/tty0", O_WRONLY);//将/dev/tty0设为text模式 
  24.          if (fd >= 0) { 
  25.             const char *msg; 
  26.             msg = "\n" 
  27.             "\n" 
  28.             "\n" 
  29.             "\n" 
  30.             "\n" 
  31.             "\n" 
  32.             "\n"  // console is 40 cols x 30 lines 
  33.             "\n" 
  34.             "\n" 
  35.             "\n" 
  36.             "\n" 
  37.             "\n" 
  38.             "\n" 
  39.             "\n" 
  40.             "             A N D R O I D "; 
  41.             write(fd, msg, strlen(msg)); 
  42.             close(fd);//关闭接口 
  43.         } 
  44.     } 
  45.     */ 
  46.     return 0; 
相关代码: 
 
 
  
  1. system/core/init/init.c  
  2. system/core/init/init.h  
  3. system/core/init/init.rc  
  4. system/core/init/logo.c 
*.rle文件的制作步骤: 
 
 
  
  1. a. 使用GIMP或者Advanced Batch Converter软件,将图象转换为RAW格式;  
  2. b. 使用android自带的rgb2565工具,将RAW格式文件转换为RLE格式(如:rgb2565 -rle < initlogo.raw > initlogo.rle)。 
  3. 注:修改这几个地方的代码编译过后要重新烧写recovery,boot 
(2),开机动画(闪动的ANDROID字样的动画图片) 
我们最主要经常要修改的这是这部内容,这里包含两种动画类型:
1,第一种类似于Windows系统的滚动条,是由前景和背景两张PNG图片组成,对应原文件位于frameworks/base/core/res/assets/p_w_picpaths/。前景图片(android-logo-mask.png)上的Android文字部分镂空,背景图片(android-logo-shine.png)则是简单的纹理。系统登录时,前景图片在最上层显示,程序代码(BootAnimation.android())控制背景图片连续滚动,透过前景图片文字镂空部分滚动显示背景纹理,从而实现动画效果。 
  
 
图片1: 前景图片           图片2: 背景图片
 
2,制件开机动画包,开机动画服务程序启动以后会先在系统指定目录检查此包是否存在,如果存在,系统将执行此包中的动画,如果检查系统不存在此包,此时系统才会去按第一方式播放动画,这里包中的内容是通过一张一张图片连续播放来实现动画效果的,最后要生成一个类似bootanimation.zip的包
3,执行过程,init.c解析init.rc(其中定义服务:“service bootanim /system/bin/bootanimation”),bootanim服务由SurfaceFlinger.readyToRun()(property_set("ctl.start", "bootanim");)执行开机动画、bootFinished()(property_set("ctl.stop", "bootanim");)执行停止开机动画。 BootAnimation.h和BootAnimation.cpp文件放在了/frameworks/base/cmds/bootanimation目录下了,增加了一个入口文件bootanimation_main.cpp。Android.mk文件中可以看到,将开机动画从原来的SurfaceFlinger里提取出来了,生成可执行文件:bootanimation。
Android.mk代码如下: 
//=============Android.mk====================== 
LOCAL_PATH:= $(call my-dir) 
include $(CLEAR_VARS) 
 
LOCAL_SRC_FILES:= / 
    bootanimation_main.cpp / 
    BootAnimation.cpp
 
# need "-lrt" on Linux simulator to pick up clock_gettime
ifeq ($(TARGET_SIMULATOR),true)
    ifeq ($(HOST_OS),linux)
        LOCAL_LDLIBS += -lrt
    endif
endif
LOCAL_SHARED_LIBRARIES := /
    libcutils /
    libutils /
    libui /
    libcorecg /
    libsgl / 
    libEGL / 
    libGLESv1_CM / 
    libmedia    
LOCAL_C_INCLUDES := / 
    $(call include-path-for, corecg graphics) 
LOCAL_MODULE:= bootanimation 
include $(BUILD_EXECUTABLE) 
//========================================== 
开机动画第一个入口:bootanimation_main.cpp
int main(int argc, char** argv)
{
 
…..........
 
    if (!noBootAnimation) {
       sp<ProcessState> proc(ProcessState::self());
        ProcessState::self()->startThreadPool();
//初始化开机动画,开始播放开机动画.booted传下去的开机操作还是关机操作的参数
        sp<BootAnimation> boot = new BootAnimation(booted);
//初始化开机声音,开始播放开机声音.这个类是根据开机动画自定义的,可根据需求自行修改删除
        sp<BootAnimationSound> bootsound = new BootAnimationSound(booted);
        IPCThreadState::self()->joinThreadPool();
    }
}
根据bootanimation_main.cpp将会初始化 BootAnimation类.下面我们来查看 BootAnimation.cpp文件.通过BootAnimation 构造函数来初始化 sbootanimation变量.根据sbootanimation来实现开关机播放不同的动画.判断开机还是关机可通过上面传过来的参数确定
BootAnimation::BootAnimation(bool shutdownAnimation) : Thread(false)
    mSession = new SurfaceComposerClient();
    mShutdownAnimation = shutdownAnimation;
    //权宜之计
    if (mShutdownAnimation) {
// 关机时播放的动画包
        mSession->setOrientation(0, 0, 0);
sprintf(sbootanimation, "/system/media/shutdownanimation.zip");
    }else{
// 开机时播放的动画包
sprintf(sbootanimation, "/system/media/bootanimation.zip");
}
}
此处可以看到 sbootanimation定义是一个zip包路径,通过这个我们可以知道,如果要通过第二种方法实现开关机动画可将制作的zip包放在/system/media/目录下文件名一致便可以了,后面会给出制作zip包的方法。如果是用第一种方法只需修改上面提到的两个图片即可。
mSession->setOrientation(0, 0, 0);此条语句是关机强制横屏,修改可通过第二个参数修改.值分别对应(0->0度,1->90度,2->180度,3->270度,)具体可修改查看效果
根据mAndroidAnimation的值来确定是播放第一种动画效果还是第二种动画效果
 
BootAnimation::threadLoop()
 
if (mAndroidAnimation) {
 r = Android(); // 执行android字体闪动的图片
 } else {
 r = movie(); // 执行bootanimation.zip中提供的动画图片
 }
==> BootAnimation::Android()会加载"p_w_picpaths/android-logo-mask.png"和"p_w_picpaths/android-logo-shine.png"
==> BootAnimation::movie()会加载bootanimation.zip中的内容
 
这里是开机动画,下面是开机音乐的代码,流程跟开机动画类型
 
BootAnimationSound.cpp
和开机动画一样, 初始化bootsound变量,来实现开关机播放不同的音乐,判断开机还是关机可通过上面传过来的参数确定
    BootAnimationSound::BootAnimationSound(bool booted) : Thread(false)
    {
        mShutdownAnimation = booted;
   if (mShutdownAnimation) {
// 关机时播放的声音
sprintf(bootsound, "system/media/audio/ui/power_off.mp3");
   }else{
// 开机时播放的声音
sprintf(bootsound, "system/media/audio/ui/power_on.mp3");
}
    }
 
通过bootsound我们知道要将你的音频文件放在system/media/audio/ui/目录即可播放声音了,具体实现播放声音的操作看下文,比较简单, playSound类实现播放声音的。
    void BootAnimationSound::playSound()
    {
        MediaPlayer* mp = new MediaPlayer();
        if (mp->setDataSource(bootsound, NULL) == NO_ERROR) {
            /*系统启动时声音从扬声器出来,而关机时如果插耳机则会从耳机出来,所以在
             * 这里强制设定。但是,这个API 涉及许可,许可服务 PermissionController
             * 在 ActivityManagerService 启动,而ActivityManagerService 启动时间比
             * SurfaceFlinger 和 Audio 都晚,从而导致开机时动画播放一段时间才有声
             * 音。所以加了此判定。
             * */
            if(mShutdownAnimation) {
                mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
            }else{
sleep(2);
}
            mp->prepare();
            mp->start();
            /* start 之后,设置音量才有效果。 start 之前设音量没有效果的。*/
            mp->setVolume(0.4, 0.4);
        } else {
            LOGE("Failed to load CameraService sounds: system/media/audio/ui/power_on_off.ogg");
        } 
    }
代码比较简单,但还是一点要特别强调在设置开关机音量的时候,执行过mp->start();以后再执行mp->setVolume(0.4, 0.4);才会有效果,这是一个很神奇的一个问题,我们徐申龙徐工通过调试很久才找到这个很操蛋的问题,注意这点会给你节省不少时间,
最后别忘了在Android.mk文件还需要引入播放声音库
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
    libui \
     libskia \
    libEGL \
    libGLESv1_CM \
    libgui \
    libmedia
请注意,libmedia是新添加的;
bootanimation.zip包的制做
第一步,我们将png图片转换成colormap:8bit 以缩小文件占用磁盘空间 (以下是ubuntu命令,不用linux,可以用windows下的做图工具来转换图片格式):
    convert -type palette boot_003.jpg boot_003.convert.png
 
做好了图片,就需要把图片打成bootanimation.zip包了。
 
    这个包,除了图片目录,还有一个desc.txt的文件,这个文本文件是用来告诉系统,如何使用图片目录来实现动画的。 所以有一定的语法,不过很简单:
    目标屏幕宽度(480)  目标屏幕高度(800) 每次帧间隔    
 
    p  重复次数  播放完成后停顿 图片文件夹名1
    p  重复次数  播放完成后停顿 图片文件夹名2
 
 
   以一个desc.txt为例:
  480 800 15        图片宽度480,高度800,这是我们I9000屏幕参数,最后15是播放动画的每秒帧率。就是一秒钟播放多少张图片,动画的最原始实现。小时候大家都玩过吧
  p 1 0 foldername        // p 是一个分隔符,1 表示播放一遍,0表示播放完后停顿 0 帧,最后是图片所在的zip包里的目录名。比如你的zip包里最后是这么个结构
                                       //  folder0(里面包含很多图片)  + desc.txt, 那么你可以在这里把foldername 替换成folder0
  根据这个语法,我们也可以自定义各种动画形式,例如下面所示:
  p 2 30 folder0        将folder0里的图片,播放2遍,播放完一遍后停顿30帧,因为我们之前设置了帧率是15帧每秒,那么这里就等于停顿2秒。
  p 0 0 folder1        将folder1里的图片无限循环播放,每次播放不停顿。
 
如果你设置的宽度和高度不充满屏幕也没关系,剩余区域,系统会填充黑色。如果你设置的宽度和高度大过屏幕,系统会自动裁剪显示居中部分的图片区域。
 
4. 将转换好的图片集打包在不同的目录下, 然后把图片目录和一个描述动画的desc.txt 无压缩率格式打包成bootanimation.zip, 下面是ubuntu命令,你可以用winrar等工具,但是注意要选择无压缩率,无损压缩。另外保持压缩包后的目录结构。
 
  zip -0 -r bootanimation.zip part0 part1 desc.txt 
 
5. 最后将这个zip文件 拷贝到你的机器里 /data/local/bootanimation.zip
 
 
需要注意的是 如果你使用winrar进行压缩打包的话,需要设置参数如下:
 
压缩格式选zip
压缩方式选:存储(即不压缩)