基于Q的Android开机动画

背景

项目中需要处理Android的原生开机动画,一定条件下还需要做到静默重启(android系统启动进入到桌面前,屏幕保持完全没有亮度的状态)。因为项目是基于Android Q做的,顺势探索了一波开机动画的细节。

开机动画到底有几个

搜了一些资料,推荐一篇博客,原理讲的很细,汇总开机动画一共有三个:
Android系统的开机画面显示过程分析
总结下:
1、Linux内核的启动画面,这个动画一般不显示。
2、第二个开机画面是在init进程启动的过程中出现的,它也是一个静态的画面。以小米手机为例,开机出现的第一个白色的 “MI” logo。
3、第三个开机动画一般各手机厂商会自行定制,也就是开机后的动画特效。
但是基于Q测试时,还发现一个“Phone is starting”的对话框页面,这个页面后才是桌面。于是引入了第四个开机动画:
4、启动Launcher之前会先启动一个FallbackHome,这个FallbackHome就是“Phone is starting”的对话框页面,这个页面一般厂商也会自行定制。
综上:目前最新的Android源码一共有四个开机动画。

自定义开机动画

一、定制第一个、第二个开机动画

这个基本没有需求,我没研究,有需求的同学可以参考Android系统的开机画面显示过程分析学习研究。

二、定制第三个开机动画

Android系统默认的开机动画是由两张图片android-logo-mask.png和android-logo-shine.png中。这两张图片保存在frameworks/base/core/res/assets/images目录中。一般厂商会自行定制此动画,谷歌也提供了替换的方法:

#define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"
#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"

替换两个目录下的任何一个即可。一般会在rom源码去替换这个文件,示例代码:
需要修改device.mk(在rom根目录的device目录中)文件,同时把自定义的bootanimation.zip放到device.mk所在git库根目录

PRODUCT_COPY_FILES += $(LOCAL_PATH)/bootanimation.zip:system/media/bootanimation.zip

注: 如果需要隐藏此动画,有个取巧的方法,可以bootanimation.zip内放不合适的image图片,就不会显示此动画了。相比改代码处理更简洁。

三、定制第四个开机动画

也就是改动src/com/android/settings/FallbackHome.java这个类。这个类是在系统应用Settings中
项目路径是:rom根目录/packages/apps/Settings,改动很简单,直接把显示dialog的代码注掉(或者自行定制)

    @Override
    protected void onResume() {
    
    
        super.onResume();
        if (mProvisioned) {
    
    
            // mHandler.postDelayed(mProgressTimeoutRunnable, PROGRESS_TIMEOUT);
        }

如果系统已经做过开机引导,不会显示此动画。
注:验收过程中,mtk平台的rom自行定制了Settings项目,改动/packages/apps/Settings无效,MTK平台下的rom,需要改动rom根目录/vendor/mediatek/proprietary/packages/apps/MtkSettings下的FallbackHome.java**

静默重启,屏幕亮度为为0

分析完上边的动画,如果需要在设备启动中变更屏幕亮度。一共需要处理两大块。
1、修改第二个动画的屏幕背光。
2、修改第三个动画的屏幕背光。

一、在misc分区记录亮度值

因为第二个开机动画,整个android的文件系统还没启动,所以无法使用文件系统记录。所以使用misc分区记录。
这里大概解释下:
android上主要有六个分区:cache,dumisc,recovery,boot,system,userdata。
后四种分区不做解释了,主要在于misc和cache两个分区的作用。cache是缓存空间,程序和系统用到的缓存数据和指令就存放在这里;CPU在调用和执行命令是会优先调用这里的数据;misc分区中有Bootloader Control Block(BCB),主要是用于存放Recovery引导信息。第二个开机动画(静态logo)就需要借用此分区。
1、从misc分区读亮度值,并设置。
设置背光值的源码位置:
vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt…(型号代号)/mt_leds.c

void mt65xx_backlight_on(void)
{
    
    
	// backlight_level增加逻辑,从misc分区读出背光值,在这里设置即可
	enum led_brightness backlight_level = get_cust_led_default_level();
	LEDS_INFO("[LEDS]LK: mt65xx_backlight_on:level =  %d\n\r",backlight_level);
	mt65xx_leds_brightness_set(MT65XX_LED_TYPE_LCD, backlight_level);
	LEDS_INFO("[LEDS]LK: mt65xx_leds_brightness_set is done\n");
}

2、暴露给app可以操作misc分区此值的工具。
app如果想修改misc分区数据,需要提供c程序,app可以使用命令调用。c程序保密,不过原理大概这样。

二、修改第三个开机动画往后的背光

1、因为从这里开始文件系统已经加载,所以使用文件记录是否设置背光为0。
2、本以为第三个开机动画到桌面显示,也就一个地方设置了背光,代码尝试改动了
frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

  private void updatePowerState() {
    
    
        ......
        if (brightness < 0 && mPowerRequest.screenBrightnessOverride > 0) {
    
    
            // 这里使用/data/backlight_0文件是否存在标记
            File file = new File("/data/backlight_0");
            brightness = file.exists() ? 0 : mPowerRequest.screenBrightnessOverride;
            mBrightnessReasonTemp.setReason(BrightnessReason.REASON_OVERRIDE);
            mAppliedScreenBrightnessOverride = true;
        } else {
    
    
            mAppliedScreenBrightnessOverride = false;
        }
        ......
  }

改动后发现并没有把整个流程的背光设置为0。
3、后来发现整个过程多个地方操作了背光,总不能所有的地方都去变动。于是找到了设置背光的源头:
vendor/mediatek/proprietary/hardware/liblights/lights.c
增加判断:

static int
write_int(char const* path, int value)
{
    
    
    int fd;

#ifdef LIGHTS_INFO_ON
	ALOGD("write %d to %s", value, path);
#endif

	// 此处增加了逻辑,如果文件存在直接返回。
    if ((access("/data/backlight_0", F_OK)) != -1) {
    
    
        return 0;
    }

    fd = open(path, O_RDWR);
	ALOGD("write_int open fd=%d\n", fd);
    if (fd >= 0) {
    
    
        char buffer[20];
        int bytes = sprintf(buffer, "%d\n", value);
        int amt = write(fd, buffer, bytes);
        close(fd);
        return amt == -1 ? -errno : 0;
    } else {
    
    
        return -errno;
    }
}

注:这里解释下此处设置背光的原理。是通过write写/sys/class/leds/lcd-backlight/brightness文件设置背光的。

三、设备进入到桌面后需要清掉自己定制的背光(毕竟特殊场景下的需求)

这里可能很多人想在桌面去改动。其实有个更好的地方!!!就是第四个动画的FallbackHome.java。这个要比桌面启动早。且更独立。并且还有最重要的一点,这个app是systemUid,可以操作更广的文件系统,权限也更高。
代码变动:

    @Override
    protected void onPause() {
    
    
        super.onPause();
        mHandler.removeCallbacks(mProgressTimeoutRunnable);

        clearMyBackLight();
    }

    private void clearMyBackLight() {
    
    
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                try {
    
    
                    // 1、需要执行提供的c程序,清掉第二个动画,也就是misc分区存储的值
                    Runtime.getRuntime().exec("/system/bin/提供的程序 clear");
                    // 2、清掉backlight_0,恢复第三个动画往后的正常屏幕背光
                    Runtime.getRuntime().exec("rm /data/backlight_0");
                    // 3、恢复重启前的用户设置的背光值,这里用了Settings.Secure存储
                    int value = Settings.Secure.getInt(getApplicationContext().getContentResolver(), "pref_key_back_light");
                    String[] args = {
    
    "echo", String.valueOf(value), ">", "/sys/class/leds/lcd-backlight/brightness"};

                    Process process = Runtime.getRuntime().exec("sh");
                    OutputStream outputStream = process.getOutputStream();
                    DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

                    String cmd = "";
                    for (String arg : args) {
    
    
                        cmd += arg + " ";
                    }
                    cmd += "\n";
                    dataOutputStream.writeBytes(cmd);
                    dataOutputStream.flush();
                    dataOutputStream.writeBytes("exit\n");
                    dataOutputStream.flush();
                } catch (Exception e) {
    
    
                    // ignore
                }
            }
        }).start();
    }

结束

一次比较神奇和艰难的探索之旅。

参考资料声明:Android系统的开机画面显示过程分析

猜你喜欢

转载自blog.csdn.net/archie_7/article/details/108264268