轉載請注明來源: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_ = 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, 所有
#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)
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); //************
.........
} }
此文章持續更新.......