android系统恢复出厂设置和升级界面的修改方法

       最近需要定制恢复出厂设置和升级的画面,将原生的绿色机器人改成其他的图片。
基于的android版本是4.4.4,改起来挺简单的,但是遇到了几个坑,特地记录下。
android 4.4.4的升级机器人图片是由两部分构成的:静态部分和动态部分。


icon_installing.png


icon_installing_overlay01.png


    静态部分提供了一个大的背景图icon_install.png,动态部分是在背景图上进行覆盖的7张小图片installationOverlay01-07.png,实现机器人肚子上旋转的动画。
整体这部分的代码路径是在platform/bootable/recovery下,主要涉及的类是screen_ui.cpp
修改的思路是替换installationOverlay01-07.png图片为自己需要的图片,然后修改installationOverlay01-07.png显示的坐标位置,同时调整一下下方progressbar的高度和文字的高度,实现整体协调的效果。

修改installationOverlay01-07.png的具体位置:
void ScreenRecoveryUI::draw_install_overlay_locked(int frame) {
    if (installationOverlay == NULL || overlay_offset_x < 0) return;
    gr_surface surface = installationOverlay[frame];
    int iconWidth = gr_get_width(surface);
    int iconHeight = gr_get_height(surface);
    // 改变iconX和iconY的位置,修改overlay图片的描画坐标,数值自己定
    int iconX = (gr_fb_width()-127) / 2;
    int iconY = (gr_fb_height()-192) / 2;
    gr_blit(surface, 0, 0, iconWidth, iconHeight,
            iconX, iconY);
}



修改progressbar的具体高度:
void ScreenRecoveryUI::draw_progress_locked()
{
    if (currentIcon == ERROR) return;

    if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
        draw_install_overlay_locked(installingFrame);
    }

    if (progressBarType != EMPTY) {
        int iconHeight = gr_get_height(backgroundIcon[INSTALLING_UPDATE]);
        int width = gr_get_width(progressBarEmpty);
        int height = gr_get_height(progressBarEmpty);

        //修改dx dy的数值,改变progressbar的位置显示
        int dx = (gr_fb_width() - width)/2;
        int dy = (3*gr_fb_height() + iconHeight - 2*height)/4;

        // Erase behind the progress bar (in case this was a progress-only update)
        gr_color(0, 0, 0, 255);
        gr_fill(dx, dy, width, height);

        if (progressBarType == DETERMINATE) {
            float p = progressScopeStart + progress * progressScopeSize;
            int pos = (int) (p * width);

            if (rtl_locale) {
                // Fill the progress bar from right to left.
                if (pos > 0) {
                    gr_blit(progressBarFill, width-pos, 0, pos, height, dx+width-pos, dy);
                }
                if (pos < width-1) {
                    gr_blit(progressBarEmpty, 0, 0, width-pos, height, dx, dy);
                }
            } else {
                // Fill the progress bar from left to right.
                if (pos > 0) {
                    gr_blit(progressBarFill, 0, 0, pos, height, dx, dy);
                }
                if (pos < width-1) {
                    gr_blit(progressBarEmpty, pos, 0, width-pos, height, dx+pos, dy);
                }
            }
        }

        if (progressBarType == INDETERMINATE) {
            static int frame = 0;
            gr_blit(progressBarIndeterminate[frame], 0, 0, width, height, dx, dy);
            // in RTL locales, we run the animation backwards, which
            // makes the spinner spin the other way.
            if (rtl_locale) {
                frame = (frame + indeterminate_frames - 1) % indeterminate_frames;
            } else {
                frame = (frame + 1) % indeterminate_frames;
            }
        }
    }
}



修改升级和恢复出厂界面下文字的位置:
void ScreenRecoveryUI::draw_background_locked(Icon icon)
{
    pagesIdentical = false;
    gr_color(0, 0, 0, 255);
    gr_fill(0, 0, gr_fb_width(), gr_fb_height());

    if (icon) {
        gr_surface surface = backgroundIcon[icon];
        gr_surface text_surface = backgroundText[icon];

        int iconWidth = gr_get_width(surface);
        int iconHeight = gr_get_height(surface);
        int textWidth = gr_get_width(text_surface);
        int textHeight = gr_get_height(text_surface);

        int iconX = (gr_fb_width() - iconWidth) / 2;
        int iconY = (gr_fb_height() - (iconHeight+textHeight+40)) / 2;

        //这里改变文字的位置坐标,会同时影响恢复出厂设置和升级界面显示下的文字位置
        int textX = (gr_fb_width() - textWidth) / 2;
        int textY = ((gr_fb_height() - (iconHeight+textHeight+40)) / 2) + iconHeight + 40;

        gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY);
        if (icon == INSTALLING_UPDATE || icon == ERASING) {
           draw_install_overlay_locked(installingFrame);
        }

        gr_color(255, 255, 255, 255);
        gr_texticon(textX, textY, text_surface);
    }
}



动画播放的频率默认是1秒钟20帧。如果修改可以在这里改:
void ScreenRecoveryUI::progress_loop() {
    double interval = 1.0 / animation_fps;
    ......
    }
}



    遇到的坑主要有两个。
    第一个就是在替换图片的时候,最开始替换的图片的位深度跟原始图片的位深度不一致,导致图片进去后花屏,后来查清楚了原来是图片位深度引起的,所以在替换图片的时候如果图片被不正常的拉伸了,可以看下是否是位深度不一样导致的。
    第二个就是遇到了一个奇怪的现象,每次烧写之后如果直接升级的话,升级的界面显示总是跟自己改的不一样,但是如果烧写后恢复出厂的话,然后再次升级,则界面显示是完全ok的,这个问题也查了很久最终定位在recovery模式下的语言locale上,因为升级调用启动程序是自己写的,在往/cache/recovery/command写入升级命令的时候只写了--update_package命令,并没有给指定--locale=en_US或是--locale=zh_CN,所以recovery模式并未识别到语言环境,导致影响了screen_ui.cpp中关于textHeight的计算,而textHeight的数值又影响了图片以及文字的高度设置,所以看起来不会按照自己设置的方式来改变。
    升级时的语言识别的逻辑是这样的:
    首先进入recovery模式后,在执行Recovery.cpp的main函数时,会对/cache/recovery/command写入的命令进行逐行解析,当解析到locale的时候,就会将当前升级操作的locale设置为读到的内容,当没有在command中读到locale的时候,系统会走load_locale_from_cache()函数,来获取上一次我们是否在/cache/recovery/last_locale中写入了之前的语言环境,如果还是没有的话,locale就真的找不到了,text的高度是根据locale来获取的,这时候就会影响text的高度的值,从而导致升级界面出现问题。
    那为什么先恢复出厂设置后再升级就没问题了呢?原因是恢复出厂设置的最后一步会在/cache/recovery/last_locale中写入语言环境,这样在下次升级的时候就可以找到一个语言的依据,也就不会导致text高度出现问题。

int
main(int argc, char **argv) {

    ......
    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 'p': previous_runs = atoi(optarg); break;
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'w': wipe_data = wipe_cache = 1; break;
        case 'c': wipe_cache = 1; break;
        case 't': show_text = 1; break;
        case 'x': just_exit = true; break;
        case 'l': locale = optarg; break;
        case 'g': {
            if (stage == NULL || *stage == '\0') {
                char buffer[20] = "1/";
                strncat(buffer, optarg, sizeof(buffer)-3);
                stage = strdup(buffer);
            }
            break;
        }
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

    if (locale == NULL) {
        load_locale_from_cache();
    }
    ......
}



static void
load_locale_from_cache() {
    // LOCALE_FILE就是/cache/recovery/last_locale
    FILE* fp = fopen_path(LOCALE_FILE, "r");
    char buffer[80];
    if (fp != NULL) {
        fgets(buffer, sizeof(buffer), fp);
        int j = 0;
        unsigned int i;
        for (i = 0; i < sizeof(buffer) && buffer[i]; ++i) {
            if (!isspace(buffer[i])) {
                buffer[j++] = buffer[i];
            }
        }
        buffer[j] = 0;
        locale = strdup(buffer);
        check_and_fclose(fp, LOCALE_FILE);
    }
}


    刚开始接触底层,有些可能说的不对,希望自己对底层一点点的熟悉起来。对于这部分的代码可以通过LOGI来进行log输出,然后在恢复出厂后在/cache/recovery/last_log中查看到自己打印的log信息。

另外看了下android 7.1的这部分的代码,发现貌似已经可以利用max_stage是否为-1来控制不显示图片,只显示文字了。

    最后附上两个博客,对了解recovery模式和recovery模式的界面描画很有帮助。
    http://blog.youkuaiyun.com/u010223349/article/details/40392789
    http://blog.youkuaiyun.com/fengying765/article/details/38301895







<think>好的,用户现在问的是如何区分Android刷机开机恢复出厂设置开机。这个问题看起来是想了解在两种不同操作后,设备启动时有什么不同之处。我需要先理解这两个操作的具体过程,然后找出它们在启动时的区别。 首先,刷机通常指的是安装或更新系统镜像,比如使用Fastboot或Recovery模式刷入新的ROM、内核或分区。而恢复出厂设置则是将设备恢复到初始状态,清除用户数据,但不会改变系统分区的内容。用户可能想知道在开机时如何判断设备是刚刷机还是刚恢复出厂设置。 接下来,我需要考虑两者的启动流程差异。刷机可能涉及系统分区的更改,因此在启动时可能会有不同的行为,比如首次启动时的初始化步骤。而恢复出厂设置主要清除用户数据,系统分区可能没有变化,但用户数据分区被格式化,导致启动时需要重新配置用户数据。 可能的关键点包括启动动画、首次设置向导的出现、系统版本变化、启动日志等。例如,刷机后系统版本可能不同,首次启动会有更长时间的优化应用过程。而恢复出厂设置后,系统版本不变,但用户数据被清空,启动后会进入设置向导,但应用优化可能较少。 还需要考虑一些特殊情况,比如某些厂商可能有不同的提示信息,或者在Recovery模式下执行的日志记录。另外,系统日志(如logcat)可能在两种情况下有不同的输出,比如刷机后会有系统分区的更新记录,而恢复出厂设置则会显示数据分区的格式化。 用户可能没有提到但相关的点包括如何通过ADB获取启动日志,或者检查系统属性来区分。比如,查看build.prop文件的修改时间,刷机后可能更新,而恢复出厂设置不会影响这个文件。 需要确保回答结构清晰,分点说明两种操作在开机时的区别,可能包括启动界面、系统提示、数据状态、日志信息等方面。同时要注意用户可能的技术水平,避免使用过于专业的术语,但又要提供足够的信息帮助区分两种情况。 最后,需要验证这些区别是否普遍适用于不同Android版本设备,或者是否存在厂商定制的情况。比如,某些厂商可能在恢复出厂设置后也显示类似刷机的提示,这时候可能需要更深入的方法来区分。</think>在 Android 设备中,"刷机开机""恢复出厂设置开机"是两种不同的系统启动场景,其底层操作表现有显著差异。以下是具体的区分方法关键特征: --- ### **1. 操作定义与目的** | **场景** | **刷机开机** | **恢复出厂设置开机** | |----------------------|--------------------------------------|---------------------------------------| | **操作内容** | 通过 Fastboot/Recovery 刷入新系统镜像 | 清除用户数据(`/data`分区)缓存 | | **影响范围** | 修改系统分区(如`system`、`vendor`) | 仅清除用户数据部分缓存(`/data`、`/cache`) | | **目的** | 升级/降级系统、修复系统故障 | 重置设备到初始状态,解决软件问题 | --- ### **2. 开机流程差异** #### **(1) 刷机开机后的首次启动** - **系统初始化**: - 若刷入的是完整系统镜像(如`.zip`包或`.img`文件),首次启动会触发**系统分区的重建**(如`ART优化`、`dex2oat`编译应用)。 - 可能出现长时间启动动画(如"正在优化应用第X个,共Y个")。 - **数据状态**: - 若未主动清除用户数据,原有用户数据可能保留,但可能与新系统不兼容。 - 若刷机时执行了`Format Data`,则行为类似恢复出厂设置。 #### **(2) 恢复出厂设置后的首次启动** - **系统初始化**: - 仅重建用户数据分区(`/data`),**系统分区保持原样**。 - 启动速度较快,无应用优化过程(除非系统更新后首次启动)。 - **数据状态**: - `/data`分区被清空,设备回到初始设置向导界面。 - 预装应用恢复出厂版本,用户安装的第三方应用全部删除。 --- ### **3. 界面与日志特征** | **特征** | **刷机开机** | **恢复出厂设置开机** | |-----------------------|--------------------------------------|---------------------------------------| | **启动动画/提示** | 可能显示厂商定制刷机标识(如`Unlocked Bootloader`警告) | 通常为默认启动动画,无特殊提示 | | **首次启动向导** | 若清除数据则触发向导;否则直接进入系统 | 必定触发初始设置向导(选择语言、登录账号等) | | **系统版本** | 可能更新为新刷入的版本 | 保持原系统版本不变 | | **日志信息(adb/logcat)** | 存在系统分区更新记录(如`dm-verity`校验) | 显示`/data`分区格式化日志 | --- ### **4. 技术层面验证方法** #### **(1) 检查分区修改时间** - **刷机开机**: 系统分区(如`system.img`、`vendor.img`)的修改时间与刷机时间一致。 ```bash adb shell ls -l /dev/block/bootdevice/by-name/system ``` - **恢复出厂设置**: 仅用户数据分区(`/data`)时间更新,系统分区时间不变。 #### **(2) 查看系统属性** - **刷机后**: 若刷入的 ROM 包含自定义标记(如`ro.build.description`),属性值会变化。 ```bash adb shell getprop ro.build.fingerprint ``` - **恢复出厂设置**: 系统属性与刷机前一致,仅用户数据重置。 #### **(3) Recovery 日志** - 刷机操作会在 Recovery 日志(`/cache/recovery/log`)中记录刷入的包名: ```text Installing zip file '/sdcard/lineage-20.zip' ``` - 恢复出厂设置会记录`Formatting /data...`等操作。 --- ### **5. 特殊情况与例外** - **厂商定制行为**: 部分厂商(如小米、三星)可能在恢复出厂设置时自动下载最新系统包,导致表现类似刷机。 - **A/B 无缝更新**: 在支持 A/B 分区的设备上,系统更新可能无感知切换分区,与刷机行为不同。 --- ### **总结** | **区分维度** | **刷机开机** | **恢复出厂设置开机** | |----------------------|----------------------------------|-------------------------------| | **系统分区变化** | 是 | 否 | | **用户数据清除** | 可选(取决于是否执行`wipe data`) | 强制清除 | | **启动耗时** | 长(需优化应用) | 短(仅重建`/data`) | | **底层日志特征** | 记录系统镜像写入 | 记录`/data`格式化 | 通过观察启动流程、数据状态、系统属性或日志信息,可明确区分两种场景。若需进一步验证,建议结合`adb`工具系统日志分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值