Recovery启动流程(2)---UI界面

时间:2024-05-31 19:37:32

转载请注明来源:cuixiaolei的技术博客

Recovery启动流程系列文章把recvoery目录下文件分成小块讲解,最后再以一条主线贯穿所有的内容。这篇文章主要讲解Recovery-UI的相关内容。

我们知道,当我们通过按键或者应用进入recovery模式,实质是kernel后加载recovery.img,kernel起来后执行的第一个进程就是init,此进程会读入init.rc启动相应的服务。在recovery模式中,启动的服务是执行recovery可执行文件,此文件是bootable/recovery/recovery.cpp文件生成,我们就从recovery.cpp文件开始分析。此出可参考我的另一篇文章android-ramdisk.img分析、recovery.img&boot.img执行过程

bootable/recovery/recovery.cpp
int
main(int argc, char **argv) { ....
Device* device = make_device();
ui = device->GetUI();
gCurrentUI = ui; ui->SetLocale(locale);
ui->Init(); ui->SetBackground(RecoveryUI::NONE);
if (show_text) ui->ShowText(true);
....
if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
prompt_and_wait(device, status);
}
.... }

1.首先新建了一个Device类的对象, Device类封装了一些操作,包括UI的操作

2.调用Device类的GetUI()返回一个RecoveryUI对象

3.调用ui->SetLocale(locale)设置语言,调用SetBackground方法设置背景图片

4.调用Init()进行初始化。

5.这里的Init从代码上看应该是ui.cpp文件中RecoveryUI类的Init()方法,但是经验上走的应该是ScreenRecoveryUI,其中的愿意我还在看,这里我是按照ScreenRecoveryUI::Init追的代码。其中RecoveryUI是ScreenRecoveryUI的父类。

6.显示recovery的主界面,即一个选择菜单

初始化

void ScreenRecoveryUI::Init() {
gr_init();             //初始化图形设备,分配Pixelflinger库渲染的内存 gr_font_size(&char_width, &char_height);
text_rows_ = gr_fb_height() / char_height;
text_cols_ = gr_fb_width() / char_width; #ifdef SUPPORT_UTF8_MULTILINGUAL
int ml_cols_ = * text_cols_; //max is 6 char for 1 utf8 character.
text_ = Alloc2d(text_rows_, ml_cols_ + );
file_viewer_text_ = Alloc2d(text_rows_, ml_cols_ + );
menu_ = Alloc2d(text_rows_, ml_cols_ + );
menu_headers_wrap = Alloc2d(text_rows_, ml_cols_ + );
#else
text_ = Alloc2d(text_rows_, text_cols_ + );
file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + );
menu_ = Alloc2d(text_rows_, text_cols_ + );
#endif text_col_ = text_row_ = ;
text_top_ = ; backgroundIcon[NONE] = nullptr;
LoadBitmapArray("icon_installing", &installing_frames, &installation);
backgroundIcon[INSTALLING_UPDATE] = installing_frames ? installation[] : nullptr;
backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];
LoadBitmap("icon_error", &backgroundIcon[ERROR]);                //LoadBitmap()  将png生成surface, 每个png图片对应一个surface, 所有surface存放在一个数组中
backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR]; LoadBitmap("icon_recovery", &backgroundIcon[RECOVERY]);
LoadBitmap("progress_empty", &progressBarEmpty);
LoadBitmap("progress_fill", &progressBarFill);
LoadBitmap("stage_empty", &stageMarkerEmpty);
LoadBitmap("stage_fill", &stageMarkerFill); /* add for AT&T recovery update install UI begin */
#ifdef TARGET_ATT_RECOVERY_UI
LoadBitmap("icon_attinstalling", &backgroundIcon[ATT_INSTALLING_UPDATE]);
LoadBitmap("progress_attempty", &progressBarEmpty_ATT);
LoadBitmap("progress_attfill", &progressBarFill_ATT);
LoadLocalizedBitmap("installing_atttext", &backgroundText[ATT_INSTALLING_UPDATE]);   //LoadLocalizedBitmap()  将区域文字所在的图片中的text信息根据当前的locale提取出来,生成对应的surface, 所有
 surface也存放在一个数组中
#endif
/* add for AT&T recovery update install UI end */ LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]);
LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]);
LoadLocalizedBitmap("no_command_text", &backgroundText[NO_COMMAND]);
LoadLocalizedBitmap("error_text", &backgroundText[ERROR]); pthread_create(&progress_thread_, nullptr, ProgressThreadStartRoutine, this);   //创建一个线程,在该循环中不停地检测currentIcon以及progressBarType来决定是不是要更新进度条。
RecoveryUI::Init();  //初始化RecoveryUI类
}
bootable/recovery/minui/ui.cpp

void RecoveryUI::Init() {
ev_init(InputCallback, this); ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1)); pthread_create(&input_thread_, nullptr, InputThreadLoop, nullptr);
}
通过RecoveryUI::Init(); 调用events.cpp文件,界面和按键/触摸联系在一起了,后面会用单独的文章介绍recovery按键和触屏的相关内容。

下面介绍几个常用的函数
void ScreenRecoveryUI::SetLocale(const char* new_locale) {
if (new_locale) {
this->locale = new_locale;
char* lang = strdup(locale);
for (char* p = lang; *p; ++p) {
if (*p == '_') {
*p = '\0';
break;
}
} // A bit cheesy: keep an explicit list of supported languages
// that are RTL.
if (strcmp(lang, "ar") == || // Arabic
strcmp(lang, "fa") == || // Persian (Farsi)
strcmp(lang, "he") == || // Hebrew (new language code)
strcmp(lang, "iw") == || // Hebrew (old language code)
strcmp(lang, "ur") == ) { // Urdu
rtl_locale = true;
}
free(lang);
} else {
new_locale = nullptr;
}
}

从recovery.cpp main()中可知,进入recovery后会分析/cache/recovery/command文件,根据内容来设定显示的文字语言

SetLocale函数根据locale判断所用的字体是否属于阿拉伯语系,阿拉伯语的书写习惯是从右到左,如果是阿拉伯语系的话,就设置一个标志,后面根据这个标志决定从右到左显示文字或进度条。关于显示文字的语言通过代码即可查看,这里只简单的列出语言设置的几条主线,不贴出具体的代码(太多了)。

g_ml_str[] (mi_string.h)-> ml_string_fetch() (multilingual.c)

ml_set_language (multilingual.c) -> ml_select() (recovery.cpp) -> prompt_and_wait() (recovery.cpp) -> main() (recovery.cpp)
SetBackground函数比较简洁,关键部分在update_screen_locked。
update_screen_locked 和update_progress_locked是recovery的UI部分的关键函数,update_screen_locked用来更新背 景, update_progress_locked用来更新进度条,因为显示的画面会一直在更新,所以这两个函数会在不同的地方被反复调用
void ScreenRecoveryUI::SetBackground(Icon icon) {
pthread_mutex_lock(&updateMutex); currentIcon = icon;
update_screen_locked(); pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::update_screen_locked() {
draw_screen_locked();
gr_flip();
}
void ScreenRecoveryUI::draw_screen_locked() {
if (!show_text) {
draw_background_locked(currentIcon);               //************   有一个bug因为此行没有,导致SetBackground函数无法更换背景图片
draw_progress_locked();
} else {
gr_color(, , , );
gr_clear();
draw_background_locked(currentIcon);            //************
    .........

}
}

此文章持续更新.......