Recovery啓動流程系列文章把recvoery目錄下文件分成小塊講解,最後再以一條主線貫穿所有的內容。這篇文章主要講解Recovery-UI的相關內容。
我們知道,當我們通過按鍵或者應用進入recovery模式,實質是kernel後加載recovery.img,kernel起來後執行的第一個進程就是init,此進程會讀入init.rc啓動相應的服務。在recovery模式中,啓動的服務是執行recovery可執行文件,此文件是bootable/recovery/recovery.cpp文件生成,我們就從recovery.cpp文件開始分析。
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_ = 6 * text_cols_; //max is 6 char for 1 utf8 character.
text_ = Alloc2d(text_rows_, ml_cols_ + 1);
file_viewer_text_ = Alloc2d(text_rows_, ml_cols_ + 1);
menu_ = Alloc2d(text_rows_, ml_cols_ + 1);
menu_headers_wrap = Alloc2d(text_rows_, ml_cols_ + 1);
#else
text_ = Alloc2d(text_rows_, text_cols_ + 1);
file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1);
menu_ = Alloc2d(text_rows_, text_cols_ + 1);
#endif
text_col_ = text_row_ = 0;
text_top_ = 1;
backgroundIcon[NONE] = nullptr;
LoadBitmapArray("icon_installing", &installing_frames, &installation);
backgroundIcon[INSTALLING_UPDATE] = installing_frames ? installation[0] : 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") == 0 || // Arabic
strcmp(lang, "fa") == 0 || // Persian (Farsi)
strcmp(lang, "he") == 0 || // Hebrew (new language code)
strcmp(lang, "iw") == 0 || // Hebrew (old language code)
strcmp(lang, "ur") == 0) { // 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(0, 0, 0, 255);
gr_clear();
draw_background_locked(currentIcon); //************
.........
}
}