目录
recovery 界面菜单
recovery 界面操作
recovery 启动流程
recovery 编译makefile
recovery 图片大小
ramdisk、boot.img、recovery.img之间的关系
author | daisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 |
recovery 界面菜单
recovery 界面显示 | android recoveryuse |
路径 | bootable/recovery/device.cpp |
背景设置 | void ScreenRecoveryUI::draw_background_locked() { gr_color(0, 0, 0, 255); } 第一个参数 0:表示红色分量的强度,这里是最小值,表示没有红色。 第二个参数 0:表示绿色分量的强度,这里是最小值,表示没有绿色。 第三个参数 0:表示蓝色分量的强度,这里是最小值,表示没有蓝色。 第四个参数 255:表示透明度或不透明度,这里是最大值,表示完全不透明。 因此,gr_color(0, 0, 0, 255) 表示的是一个完全不透明的黑色。 如果要设置绿色不透明背景,修改参数为gr_color(0, 255, 0, 255) |
路径 | bootable/recovery/screen_ui.cpp |
#include "device.h"
static const char* MENU_ITEMS[] = {
"Reboot system now",
"Reboot to bootloader",
"Apply update from ADB",
"Apply update from SD card",
"Wipe data/factory reset",
#ifndef AB_OTA_UPDATER
"Wipe cache partition",
#endif // !AB_OTA_UPDATER
"Mount /system",
"View recovery logs",
"Run graphics test",
"Power off",
NULL,
};
static const Device::BuiltinAction MENU_ACTIONS[] = {
Device::REBOOT,
Device::REBOOT_BOOTLOADER,
Device::APPLY_ADB_SIDELOAD,
Device::APPLY_SDCARD,
Device::WIPE_DATA,
#ifndef AB_OTA_UPDATER
Device::WIPE_CACHE,
#endif // !AB_OTA_UPDATER
Device::MOUNT_SYSTEM,
Device::VIEW_RECOVERY_LOGS,
Device::RUN_GRAPHICS_TEST,
Device::SHUTDOWN,
};
static_assert(sizeof(MENU_ITEMS) / sizeof(MENU_ITEMS[0]) ==
sizeof(MENU_ACTIONS) / sizeof(MENU_ACTIONS[0]) + 1,
"MENU_ITEMS and MENU_ACTIONS should have the same length, "
"except for the extra NULL entry in MENU_ITEMS.");
const char* const* Device::GetMenuItems() {
return MENU_ITEMS;
}
这段代码定义了两个数组:MENU_ITEMS和MENU_ACTIONS。这两个数组用于存储菜单项和对应的操作。
MENU_ITEMS是一个字符串数组,包含了一系列菜单项的名称。每个菜单项都是一个字符串常量。
MENU_ACTIONS是一个Device::BuiltinAction类型的数组,用于存储与每个菜单项对应的操作。Device::BuiltinAction是一个枚举类型,表示设备的内置操作,如重启、应用更新、擦除数据等。
在MENU_ITEMS数组的末尾,有一个NULL指针,表示数组的结束。
代码中的GetMenuItems()函数返回了MENU_ITEMS数组的地址,即菜单项的名称数组的地址。
最后,代码使用了static_assert语句来确保MENU_ITEMS和MENU_ACTIONS数组的长度相同,除了MENU_ITEMS数组中的额外的NULL条目。如果长度不同,编译时将会报错。
recovery 界面操作
代码中的GetMenuItems()函数返回了MENU_ITEMS数组的地址,即菜单项的名称数组的地址。具体经过switch和case进行具体的操作
// Return REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER. Returning NO_ACTION
// means to take the default, which is to reboot or shutdown depending
// on if the --shutdown_after flag was passed to recovery.
static Device::BuiltinAction
prompt_and_wait(Device* device, int status) {
for (;;) {
finish_recovery(NULL);
switch (status) {
case INSTALL_SUCCESS:
case INSTALL_NONE:
ui->SetBackground(RecoveryUI::NO_COMMAND);
break;
case INSTALL_ERROR:
case INSTALL_CORRUPT:
ui->SetBackground(RecoveryUI::ERROR);
break;
}
ui->SetProgressType(RecoveryUI::EMPTY);
int chosen_item = get_menu_selection(nullptr, device->GetMenuItems(), 0, 0, device);
// device-specific code may take some action here. It may
// return one of the core actions handled in the switch
// statement below.
Device::BuiltinAction chosen_action = device->InvokeMenuItem(chosen_item);
bool should_wipe_cache = false;
switch (chosen_action) {
case Device::NO_ACTION:
break;
case Device::REBOOT:
case Device::SHUTDOWN:
case Device::REBOOT_BOOTLOADER:
return chosen_action;
case Device::WIPE_DATA:
wipe_data(ui->IsTextVisible(), device);
if (!ui->IsTextVisible()) return Device::NO_ACTION;
break;
case Device::WIPE_CACHE:
wipe_cache(ui->IsTextVisible(), device);
if (!ui->IsTextVisible()) return Device::NO_ACTION;
break;
case Device::APPLY_ADB_SIDELOAD:
case Device::APPLY_SDCARD:
//省略代码……
break;
case Device::VIEW_RECOVERY_LOGS:
choose_recovery_file(device);
break;
case Device::RUN_GRAPHICS_TEST:
run_graphics_test(device);
break;
case Device::MOUNT_SYSTEM:
#ifdef USE_MDTP
if (is_mdtp_activated()) {
ui->Print("Mounting /system forbidden by MDTP.\n");
}
else
#endif
//省略代码……
break;
}
}
}
这段代码定义了一个函数prompt_and_wait,该函数用于提示用户选择一个操作,并等待用户的输入。
函数的参数包括一个指向Device对象的指针device和一个整数status。
函数使用一个无限循环for (;;) {}来不断执行以下操作:
调用finish_recovery(NULL)函数,完成recovery操作的最后步骤。
根据status的值,设置recovery界面的背景和进度条的类型。
如果status的值是INSTALL_SUCCESS或INSTALL_NONE,则将背景设置为RecoveryUI::NO_COMMAND;如果status的值是INSTALL_ERROR或INSTALL_CORRUPT,则将背景设置为RecoveryUI::ERROR。
将进度条的类型设置为RecoveryUI::EMPTY,表示没有进度信息。
调用get_menu_selection函数,显示菜单并等待用户选择。该函数的参数包括一个空指针nullptr,表示不显示标题;device->GetMenuItems(),表示获取设备的菜单项;0,表示不显示菜单的起始索引;0,表示不显示菜单的结束索引;device,表示设备对象。
函数最终返回用户选择的操作,可以是Device::REBOOT、Device::SHUTDOWN或Device::REBOOT_BOOTLOADER。如果用户没有选择任何操作,则返回Device::NO_ACTION,表示采取默认操作,即根据--shutdown_after标志决定是重启还是关机。
recovery 启动流程
参考链接 | Recovery启动流程(2)---UI界面【转】-腾讯云开发者社区-腾讯云 https://www.cnblogs.com/xiaolei-kaiyuan/p/5456227.html android-ramdisk.img分析、recovery.img&boot.img执行过程 |
我们知道,当我们通过按键或者应用进入recovery模式,实质是kernel后加载recovery.img,kernel起来后执行的第一个进程就是init,此进程会读入init.rc启动相应的服务。在recovery模式中,启动的服务是执行recovery可执行文件,此文件是bootable/recovery/recovery.cpp文件生成,我们就从recovery.cpp文件开始分析。
从recovery.cpp main()中可知,进入recovery后会分析/cache/recovery/command文件,根据内容来设定显示的文字语言
SetLocale函数根据locale判断所用的字体是否属于阿拉伯语系,阿拉伯语的书写习惯是从右到左,如果是阿拉伯语系的话,就设置一个标志,后面根据这个标志决定从右到左显示文字或进度条。关于显示文字的语言通过代码即可查看,这里只简单的列出语言设置的几条主线,不贴出具体的代码(太多了)。
recovery 编译makefile
makefile路径 | build/core/Makefile |
代码 | /res 对应路径 bootable/recovery/res-xhdpi bootable/recovery/res-mdpi |
build/core/Makefile
# Otherwise, use the default medium density.
recovery_densities := ldpi
endif
ifneq (,$(wildcard $(recovery_resources_common)-$(recovery_density)))
recovery_resources_common := $(recovery_resources_common)-$(recovery_density)
else
# recovery_resources_common := $(recovery_resources_common)-xhdpi
recovery_resources_common := $(recovery_resources_common)-mdpi
endif
recovery 图片大小
路径 | bootable/recovery/fonts |
内容 | 2*22.png 打开如图用ps查看,并裁剪其中一个字符的大小是12*22像素 注意要包含空余空余 |
img文件 | 编译出来的recovery.img |
ramdisk、boot.img、recovery.img之间的关系
ramdisk.img会被打包到boot.img和recovery.img中(不是同一个ramdisk.img).
ramdisk.img中比较重要的文件是"init","init.rc",其中init是system/core/init/init.c编译而来,
boot.img中ramdisk里的init.rc位于system/core/init/init.rc,
recovery.img中ramdisk里的init.rc位于bootable/recovery/etc/init.rc。
kernel加载结束以后第一个进程是执行init,init会解析init.rc文件,并起相应的服务。
由此可以知道正常开机和进入recovery模式起的进程是不同的。
感悟
recovery这个块是自己在调试低分辨率屏幕时,kernel阶段正常显示,但是recovery界面灭有显示而排查的,后面发现主要是由于lk阶段的panel_xxxx_video.h文件初始化的command有关,但是recovery的fronts中的字符库分辨率大小确实影响了显示recovery.img的背景显示。
另外在排查问题的过程中阅读别人的博客学习,但是很容易就忘记,所以就把优质博客记录下来一方面方便自己查阅,另一方面也是帮助大家过滤