zoukankan      html  css  js  c++  java
  • 【转】如何定制android源码的编译选项 & 后期安装? ---- 不错

    原文网址:http://blog.sina.com.cn/s/blog_3e3fcadd0100z3o9.html

    Android编译过程比较长,配置起来也很麻烦。现仅就工作遇到的问题做个总结。
    所用硬件平台为amlogic stvm3。

    ---------------------------------------------------------------------------
    关于版本号
    文件build/core/version_defaults.mk用来检查一些跟版本相关的变量是否定义;如果未定义,则使用默认值。
    这些变量包括
         PLATFORM_VERSION                           # 如 2.2.5
         PLATFORM_SDK_VERSION                 #  8, 对应2.2.5
         PLATFORM_VERSION_CODENAME   # REL,即发行版
         DEFAULT_APP_TARGET_SDK              # 同SDK_VERSION或VERSION_CODENAME
         BUILD_ID                                                # 默认为UNKNOWN
         BUILD_NUMBER                                     # 默认eng.$(USER).$(shell date +%Y%m%d.%H%M%S)的形式。

     version_defaults.mk首先包含进build_id.mk。用户应当配置build_id.mk,而不应该改动version_defaults.mk文件。然后检查上述变量,如未定义则赋值默认值。


    ---------------------------------------------------------------------------
    关于调试功能(adb)的开启
    编译android源码之前总是要先运行build/envsetup.sh,以初始化一些常用命令(实际上是bash的函数,如add_lunch_combo)。
    其中也从以下文件中引入了一些编译设置:
        device/${CHIPSET_VENDOR}/vendorsetup.sh
    我们这里使用的CHIPSET_VENDOR为amlogic。
    比如我们有文件device/amlogic/vendorsetup.sh,内容为"产品名-编译类型(flavor)"列表(称为combo),如下:
        add_lunch_combo   m1ref-eng
        add_lunch_combo   m1ref-user
        add_lunch_combo   m2ref-eng
        add_lunch_combo   m2ref-user  
        add_lunch_combo   stvm3-eng
        add_lunch_combo   stvm3-user
    其中,m1ref和stvm3是产品名(作前缀),后面为编译类型。
    除此前缀外可选的combo值有: eng, user, userdebug, tests。
    (参考文件build/core/main.mk中对于变量TARGET_BUILD_VARIANT的筛查条件)
    我们可以修改vendorsetup.sh文件,来改变为特定设备编译的结果。
    以下是各个编译类型的特点:
          eng: 工程模式,用于平台级的调试,是默认的编译类型。
                   待安装的模块tag有: eng, debug, user, development.
                   安装不带tag的非APK模块;
                   所安装应用由产品定义文件给出;
                   默认属性:  ro.secure=0, ro.deuggable=1, ro.kernel.android.checkjni=1
                   adbd默认开启,adb以root身份运行。
          user: 即最终用户版;
                   待安装的应用tag有: user
                   安装不带tag的非APK模块;
                   所安装应用由产品定义文件给出;
                   默认属性有ro.secure=1, ro.debuggable=0;
                   默认关闭adbd服务(但可通过应用settings来打开,且adb以shell身份运行);
          userdebug: 与user类似,除了:
                   支持有限的调试功能;
                   待安装的应用tag有:debug;
                   默认属性有ro.secure=1, ro.debuggable=1;
                   默认打开adbd服务,adb以shell身份运行;

    例如,由文件build/core/main.mk可以看出,当使用含有userdebug的combo值时,此文件中的临时变量enable_target_debugging会保持为true,相应地,编译过程会执行:
        ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=1 persist.service.adb.enable=1
    这意味着目标系统中根目录下的文件/default.prop文件(对应变量 INSTALLED_DEFAULT_PROP_TARGET )会含有以下行(参考文件build/core/Makefile):
           persist.service.adb.enable=1
    由此,目标系统会默认开启adbd服务,你就可以通过其它PC来连接目标系统了。

    所以,如要默认开启adbd服务,可在设备(如stvm3)定制文件device/amlogic/vendorsetup.sh中增加以下行:
          add_lunch_combo   stvm3-userdebug
    这样在执行bash的lunch函数时,选择此combo就可以默认打开adbd服务(adb以shell身份运行)。

    但是,即使adbd已经开启,你仍可能无法通过网络连接到Android进行调试,这涉及到Android的二个属性:
                  service.adb.tcp.port         (优先级高)
                  persist.adb.tcp.port          (优先级低)
            注:可查看源码文件system/core/adb/adb.c。
    默认地,这两个属性值是5555。有两种方法来设置此变量:
    1)(永久性改变)在Android配置文件/init.rc或/init.$MANUFACTUROR.rc中添加一行:
             setprop  service.adb.tcp.port    5555
    2)(临时性改变)在命令行上(你可能需要先通过串口开一个终端)执行如下命令:
             setprop  service.adb.tcp.port    5555

    检查adbd是否支持通过网络链接Android:执行命令
             netstat -l -n  |  grep ":5555"
    如果有LISTEN状态的输出,则表示adbd支持网络模式  :)  。

    ---------------------------------------------------------------------------
    具体地说,TARGET_PRODUCT是怎么定义的?
    在针对一个板子编译Android前总要先执行build/envsetup.sh(它会包含设备相关的环境设置,如device/amlogic/vendorsetup.sh),然后运行新获得的lunch函数来选择编译目标类型(即combo),如'stvm3-userdebug'。查看文件build/envsetup.sh可知(line 519~549),TARGET_PRODUCT就是combo在‘-’前的部分(如'stvm3'),TARGET_BUILD_VARIANT为combo在‘-’后的部分(如'userdebug')。
    根据build/core/main.mk文件,tags_to_install会包含‘debug',所以firmware会默认打开'adbd' (见上一小节)。
    [用于代替lunch进行类似定义的还有build/buildspec.mk或函数choosecombo()].

    根据以下的包含或调用关系:
    build/envsetup.sh (in get_build_var():make --no-print-directory -C "$T" -f build/core/config.mk dumpvar-$1)
    -> build/core/config.mk (include $(BUILD_SYSTEM)/envsetup.mk)
    -> build/core/envsetup.mk (include $(BUILD_SYSTEM)/product_config.mk)
    -> build/core/product_config.mk (invoke get-all-product-makefiles())
    -> build/core/product.mk (define get-all-product-makefiles())
    -> stvm3/AndroidProducts.mk
    -> device/amlogic/stvm3/stvm3.mk
    可知,板子的编译过程会在device/amlogic/stvm3/stvm3.mk中重新定义以下变量:
        PRODUCT_NAME := stvm3
        PRODUCT_MANUFACTURER := my_manufacturer_name
        PRODUCT_DEVICE := stvm3
        PRODUCT_MODEL := M3 media box board
        PRODUCT_LOCALES := en_US en_GB fr_FR zh_TW zh_CN
    另,device/amlogic/stvm3/stvm3.mk还会包含device/amlogic/common/mbx_amlogic.mk,后者也定义了PRODUCT_NAME、PRODUCT_BRAND等变量(但随后部分变量被stvm3.mk覆盖),并且覆盖了所包含的device/amlogic/common/core_amlogic.mk文件的同名定义。
    由此可见,core_amlogic.mk优先级低于具体设备(如mbx_amlogic.mk)的配置文件。


    ---------------------------------------------------------------------------
    product的基本描述(或定义): 涉及以下几个变量:
       PRODUCT_NAME     (预定以的值有: core, sim, sdk, generic_x86, full, generic)
       PRODUCT_BRAND   (貌似与PRODUCT_NAME区别不大)
       PRODUCT_DEVICE
       PRODUCT_CHARACTERISTICS
    这些变量首先在文件build/target/product/core.mk初始化,而后在build/target/product/{sim,sdk,generic,full}.mk中被覆盖。对于stvm3板子来说,它们在device/amlogic/common/core_amlogic.mk中预初始化,在文件device/amlogic/common/{mid,tv,mbx}_amlogic.mk的末尾它们的值被覆盖。

       
    ---------------------------------------------------------------------------
    另:/default.prop是如何生效的?
    文件system/core/init/init.c :   main(argc, argv):
             snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
             parse_config_file(tmp);

             action_for_each_trigger("early-init", action_add_queue_tail);
             queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
             queue_builtin_action(property_init_action, "property_init");
             queue_builtin_action(keychord_init_action, "keychord_init");
             queue_builtin_action(logo_init_action, "logo_init");
             queue_builtin_action(console_init_action, "console_init");
             queue_builtin_action(set_init_properties_action, "set_init_properties");
             ...

             queue_builtin_action(property_service_init_action, "property_service_init");
             queue_builtin_action(signal_init_action, "signal_init");
             queue_builtin_action(check_startup_action, "check_startup");
             ...
            queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");

             device_fd = device_init();

             property_init();                  // <-------- 在这里初始化各种属性。
             ...
             for(;;) {
                 execute_one_command();
                 ...
                 // 通过poll处理各种事件,包括基于通道/dev/socket/property_service的属性设置
                 //    事件:handle_property_set_fd();
                 //由system/core/init/property_service.c:property_set()看出,无论属性的prefix是什么,
                 //    如果它是个新属性(即代码中的pi==0),总是可以把它加到属性集中去的,不管是不是"ro."属性。
                 // 比如frameworks/base/services/java/com/android/server/BootReceiver.java中对属性"ro.runtime.firstboot"
                //     的读取和设置。
             }


    文件system/core/init/property_service.c :
            void property_init(void) {
                    ...
                    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);  // <-------- 读取属性文件。
            }
    这里,PROP_PATH_RAMDISK_DEFAULT就是文件“/default.prop”,参见bionic/libc/include/sys/_system_properties.h :

        #define  PROP_SERVICE_NAME                      "property_service" 
        #define  PROP_PATH_RAMDISK_DEFAULT    "/default.prop" 
        #define  PROP_PATH_SYSTEM_BUILD           "/system/build.prop" 
        #define  PROP_PATH_SYSTEM_DEFAULT     "/system/default.prop" 
        #define  PROP_PATH_LOCAL_OVERRIDE     "/data/local.prop"

    ---------------------------------------------------------------------------
    StatusBar的默认隐藏
    默认地,Android会显示statusbar。应用程序要想隐藏StatusBar,需要在Activityde 的onCreate()里写如下代码:
            //to remove title bar in Java code:
                MyActivity.requestWindowFeature(Window.FEATURE_NO_TITLE);
                setContentView(R.layout.myWind);
            //to remove status bar in Java code:
                getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  
                                                     WindowManager.LayoutParams.FLAG_FULLSCREEN);
                setContentView(R.layout.myWind);

    或者在AndroidManifest.xml文件添加以下属性到相关Activity:
            //to remove title bar in Manifest.xml:
                      android:theme="@android:style/Theme.NoTitleBar"
            //to remove title bar & status bar in Manifest.xml:
                      android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
    有些清况下,我们需要在系统级别默认隐藏StatusBar。做法如下:
      1) 建立一个属性,如“persist.service.statusbar”,用来表示StatusBar当前是否显示;在frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java文件的makeStatusBarView()和mBroadcastReceiver(例如针对事件android.statusbar.visibility.changed)里,根据此属性值来显示或隐藏StatusBar.
      2) 在Settings应用里,增加切换显示/隐藏StatusBar的控制UI(如在文件packages/apps/Settings/src/com/android/settings/DisplaySettings.java中),当有变化发生时,先设置属性值“persist.service.statusbar”,然后发出广播"android.statusbar.visibility.changed"。
     
      注: 属性名的选择:以“persistent.”开头的属性值在发生改变时会被自动保存在目标系统的/data/property/目录下,每一个属性有一个文件来记录器内容。

    注:文件system/core/include/arch/linux-arm/AndroidConfig.h含有很多预定义来控制编译过程,如HAVE_LIBC_SYSTEM_PROPERTIES, HAVE_SYS_SOCKET_H。

    ---------------------------------------------------------------------------
    .apk包列表的定制
    设备无关的公共的包的定制可以在以下文件中执行:
            build/target/product/core.mk 或
            build/target/product/generic.mk 或
            build/target/product/full.mk 等。
    对于特定product的包的定制,可以通过以下文件(product名为stvm3):
            device/amlogic/stvm3/stvm3.mk
    涉及到的makefile变量为'PRODUCT_PACKAGES'.
    另外,对于一个具体设备来说,有一些默认安装的包在其它的文件里设定,如
            ‘Home‘        在 文件 device/amlogic/common/core_amlogic.mk中;
            ‘Launcher2’ 在 文件 device/amlogic/common/mbx_amlogic.mk中;


    ---------------------------------------------------------------------------
    后期prebuild文件的安装
    Android build system 主要有两大部分构成:
            1) 配置部分;
            2) 目标构建部分。 

    Build system的主流程文件为build/core/main.mk文件。


    1)文件build/core/main.mk的非常关键的一个步骤就是找到$TOP目录下所有Android.mk文件,并include 它们。在Include的过程中,就会确定子模块的构建目标、类型、和规则。 其中的代码为:

        #
        # Include all of the makefiles in the system
        #

        # Can't use first-makefiles-under here because
        # --mindepth=2 makes the prunes not work.
        subdir_makefiles :=
             $(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk)

        include $(subdir_makefiles)

    这样就包含了build/target/board/Android.mk文件。

    2)文件build/target/board/Android.mk中有检测和包含$(TARGET_DEVICE_DIR)/AndroidBoard.mk的代码:
            include  $(TARGET_DEVICE_DIR)/AndroidBoard.mk

    3)(product名为stvm3) 文件device/amlogic/stvm3/AndroidBoard.mk中有安装busybox的过程:
          file := $(TARGET_OUT_EXECUTABLES)/busybox
          ALL_PREBUILT += $(file)
         $(file) : $(LOCAL_PATH)/busybox | $(ACP)
                        $(transform-prebuilt-to-target)
          这里如果还需要安装busybox(即生成所包含的命令的快捷方式), 就需要再增加一些命令,如
                       cd  $(TARGET_OUT_EXECUTABLES) && (
                                 for cmd in ls  cp  grep  find ; do ln -fs busybox ${cmd}; done
                        )
    4) 拷贝一些现成的文件到firmware中:
       可以使用Android.mk:为要拷贝的文件增加一个Android.mk文件,或者在已有的Android.mk文件中增加对应的命令。按照上面的描述,该Android.mk文件会自动被main.mk执行,因此就可以完成拷贝。如,要为stvm3板子增加一个定制的busybox文件(当然要放到/system/bin下),我们可以建立以下文件:
             packages/my_customizations/myBusybox/Android.mk
    其内容如下:
             LOCAL_PATH:= $(call my-dir)
             include $(CLEAR_VARS)
             LOCAL_CERTIFICATE := platform

             LOCAL_POST_PROCESS_COMMAND :=
                           $(shell cp $(LOCAL_PATH)/my_prebuilt_busybox   $(TARGET_OUT_EXECUTABLES))
    为此,我们事先要把拷贝的源文件my_prebuilt_busybox放到目录packages/my_customizations/myBusybox/下。
    对于多个这样的文件(如*.apk, 应放到/system/app下),可以事先把它们都放到此目录下,然后修改上面的最后一行为:
             LOCAL_POST_PROCESS_COMMAND :=
                           $(shell cp $(LOCAL_PATH)/*.apk    $(TARGET_OUT)/app)
             注:如要放到/data/app下,可使用变量 $(TARGET_OUT_DATA).


    ---------------------------------------------------------------------------
    Android开机LOGO的定制(三个阶段各有显示,或图片,或动画):
    1)bootloader阶段的LOGO
    uboot支持在boot阶段显示一个logo。对于本人工作涉及的设备,此logo的内容存放在独立的一个MTD分区上。
    1.1) logo的准备/定制:把自己的logo放到升级包中:
    (LINUX内核中有kernel/drivers/amlogic/display/aml_logo/loader/logo_setup_uboot.c,参考文件drivers/amlogic/display/aml_logo/Makefile)

        Android源码内有文件device/amlogic/stvm3/logo.bmp,在device/amlogic/stvm3/BoardConfig.mk文件中给此文件取了一个别名:
              TARGET_AMLOGIC_LOGO := device/amlogic/stvm3/logo.bmp
        在文件build/core/Makefile中有:
              $(BUILT_TARGET_FILES_PACKAGE):
                   ifdef TARGET_AMLOGIC_LOGO
                       $(hide) $(ACP) $(TARGET_AMLOGIC_LOGO) $(zip_root)/LOGO/logo
                   endif
        这是要把此文件拷贝到目标包中,等待进一步处理。
        在生成最后的升级包文件otapackage时,会从目标包中取出此文件,并添加进升级包,见文件build/tools/releasetools/ota_from_target_files (一个python脚本):
                def CopyFirmwareFiles(input_zip, output_zip, script):
                      ... ... ...
                      logo_img_exists = 0
                      try:        # 解压logo文件成logo.img
                          logo_img_info = input_zip.getinfo("LOGO/logo")
                          logo_img_exists = 1
                          logo_img = common.File("logo.img", input_zip.read("LOGO/logo"))
                      except KeyError:
                          print 'WARNING: Did not find logo'

                      if logo_img_exists:   # 在升级脚本中插入代码
                          common.CheckSize(logo_img.data, "logo.img", OPTIONS.info_dict)
                          common.ZipWriteStr(output_zip, "logo.img", logo_img.data)
                          script.WriteRawImage("/logo", "logo.img")
              实际上插入的升级脚本为(见升级文件update.zip中的文件/META-INF/com/google/android/updater-script):
                     assert(package_extract_file("logo.img", "/tmp/logo.img"),
                                 write_raw_image("/tmp/logo.img", "logo"),        # 升级过程中把文件logo.img写入'logo'分区。
                                 delete("/tmp/logo.img"));
      1.2)  logo的显示
          在uboot文件board/amlogc/8726m_mid_refb[01..12]、aml8726m_mid/upgrade.c、aml8726m_mid/mid_aml8726m.c中有:
            int logo_display(void)
            {
                int ret = 0;
                run_command ("nand read ${loadaddr} ${aml_logo_start} ${aml_logo_size}", 0);
                ret = run_command ("bmp display ${loadaddr} 0 0", 0);
                run_command ("lcd bl on", 0);
                return ret;
            }
           这就是从logo分区读取logo,然后用uboot的"bmp display"命令来显示它。此函数在
           AMLOGIC_NORMAL_BOOT、AMLOGIC_UPDATE_REBOOT等boot模式下都会被调用。
       

    2)Linux kernel启动阶段的LOGO
    标准Linux的开机logo,默认logo为Linux企鹅,但多数系统关闭此功能: (对应内核源文件drivers/video/logo/{Kconfig, logo.c})
            配置kernel时选择 CONFIG_LOGO并选择一种格式(如standard 224-color Linux logo)的logo,然后自定义同目录下对应的*.ppm文件。重新编译内核即可。
            注: 可使用以下方法把常见的.png图像转化为Linux开机可用的图像(所用工具在netpbm包中):
                   pngtopnm my_linux_logo_clut224.png > my_linux_logo_clut224.pnm              #先转成.pnm文件
                   pnmquant  224  my_linux_logo_clut224.pnm  >  my_linux_logo_clut224.pnm  #调整,可忽略
                   pnmtoplainpnm  my_linux_logo_clut224.pnm > my_linux_logo_clut224.ppm   #再转成.ppm图像

    3)Android平台图形系统初始化之后的logo和动画
    在启动完全结束前,Android的init进程会先后两次显示一些内容:
      * 首先显示静态图像(在进行logo_init时,对应的函数是logo_init_action());
      * 随后马上显示动画效果(在进行console_init时,对应的函数是console_init_action())。
    3.1)‘ANDROID'静态图像或文字的显示
             文件system/core/init/init.c的函数console_init_action()会通过load_565rle_image()或load_565rle_image_mbx()先尝试显示图片INIT_IMAGE_FILE(一张565rle的压缩的位图):
                             init/init.h:  #define  INIT_IMAGE_FILE    "/initlogo.rle"
             如果失败,再直接在终端/dev/tty0上打印字符串"A N D R O I D"。
             注:由常见的.png图像生成此565rle图的方法:
                    先使用imagemagick包中的convert命令:
                      convert  -depth  8  my_android_logo.png   rgb:my_android_logo.raw     #先转为raw模式
                    再使用android自带的工具out/host/linux-x86/bin/rgb2565命令:
                       rgb2565   -rle  < my_android_logo.raw    > my_android_initlogo.rle
                   
    3.2)’anDRoID‘文字的发光动画 或 自定义“电影”  (参考http://www.ziyouku.com/archives/android-boot-interface-changes.html)
            init.c会分析并执行init.rc中的命令,而init.rc中有以下命令:
                service bootanim /system/bin/bootanimation
                      user graphics
                      group graphics
                      disabled
                      oneshot
            这个命令就是要执行Android的开机动画。
            属性"debug.sf.nobootanimation"决定着是否要显示开机动画(见frameworks/base/cmds/bootanimation/bootanimation_main.cpp的main()开头)。

            【另外,文件frameworks/base/services/surfaceflinger/Android.mk要求生成libsurfaceflinger.so库,其中源文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp的SurfaceFlinger::readyToRun()方法在最后执行函数
                           property_set("ctl.start", "bootanim");    // "bootanim"是init.rc中的服务名。
             来请求启动Android开机动画服务, 而在SurfaceFlinger::bootFinished()方法中调用函数
                           property_set("ctl.stop", "bootanim");
             请求停止开机动画服务。
             使用以上属性来启/停服务的典型代表是system/core/libsysutils/src/ServiceManager.cpp,它通过设置这些属性来通知init进程去启动/停止某个服务。
             注:     由此可知:在PC的命令行上,执行"setprop  ctl.start  bootanim"可能会手动启动开机动画,该动画可一直持续到再执行"setprop  ctl.stop  bootanim"才停止。
             】

            命令/system/bin/bootanimation的只要内容就是启动一个线程(frameworks/base/include/utils/threads.h和frameworks/base/libs/utils/Threads.cpp)来执行动画。一个Thread类有以下主要成员:
                         *)   readyToRun():线程做一次性初始化的好地方;
                         *)   threadLoop(): 线程内被循环调用的函数,如果返回true则会被再次调用,否则退出线程循环;
                         *)   Thread::_readyToRun():是对readyToRun()和threadLoop()行为的封装,也就是线程执行的主体;
                         *)   run():生成新linux线程并启动它的执行(即调用_readyToRun);
                         *)   requestExit():终止线程的执行;
                         *)   protected bool  exitPending() const :returns true if requestExit() has been called。
            对于BootAnimation线程,其源码在文件frameworks/base/cmds/bootanimation/BootAnimation.cpp中:
               BootAnimation::onFirstRef():启动线程,名字为"BootAnimation";
               BootAnimation::readyToRun():初始化surface,并先后测试能否打开两个动画文件(/data/local/bootanimation.zip 和/system/media/bootanimation.zip,这2个文件默认不存在),如果能打开其一,则准备执行movie(),否则准备执行android();
               BootAnimation::threadLoop():分清况具体执行android()或movie();执行一次,然后线程退出。
               BootAnimation::android():显示'anDRoID'字样的动画。这要用到以下文件:
                       frameworks/base/core/res/assets/images/android-logo-mask.png   ('anDRoID'字样)
                       frameworks/base/core/res/assets/images/android-logo-shine.png    (闪动条)
                      这2个文件最终会被打包进firmware中的/system/framework/framework-res.apk文件中。
               BootAnimation::movie():播放动画文件/data/local/bootanimation.zip 或/system/media/bootanimation.zip。如要定制此开机动画,可象前述“拷贝一些现成的文件到firmware中”一节中所描述的那样,创键一个新的文件(如packages/my_customizations/customBootanimation/Android.mk,内容如下:
                   LOCAL_PATH:= $(call my-dir)
                   include $(CLEAR_VARS)
                   LOCAL_CERTIFICATE := platform
                   LOCAL_POST_PROCESS_COMMAND :=
                             $(shell cp -r $(LOCAL_PATH)/my_bootanimation.zip  $(TARGET_OUT)/media/bootanimation.zip)
                   播放前,先分析.zip中的desc.txt文件以获得播放的参数。


    附:bootanimation.zip文件中desc.txt文件的格式
    desc.txt里面的内容示例 (分析过程见frameworks/base/cmds/bootanimation/BootAnimation.cpp : BootAnimation::movie()开头的for(;;)循环):

    480  800  30       # width, height, fps
    p   1   0   part0    # for the first    Animation::Part:  count, pause, path (path下有Animation::Frame的内容)
    p   0   0   part1    # for a second Animation::Part:  count, pause, path (path下有Animation::Frame的内容)

    命令格式说明
    '480 800'是每帧(即每张图片)的分辨率,注意不要超过手机实际的分辨率(如480x854),否则画面显示不全。'30'代表每秒播放的帧数,打个比方,part0文件夹里面共76个图片,播放时间就是76/30=2.533333秒播放完毕,当然手机的处理能力会造成一定的延时,尤其是你的图片文件比较大的情况下,手机想播快也快不起来。
    在类似“p  n1  n2  dir_name ”的文本行中,p是分界符,n1是循环次数(0表示无限循环),n2是一次循环后暂停的时间(即n2帧所花的时间),dir_name是要循环播放的文件所在的目录名。如:
        ‘p  1(代表着播放一次)  0(空指令) part0‘:这句指令代表着part0文件夹内的图片只按名称顺序播放一次。
        ’p  0(重复播放)             0(空指令) part1‘:这句指令代表着part1文件夹内的图片会循环反复播放。

    另外,类似的指令如:
        ’p  0  10 part1‘:这里,‘0’代表循环播放,’10‘代表着播放完一遍part1文件夹内的所有图片之后停顿10帧的时间,然后再循环播放一遍,再停顿10帧的时间,再播放,再停顿·········重复下去。
        'p  1  20 part1'  同理,这句代表着播放完part1文件夹内的图片之后,停顿20帧的时间,然后继续播放下一个part的帧。

        :) :)


    另:可根据http://www.cnblogs.com/cnhome/archive/2010/05/24/1743051.html制作动画文件。
    ---------------------------------------------------------------------------
    在Amlogic开发板上修改开机画面:
    1.  (第一张画面)替换文件device/amlogic/stvm3/logo.bmp为公司的logo;
    2.  (第二张画面)替换文件device/amlogic/stvm3/initlogo-robot-1280x720.rle;

    <end>

  • 相关阅读:
    IDEA右侧代码预览、代码地图消失(快捷键:Ctrl+Shift+g)
    vscode 清除多余空行
    StringJoiner
    redis远程连接
    el-container全屏布局(ElementUI)
    阿里云开启selinux无法启动系统问题
    fail模块场景(ansible)
    "***.sh" is read-only (add ! to override) 问题解决
    ansible 报错解决:ERROR! this task '****' has extra params, which is only allowed in the following modules:..
    java实现Excel定制导出(基于POI的工具类)
  • 原文地址:https://www.cnblogs.com/wi100sh/p/4556043.html
Copyright © 2011-2022 走看看