summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Android.mk3
-rw-r--r--OWNERS3
-rw-r--r--applypatch/imgdiff.cpp25
-rw-r--r--install.cpp32
-rw-r--r--screen_ui.cpp794
-rw-r--r--screen_ui.h221
-rw-r--r--tests/Android.mk1
-rw-r--r--tests/component/imgdiff_test.cpp33
-rw-r--r--tests/component/updater_test.cpp163
-rw-r--r--ui.cpp330
-rw-r--r--ui.h288
-rw-r--r--updater/Android.mk1
-rw-r--r--updater/blockimg.cpp175
-rw-r--r--vr_ui.cpp8
-rw-r--r--vr_ui.h16
-rw-r--r--wear_ui.cpp502
-rw-r--r--wear_ui.h77
17 files changed, 1389 insertions, 1283 deletions
diff --git a/Android.mk b/Android.mk
index 95c8823e3..3eed7a696 100644
--- a/Android.mk
+++ b/Android.mk
@@ -59,7 +59,8 @@ LOCAL_STATIC_LIBRARIES := \
libvintf_recovery \
libcrypto_utils \
libcrypto \
- libbase
+ libbase \
+ libziparchive \
include $(BUILD_STATIC_LIBRARY)
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 000000000..09754c650
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+enh+aosp-gerrit@google.com
+tbao@google.com
+xunchang@google.com
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index 41d73ab98..fc240644f 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -693,6 +693,20 @@ static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
continue;
}
+ // The footer contains the size of the uncompressed data. Double-check to make sure that it
+ // matches the size of the data we got when we actually did the decompression.
+ size_t footer_index = pos + raw_data_len + GZIP_FOOTER_LEN - 4;
+ if (sz - footer_index < 4) {
+ printf("Warning: invalid footer position; treating as a nomal chunk\n");
+ continue;
+ }
+ size_t footer_size = get_unaligned<uint32_t>(img->data() + footer_index);
+ if (footer_size != uncompressed_len) {
+ printf("Warning: footer size %zu != decompressed size %zu; treating as a nomal chunk\n",
+ footer_size, uncompressed_len);
+ continue;
+ }
+
ImageChunk body(CHUNK_DEFLATE, pos, img, raw_data_len);
uncompressed_data.resize(uncompressed_len);
body.SetUncompressedData(std::move(uncompressed_data));
@@ -704,17 +718,6 @@ static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
chunks->emplace_back(CHUNK_NORMAL, pos, img, GZIP_FOOTER_LEN);
pos += GZIP_FOOTER_LEN;
-
- // The footer (that we just skipped over) contains the size of
- // the uncompressed data. Double-check to make sure that it
- // matches the size of the data we got when we actually did
- // the decompression.
- size_t footer_size = get_unaligned<uint32_t>(img->data() + pos - 4);
- if (footer_size != body.DataLengthForPatch()) {
- printf("Error: footer size %zu != decompressed size %zu\n", footer_size,
- body.GetRawDataLength());
- return false;
- }
} else {
// Use a normal chunk to take all the contents until the next gzip chunk (or EOF); we expect
// the number of chunks to be small (5 for typical boot and recovery images).
diff --git a/install.cpp b/install.cpp
index a1f2e4fbd..7ba8f0139 100644
--- a/install.cpp
+++ b/install.cpp
@@ -27,6 +27,7 @@
#include <unistd.h>
#include <algorithm>
+#include <atomic>
#include <chrono>
#include <condition_variable>
#include <functional>
@@ -65,18 +66,14 @@ static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25;
static std::condition_variable finish_log_temperature;
// This function parses and returns the build.version.incremental
-static int parse_build_number(const std::string& str) {
+static std::string parse_build_number(const std::string& str) {
size_t pos = str.find('=');
if (pos != std::string::npos) {
- std::string num_string = android::base::Trim(str.substr(pos+1));
- int build_number;
- if (android::base::ParseInt(num_string.c_str(), &build_number, 0)) {
- return build_number;
- }
+ return android::base::Trim(str.substr(pos+1));
}
LOG(ERROR) << "Failed to parse build number in " << str;
- return -1;
+ return "";
}
bool read_metadata_from_package(ZipArchiveHandle zip, std::string* metadata) {
@@ -113,14 +110,14 @@ static void read_source_target_build(ZipArchiveHandle zip, std::vector<std::stri
for (const std::string& line : lines) {
std::string str = android::base::Trim(line);
if (android::base::StartsWith(str, "pre-build-incremental")) {
- int source_build = parse_build_number(str);
- if (source_build != -1) {
- log_buffer->push_back(android::base::StringPrintf("source_build: %d", source_build));
+ std::string source_build = parse_build_number(str);
+ if (!source_build.empty()) {
+ log_buffer->push_back("source_build: " + source_build);
}
} else if (android::base::StartsWith(str, "post-build-incremental")) {
- int target_build = parse_build_number(str);
- if (target_build != -1) {
- log_buffer->push_back(android::base::StringPrintf("target_build: %d", target_build));
+ std::string target_build = parse_build_number(str);
+ if (!target_build.empty()) {
+ log_buffer->push_back("target_build: " + target_build);
}
}
}
@@ -294,11 +291,12 @@ int update_binary_command(const std::string& package, ZipArchiveHandle zip,
}
#endif // !AB_OTA_UPDATER
-static void log_max_temperature(int* max_temperature) {
+static void log_max_temperature(int* max_temperature, const std::atomic<bool>& logger_finished) {
CHECK(max_temperature != nullptr);
std::mutex mtx;
std::unique_lock<std::mutex> lck(mtx);
- while (finish_log_temperature.wait_for(lck, 20s) == std::cv_status::timeout) {
+ while (!logger_finished.load() &&
+ finish_log_temperature.wait_for(lck, 20s) == std::cv_status::timeout) {
*max_temperature = std::max(*max_temperature, GetMaxValueFromThermalZone());
}
}
@@ -403,7 +401,8 @@ static int try_update_binary(const std::string& package, ZipArchiveHandle zip, b
}
close(pipefd[1]);
- std::thread temperature_logger(log_max_temperature, max_temperature);
+ std::atomic<bool> logger_finished(false);
+ std::thread temperature_logger(log_max_temperature, max_temperature, std::ref(logger_finished));
*wipe_cache = false;
bool retry_update = false;
@@ -467,6 +466,7 @@ static int try_update_binary(const std::string& package, ZipArchiveHandle zip, b
int status;
waitpid(pid, &status, 0);
+ logger_finished.store(true);
finish_log_temperature.notify_one();
temperature_logger.join();
diff --git a/screen_ui.cpp b/screen_ui.cpp
index a7d9c9f4b..d9574d869 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -45,9 +45,9 @@
// Return the current time as a double (including fractions of a second).
static double now() {
- struct timeval tv;
- gettimeofday(&tv, nullptr);
- return tv.tv_sec + tv.tv_usec / 1000000.0;
+ struct timeval tv;
+ gettimeofday(&tv, nullptr);
+ return tv.tv_sec + tv.tv_usec / 1000000.0;
}
ScreenRecoveryUI::ScreenRecoveryUI()
@@ -82,25 +82,30 @@ ScreenRecoveryUI::ScreenRecoveryUI()
max_stage(-1),
updateMutex(PTHREAD_MUTEX_INITIALIZER) {}
-GRSurface* ScreenRecoveryUI::GetCurrentFrame() {
- if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
- return intro_done ? loopFrames[current_frame] : introFrames[current_frame];
- }
- return error_icon;
-}
-
-GRSurface* ScreenRecoveryUI::GetCurrentText() {
- switch (currentIcon) {
- case ERASING: return erasing_text;
- case ERROR: return error_text;
- case INSTALLING_UPDATE: return installing_text;
- case NO_COMMAND: return no_command_text;
- case NONE: abort();
- }
+GRSurface* ScreenRecoveryUI::GetCurrentFrame() const {
+ if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
+ return intro_done ? loopFrames[current_frame] : introFrames[current_frame];
+ }
+ return error_icon;
+}
+
+GRSurface* ScreenRecoveryUI::GetCurrentText() const {
+ switch (currentIcon) {
+ case ERASING:
+ return erasing_text;
+ case ERROR:
+ return error_text;
+ case INSTALLING_UPDATE:
+ return installing_text;
+ case NO_COMMAND:
+ return no_command_text;
+ case NONE:
+ abort();
+ }
}
int ScreenRecoveryUI::PixelsFromDp(int dp) const {
- return dp * density_;
+ return dp * density_;
}
// Here's the intended layout:
@@ -127,17 +132,16 @@ static constexpr int kLayouts[LAYOUT_MAX][DIMENSION_MAX] = {
{ 52, 112, }, // LANDSCAPE_LARGE
};
-int ScreenRecoveryUI::GetAnimationBaseline() {
- return GetTextBaseline() - PixelsFromDp(kLayouts[layout_][ICON]) -
- gr_get_height(loopFrames[0]);
+int ScreenRecoveryUI::GetAnimationBaseline() const {
+ return GetTextBaseline() - PixelsFromDp(kLayouts[layout_][ICON]) - gr_get_height(loopFrames[0]);
}
-int ScreenRecoveryUI::GetTextBaseline() {
- return GetProgressBaseline() - PixelsFromDp(kLayouts[layout_][TEXT]) -
- gr_get_height(installing_text);
+int ScreenRecoveryUI::GetTextBaseline() const {
+ return GetProgressBaseline() - PixelsFromDp(kLayouts[layout_][TEXT]) -
+ gr_get_height(installing_text);
}
-int ScreenRecoveryUI::GetProgressBaseline() {
+int ScreenRecoveryUI::GetProgressBaseline() const {
int elements_sum = gr_get_height(loopFrames[0]) + PixelsFromDp(kLayouts[layout_][ICON]) +
gr_get_height(installing_text) + PixelsFromDp(kLayouts[layout_][TEXT]) +
gr_get_height(progressBarFill);
@@ -148,34 +152,33 @@ int ScreenRecoveryUI::GetProgressBaseline() {
// Clear the screen and draw the currently selected background icon (if any).
// Should only be called with updateMutex locked.
void ScreenRecoveryUI::draw_background_locked() {
- pagesIdentical = false;
- gr_color(0, 0, 0, 255);
- gr_clear();
-
- if (currentIcon != NONE) {
- if (max_stage != -1) {
- int stage_height = gr_get_height(stageMarkerEmpty);
- int stage_width = gr_get_width(stageMarkerEmpty);
- int x = (gr_fb_width() - max_stage * gr_get_width(stageMarkerEmpty)) / 2;
- int y = gr_fb_height() - stage_height;
- for (int i = 0; i < max_stage; ++i) {
- GRSurface* stage_surface = (i < stage) ? stageMarkerFill : stageMarkerEmpty;
- gr_blit(stage_surface, 0, 0, stage_width, stage_height, x, y);
- x += stage_width;
- }
- }
+ pagesIdentical = false;
+ gr_color(0, 0, 0, 255);
+ gr_clear();
- GRSurface* text_surface = GetCurrentText();
- int text_x = (gr_fb_width() - gr_get_width(text_surface)) / 2;
- int text_y = GetTextBaseline();
- gr_color(255, 255, 255, 255);
- gr_texticon(text_x, text_y, text_surface);
+ if (currentIcon != NONE) {
+ if (max_stage != -1) {
+ int stage_height = gr_get_height(stageMarkerEmpty);
+ int stage_width = gr_get_width(stageMarkerEmpty);
+ int x = (gr_fb_width() - max_stage * gr_get_width(stageMarkerEmpty)) / 2;
+ int y = gr_fb_height() - stage_height;
+ for (int i = 0; i < max_stage; ++i) {
+ GRSurface* stage_surface = (i < stage) ? stageMarkerFill : stageMarkerEmpty;
+ gr_blit(stage_surface, 0, 0, stage_width, stage_height, x, y);
+ x += stage_width;
+ }
}
+
+ GRSurface* text_surface = GetCurrentText();
+ int text_x = (gr_fb_width() - gr_get_width(text_surface)) / 2;
+ int text_y = GetTextBaseline();
+ gr_color(255, 255, 255, 255);
+ gr_texticon(text_x, text_y, text_surface);
+ }
}
-// Draws the animation and progress bar (if any) on the screen.
-// Does not flip pages.
-// Should only be called with updateMutex locked.
+// Draws the animation and progress bar (if any) on the screen. Does not flip pages. Should only be
+// called with updateMutex locked.
void ScreenRecoveryUI::draw_foreground_locked() {
if (currentIcon != NONE) {
GRSurface* frame = GetCurrentFrame();
@@ -223,67 +226,67 @@ void ScreenRecoveryUI::draw_foreground_locked() {
}
}
-void ScreenRecoveryUI::SetColor(UIElement e) {
- switch (e) {
- case INFO:
- gr_color(249, 194, 0, 255);
- break;
- case HEADER:
- gr_color(247, 0, 6, 255);
- break;
- case MENU:
- case MENU_SEL_BG:
- gr_color(0, 106, 157, 255);
- break;
- case MENU_SEL_BG_ACTIVE:
- gr_color(0, 156, 100, 255);
- break;
- case MENU_SEL_FG:
- gr_color(255, 255, 255, 255);
- break;
- case LOG:
- gr_color(196, 196, 196, 255);
- break;
- case TEXT_FILL:
- gr_color(0, 0, 0, 160);
- break;
- default:
- gr_color(255, 255, 255, 255);
- break;
- }
+void ScreenRecoveryUI::SetColor(UIElement e) const {
+ switch (e) {
+ case INFO:
+ gr_color(249, 194, 0, 255);
+ break;
+ case HEADER:
+ gr_color(247, 0, 6, 255);
+ break;
+ case MENU:
+ case MENU_SEL_BG:
+ gr_color(0, 106, 157, 255);
+ break;
+ case MENU_SEL_BG_ACTIVE:
+ gr_color(0, 156, 100, 255);
+ break;
+ case MENU_SEL_FG:
+ gr_color(255, 255, 255, 255);
+ break;
+ case LOG:
+ gr_color(196, 196, 196, 255);
+ break;
+ case TEXT_FILL:
+ gr_color(0, 0, 0, 160);
+ break;
+ default:
+ gr_color(255, 255, 255, 255);
+ break;
+ }
}
-void ScreenRecoveryUI::DrawHorizontalRule(int* y) {
- SetColor(MENU);
- *y += 4;
- gr_fill(0, *y, gr_fb_width(), *y + 2);
- *y += 4;
+int ScreenRecoveryUI::DrawHorizontalRule(int y) const {
+ gr_fill(0, y + 4, gr_fb_width(), y + 6);
+ return 8;
}
void ScreenRecoveryUI::DrawHighlightBar(int x, int y, int width, int height) const {
- gr_fill(x, y, x + width, y + height);
+ gr_fill(x, y, x + width, y + height);
}
-void ScreenRecoveryUI::DrawTextLine(int x, int* y, const char* line, bool bold) const {
- gr_text(gr_sys_font(), x, *y, line, bold);
- *y += char_height_ + 4;
+int ScreenRecoveryUI::DrawTextLine(int x, int y, const char* line, bool bold) const {
+ gr_text(gr_sys_font(), x, y, line, bold);
+ return char_height_ + 4;
}
-void ScreenRecoveryUI::DrawTextLines(int x, int* y, const char* const* lines) const {
- for (size_t i = 0; lines != nullptr && lines[i] != nullptr; ++i) {
- DrawTextLine(x, y, lines[i], false);
- }
+int ScreenRecoveryUI::DrawTextLines(int x, int y, const char* const* lines) const {
+ int offset = 0;
+ for (size_t i = 0; lines != nullptr && lines[i] != nullptr; ++i) {
+ offset += DrawTextLine(x, y + offset, lines[i], false);
+ }
+ return offset;
}
static const char* REGULAR_HELP[] = {
- "Use volume up/down and power.",
- NULL
+ "Use volume up/down and power.",
+ NULL
};
static const char* LONG_PRESS_HELP[] = {
- "Any button cycles highlight.",
- "Long-press activates.",
- NULL
+ "Any button cycles highlight.",
+ "Long-press activates.",
+ NULL
};
// Redraws everything on the screen. Does not flip pages. Should only be called with updateMutex
@@ -294,6 +297,7 @@ void ScreenRecoveryUI::draw_screen_locked() {
draw_foreground_locked();
return;
}
+
gr_color(0, 0, 0, 255);
gr_clear();
@@ -305,18 +309,17 @@ void ScreenRecoveryUI::draw_screen_locked() {
android::base::GetProperty("ro.bootimage.build.fingerprint", "");
SetColor(INFO);
- DrawTextLine(x, &y, "Android Recovery", true);
+ y += DrawTextLine(x, y, "Android Recovery", true);
for (const auto& chunk : android::base::Split(recovery_fingerprint, ":")) {
- DrawTextLine(x, &y, chunk.c_str(), false);
+ y += DrawTextLine(x, y, chunk.c_str(), false);
}
- DrawTextLines(x, &y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP);
+ y += DrawTextLines(x, y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP);
SetColor(HEADER);
- DrawTextLines(x, &y, menu_headers_);
+ y += DrawTextLines(x, y, menu_headers_);
SetColor(MENU);
- DrawHorizontalRule(&y);
- y += 4;
+ y += DrawHorizontalRule(y) + 4;
for (int i = 0; i < menu_items; ++i) {
if (i == menu_sel) {
// Draw the highlight bar.
@@ -324,13 +327,13 @@ void ScreenRecoveryUI::draw_screen_locked() {
DrawHighlightBar(0, y - 2, gr_fb_width(), char_height_ + 4);
// Bold white text for the selected item.
SetColor(MENU_SEL_FG);
- DrawTextLine(x, &y, menu_[i], true);
+ y += DrawTextLine(x, y, menu_[i], true);
SetColor(MENU);
} else {
- DrawTextLine(x, &y, menu_[i], false);
+ y += DrawTextLine(x, y, menu_[i], false);
}
}
- DrawHorizontalRule(&y);
+ y += DrawHorizontalRule(y);
}
// Display from the bottom up, until we hit the top of the screen, the bottom of the menu, or
@@ -338,10 +341,9 @@ void ScreenRecoveryUI::draw_screen_locked() {
SetColor(LOG);
int row = (text_top_ + text_rows_ - 1) % text_rows_;
size_t count = 0;
- for (int ty = gr_fb_height() - kMarginHeight - char_height_;
- ty >= y && count < text_rows_; ty -= char_height_, ++count) {
- int temp_y = ty;
- DrawTextLine(x, &temp_y, text_[row], false);
+ for (int ty = gr_fb_height() - kMarginHeight - char_height_; ty >= y && count < text_rows_;
+ ty -= char_height_, ++count) {
+ DrawTextLine(x, ty, text_[row], false);
--row;
if (row < 0) row = text_rows_ - 1;
}
@@ -350,81 +352,81 @@ void ScreenRecoveryUI::draw_screen_locked() {
// Redraw everything on the screen and flip the screen (make it visible).
// Should only be called with updateMutex locked.
void ScreenRecoveryUI::update_screen_locked() {
- draw_screen_locked();
- gr_flip();
+ draw_screen_locked();
+ gr_flip();
}
// Updates only the progress bar, if possible, otherwise redraws the screen.
// Should only be called with updateMutex locked.
void ScreenRecoveryUI::update_progress_locked() {
- if (show_text || !pagesIdentical) {
- draw_screen_locked(); // Must redraw the whole screen
- pagesIdentical = true;
- } else {
- draw_foreground_locked(); // Draw only the progress bar and overlays
- }
- gr_flip();
+ if (show_text || !pagesIdentical) {
+ draw_screen_locked(); // Must redraw the whole screen
+ pagesIdentical = true;
+ } else {
+ draw_foreground_locked(); // Draw only the progress bar and overlays
+ }
+ gr_flip();
}
// Keeps the progress bar updated, even when the process is otherwise busy.
void* ScreenRecoveryUI::ProgressThreadStartRoutine(void* data) {
- reinterpret_cast<ScreenRecoveryUI*>(data)->ProgressThreadLoop();
- return nullptr;
+ reinterpret_cast<ScreenRecoveryUI*>(data)->ProgressThreadLoop();
+ return nullptr;
}
void ScreenRecoveryUI::ProgressThreadLoop() {
- double interval = 1.0 / animation_fps;
- while (true) {
- double start = now();
- pthread_mutex_lock(&updateMutex);
-
- bool redraw = false;
-
- // update the installation animation, if active
- // skip this if we have a text overlay (too expensive to update)
- if ((currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) && !show_text) {
- if (!intro_done) {
- if (current_frame == intro_frames - 1) {
- intro_done = true;
- current_frame = 0;
- } else {
- ++current_frame;
- }
- } else {
- current_frame = (current_frame + 1) % loop_frames;
- }
-
- redraw = true;
- }
+ double interval = 1.0 / animation_fps;
+ while (true) {
+ double start = now();
+ pthread_mutex_lock(&updateMutex);
- // move the progress bar forward on timed intervals, if configured
- int duration = progressScopeDuration;
- if (progressBarType == DETERMINATE && duration > 0) {
- double elapsed = now() - progressScopeTime;
- float p = 1.0 * elapsed / duration;
- if (p > 1.0) p = 1.0;
- if (p > progress) {
- progress = p;
- redraw = true;
- }
+ bool redraw = false;
+
+ // update the installation animation, if active
+ // skip this if we have a text overlay (too expensive to update)
+ if ((currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) && !show_text) {
+ if (!intro_done) {
+ if (current_frame == intro_frames - 1) {
+ intro_done = true;
+ current_frame = 0;
+ } else {
+ ++current_frame;
}
+ } else {
+ current_frame = (current_frame + 1) % loop_frames;
+ }
- if (redraw) update_progress_locked();
+ redraw = true;
+ }
- pthread_mutex_unlock(&updateMutex);
- double end = now();
- // minimum of 20ms delay between frames
- double delay = interval - (end-start);
- if (delay < 0.02) delay = 0.02;
- usleep(static_cast<useconds_t>(delay * 1000000));
+ // move the progress bar forward on timed intervals, if configured
+ int duration = progressScopeDuration;
+ if (progressBarType == DETERMINATE && duration > 0) {
+ double elapsed = now() - progressScopeTime;
+ float p = 1.0 * elapsed / duration;
+ if (p > 1.0) p = 1.0;
+ if (p > progress) {
+ progress = p;
+ redraw = true;
+ }
}
+
+ if (redraw) update_progress_locked();
+
+ pthread_mutex_unlock(&updateMutex);
+ double end = now();
+ // minimum of 20ms delay between frames
+ double delay = interval - (end - start);
+ if (delay < 0.02) delay = 0.02;
+ usleep(static_cast<useconds_t>(delay * 1000000));
+ }
}
void ScreenRecoveryUI::LoadBitmap(const char* filename, GRSurface** surface) {
- int result = res_create_display_surface(filename, surface);
- if (result < 0) {
- LOG(ERROR) << "couldn't load bitmap " << filename << " (error " << result << ")";
- }
+ int result = res_create_display_surface(filename, surface);
+ if (result < 0) {
+ LOG(ERROR) << "couldn't load bitmap " << filename << " (error " << result << ")";
+ }
}
void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** surface) {
@@ -435,22 +437,22 @@ void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** sur
}
static char** Alloc2d(size_t rows, size_t cols) {
- char** result = new char*[rows];
- for (size_t i = 0; i < rows; ++i) {
- result[i] = new char[cols];
- memset(result[i], 0, cols);
- }
- return result;
+ char** result = new char*[rows];
+ for (size_t i = 0; i < rows; ++i) {
+ result[i] = new char[cols];
+ memset(result[i], 0, cols);
+ }
+ return result;
}
// Choose the right background string to display during update.
void ScreenRecoveryUI::SetSystemUpdateText(bool security_update) {
- if (security_update) {
- LoadLocalizedBitmap("installing_security_text", &installing_text);
- } else {
- LoadLocalizedBitmap("installing_text", &installing_text);
- }
- Redraw();
+ if (security_update) {
+ LoadLocalizedBitmap("installing_security_text", &installing_text);
+ } else {
+ LoadLocalizedBitmap("installing_text", &installing_text);
+ }
+ Redraw();
}
bool ScreenRecoveryUI::InitTextParams() {
@@ -506,309 +508,309 @@ bool ScreenRecoveryUI::Init(const std::string& locale) {
}
void ScreenRecoveryUI::LoadAnimation() {
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir("/res/images"), closedir);
- dirent* de;
- std::vector<std::string> intro_frame_names;
- std::vector<std::string> loop_frame_names;
-
- while ((de = readdir(dir.get())) != nullptr) {
- int value, num_chars;
- if (sscanf(de->d_name, "intro%d%n.png", &value, &num_chars) == 1) {
- intro_frame_names.emplace_back(de->d_name, num_chars);
- } else if (sscanf(de->d_name, "loop%d%n.png", &value, &num_chars) == 1) {
- loop_frame_names.emplace_back(de->d_name, num_chars);
- }
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir("/res/images"), closedir);
+ dirent* de;
+ std::vector<std::string> intro_frame_names;
+ std::vector<std::string> loop_frame_names;
+
+ while ((de = readdir(dir.get())) != nullptr) {
+ int value, num_chars;
+ if (sscanf(de->d_name, "intro%d%n.png", &value, &num_chars) == 1) {
+ intro_frame_names.emplace_back(de->d_name, num_chars);
+ } else if (sscanf(de->d_name, "loop%d%n.png", &value, &num_chars) == 1) {
+ loop_frame_names.emplace_back(de->d_name, num_chars);
}
+ }
- intro_frames = intro_frame_names.size();
- loop_frames = loop_frame_names.size();
+ intro_frames = intro_frame_names.size();
+ loop_frames = loop_frame_names.size();
- // It's okay to not have an intro.
- if (intro_frames == 0) intro_done = true;
- // But you must have an animation.
- if (loop_frames == 0) abort();
+ // It's okay to not have an intro.
+ if (intro_frames == 0) intro_done = true;
+ // But you must have an animation.
+ if (loop_frames == 0) abort();
- std::sort(intro_frame_names.begin(), intro_frame_names.end());
- std::sort(loop_frame_names.begin(), loop_frame_names.end());
+ std::sort(intro_frame_names.begin(), intro_frame_names.end());
+ std::sort(loop_frame_names.begin(), loop_frame_names.end());
- introFrames = new GRSurface*[intro_frames];
- for (size_t i = 0; i < intro_frames; i++) {
- LoadBitmap(intro_frame_names.at(i).c_str(), &introFrames[i]);
- }
+ introFrames = new GRSurface*[intro_frames];
+ for (size_t i = 0; i < intro_frames; i++) {
+ LoadBitmap(intro_frame_names.at(i).c_str(), &introFrames[i]);
+ }
- loopFrames = new GRSurface*[loop_frames];
- for (size_t i = 0; i < loop_frames; i++) {
- LoadBitmap(loop_frame_names.at(i).c_str(), &loopFrames[i]);
- }
+ loopFrames = new GRSurface*[loop_frames];
+ for (size_t i = 0; i < loop_frames; i++) {
+ LoadBitmap(loop_frame_names.at(i).c_str(), &loopFrames[i]);
+ }
}
void ScreenRecoveryUI::SetBackground(Icon icon) {
- pthread_mutex_lock(&updateMutex);
+ pthread_mutex_lock(&updateMutex);
- currentIcon = icon;
- update_screen_locked();
+ currentIcon = icon;
+ update_screen_locked();
- pthread_mutex_unlock(&updateMutex);
+ pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::SetProgressType(ProgressType type) {
- pthread_mutex_lock(&updateMutex);
- if (progressBarType != type) {
- progressBarType = type;
- }
- progressScopeStart = 0;
- progressScopeSize = 0;
- progress = 0;
- update_progress_locked();
- pthread_mutex_unlock(&updateMutex);
+ pthread_mutex_lock(&updateMutex);
+ if (progressBarType != type) {
+ progressBarType = type;
+ }
+ progressScopeStart = 0;
+ progressScopeSize = 0;
+ progress = 0;
+ update_progress_locked();
+ pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::ShowProgress(float portion, float seconds) {
- pthread_mutex_lock(&updateMutex);
- progressBarType = DETERMINATE;
- progressScopeStart += progressScopeSize;
- progressScopeSize = portion;
- progressScopeTime = now();
- progressScopeDuration = seconds;
- progress = 0;
- update_progress_locked();
- pthread_mutex_unlock(&updateMutex);
+ pthread_mutex_lock(&updateMutex);
+ progressBarType = DETERMINATE;
+ progressScopeStart += progressScopeSize;
+ progressScopeSize = portion;
+ progressScopeTime = now();
+ progressScopeDuration = seconds;
+ progress = 0;
+ update_progress_locked();
+ pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::SetProgress(float fraction) {
- pthread_mutex_lock(&updateMutex);
- if (fraction < 0.0) fraction = 0.0;
- if (fraction > 1.0) fraction = 1.0;
- if (progressBarType == DETERMINATE && fraction > progress) {
- // Skip updates that aren't visibly different.
- int width = gr_get_width(progressBarEmpty);
- float scale = width * progressScopeSize;
- if ((int) (progress * scale) != (int) (fraction * scale)) {
- progress = fraction;
- update_progress_locked();
- }
+ pthread_mutex_lock(&updateMutex);
+ if (fraction < 0.0) fraction = 0.0;
+ if (fraction > 1.0) fraction = 1.0;
+ if (progressBarType == DETERMINATE && fraction > progress) {
+ // Skip updates that aren't visibly different.
+ int width = gr_get_width(progressBarEmpty);
+ float scale = width * progressScopeSize;
+ if ((int)(progress * scale) != (int)(fraction * scale)) {
+ progress = fraction;
+ update_progress_locked();
}
- pthread_mutex_unlock(&updateMutex);
+ }
+ pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::SetStage(int current, int max) {
- pthread_mutex_lock(&updateMutex);
- stage = current;
- max_stage = max;
- pthread_mutex_unlock(&updateMutex);
+ pthread_mutex_lock(&updateMutex);
+ stage = current;
+ max_stage = max;
+ pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::PrintV(const char* fmt, bool copy_to_stdout, va_list ap) {
- std::string str;
- android::base::StringAppendV(&str, fmt, ap);
+ std::string str;
+ android::base::StringAppendV(&str, fmt, ap);
- if (copy_to_stdout) {
- fputs(str.c_str(), stdout);
- }
+ if (copy_to_stdout) {
+ fputs(str.c_str(), stdout);
+ }
- pthread_mutex_lock(&updateMutex);
- if (text_rows_ > 0 && text_cols_ > 0) {
- for (const char* ptr = str.c_str(); *ptr != '\0'; ++ptr) {
- if (*ptr == '\n' || text_col_ >= text_cols_) {
- text_[text_row_][text_col_] = '\0';
- text_col_ = 0;
- text_row_ = (text_row_ + 1) % text_rows_;
- if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_;
- }
- if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr;
- }
+ pthread_mutex_lock(&updateMutex);
+ if (text_rows_ > 0 && text_cols_ > 0) {
+ for (const char* ptr = str.c_str(); *ptr != '\0'; ++ptr) {
+ if (*ptr == '\n' || text_col_ >= text_cols_) {
text_[text_row_][text_col_] = '\0';
- update_screen_locked();
+ text_col_ = 0;
+ text_row_ = (text_row_ + 1) % text_rows_;
+ if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_;
+ }
+ if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr;
}
- pthread_mutex_unlock(&updateMutex);
+ text_[text_row_][text_col_] = '\0';
+ update_screen_locked();
+ }
+ pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::Print(const char* fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- PrintV(fmt, true, ap);
- va_end(ap);
+ va_list ap;
+ va_start(ap, fmt);
+ PrintV(fmt, true, ap);
+ va_end(ap);
}
void ScreenRecoveryUI::PrintOnScreenOnly(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- PrintV(fmt, false, ap);
- va_end(ap);
+ va_list ap;
+ va_start(ap, fmt);
+ PrintV(fmt, false, ap);
+ va_end(ap);
}
void ScreenRecoveryUI::PutChar(char ch) {
- pthread_mutex_lock(&updateMutex);
- if (ch != '\n') text_[text_row_][text_col_++] = ch;
- if (ch == '\n' || text_col_ >= text_cols_) {
- text_col_ = 0;
- ++text_row_;
+ pthread_mutex_lock(&updateMutex);
+ if (ch != '\n') text_[text_row_][text_col_++] = ch;
+ if (ch == '\n' || text_col_ >= text_cols_) {
+ text_col_ = 0;
+ ++text_row_;
- if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_;
- }
- pthread_mutex_unlock(&updateMutex);
+ if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_;
+ }
+ pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::ClearText() {
- pthread_mutex_lock(&updateMutex);
- text_col_ = 0;
- text_row_ = 0;
- text_top_ = 1;
- for (size_t i = 0; i < text_rows_; ++i) {
- memset(text_[i], 0, text_cols_ + 1);
- }
- pthread_mutex_unlock(&updateMutex);
+ pthread_mutex_lock(&updateMutex);
+ text_col_ = 0;
+ text_row_ = 0;
+ text_top_ = 1;
+ for (size_t i = 0; i < text_rows_; ++i) {
+ memset(text_[i], 0, text_cols_ + 1);
+ }
+ pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::ShowFile(FILE* fp) {
- std::vector<off_t> offsets;
- offsets.push_back(ftello(fp));
- ClearText();
-
- struct stat sb;
- fstat(fileno(fp), &sb);
-
- bool show_prompt = false;
- while (true) {
- if (show_prompt) {
- PrintOnScreenOnly("--(%d%% of %d bytes)--",
- static_cast<int>(100 * (double(ftello(fp)) / double(sb.st_size))),
- static_cast<int>(sb.st_size));
- Redraw();
- while (show_prompt) {
- show_prompt = false;
- int key = WaitKey();
- if (key == KEY_POWER || key == KEY_ENTER) {
- return;
- } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
- if (offsets.size() <= 1) {
- show_prompt = true;
- } else {
- offsets.pop_back();
- fseek(fp, offsets.back(), SEEK_SET);
- }
- } else {
- if (feof(fp)) {
- return;
- }
- offsets.push_back(ftello(fp));
- }
- }
- ClearText();
- }
-
- int ch = getc(fp);
- if (ch == EOF) {
- while (text_row_ < text_rows_ - 1) PutChar('\n');
+ std::vector<off_t> offsets;
+ offsets.push_back(ftello(fp));
+ ClearText();
+
+ struct stat sb;
+ fstat(fileno(fp), &sb);
+
+ bool show_prompt = false;
+ while (true) {
+ if (show_prompt) {
+ PrintOnScreenOnly("--(%d%% of %d bytes)--",
+ static_cast<int>(100 * (double(ftello(fp)) / double(sb.st_size))),
+ static_cast<int>(sb.st_size));
+ Redraw();
+ while (show_prompt) {
+ show_prompt = false;
+ int key = WaitKey();
+ if (key == KEY_POWER || key == KEY_ENTER) {
+ return;
+ } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
+ if (offsets.size() <= 1) {
show_prompt = true;
+ } else {
+ offsets.pop_back();
+ fseek(fp, offsets.back(), SEEK_SET);
+ }
} else {
- PutChar(ch);
- if (text_col_ == 0 && text_row_ >= text_rows_ - 1) {
- show_prompt = true;
- }
+ if (feof(fp)) {
+ return;
+ }
+ offsets.push_back(ftello(fp));
}
+ }
+ ClearText();
}
+
+ int ch = getc(fp);
+ if (ch == EOF) {
+ while (text_row_ < text_rows_ - 1) PutChar('\n');
+ show_prompt = true;
+ } else {
+ PutChar(ch);
+ if (text_col_ == 0 && text_row_ >= text_rows_ - 1) {
+ show_prompt = true;
+ }
+ }
+ }
}
void ScreenRecoveryUI::ShowFile(const char* filename) {
- FILE* fp = fopen_path(filename, "re");
- if (fp == nullptr) {
- Print(" Unable to open %s: %s\n", filename, strerror(errno));
- return;
- }
+ FILE* fp = fopen_path(filename, "re");
+ if (fp == nullptr) {
+ Print(" Unable to open %s: %s\n", filename, strerror(errno));
+ return;
+ }
- char** old_text = text_;
- size_t old_text_col = text_col_;
- size_t old_text_row = text_row_;
- size_t old_text_top = text_top_;
+ char** old_text = text_;
+ size_t old_text_col = text_col_;
+ size_t old_text_row = text_row_;
+ size_t old_text_top = text_top_;
- // Swap in the alternate screen and clear it.
- text_ = file_viewer_text_;
- ClearText();
+ // Swap in the alternate screen and clear it.
+ text_ = file_viewer_text_;
+ ClearText();
- ShowFile(fp);
- fclose(fp);
+ ShowFile(fp);
+ fclose(fp);
- text_ = old_text;
- text_col_ = old_text_col;
- text_row_ = old_text_row;
- text_top_ = old_text_top;
+ text_ = old_text;
+ text_col_ = old_text_col;
+ text_row_ = old_text_row;
+ text_top_ = old_text_top;
}
-void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const * items,
+void ScreenRecoveryUI::StartMenu(const char* const* headers, const char* const* items,
int initial_selection) {
- pthread_mutex_lock(&updateMutex);
- if (text_rows_ > 0 && text_cols_ > 0) {
- menu_headers_ = headers;
- size_t i = 0;
- for (; i < text_rows_ && items[i] != nullptr; ++i) {
- strncpy(menu_[i], items[i], text_cols_ - 1);
- menu_[i][text_cols_ - 1] = '\0';
- }
- menu_items = i;
- show_menu = true;
- menu_sel = initial_selection;
- update_screen_locked();
+ pthread_mutex_lock(&updateMutex);
+ if (text_rows_ > 0 && text_cols_ > 0) {
+ menu_headers_ = headers;
+ size_t i = 0;
+ for (; i < text_rows_ && items[i] != nullptr; ++i) {
+ strncpy(menu_[i], items[i], text_cols_ - 1);
+ menu_[i][text_cols_ - 1] = '\0';
}
- pthread_mutex_unlock(&updateMutex);
+ menu_items = i;
+ show_menu = true;
+ menu_sel = initial_selection;
+ update_screen_locked();
+ }
+ pthread_mutex_unlock(&updateMutex);
}
int ScreenRecoveryUI::SelectMenu(int sel) {
- pthread_mutex_lock(&updateMutex);
- if (show_menu) {
- int old_sel = menu_sel;
- menu_sel = sel;
+ pthread_mutex_lock(&updateMutex);
+ if (show_menu) {
+ int old_sel = menu_sel;
+ menu_sel = sel;
- // Wrap at top and bottom.
- if (menu_sel < 0) menu_sel = menu_items - 1;
- if (menu_sel >= menu_items) menu_sel = 0;
+ // Wrap at top and bottom.
+ if (menu_sel < 0) menu_sel = menu_items - 1;
+ if (menu_sel >= menu_items) menu_sel = 0;
- sel = menu_sel;
- if (menu_sel != old_sel) update_screen_locked();
- }
- pthread_mutex_unlock(&updateMutex);
- return sel;
+ sel = menu_sel;
+ if (menu_sel != old_sel) update_screen_locked();
+ }
+ pthread_mutex_unlock(&updateMutex);
+ return sel;
}
void ScreenRecoveryUI::EndMenu() {
- pthread_mutex_lock(&updateMutex);
- if (show_menu && text_rows_ > 0 && text_cols_ > 0) {
- show_menu = false;
- update_screen_locked();
- }
- pthread_mutex_unlock(&updateMutex);
+ pthread_mutex_lock(&updateMutex);
+ if (show_menu && text_rows_ > 0 && text_cols_ > 0) {
+ show_menu = false;
+ update_screen_locked();
+ }
+ pthread_mutex_unlock(&updateMutex);
}
bool ScreenRecoveryUI::IsTextVisible() {
- pthread_mutex_lock(&updateMutex);
- int visible = show_text;
- pthread_mutex_unlock(&updateMutex);
- return visible;
+ pthread_mutex_lock(&updateMutex);
+ int visible = show_text;
+ pthread_mutex_unlock(&updateMutex);
+ return visible;
}
bool ScreenRecoveryUI::WasTextEverVisible() {
- pthread_mutex_lock(&updateMutex);
- int ever_visible = show_text_ever;
- pthread_mutex_unlock(&updateMutex);
- return ever_visible;
+ pthread_mutex_lock(&updateMutex);
+ int ever_visible = show_text_ever;
+ pthread_mutex_unlock(&updateMutex);
+ return ever_visible;
}
void ScreenRecoveryUI::ShowText(bool visible) {
- pthread_mutex_lock(&updateMutex);
- show_text = visible;
- if (show_text) show_text_ever = true;
- update_screen_locked();
- pthread_mutex_unlock(&updateMutex);
+ pthread_mutex_lock(&updateMutex);
+ show_text = visible;
+ if (show_text) show_text_ever = true;
+ update_screen_locked();
+ pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::Redraw() {
- pthread_mutex_lock(&updateMutex);
- update_screen_locked();
- pthread_mutex_unlock(&updateMutex);
+ pthread_mutex_lock(&updateMutex);
+ update_screen_locked();
+ pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::KeyLongPress(int) {
- // Redraw so that if we're in the menu, the highlight
- // will change color to indicate a successful long press.
- Redraw();
+ // Redraw so that if we're in the menu, the highlight
+ // will change color to indicate a successful long press.
+ Redraw();
}
diff --git a/screen_ui.h b/screen_ui.h
index 2500575ca..8402fac00 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -30,152 +30,163 @@ struct GRSurface;
// Implementation of RecoveryUI appropriate for devices with a screen
// (shows an icon + a progress bar, text logging, menu, etc.)
class ScreenRecoveryUI : public RecoveryUI {
- public:
- ScreenRecoveryUI();
+ public:
+ ScreenRecoveryUI();
- bool Init(const std::string& locale) override;
+ bool Init(const std::string& locale) override;
- // overall recovery state ("background image")
- void SetBackground(Icon icon);
- void SetSystemUpdateText(bool security_update);
+ // overall recovery state ("background image")
+ void SetBackground(Icon icon) override;
+ void SetSystemUpdateText(bool security_update) override;
- // progress indicator
- void SetProgressType(ProgressType type) override;
- void ShowProgress(float portion, float seconds) override;
- void SetProgress(float fraction) override;
+ // progress indicator
+ void SetProgressType(ProgressType type) override;
+ void ShowProgress(float portion, float seconds) override;
+ void SetProgress(float fraction) override;
- void SetStage(int current, int max) override;
+ void SetStage(int current, int max) override;
- // text log
- void ShowText(bool visible) override;
- bool IsTextVisible() override;
- bool WasTextEverVisible() override;
+ // text log
+ void ShowText(bool visible) override;
+ bool IsTextVisible() override;
+ bool WasTextEverVisible() override;
- // printing messages
- void Print(const char* fmt, ...) __printflike(2, 3);
- void PrintOnScreenOnly(const char* fmt, ...) __printflike(2, 3);
- void ShowFile(const char* filename);
+ // printing messages
+ void Print(const char* fmt, ...) override __printflike(2, 3);
+ void PrintOnScreenOnly(const char* fmt, ...) override __printflike(2, 3);
+ void ShowFile(const char* filename) override;
- // menu display
- void StartMenu(const char* const * headers, const char* const * items,
- int initial_selection);
- int SelectMenu(int sel);
- void EndMenu();
+ // menu display
+ void StartMenu(const char* const* headers, const char* const* items,
+ int initial_selection) override;
+ int SelectMenu(int sel) override;
+ void EndMenu() override;
- void KeyLongPress(int);
+ void KeyLongPress(int) override;
- void Redraw();
+ void Redraw();
- enum UIElement {
- HEADER, MENU, MENU_SEL_BG, MENU_SEL_BG_ACTIVE, MENU_SEL_FG, LOG, TEXT_FILL, INFO
- };
- void SetColor(UIElement e);
+ enum UIElement {
+ HEADER,
+ MENU,
+ MENU_SEL_BG,
+ MENU_SEL_BG_ACTIVE,
+ MENU_SEL_FG,
+ LOG,
+ TEXT_FILL,
+ INFO
+ };
+ void SetColor(UIElement e) const;
- protected:
- // The margin that we don't want to use for showing texts (e.g. round screen, or screen with
- // rounded corners).
- const int kMarginWidth;
- const int kMarginHeight;
+ protected:
+ // The margin that we don't want to use for showing texts (e.g. round screen, or screen with
+ // rounded corners).
+ const int kMarginWidth;
+ const int kMarginHeight;
- // The scale factor from dp to pixels. 1.0 for mdpi, 4.0 for xxxhdpi.
- const float density_;
+ // The scale factor from dp to pixels. 1.0 for mdpi, 4.0 for xxxhdpi.
+ const float density_;
- Icon currentIcon;
+ Icon currentIcon;
- // The layout to use.
- int layout_;
+ // The layout to use.
+ int layout_;
- GRSurface* error_icon;
+ GRSurface* error_icon;
- GRSurface* erasing_text;
- GRSurface* error_text;
- GRSurface* installing_text;
- GRSurface* no_command_text;
+ GRSurface* erasing_text;
+ GRSurface* error_text;
+ GRSurface* installing_text;
+ GRSurface* no_command_text;
- GRSurface** introFrames;
- GRSurface** loopFrames;
+ GRSurface** introFrames;
+ GRSurface** loopFrames;
- GRSurface* progressBarEmpty;
- GRSurface* progressBarFill;
- GRSurface* stageMarkerEmpty;
- GRSurface* stageMarkerFill;
+ GRSurface* progressBarEmpty;
+ GRSurface* progressBarFill;
+ GRSurface* stageMarkerEmpty;
+ GRSurface* stageMarkerFill;
- ProgressType progressBarType;
+ ProgressType progressBarType;
- float progressScopeStart, progressScopeSize, progress;
- double progressScopeTime, progressScopeDuration;
+ float progressScopeStart, progressScopeSize, progress;
+ double progressScopeTime, progressScopeDuration;
- // true when both graphics pages are the same (except for the progress bar).
- bool pagesIdentical;
+ // true when both graphics pages are the same (except for the progress bar).
+ bool pagesIdentical;
- size_t text_cols_, text_rows_;
+ size_t text_cols_, text_rows_;
- // Log text overlay, displayed when a magic key is pressed.
- char** text_;
- size_t text_col_, text_row_, text_top_;
+ // Log text overlay, displayed when a magic key is pressed.
+ char** text_;
+ size_t text_col_, text_row_, text_top_;
- bool show_text;
- bool show_text_ever; // has show_text ever been true?
+ bool show_text;
+ bool show_text_ever; // has show_text ever been true?
- char** menu_;
- const char* const* menu_headers_;
- bool show_menu;
- int menu_items, menu_sel;
+ char** menu_;
+ const char* const* menu_headers_;
+ bool show_menu;
+ int menu_items, menu_sel;
- // An alternate text screen, swapped with 'text_' when we're viewing a log file.
- char** file_viewer_text_;
+ // An alternate text screen, swapped with 'text_' when we're viewing a log file.
+ char** file_viewer_text_;
- pthread_t progress_thread_;
+ pthread_t progress_thread_;
- // Number of intro frames and loop frames in the animation.
- size_t intro_frames;
- size_t loop_frames;
+ // Number of intro frames and loop frames in the animation.
+ size_t intro_frames;
+ size_t loop_frames;
- size_t current_frame;
- bool intro_done;
+ size_t current_frame;
+ bool intro_done;
- // Number of frames per sec (default: 30) for both parts of the animation.
- int animation_fps;
+ // Number of frames per sec (default: 30) for both parts of the animation.
+ int animation_fps;
- int stage, max_stage;
+ int stage, max_stage;
- int char_width_;
- int char_height_;
+ int char_width_;
+ int char_height_;
- pthread_mutex_t updateMutex;
+ pthread_mutex_t updateMutex;
- virtual bool InitTextParams();
+ virtual bool InitTextParams();
- virtual void draw_background_locked();
- virtual void draw_foreground_locked();
- virtual void draw_screen_locked();
- virtual void update_screen_locked();
- virtual void update_progress_locked();
+ virtual void draw_background_locked();
+ virtual void draw_foreground_locked();
+ virtual void draw_screen_locked();
+ virtual void update_screen_locked();
+ virtual void update_progress_locked();
- GRSurface* GetCurrentFrame();
- GRSurface* GetCurrentText();
+ GRSurface* GetCurrentFrame() const;
+ GRSurface* GetCurrentText() const;
- static void* ProgressThreadStartRoutine(void* data);
- void ProgressThreadLoop();
+ static void* ProgressThreadStartRoutine(void* data);
+ void ProgressThreadLoop();
- virtual void ShowFile(FILE*);
- virtual void PrintV(const char*, bool, va_list);
- void PutChar(char);
- void ClearText();
+ virtual void ShowFile(FILE*);
+ virtual void PrintV(const char*, bool, va_list);
+ void PutChar(char);
+ void ClearText();
- void LoadAnimation();
- void LoadBitmap(const char* filename, GRSurface** surface);
- void LoadLocalizedBitmap(const char* filename, GRSurface** surface);
+ void LoadAnimation();
+ void LoadBitmap(const char* filename, GRSurface** surface);
+ void LoadLocalizedBitmap(const char* filename, GRSurface** surface);
- int PixelsFromDp(int dp) const;
- virtual int GetAnimationBaseline();
- virtual int GetProgressBaseline();
- virtual int GetTextBaseline();
+ int PixelsFromDp(int dp) const;
+ virtual int GetAnimationBaseline() const;
+ virtual int GetProgressBaseline() const;
+ virtual int GetTextBaseline() const;
- virtual void DrawHorizontalRule(int* y);
- virtual void DrawHighlightBar(int x, int y, int width, int height) const;
- virtual void DrawTextLine(int x, int* y, const char* line, bool bold) const;
- void DrawTextLines(int x, int* y, const char* const* lines) const;
+ // Draws a highlight bar at (x, y) - (x + width, y + height).
+ virtual void DrawHighlightBar(int x, int y, int width, int height) const;
+ // Draws a horizontal rule at Y. Returns the offset it should be moving along Y-axis.
+ virtual int DrawHorizontalRule(int y) const;
+ // Draws a line of text. Returns the offset it should be moving along Y-axis.
+ virtual int DrawTextLine(int x, int y, const char* line, bool bold) const;
+ // Draws multiple text lines. Returns the offset it should be moving along Y-axis.
+ int DrawTextLines(int x, int y, const char* const* lines) const;
};
#endif // RECOVERY_UI_H
diff --git a/tests/Android.mk b/tests/Android.mk
index 346873dbe..8b1dc1099 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -160,6 +160,7 @@ LOCAL_STATIC_LIBRARIES := \
libfec_rs \
libsquashfs_utils \
libcutils \
+ libbrotli \
$(tune2fs_static_libraries)
testdata_files := $(call find-subdir-files, testdata/*)
diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp
index 6f5960bbd..bf25aebb0 100644
--- a/tests/component/imgdiff_test.cpp
+++ b/tests/component/imgdiff_test.cpp
@@ -328,6 +328,39 @@ TEST(ImgdiffTest, image_mode_simple) {
verify_patched_image(src, patch, tgt);
}
+TEST(ImgdiffTest, image_mode_bad_gzip) {
+ // Modify the uncompressed length in the gzip footer.
+ const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
+ '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
+ '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
+ '\xff', '\xff', '\xff' };
+ const std::string src(src_data.cbegin(), src_data.cend());
+ TemporaryFile src_file;
+ ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
+
+ // Modify the uncompressed length in the gzip footer.
+ const std::vector<char> tgt_data = {
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
+ '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
+ '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\xff', '\xff', '\xff'
+ };
+ const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
+ TemporaryFile tgt_file;
+ ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
+
+ TemporaryFile patch_file;
+ std::vector<const char*> args = {
+ "imgdiff", src_file.path, tgt_file.path, patch_file.path,
+ };
+ ASSERT_EQ(0, imgdiff(args.size(), args.data()));
+
+ // Verify.
+ std::string patch;
+ ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
+ verify_patched_image(src, patch, tgt);
+}
+
TEST(ImgdiffTest, image_mode_different_num_chunks) {
// src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd) + gzipped "test".
const std::vector<char> src_data = {
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index 35e87fd56..357a39ef7 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -15,10 +15,12 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#include <algorithm>
#include <memory>
#include <string>
#include <vector>
@@ -29,6 +31,7 @@
#include <android-base/strings.h>
#include <android-base/test_utils.h>
#include <bootloader_message/bootloader_message.h>
+#include <brotli/encode.h>
#include <bsdiff.h>
#include <gtest/gtest.h>
#include <ziparchive/zip_archive.h>
@@ -224,102 +227,6 @@ TEST_F(UpdaterTest, file_getprop) {
expect("", script6.c_str(), kNoCause);
}
-TEST_F(UpdaterTest, package_extract_dir) {
- // package_extract_dir expects 2 arguments.
- expect(nullptr, "package_extract_dir()", kArgsParsingFailure);
- expect(nullptr, "package_extract_dir(\"arg1\")", kArgsParsingFailure);
- expect(nullptr, "package_extract_dir(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
-
- std::string zip_path = from_testdata_base("ziptest_valid.zip");
- ZipArchiveHandle handle;
- ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
-
- // Need to set up the ziphandle.
- UpdaterInfo updater_info;
- updater_info.package_zip = handle;
-
- // Extract "b/c.txt" and "b/d.txt" with package_extract_dir("b", "<dir>").
- TemporaryDir td;
- std::string temp_dir(td.path);
- std::string script("package_extract_dir(\"b\", \"" + temp_dir + "\")");
- expect("t", script.c_str(), kNoCause, &updater_info);
-
- // Verify.
- std::string data;
- std::string file_c = temp_dir + "/c.txt";
- ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
- ASSERT_EQ(kCTxtContents, data);
-
- std::string file_d = temp_dir + "/d.txt";
- ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
- ASSERT_EQ(kDTxtContents, data);
-
- // Modify the contents in order to retry. It's expected to be overwritten.
- ASSERT_TRUE(android::base::WriteStringToFile("random", file_c));
- ASSERT_TRUE(android::base::WriteStringToFile("random", file_d));
-
- // Extract again and verify.
- expect("t", script.c_str(), kNoCause, &updater_info);
-
- ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
- ASSERT_EQ(kCTxtContents, data);
- ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
- ASSERT_EQ(kDTxtContents, data);
-
- // Clean up the temp files under td.
- ASSERT_EQ(0, unlink(file_c.c_str()));
- ASSERT_EQ(0, unlink(file_d.c_str()));
-
- // Extracting "b/" (with slash) should give the same result.
- script = "package_extract_dir(\"b/\", \"" + temp_dir + "\")";
- expect("t", script.c_str(), kNoCause, &updater_info);
-
- ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
- ASSERT_EQ(kCTxtContents, data);
- ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
- ASSERT_EQ(kDTxtContents, data);
-
- ASSERT_EQ(0, unlink(file_c.c_str()));
- ASSERT_EQ(0, unlink(file_d.c_str()));
-
- // Extracting "" is allowed. The entries will carry the path name.
- script = "package_extract_dir(\"\", \"" + temp_dir + "\")";
- expect("t", script.c_str(), kNoCause, &updater_info);
-
- std::string file_a = temp_dir + "/a.txt";
- ASSERT_TRUE(android::base::ReadFileToString(file_a, &data));
- ASSERT_EQ(kATxtContents, data);
- std::string file_b = temp_dir + "/b.txt";
- ASSERT_TRUE(android::base::ReadFileToString(file_b, &data));
- ASSERT_EQ(kBTxtContents, data);
- std::string file_b_c = temp_dir + "/b/c.txt";
- ASSERT_TRUE(android::base::ReadFileToString(file_b_c, &data));
- ASSERT_EQ(kCTxtContents, data);
- std::string file_b_d = temp_dir + "/b/d.txt";
- ASSERT_TRUE(android::base::ReadFileToString(file_b_d, &data));
- ASSERT_EQ(kDTxtContents, data);
-
- ASSERT_EQ(0, unlink(file_a.c_str()));
- ASSERT_EQ(0, unlink(file_b.c_str()));
- ASSERT_EQ(0, unlink(file_b_c.c_str()));
- ASSERT_EQ(0, unlink(file_b_d.c_str()));
- ASSERT_EQ(0, rmdir((temp_dir + "/b").c_str()));
-
- // Extracting non-existent entry should still give "t".
- script = "package_extract_dir(\"doesntexist\", \"" + temp_dir + "\")";
- expect("t", script.c_str(), kNoCause, &updater_info);
-
- // Only relative zip_path is allowed.
- script = "package_extract_dir(\"/b\", \"" + temp_dir + "\")";
- expect("", script.c_str(), kNoCause, &updater_info);
-
- // Only absolute dest_path is allowed.
- script = "package_extract_dir(\"b\", \"path\")";
- expect("", script.c_str(), kNoCause, &updater_info);
-
- CloseArchive(handle);
-}
-
// TODO: Test extracting to block device.
TEST_F(UpdaterTest, package_extract_file) {
// package_extract_file expects 1 or 2 arguments.
@@ -672,4 +579,68 @@ TEST_F(UpdaterTest, new_data_short_write) {
std::string script_exact_data = "block_image_update(\"" + std::string(update_file.path) +
R"(", package_extract_file("transfer_list"), "exact_new_data", "patch_data"))";
expect("t", script_exact_data.c_str(), kNoCause, &updater_info);
+ CloseArchive(handle);
+}
+
+TEST_F(UpdaterTest, brotli_new_data) {
+ // Create a zip file with new_data.
+ TemporaryFile zip_file;
+ FILE* zip_file_ptr = fdopen(zip_file.fd, "wb");
+ ZipWriter zip_writer(zip_file_ptr);
+
+ // Add a brotli compressed new data entry.
+ ASSERT_EQ(0, zip_writer.StartEntry("new.dat.br", 0));
+
+ auto generator = []() { return rand() % 128; };
+ // Generate 2048 blocks of random data.
+ std::string brotli_new_data;
+ brotli_new_data.reserve(4096 * 2048);
+ generate_n(back_inserter(brotli_new_data), 4096 * 2048, generator);
+
+ size_t encoded_size = BrotliEncoderMaxCompressedSize(brotli_new_data.size());
+ std::vector<uint8_t> encoded_data(encoded_size);
+ ASSERT_TRUE(BrotliEncoderCompress(
+ BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, brotli_new_data.size(),
+ reinterpret_cast<const uint8_t*>(brotli_new_data.data()), &encoded_size, encoded_data.data()));
+
+ ASSERT_EQ(0, zip_writer.WriteBytes(encoded_data.data(), encoded_size));
+ ASSERT_EQ(0, zip_writer.FinishEntry());
+ // Add a dummy patch data.
+ ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0));
+ ASSERT_EQ(0, zip_writer.FinishEntry());
+
+ std::vector<std::string> transfer_list = {
+ "4", "2048", "0", "0", "new 4,0,512,512,1024", "new 2,1024,2048",
+ };
+ ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0));
+ std::string commands = android::base::Join(transfer_list, '\n');
+ ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size()));
+ ASSERT_EQ(0, zip_writer.FinishEntry());
+ ASSERT_EQ(0, zip_writer.Finish());
+ ASSERT_EQ(0, fclose(zip_file_ptr));
+
+ MemMapping map;
+ ASSERT_TRUE(map.MapFile(zip_file.path));
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
+
+ // Set up the handler, command_pipe, patch offset & length.
+ UpdaterInfo updater_info;
+ updater_info.package_zip = handle;
+ TemporaryFile temp_pipe;
+ updater_info.cmd_pipe = fopen(temp_pipe.path, "wb");
+ updater_info.package_zip_addr = map.addr;
+ updater_info.package_zip_len = map.length;
+
+ // Check if we can decompress the new data correctly.
+ TemporaryFile update_file;
+ std::string script_new_data =
+ "block_image_update(\"" + std::string(update_file.path) +
+ R"(", package_extract_file("transfer_list"), "new.dat.br", "patch_data"))";
+ expect("t", script_new_data.c_str(), kNoCause, &updater_info);
+
+ std::string updated_content;
+ ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content));
+ ASSERT_EQ(brotli_new_data, updated_content);
+ CloseArchive(handle);
}
diff --git a/ui.cpp b/ui.cpp
index cad744930..30b42a19a 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -71,23 +71,23 @@ RecoveryUI::RecoveryUI()
}
void RecoveryUI::OnKeyDetected(int key_code) {
- if (key_code == KEY_POWER) {
- has_power_key = true;
- } else if (key_code == KEY_DOWN || key_code == KEY_VOLUMEDOWN) {
- has_down_key = true;
- } else if (key_code == KEY_UP || key_code == KEY_VOLUMEUP) {
- has_up_key = true;
- }
+ if (key_code == KEY_POWER) {
+ has_power_key = true;
+ } else if (key_code == KEY_DOWN || key_code == KEY_VOLUMEDOWN) {
+ has_down_key = true;
+ } else if (key_code == KEY_UP || key_code == KEY_VOLUMEUP) {
+ has_up_key = true;
+ }
}
// Reads input events, handles special hot keys, and adds to the key queue.
static void* InputThreadLoop(void*) {
- while (true) {
- if (!ev_wait(-1)) {
- ev_dispatch();
- }
+ while (true) {
+ if (!ev_wait(-1)) {
+ ev_dispatch();
}
- return nullptr;
+ }
+ return nullptr;
}
bool RecoveryUI::InitScreensaver() {
@@ -141,39 +141,39 @@ bool RecoveryUI::Init(const std::string& locale) {
}
int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) {
- struct input_event ev;
- if (ev_get_input(fd, epevents, &ev) == -1) {
- return -1;
- }
+ struct input_event ev;
+ if (ev_get_input(fd, epevents, &ev) == -1) {
+ return -1;
+ }
- if (ev.type == EV_SYN) {
- return 0;
- } else if (ev.type == EV_REL) {
- if (ev.code == REL_Y) {
- // accumulate the up or down motion reported by
- // the trackball. When it exceeds a threshold
- // (positive or negative), fake an up/down
- // key event.
- rel_sum += ev.value;
- if (rel_sum > 3) {
- ProcessKey(KEY_DOWN, 1); // press down key
- ProcessKey(KEY_DOWN, 0); // and release it
- rel_sum = 0;
- } else if (rel_sum < -3) {
- ProcessKey(KEY_UP, 1); // press up key
- ProcessKey(KEY_UP, 0); // and release it
- rel_sum = 0;
- }
- }
- } else {
+ if (ev.type == EV_SYN) {
+ return 0;
+ } else if (ev.type == EV_REL) {
+ if (ev.code == REL_Y) {
+ // accumulate the up or down motion reported by
+ // the trackball. When it exceeds a threshold
+ // (positive or negative), fake an up/down
+ // key event.
+ rel_sum += ev.value;
+ if (rel_sum > 3) {
+ ProcessKey(KEY_DOWN, 1); // press down key
+ ProcessKey(KEY_DOWN, 0); // and release it
rel_sum = 0;
+ } else if (rel_sum < -3) {
+ ProcessKey(KEY_UP, 1); // press up key
+ ProcessKey(KEY_UP, 0); // and release it
+ rel_sum = 0;
+ }
}
+ } else {
+ rel_sum = 0;
+ }
- if (ev.type == EV_KEY && ev.code <= KEY_MAX) {
- ProcessKey(ev.code, ev.value);
- }
+ if (ev.type == EV_KEY && ev.code <= KEY_MAX) {
+ ProcessKey(ev.code, ev.value);
+ }
- return 0;
+ return 0;
}
// Process a key-up or -down event. A key is "registered" when it is
@@ -189,82 +189,84 @@ int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) {
//
// updown == 1 for key down events; 0 for key up events
void RecoveryUI::ProcessKey(int key_code, int updown) {
- bool register_key = false;
- bool long_press = false;
- bool reboot_enabled;
+ bool register_key = false;
+ bool long_press = false;
+ bool reboot_enabled;
- pthread_mutex_lock(&key_queue_mutex);
- key_pressed[key_code] = updown;
- if (updown) {
- ++key_down_count;
- key_last_down = key_code;
- key_long_press = false;
- key_timer_t* info = new key_timer_t;
- info->ui = this;
- info->key_code = key_code;
- info->count = key_down_count;
- pthread_t thread;
- pthread_create(&thread, nullptr, &RecoveryUI::time_key_helper, info);
- pthread_detach(thread);
- } else {
- if (key_last_down == key_code) {
- long_press = key_long_press;
- register_key = true;
- }
- key_last_down = -1;
+ pthread_mutex_lock(&key_queue_mutex);
+ key_pressed[key_code] = updown;
+ if (updown) {
+ ++key_down_count;
+ key_last_down = key_code;
+ key_long_press = false;
+ key_timer_t* info = new key_timer_t;
+ info->ui = this;
+ info->key_code = key_code;
+ info->count = key_down_count;
+ pthread_t thread;
+ pthread_create(&thread, nullptr, &RecoveryUI::time_key_helper, info);
+ pthread_detach(thread);
+ } else {
+ if (key_last_down == key_code) {
+ long_press = key_long_press;
+ register_key = true;
}
- reboot_enabled = enable_reboot;
- pthread_mutex_unlock(&key_queue_mutex);
+ key_last_down = -1;
+ }
+ reboot_enabled = enable_reboot;
+ pthread_mutex_unlock(&key_queue_mutex);
+
+ if (register_key) {
+ switch (CheckKey(key_code, long_press)) {
+ case RecoveryUI::IGNORE:
+ break;
+
+ case RecoveryUI::TOGGLE:
+ ShowText(!IsTextVisible());
+ break;
- if (register_key) {
- switch (CheckKey(key_code, long_press)) {
- case RecoveryUI::IGNORE:
- break;
-
- case RecoveryUI::TOGGLE:
- ShowText(!IsTextVisible());
- break;
-
- case RecoveryUI::REBOOT:
- if (reboot_enabled) {
- reboot("reboot,");
- while (true) { pause(); }
- }
- break;
-
- case RecoveryUI::ENQUEUE:
- EnqueueKey(key_code);
- break;
+ case RecoveryUI::REBOOT:
+ if (reboot_enabled) {
+ reboot("reboot,");
+ while (true) {
+ pause();
+ }
}
+ break;
+
+ case RecoveryUI::ENQUEUE:
+ EnqueueKey(key_code);
+ break;
}
+ }
}
void* RecoveryUI::time_key_helper(void* cookie) {
- key_timer_t* info = static_cast<key_timer_t*>(cookie);
- info->ui->time_key(info->key_code, info->count);
- delete info;
- return nullptr;
+ key_timer_t* info = static_cast<key_timer_t*>(cookie);
+ info->ui->time_key(info->key_code, info->count);
+ delete info;
+ return nullptr;
}
void RecoveryUI::time_key(int key_code, int count) {
- usleep(750000); // 750 ms == "long"
- bool long_press = false;
- pthread_mutex_lock(&key_queue_mutex);
- if (key_last_down == key_code && key_down_count == count) {
- long_press = key_long_press = true;
- }
- pthread_mutex_unlock(&key_queue_mutex);
- if (long_press) KeyLongPress(key_code);
+ usleep(750000); // 750 ms == "long"
+ bool long_press = false;
+ pthread_mutex_lock(&key_queue_mutex);
+ if (key_last_down == key_code && key_down_count == count) {
+ long_press = key_long_press = true;
+ }
+ pthread_mutex_unlock(&key_queue_mutex);
+ if (long_press) KeyLongPress(key_code);
}
void RecoveryUI::EnqueueKey(int key_code) {
- pthread_mutex_lock(&key_queue_mutex);
- const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
- if (key_queue_len < queue_max) {
- key_queue[key_queue_len++] = key_code;
- pthread_cond_signal(&key_queue_cond);
- }
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_lock(&key_queue_mutex);
+ const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
+ if (key_queue_len < queue_max) {
+ key_queue[key_queue_len++] = key_code;
+ pthread_cond_signal(&key_queue_cond);
+ }
+ pthread_mutex_unlock(&key_queue_mutex);
}
int RecoveryUI::WaitKey() {
@@ -330,98 +332,96 @@ int RecoveryUI::WaitKey() {
}
bool RecoveryUI::IsUsbConnected() {
- int fd = open("/sys/class/android_usb/android0/state", O_RDONLY);
- if (fd < 0) {
- printf("failed to open /sys/class/android_usb/android0/state: %s\n",
- strerror(errno));
- return 0;
- }
+ int fd = open("/sys/class/android_usb/android0/state", O_RDONLY);
+ if (fd < 0) {
+ printf("failed to open /sys/class/android_usb/android0/state: %s\n", strerror(errno));
+ return 0;
+ }
- char buf;
- // USB is connected if android_usb state is CONNECTED or CONFIGURED.
- int connected = (TEMP_FAILURE_RETRY(read(fd, &buf, 1)) == 1) && (buf == 'C');
- if (close(fd) < 0) {
- printf("failed to close /sys/class/android_usb/android0/state: %s\n",
- strerror(errno));
- }
- return connected;
+ char buf;
+ // USB is connected if android_usb state is CONNECTED or CONFIGURED.
+ int connected = (TEMP_FAILURE_RETRY(read(fd, &buf, 1)) == 1) && (buf == 'C');
+ if (close(fd) < 0) {
+ printf("failed to close /sys/class/android_usb/android0/state: %s\n", strerror(errno));
+ }
+ return connected;
}
bool RecoveryUI::IsKeyPressed(int key) {
- pthread_mutex_lock(&key_queue_mutex);
- int pressed = key_pressed[key];
- pthread_mutex_unlock(&key_queue_mutex);
- return pressed;
+ pthread_mutex_lock(&key_queue_mutex);
+ int pressed = key_pressed[key];
+ pthread_mutex_unlock(&key_queue_mutex);
+ return pressed;
}
bool RecoveryUI::IsLongPress() {
- pthread_mutex_lock(&key_queue_mutex);
- bool result = key_long_press;
- pthread_mutex_unlock(&key_queue_mutex);
- return result;
+ pthread_mutex_lock(&key_queue_mutex);
+ bool result = key_long_press;
+ pthread_mutex_unlock(&key_queue_mutex);
+ return result;
}
bool RecoveryUI::HasThreeButtons() {
- return has_power_key && has_up_key && has_down_key;
+ return has_power_key && has_up_key && has_down_key;
}
void RecoveryUI::FlushKeys() {
- pthread_mutex_lock(&key_queue_mutex);
- key_queue_len = 0;
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_lock(&key_queue_mutex);
+ key_queue_len = 0;
+ pthread_mutex_unlock(&key_queue_mutex);
}
RecoveryUI::KeyAction RecoveryUI::CheckKey(int key, bool is_long_press) {
- pthread_mutex_lock(&key_queue_mutex);
- key_long_press = false;
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_lock(&key_queue_mutex);
+ key_long_press = false;
+ pthread_mutex_unlock(&key_queue_mutex);
- // If we have power and volume up keys, that chord is the signal to toggle the text display.
- if (HasThreeButtons()) {
- if (key == KEY_VOLUMEUP && IsKeyPressed(KEY_POWER)) {
- return TOGGLE;
- }
- } else {
- // Otherwise long press of any button toggles to the text display,
- // and there's no way to toggle back (but that's pretty useless anyway).
- if (is_long_press && !IsTextVisible()) {
- return TOGGLE;
- }
+ // If we have power and volume up keys, that chord is the signal to toggle the text display.
+ if (HasThreeButtons()) {
+ if (key == KEY_VOLUMEUP && IsKeyPressed(KEY_POWER)) {
+ return TOGGLE;
+ }
+ } else {
+ // Otherwise long press of any button toggles to the text display,
+ // and there's no way to toggle back (but that's pretty useless anyway).
+ if (is_long_press && !IsTextVisible()) {
+ return TOGGLE;
+ }
- // Also, for button-limited devices, a long press is translated to KEY_ENTER.
- if (is_long_press && IsTextVisible()) {
- EnqueueKey(KEY_ENTER);
- return IGNORE;
- }
+ // Also, for button-limited devices, a long press is translated to KEY_ENTER.
+ if (is_long_press && IsTextVisible()) {
+ EnqueueKey(KEY_ENTER);
+ return IGNORE;
}
+ }
- // Press power seven times in a row to reboot.
- if (key == KEY_POWER) {
- pthread_mutex_lock(&key_queue_mutex);
- bool reboot_enabled = enable_reboot;
- pthread_mutex_unlock(&key_queue_mutex);
+ // Press power seven times in a row to reboot.
+ if (key == KEY_POWER) {
+ pthread_mutex_lock(&key_queue_mutex);
+ bool reboot_enabled = enable_reboot;
+ pthread_mutex_unlock(&key_queue_mutex);
- if (reboot_enabled) {
- ++consecutive_power_keys;
- if (consecutive_power_keys >= 7) {
- return REBOOT;
- }
- }
- } else {
- consecutive_power_keys = 0;
+ if (reboot_enabled) {
+ ++consecutive_power_keys;
+ if (consecutive_power_keys >= 7) {
+ return REBOOT;
+ }
}
+ } else {
+ consecutive_power_keys = 0;
+ }
- last_key = key;
- return (IsTextVisible() || screensaver_state_ == ScreensaverState::OFF) ? ENQUEUE : IGNORE;
+ last_key = key;
+ return (IsTextVisible() || screensaver_state_ == ScreensaverState::OFF) ? ENQUEUE : IGNORE;
}
void RecoveryUI::KeyLongPress(int) {
}
void RecoveryUI::SetEnableReboot(bool enabled) {
- pthread_mutex_lock(&key_queue_mutex);
- enable_reboot = enabled;
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_lock(&key_queue_mutex);
+ enable_reboot = enabled;
+ pthread_mutex_unlock(&key_queue_mutex);
}
void RecoveryUI::SetLocale(const std::string& new_locale) {
diff --git a/ui.h b/ui.h
index 823eb6574..7eb04aec8 100644
--- a/ui.h
+++ b/ui.h
@@ -25,163 +25,155 @@
// Abstract class for controlling the user interface during recovery.
class RecoveryUI {
- public:
- RecoveryUI();
+ public:
+ RecoveryUI();
- virtual ~RecoveryUI() { }
+ virtual ~RecoveryUI() {}
- // Initialize the object; called before anything else. UI texts will be
- // initialized according to the given locale. Returns true on success.
- virtual bool Init(const std::string& locale);
+ // Initializes the object; called before anything else. UI texts will be initialized according to
+ // the given locale. Returns true on success.
+ virtual bool Init(const std::string& locale);
- // Show a stage indicator. Call immediately after Init().
- virtual void SetStage(int current, int max) = 0;
+ // Shows a stage indicator. Called immediately after Init().
+ virtual void SetStage(int current, int max) = 0;
- // Set the overall recovery state ("background image").
- enum Icon { NONE, INSTALLING_UPDATE, ERASING, NO_COMMAND, ERROR };
- virtual void SetBackground(Icon icon) = 0;
- virtual void SetSystemUpdateText(bool security_update) = 0;
+ // Sets the overall recovery state ("background image").
+ enum Icon { NONE, INSTALLING_UPDATE, ERASING, NO_COMMAND, ERROR };
+ virtual void SetBackground(Icon icon) = 0;
+ virtual void SetSystemUpdateText(bool security_update) = 0;
- // --- progress indicator ---
- enum ProgressType { EMPTY, INDETERMINATE, DETERMINATE };
- virtual void SetProgressType(ProgressType determinate) = 0;
-
- // Show a progress bar and define the scope of the next operation:
- // portion - fraction of the progress bar the next operation will use
- // seconds - expected time interval (progress bar moves at this minimum rate)
- virtual void ShowProgress(float portion, float seconds) = 0;
-
- // Set progress bar position (0.0 - 1.0 within the scope defined
- // by the last call to ShowProgress).
- virtual void SetProgress(float fraction) = 0;
-
- // --- text log ---
-
- virtual void ShowText(bool visible) = 0;
-
- virtual bool IsTextVisible() = 0;
-
- virtual bool WasTextEverVisible() = 0;
-
- // Write a message to the on-screen log (shown if the user has
- // toggled on the text display). Print() will also dump the message
- // to stdout / log file, while PrintOnScreenOnly() not.
- virtual void Print(const char* fmt, ...) __printflike(2, 3) = 0;
- virtual void PrintOnScreenOnly(const char* fmt, ...) __printflike(2, 3) = 0;
-
- virtual void ShowFile(const char* filename) = 0;
+ // --- progress indicator ---
+ enum ProgressType { EMPTY, INDETERMINATE, DETERMINATE };
+ virtual void SetProgressType(ProgressType determinate) = 0;
- // --- key handling ---
+ // Shows a progress bar and define the scope of the next operation:
+ // portion - fraction of the progress bar the next operation will use
+ // seconds - expected time interval (progress bar moves at this minimum rate)
+ virtual void ShowProgress(float portion, float seconds) = 0;
- // Wait for a key and return it. May return -1 after timeout.
- virtual int WaitKey();
+ // Sets progress bar position (0.0 - 1.0 within the scope defined by the last call to
+ // ShowProgress).
+ virtual void SetProgress(float fraction) = 0;
- virtual bool IsKeyPressed(int key);
- virtual bool IsLongPress();
+ // --- text log ---
- // Returns true if you have the volume up/down and power trio typical
- // of phones and tablets, false otherwise.
- virtual bool HasThreeButtons();
-
- // Erase any queued-up keys.
- virtual void FlushKeys();
-
- // Called on each key press, even while operations are in progress.
- // Return value indicates whether an immediate operation should be
- // triggered (toggling the display, rebooting the device), or if
- // the key should be enqueued for use by the main thread.
- enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE };
- virtual KeyAction CheckKey(int key, bool is_long_press);
-
- // Called when a key is held down long enough to have been a
- // long-press (but before the key is released). This means that
- // if the key is eventually registered (released without any other
- // keys being pressed in the meantime), CheckKey will be called with
- // 'is_long_press' true.
- virtual void KeyLongPress(int key);
-
- // Normally in recovery there's a key sequence that triggers
- // immediate reboot of the device, regardless of what recovery is
- // doing (with the default CheckKey implementation, it's pressing
- // the power button 7 times in row). Call this to enable or
- // disable that feature. It is enabled by default.
- virtual void SetEnableReboot(bool enabled);
-
- // --- menu display ---
-
- // Display some header text followed by a menu of items, which appears
- // at the top of the screen (in place of any scrolling ui_print()
- // output, if necessary).
- virtual void StartMenu(const char* const * headers, const char* const * items,
- int initial_selection) = 0;
-
- // Set the menu highlight to the given index, wrapping if necessary.
- // Returns the actual item selected.
- virtual int SelectMenu(int sel) = 0;
-
- // End menu mode, resetting the text overlay so that ui_print()
- // statements will be displayed.
- virtual void EndMenu() = 0;
-
- protected:
- void EnqueueKey(int key_code);
-
- // The locale that's used to show the rendered texts.
- std::string locale_;
- bool rtl_locale_;
-
- // The normal and dimmed brightness percentages (default: 50 and 25, which means 50% and 25%
- // of the max_brightness). Because the absolute values may vary across devices. These two
- // values can be configured via subclassing. Setting brightness_normal_ to 0 to disable
- // screensaver.
- unsigned int brightness_normal_;
- unsigned int brightness_dimmed_;
-
- private:
- // Key event input queue
- pthread_mutex_t key_queue_mutex;
- pthread_cond_t key_queue_cond;
- int key_queue[256], key_queue_len;
- char key_pressed[KEY_MAX + 1]; // under key_queue_mutex
- int key_last_down; // under key_queue_mutex
- bool key_long_press; // under key_queue_mutex
- int key_down_count; // under key_queue_mutex
- bool enable_reboot; // under key_queue_mutex
- int rel_sum;
-
- int consecutive_power_keys;
- int last_key;
-
- bool has_power_key;
- bool has_up_key;
- bool has_down_key;
-
- struct key_timer_t {
- RecoveryUI* ui;
- int key_code;
- int count;
- };
-
- pthread_t input_thread_;
-
- void OnKeyDetected(int key_code);
- int OnInputEvent(int fd, uint32_t epevents);
- void ProcessKey(int key_code, int updown);
-
- bool IsUsbConnected();
-
- static void* time_key_helper(void* cookie);
- void time_key(int key_code, int count);
-
- void SetLocale(const std::string&);
-
- enum class ScreensaverState { DISABLED, NORMAL, DIMMED, OFF };
- ScreensaverState screensaver_state_;
- // The following two contain the absolute values computed from brightness_normal_ and
- // brightness_dimmed_ respectively.
- unsigned int brightness_normal_value_;
- unsigned int brightness_dimmed_value_;
- bool InitScreensaver();
+ virtual void ShowText(bool visible) = 0;
+
+ virtual bool IsTextVisible() = 0;
+
+ virtual bool WasTextEverVisible() = 0;
+
+ // Writes a message to the on-screen log (shown if the user has toggled on the text display).
+ // Print() will also dump the message to stdout / log file, while PrintOnScreenOnly() not.
+ virtual void Print(const char* fmt, ...) __printflike(2, 3) = 0;
+ virtual void PrintOnScreenOnly(const char* fmt, ...) __printflike(2, 3) = 0;
+
+ virtual void ShowFile(const char* filename) = 0;
+
+ // --- key handling ---
+
+ // Waits for a key and return it. May return -1 after timeout.
+ virtual int WaitKey();
+
+ virtual bool IsKeyPressed(int key);
+ virtual bool IsLongPress();
+
+ // Returns true if you have the volume up/down and power trio typical of phones and tablets, false
+ // otherwise.
+ virtual bool HasThreeButtons();
+
+ // Erases any queued-up keys.
+ virtual void FlushKeys();
+
+ // Called on each key press, even while operations are in progress. Return value indicates whether
+ // an immediate operation should be triggered (toggling the display, rebooting the device), or if
+ // the key should be enqueued for use by the main thread.
+ enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE };
+ virtual KeyAction CheckKey(int key, bool is_long_press);
+
+ // Called when a key is held down long enough to have been a long-press (but before the key is
+ // released). This means that if the key is eventually registered (released without any other keys
+ // being pressed in the meantime), CheckKey will be called with 'is_long_press' true.
+ virtual void KeyLongPress(int key);
+
+ // Normally in recovery there's a key sequence that triggers immediate reboot of the device,
+ // regardless of what recovery is doing (with the default CheckKey implementation, it's pressing
+ // the power button 7 times in row). Call this to enable or disable that feature. It is enabled by
+ // default.
+ virtual void SetEnableReboot(bool enabled);
+
+ // --- menu display ---
+
+ // Display some header text followed by a menu of items, which appears at the top of the screen
+ // (in place of any scrolling ui_print() output, if necessary).
+ virtual void StartMenu(const char* const* headers, const char* const* items,
+ int initial_selection) = 0;
+
+ // Sets the menu highlight to the given index, wrapping if necessary. Returns the actual item
+ // selected.
+ virtual int SelectMenu(int sel) = 0;
+
+ // Ends menu mode, resetting the text overlay so that ui_print() statements will be displayed.
+ virtual void EndMenu() = 0;
+
+ protected:
+ void EnqueueKey(int key_code);
+
+ // The locale that's used to show the rendered texts.
+ std::string locale_;
+ bool rtl_locale_;
+
+ // The normal and dimmed brightness percentages (default: 50 and 25, which means 50% and 25% of
+ // the max_brightness). Because the absolute values may vary across devices. These two values can
+ // be configured via subclassing. Setting brightness_normal_ to 0 to disable screensaver.
+ unsigned int brightness_normal_;
+ unsigned int brightness_dimmed_;
+
+ private:
+ // Key event input queue
+ pthread_mutex_t key_queue_mutex;
+ pthread_cond_t key_queue_cond;
+ int key_queue[256], key_queue_len;
+ char key_pressed[KEY_MAX + 1]; // under key_queue_mutex
+ int key_last_down; // under key_queue_mutex
+ bool key_long_press; // under key_queue_mutex
+ int key_down_count; // under key_queue_mutex
+ bool enable_reboot; // under key_queue_mutex
+ int rel_sum;
+
+ int consecutive_power_keys;
+ int last_key;
+
+ bool has_power_key;
+ bool has_up_key;
+ bool has_down_key;
+
+ struct key_timer_t {
+ RecoveryUI* ui;
+ int key_code;
+ int count;
+ };
+
+ pthread_t input_thread_;
+
+ void OnKeyDetected(int key_code);
+ int OnInputEvent(int fd, uint32_t epevents);
+ void ProcessKey(int key_code, int updown);
+
+ bool IsUsbConnected();
+
+ static void* time_key_helper(void* cookie);
+ void time_key(int key_code, int count);
+
+ void SetLocale(const std::string&);
+
+ enum class ScreensaverState { DISABLED, NORMAL, DIMMED, OFF };
+ ScreensaverState screensaver_state_;
+ // The following two contain the absolute values computed from brightness_normal_ and
+ // brightness_dimmed_ respectively.
+ unsigned int brightness_normal_value_;
+ unsigned int brightness_dimmed_value_;
+ bool InitScreensaver();
};
#endif // RECOVERY_UI_H
diff --git a/updater/Android.mk b/updater/Android.mk
index a113fe86c..86dc48e30 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -47,6 +47,7 @@ updater_common_static_libraries := \
libcrypto_utils \
libcutils \
libtune2fs \
+ libbrotli \
$(tune2fs_static_libraries)
# libupdater (static library)
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index df366b0b8..2bec487fe 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -44,6 +44,7 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <applypatch/applypatch.h>
+#include <brotli/decode.h>
#include <openssl/sha.h>
#include <private/android_filesystem_config.h>
#include <ziparchive/zip_archive.h>
@@ -149,40 +150,32 @@ static void allocate(size_t size, std::vector<uint8_t>& buffer) {
class RangeSinkWriter {
public:
RangeSinkWriter(int fd, const RangeSet& tgt)
- : fd_(fd), tgt_(tgt), next_range_(0), current_range_left_(0), bytes_written_(0) {
+ : fd_(fd),
+ tgt_(tgt),
+ next_range_(0),
+ current_range_left_(0),
+ bytes_written_(0) {
CHECK_NE(tgt.size(), static_cast<size_t>(0));
};
+ virtual ~RangeSinkWriter() {};
+
bool Finished() const {
return next_range_ == tgt_.size() && current_range_left_ == 0;
}
- size_t Write(const uint8_t* data, size_t size) {
+ // Return number of bytes consumed; and 0 indicates a writing failure.
+ virtual size_t Write(const uint8_t* data, size_t size) {
if (Finished()) {
LOG(ERROR) << "range sink write overrun; can't write " << size << " bytes";
return 0;
}
- size_t written = 0;
+ size_t consumed = 0;
while (size > 0) {
// Move to the next range as needed.
- if (current_range_left_ == 0) {
- if (next_range_ < tgt_.size()) {
- const Range& range = tgt_[next_range_];
- off64_t offset = static_cast<off64_t>(range.first) * BLOCKSIZE;
- current_range_left_ = (range.second - range.first) * BLOCKSIZE;
- next_range_++;
- if (!discard_blocks(fd_, offset, current_range_left_)) {
- break;
- }
-
- if (!check_lseek(fd_, offset, SEEK_SET)) {
- break;
- }
- } else {
- // We can't write any more; return how many bytes have been written so far.
- break;
- }
+ if (!SeekToOutputRange()) {
+ break;
}
size_t write_now = size;
@@ -198,21 +191,47 @@ class RangeSinkWriter {
size -= write_now;
current_range_left_ -= write_now;
- written += write_now;
+ consumed += write_now;
}
- bytes_written_ += written;
- return written;
+ bytes_written_ += consumed;
+ return consumed;
}
size_t BytesWritten() const {
return bytes_written_;
}
- private:
- // The input data.
+ protected:
+ // Set up the output cursor, move to next range if needed.
+ bool SeekToOutputRange() {
+ // We haven't finished the current range yet.
+ if (current_range_left_ != 0) {
+ return true;
+ }
+ // We can't write any more; let the write function return how many bytes have been written
+ // so far.
+ if (next_range_ >= tgt_.size()) {
+ return false;
+ }
+
+ const Range& range = tgt_[next_range_];
+ off64_t offset = static_cast<off64_t>(range.first) * BLOCKSIZE;
+ current_range_left_ = (range.second - range.first) * BLOCKSIZE;
+ next_range_++;
+
+ if (!discard_blocks(fd_, offset, current_range_left_)) {
+ return false;
+ }
+ if (!check_lseek(fd_, offset, SEEK_SET)) {
+ return false;
+ }
+ return true;
+ }
+
+ // The output file descriptor.
int fd_;
- // The destination for the data.
+ // The destination ranges for the data.
const RangeSet& tgt_;
// The next range that we should write to.
size_t next_range_;
@@ -222,6 +241,75 @@ class RangeSinkWriter {
size_t bytes_written_;
};
+class BrotliNewDataWriter : public RangeSinkWriter {
+ public:
+ BrotliNewDataWriter(int fd, const RangeSet& tgt, BrotliDecoderState* state)
+ : RangeSinkWriter(fd, tgt), state_(state) {}
+
+ size_t Write(const uint8_t* data, size_t size) override {
+ if (Finished()) {
+ LOG(ERROR) << "Brotli new data write overrun; can't write " << size << " bytes";
+ return 0;
+ }
+ CHECK(state_ != nullptr);
+
+ size_t consumed = 0;
+ while (true) {
+ // Move to the next range as needed.
+ if (!SeekToOutputRange()) {
+ break;
+ }
+
+ size_t available_in = size;
+ size_t write_now = std::min<size_t>(32768, current_range_left_);
+ uint8_t buffer[write_now];
+
+ size_t available_out = write_now;
+ uint8_t* next_out = buffer;
+
+ // The brotli decoder will update |data|, |available_in|, |next_out| and |available_out|.
+ BrotliDecoderResult result = BrotliDecoderDecompressStream(
+ state_, &available_in, &data, &available_out, &next_out, nullptr);
+
+ // We don't have a way to recover from the decode error; report the failure.
+ if (result == BROTLI_DECODER_RESULT_ERROR) {
+ LOG(ERROR) << "Decompression failed with "
+ << BrotliDecoderErrorString(BrotliDecoderGetErrorCode(state_));
+ return 0;
+ }
+
+ if (write_all(fd_, buffer, write_now - available_out) == -1) {
+ return 0;
+ }
+
+ LOG(DEBUG) << "bytes written: " << write_now - available_out << ", bytes consumed "
+ << size - available_in << ", decoder status " << result;
+
+ // Update the total bytes written to output by the current writer; this is different from the
+ // consumed input bytes.
+ bytes_written_ += write_now - available_out;
+ current_range_left_ -= (write_now - available_out);
+ consumed += (size - available_in);
+
+ // Update the remaining size. The input data ptr is already updated by brotli decoder
+ // function.
+ size = available_in;
+
+ // Continue if we have more output to write, or more input to consume.
+ if (result == BROTLI_DECODER_RESULT_SUCCESS ||
+ (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT && size == 0)) {
+ break;
+ }
+ }
+
+ return consumed;
+ }
+
+ private:
+ // Pointer to the decoder state. (initialized by PerformBlockImageUpdate)
+ BrotliDecoderState* state_;
+};
+
/**
* All of the data for all the 'new' transfers is contained in one file in the update package,
* concatenated together in the order in which transfers.list will need it. We want to stream it out
@@ -243,8 +331,10 @@ class RangeSinkWriter {
struct NewThreadInfo {
ZipArchiveHandle za;
ZipEntry entry;
+ bool brotli_compressed;
- RangeSinkWriter* writer;
+ std::unique_ptr<RangeSinkWriter> writer;
+ BrotliDecoderState* brotli_decoder_state;
bool receiver_available;
pthread_mutex_t mu;
@@ -264,9 +354,16 @@ static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) {
// At this point nti->writer is set, and we own it. The main thread is waiting for it to
// disappear from nti.
- size_t written = nti->writer->Write(data, size);
- data += written;
- size -= written;
+ size_t consumed = nti->writer->Write(data, size);
+
+ // We encounter a fatal error if we fail to consume any input bytes. If this happens, abort the
+ // extraction.
+ if (consumed == 0) {
+ LOG(ERROR) << "Failed to process " << size << " input bytes.";
+ return false;
+ }
+ data += consumed;
+ size -= consumed;
if (nti->writer->Finished()) {
// We have written all the bytes desired by this writer.
@@ -1142,9 +1239,13 @@ static int PerformCommandNew(CommandParameters& params) {
if (params.canwrite) {
LOG(INFO) << " writing " << tgt.blocks() << " blocks of new data";
- RangeSinkWriter writer(params.fd, tgt);
pthread_mutex_lock(&params.nti.mu);
- params.nti.writer = &writer;
+ if (params.nti.brotli_compressed) {
+ params.nti.writer =
+ std::make_unique<BrotliNewDataWriter>(params.fd, tgt, params.nti.brotli_decoder_state);
+ } else {
+ params.nti.writer = std::make_unique<RangeSinkWriter>(params.fd, tgt);
+ }
pthread_cond_broadcast(&params.nti.cv);
while (params.nti.writer != nullptr) {
@@ -1384,6 +1485,12 @@ static Value* PerformBlockImageUpdate(const char* name, State* state,
if (params.canwrite) {
params.nti.za = za;
params.nti.entry = new_entry;
+ // The entry is compressed by brotli if has a 'br' extension.
+ params.nti.brotli_compressed = android::base::EndsWith(new_data_fn->data, ".br");
+ if (params.nti.brotli_compressed) {
+ // Initialize brotli decoder state.
+ params.nti.brotli_decoder_state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
+ }
params.nti.receiver_available = true;
pthread_mutex_init(&params.nti.mu, nullptr);
@@ -1526,6 +1633,10 @@ pbiudone:
}
// params.fd will be automatically closed because it's a unique_fd.
+ if (params.nti.brotli_decoder_state != nullptr) {
+ BrotliDecoderDestroyInstance(params.nti.brotli_decoder_state);
+ }
+
// Only delete the stash if the update cannot be resumed, or it's a verification run and we
// created the stash.
if (params.isunresumable || (!params.canwrite && params.createdstash)) {
diff --git a/vr_ui.cpp b/vr_ui.cpp
index 8b8261e35..125167268 100644
--- a/vr_ui.cpp
+++ b/vr_ui.cpp
@@ -27,9 +27,9 @@ bool VrRecoveryUI::InitTextParams() {
return true;
}
-void VrRecoveryUI::DrawTextLine(int x, int* y, const char* line, bool bold) const {
+int VrRecoveryUI::DrawTextLine(int x, int y, const char* line, bool bold) const {
int mid_divide = gr_fb_width() / 2;
- gr_text(gr_sys_font(), x + kStereoOffset, *y, line, bold);
- gr_text(gr_sys_font(), x - kStereoOffset + mid_divide, *y, line, bold);
- *y += char_height_ + 4;
+ gr_text(gr_sys_font(), x + kStereoOffset, y, line, bold);
+ gr_text(gr_sys_font(), x - kStereoOffset + mid_divide, y, line, bold);
+ return char_height_ + 4;
}
diff --git a/vr_ui.h b/vr_ui.h
index 31ca4a61d..d996c145f 100644
--- a/vr_ui.h
+++ b/vr_ui.h
@@ -20,17 +20,17 @@
#include "screen_ui.h"
class VrRecoveryUI : public ScreenRecoveryUI {
- public:
- VrRecoveryUI();
+ public:
+ VrRecoveryUI();
- protected:
- // Pixel offsets to move drawing functions to visible range.
- // Can vary per device depending on screen size and lens distortion.
- const int kStereoOffset;
+ protected:
+ // Pixel offsets to move drawing functions to visible range.
+ // Can vary per device depending on screen size and lens distortion.
+ const int kStereoOffset;
- bool InitTextParams() override;
+ bool InitTextParams() override;
- void DrawTextLine(int x, int* y, const char* line, bool bold) const override;
+ int DrawTextLine(int x, int y, const char* line, bool bold) const override;
};
#endif // RECOVERY_VR_UI_H
diff --git a/wear_ui.cpp b/wear_ui.cpp
index 6c0286558..18c30d34a 100644
--- a/wear_ui.cpp
+++ b/wear_ui.cpp
@@ -45,167 +45,158 @@ static WearRecoveryUI* self = NULL;
// Return the current time as a double (including fractions of a second).
static double now() {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec + tv.tv_usec / 1000000.0;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec + tv.tv_usec / 1000000.0;
}
-WearRecoveryUI::WearRecoveryUI() :
- progress_bar_y(259),
- outer_height(0),
- outer_width(0),
- menu_unusable_rows(0) {
- intro_frames = 22;
- loop_frames = 60;
- animation_fps = 30;
+WearRecoveryUI::WearRecoveryUI()
+ : progress_bar_y(259), outer_height(0), outer_width(0), menu_unusable_rows(0) {
+ intro_frames = 22;
+ loop_frames = 60;
+ animation_fps = 30;
- for (size_t i = 0; i < 5; i++)
- backgroundIcon[i] = NULL;
+ for (size_t i = 0; i < 5; i++) backgroundIcon[i] = NULL;
- self = this;
+ self = this;
}
-int WearRecoveryUI::GetProgressBaseline() {
- return progress_bar_y;
+int WearRecoveryUI::GetProgressBaseline() const {
+ return progress_bar_y;
}
// Draw background frame on the screen. Does not flip pages.
// Should only be called with updateMutex locked.
// TODO merge drawing routines with screen_ui
-void WearRecoveryUI::draw_background_locked()
-{
- pagesIdentical = false;
- gr_color(0, 0, 0, 255);
- gr_fill(0, 0, gr_fb_width(), gr_fb_height());
-
- if (currentIcon != NONE) {
- GRSurface* surface;
- if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
- if (!intro_done) {
- surface = introFrames[current_frame];
- } else {
- surface = loopFrames[current_frame];
- }
- }
- else {
- surface = backgroundIcon[currentIcon];
- }
+void WearRecoveryUI::draw_background_locked() {
+ pagesIdentical = false;
+ gr_color(0, 0, 0, 255);
+ gr_fill(0, 0, gr_fb_width(), gr_fb_height());
+
+ if (currentIcon != NONE) {
+ GRSurface* surface;
+ if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
+ if (!intro_done) {
+ surface = introFrames[current_frame];
+ } else {
+ surface = loopFrames[current_frame];
+ }
+ } else {
+ surface = backgroundIcon[currentIcon];
+ }
- int width = gr_get_width(surface);
- int height = gr_get_height(surface);
+ int width = gr_get_width(surface);
+ int height = gr_get_height(surface);
- int x = (gr_fb_width() - width) / 2;
- int y = (gr_fb_height() - height) / 2;
+ int x = (gr_fb_width() - width) / 2;
+ int y = (gr_fb_height() - height) / 2;
- gr_blit(surface, 0, 0, width, height, x, y);
- }
+ gr_blit(surface, 0, 0, width, height, x, y);
+ }
}
-static const char* HEADERS[] = {
- "Swipe up/down to move.",
- "Swipe left/right to select.",
- "",
- NULL
+static const char* SWIPE_HELP[] = {
+ "Swipe up/down to move.",
+ "Swipe left/right to select.",
+ "",
+ NULL
};
// TODO merge drawing routines with screen_ui
-void WearRecoveryUI::draw_screen_locked()
-{
- char cur_selection_str[50];
+void WearRecoveryUI::draw_screen_locked() {
+ char cur_selection_str[50];
+
+ draw_background_locked();
+ if (!show_text) {
+ draw_foreground_locked();
+ } else {
+ SetColor(TEXT_FILL);
+ gr_fill(0, 0, gr_fb_width(), gr_fb_height());
- draw_background_locked();
- if (!show_text) {
- draw_foreground_locked();
- } else {
- SetColor(TEXT_FILL);
- gr_fill(0, 0, gr_fb_width(), gr_fb_height());
-
- int y = outer_height;
- int x = outer_width;
- if (show_menu) {
- std::string recovery_fingerprint =
- android::base::GetProperty("ro.bootimage.build.fingerprint", "");
- SetColor(HEADER);
- DrawTextLine(x + 4, &y, "Android Recovery", true);
- for (auto& chunk: android::base::Split(recovery_fingerprint, ":")) {
- DrawTextLine(x +4, &y, chunk.c_str(), false);
- }
-
- // This is actually the help strings.
- DrawTextLines(x + 4, &y, HEADERS);
- SetColor(HEADER);
- DrawTextLines(x + 4, &y, menu_headers_);
-
- // Show the current menu item number in relation to total number if
- // items don't fit on the screen.
- if (menu_items > menu_end - menu_start) {
- sprintf(cur_selection_str, "Current item: %d/%d", menu_sel + 1, menu_items);
- gr_text(gr_sys_font(), x+4, y, cur_selection_str, 1);
- y += char_height_+4;
- }
-
- // Menu begins here
- SetColor(MENU);
-
- for (int i = menu_start; i < menu_end; ++i) {
-
- if (i == menu_sel) {
- // draw the highlight bar
- SetColor(MENU_SEL_BG);
- gr_fill(x, y-2, gr_fb_width()-x, y+char_height_+2);
- // white text of selected item
- SetColor(MENU_SEL_FG);
- if (menu_[i][0]) {
- gr_text(gr_sys_font(), x + 4, y, menu_[i], 1);
- }
- SetColor(MENU);
- } else if (menu_[i][0]) {
- gr_text(gr_sys_font(), x + 4, y, menu_[i], 0);
- }
- y += char_height_+4;
- }
- SetColor(MENU);
- y += 4;
- gr_fill(0, y, gr_fb_width(), y+2);
- y += 4;
- }
+ int y = outer_height;
+ int x = outer_width;
+ if (show_menu) {
+ std::string recovery_fingerprint =
+ android::base::GetProperty("ro.bootimage.build.fingerprint", "");
+ SetColor(HEADER);
+ y += DrawTextLine(x + 4, y, "Android Recovery", true);
+ for (auto& chunk : android::base::Split(recovery_fingerprint, ":")) {
+ y += DrawTextLine(x + 4, y, chunk.c_str(), false);
+ }
- SetColor(LOG);
-
- // display from the bottom up, until we hit the top of the
- // screen, the bottom of the menu, or we've displayed the
- // entire text buffer.
- int ty;
- int row = (text_top_ + text_rows_ - 1) % text_rows_;
- size_t count = 0;
- for (int ty = gr_fb_height() - char_height_ - outer_height;
- ty > y + 2 && count < text_rows_;
- ty -= char_height_, ++count) {
- gr_text(gr_sys_font(), x+4, ty, text_[row], 0);
- --row;
- if (row < 0) row = text_rows_ - 1;
+ // This is actually the help strings.
+ y += DrawTextLines(x + 4, y, SWIPE_HELP);
+ SetColor(HEADER);
+ y += DrawTextLines(x + 4, y, menu_headers_);
+
+ // Show the current menu item number in relation to total number if
+ // items don't fit on the screen.
+ if (menu_items > menu_end - menu_start) {
+ sprintf(cur_selection_str, "Current item: %d/%d", menu_sel + 1, menu_items);
+ gr_text(gr_sys_font(), x + 4, y, cur_selection_str, 1);
+ y += char_height_ + 4;
+ }
+
+ // Menu begins here
+ SetColor(MENU);
+
+ for (int i = menu_start; i < menu_end; ++i) {
+ if (i == menu_sel) {
+ // draw the highlight bar
+ SetColor(MENU_SEL_BG);
+ gr_fill(x, y - 2, gr_fb_width() - x, y + char_height_ + 2);
+ // white text of selected item
+ SetColor(MENU_SEL_FG);
+ if (menu_[i][0]) {
+ gr_text(gr_sys_font(), x + 4, y, menu_[i], 1);
+ }
+ SetColor(MENU);
+ } else if (menu_[i][0]) {
+ gr_text(gr_sys_font(), x + 4, y, menu_[i], 0);
}
+ y += char_height_ + 4;
+ }
+ SetColor(MENU);
+ y += 4;
+ gr_fill(0, y, gr_fb_width(), y + 2);
+ y += 4;
+ }
+
+ SetColor(LOG);
+
+ // display from the bottom up, until we hit the top of the
+ // screen, the bottom of the menu, or we've displayed the
+ // entire text buffer.
+ int ty;
+ int row = (text_top_ + text_rows_ - 1) % text_rows_;
+ size_t count = 0;
+ for (int ty = gr_fb_height() - char_height_ - outer_height; ty > y + 2 && count < text_rows_;
+ ty -= char_height_, ++count) {
+ gr_text(gr_sys_font(), x + 4, ty, text_[row], 0);
+ --row;
+ if (row < 0) row = text_rows_ - 1;
}
+ }
}
// TODO merge drawing routines with screen_ui
void WearRecoveryUI::update_progress_locked() {
- draw_screen_locked();
- gr_flip();
+ draw_screen_locked();
+ gr_flip();
}
bool WearRecoveryUI::InitTextParams() {
- if (!ScreenRecoveryUI::InitTextParams()) {
- return false;
- }
+ if (!ScreenRecoveryUI::InitTextParams()) {
+ return false;
+ }
- text_cols_ = (gr_fb_width() - (outer_width * 2)) / char_width_;
+ text_cols_ = (gr_fb_width() - (outer_width * 2)) / char_width_;
- if (text_rows_ > kMaxRows) text_rows_ = kMaxRows;
- if (text_cols_ > kMaxCols) text_cols_ = kMaxCols;
+ if (text_rows_ > kMaxRows) text_rows_ = kMaxRows;
+ if (text_cols_ > kMaxCols) text_cols_ = kMaxCols;
- visible_text_rows = (gr_fb_height() - (outer_height * 2)) / char_height_;
- return true;
+ visible_text_rows = (gr_fb_height() - (outer_height * 2)) / char_height_;
+ return true;
}
bool WearRecoveryUI::Init(const std::string& locale) {
@@ -222,7 +213,8 @@ bool WearRecoveryUI::Init(const std::string& locale) {
return true;
}
-void WearRecoveryUI::SetStage(int current, int max) {}
+void WearRecoveryUI::SetStage(int current, int max) {
+}
void WearRecoveryUI::Print(const char* fmt, ...) {
char buf[256];
@@ -252,165 +244,153 @@ void WearRecoveryUI::Print(const char* fmt, ...) {
pthread_mutex_unlock(&updateMutex);
}
-void WearRecoveryUI::StartMenu(const char* const * headers, const char* const * items,
+void WearRecoveryUI::StartMenu(const char* const* headers, const char* const* items,
int initial_selection) {
- pthread_mutex_lock(&updateMutex);
- if (text_rows_ > 0 && text_cols_ > 0) {
- menu_headers_ = headers;
- size_t i = 0;
- // "i < text_rows_" is removed from the loop termination condition,
- // which is different from the one in ScreenRecoveryUI::StartMenu().
- // Because WearRecoveryUI supports scrollable menu, it's fine to have
- // more entries than text_rows_. The menu may be truncated otherwise.
- // Bug: 23752519
- for (; items[i] != nullptr; i++) {
- strncpy(menu_[i], items[i], text_cols_ - 1);
- menu_[i][text_cols_ - 1] = '\0';
- }
- menu_items = i;
- show_menu = true;
- menu_sel = initial_selection;
- menu_start = 0;
- menu_end = visible_text_rows - 1 - menu_unusable_rows;
- if (menu_items <= menu_end)
- menu_end = menu_items;
- update_screen_locked();
+ pthread_mutex_lock(&updateMutex);
+ if (text_rows_ > 0 && text_cols_ > 0) {
+ menu_headers_ = headers;
+ size_t i = 0;
+ // "i < text_rows_" is removed from the loop termination condition,
+ // which is different from the one in ScreenRecoveryUI::StartMenu().
+ // Because WearRecoveryUI supports scrollable menu, it's fine to have
+ // more entries than text_rows_. The menu may be truncated otherwise.
+ // Bug: 23752519
+ for (; items[i] != nullptr; i++) {
+ strncpy(menu_[i], items[i], text_cols_ - 1);
+ menu_[i][text_cols_ - 1] = '\0';
}
- pthread_mutex_unlock(&updateMutex);
+ menu_items = i;
+ show_menu = true;
+ menu_sel = initial_selection;
+ menu_start = 0;
+ menu_end = visible_text_rows - 1 - menu_unusable_rows;
+ if (menu_items <= menu_end) menu_end = menu_items;
+ update_screen_locked();
+ }
+ pthread_mutex_unlock(&updateMutex);
}
int WearRecoveryUI::SelectMenu(int sel) {
- int old_sel;
- pthread_mutex_lock(&updateMutex);
- if (show_menu) {
- old_sel = menu_sel;
- menu_sel = sel;
- if (menu_sel < 0) menu_sel = 0;
- if (menu_sel >= menu_items) menu_sel = menu_items-1;
- if (menu_sel < menu_start) {
- menu_start--;
- menu_end--;
- } else if (menu_sel >= menu_end && menu_sel < menu_items) {
- menu_end++;
- menu_start++;
- }
- sel = menu_sel;
- if (menu_sel != old_sel) update_screen_locked();
+ int old_sel;
+ pthread_mutex_lock(&updateMutex);
+ if (show_menu) {
+ old_sel = menu_sel;
+ menu_sel = sel;
+ if (menu_sel < 0) menu_sel = 0;
+ if (menu_sel >= menu_items) menu_sel = menu_items - 1;
+ if (menu_sel < menu_start) {
+ menu_start--;
+ menu_end--;
+ } else if (menu_sel >= menu_end && menu_sel < menu_items) {
+ menu_end++;
+ menu_start++;
}
- pthread_mutex_unlock(&updateMutex);
- return sel;
+ sel = menu_sel;
+ if (menu_sel != old_sel) update_screen_locked();
+ }
+ pthread_mutex_unlock(&updateMutex);
+ return sel;
}
void WearRecoveryUI::ShowFile(FILE* fp) {
- std::vector<off_t> offsets;
- offsets.push_back(ftello(fp));
- ClearText();
-
- struct stat sb;
- fstat(fileno(fp), &sb);
-
- bool show_prompt = false;
- while (true) {
- if (show_prompt) {
- Print("--(%d%% of %d bytes)--",
- static_cast<int>(100 * (double(ftello(fp)) / double(sb.st_size))),
- static_cast<int>(sb.st_size));
- Redraw();
- while (show_prompt) {
- show_prompt = false;
- int key = WaitKey();
- if (key == KEY_POWER || key == KEY_ENTER) {
- return;
- } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
- if (offsets.size() <= 1) {
- show_prompt = true;
- } else {
- offsets.pop_back();
- fseek(fp, offsets.back(), SEEK_SET);
- }
- } else {
- if (feof(fp)) {
- return;
- }
- offsets.push_back(ftello(fp));
- }
- }
- ClearText();
- }
-
- int ch = getc(fp);
- if (ch == EOF) {
- text_row_ = text_top_ = text_rows_ - 2;
+ std::vector<off_t> offsets;
+ offsets.push_back(ftello(fp));
+ ClearText();
+
+ struct stat sb;
+ fstat(fileno(fp), &sb);
+
+ bool show_prompt = false;
+ while (true) {
+ if (show_prompt) {
+ Print("--(%d%% of %d bytes)--",
+ static_cast<int>(100 * (double(ftello(fp)) / double(sb.st_size))),
+ static_cast<int>(sb.st_size));
+ Redraw();
+ while (show_prompt) {
+ show_prompt = false;
+ int key = WaitKey();
+ if (key == KEY_POWER || key == KEY_ENTER) {
+ return;
+ } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
+ if (offsets.size() <= 1) {
show_prompt = true;
+ } else {
+ offsets.pop_back();
+ fseek(fp, offsets.back(), SEEK_SET);
+ }
} else {
- PutChar(ch);
- if (text_col_ == 0 && text_row_ >= text_rows_ - 2) {
- text_top_ = text_row_;
- show_prompt = true;
- }
+ if (feof(fp)) {
+ return;
+ }
+ offsets.push_back(ftello(fp));
}
+ }
+ ClearText();
}
-}
-void WearRecoveryUI::PutChar(char ch) {
- pthread_mutex_lock(&updateMutex);
- if (ch != '\n') text_[text_row_][text_col_++] = ch;
- if (ch == '\n' || text_col_ >= text_cols_) {
- text_col_ = 0;
- ++text_row_;
+ int ch = getc(fp);
+ if (ch == EOF) {
+ text_row_ = text_top_ = text_rows_ - 2;
+ show_prompt = true;
+ } else {
+ PutChar(ch);
+ if (text_col_ == 0 && text_row_ >= text_rows_ - 2) {
+ text_top_ = text_row_;
+ show_prompt = true;
+ }
}
- pthread_mutex_unlock(&updateMutex);
+ }
}
-void WearRecoveryUI::ShowFile(const char* filename) {
- FILE* fp = fopen_path(filename, "re");
- if (fp == nullptr) {
- Print(" Unable to open %s: %s\n", filename, strerror(errno));
- return;
- }
- ShowFile(fp);
- fclose(fp);
+void WearRecoveryUI::PutChar(char ch) {
+ pthread_mutex_lock(&updateMutex);
+ if (ch != '\n') text_[text_row_][text_col_++] = ch;
+ if (ch == '\n' || text_col_ >= text_cols_) {
+ text_col_ = 0;
+ ++text_row_;
+ }
+ pthread_mutex_unlock(&updateMutex);
}
-void WearRecoveryUI::ClearText() {
- pthread_mutex_lock(&updateMutex);
- text_col_ = 0;
- text_row_ = 0;
- text_top_ = 1;
- for (size_t i = 0; i < text_rows_; ++i) {
- memset(text_[i], 0, text_cols_ + 1);
- }
- pthread_mutex_unlock(&updateMutex);
+void WearRecoveryUI::ShowFile(const char* filename) {
+ FILE* fp = fopen_path(filename, "re");
+ if (fp == nullptr) {
+ Print(" Unable to open %s: %s\n", filename, strerror(errno));
+ return;
+ }
+ ShowFile(fp);
+ fclose(fp);
}
void WearRecoveryUI::PrintOnScreenOnly(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- PrintV(fmt, false, ap);
- va_end(ap);
+ va_list ap;
+ va_start(ap, fmt);
+ PrintV(fmt, false, ap);
+ va_end(ap);
}
void WearRecoveryUI::PrintV(const char* fmt, bool copy_to_stdout, va_list ap) {
- std::string str;
- android::base::StringAppendV(&str, fmt, ap);
+ std::string str;
+ android::base::StringAppendV(&str, fmt, ap);
- if (copy_to_stdout) {
- fputs(str.c_str(), stdout);
- }
+ if (copy_to_stdout) {
+ fputs(str.c_str(), stdout);
+ }
- pthread_mutex_lock(&updateMutex);
- if (text_rows_ > 0 && text_cols_ > 0) {
- for (const char* ptr = str.c_str(); *ptr != '\0'; ++ptr) {
- if (*ptr == '\n' || text_col_ >= text_cols_) {
- text_[text_row_][text_col_] = '\0';
- text_col_ = 0;
- text_row_ = (text_row_ + 1) % text_rows_;
- if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_;
- }
- if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr;
- }
+ pthread_mutex_lock(&updateMutex);
+ if (text_rows_ > 0 && text_cols_ > 0) {
+ for (const char* ptr = str.c_str(); *ptr != '\0'; ++ptr) {
+ if (*ptr == '\n' || text_col_ >= text_cols_) {
text_[text_row_][text_col_] = '\0';
- update_screen_locked();
+ text_col_ = 0;
+ text_row_ = (text_row_ + 1) % text_rows_;
+ if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_;
+ }
+ if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr;
}
- pthread_mutex_unlock(&updateMutex);
+ text_[text_row_][text_col_] = '\0';
+ update_screen_locked();
+ }
+ pthread_mutex_unlock(&updateMutex);
}
diff --git a/wear_ui.h b/wear_ui.h
index 4cd852f21..a814118c7 100644
--- a/wear_ui.h
+++ b/wear_ui.h
@@ -22,64 +22,61 @@
#include <string>
class WearRecoveryUI : public ScreenRecoveryUI {
- public:
- WearRecoveryUI();
+ public:
+ WearRecoveryUI();
- bool Init(const std::string& locale) override;
+ bool Init(const std::string& locale) override;
- void SetStage(int current, int max) override;
+ void SetStage(int current, int max) override;
- // printing messages
- void Print(const char* fmt, ...) override;
- void PrintOnScreenOnly(const char* fmt, ...) override __printflike(2, 3);
- void ShowFile(const char* filename) override;
- void ShowFile(FILE* fp) override;
+ // printing messages
+ void Print(const char* fmt, ...) override;
+ void PrintOnScreenOnly(const char* fmt, ...) override __printflike(2, 3);
+ void ShowFile(const char* filename) override;
+ void ShowFile(FILE* fp) override;
- // menu display
- void StartMenu(const char* const * headers, const char* const * items,
- int initial_selection) override;
- int SelectMenu(int sel) override;
+ // menu display
+ void StartMenu(const char* const* headers, const char* const* items,
+ int initial_selection) override;
+ int SelectMenu(int sel) override;
- protected:
- // progress bar vertical position, it's centered horizontally
- int progress_bar_y;
+ protected:
+ // progress bar vertical position, it's centered horizontally
+ int progress_bar_y;
- // outer of window
- int outer_height, outer_width;
+ // outer of window
+ int outer_height, outer_width;
- // Unusable rows when displaying the recovery menu, including the lines
- // for headers (Android Recovery, build id and etc) and the bottom lines
- // that may otherwise go out of the screen.
- int menu_unusable_rows;
+ // Unusable rows when displaying the recovery menu, including the lines for headers (Android
+ // Recovery, build id and etc) and the bottom lines that may otherwise go out of the screen.
+ int menu_unusable_rows;
- int GetProgressBaseline() override;
+ int GetProgressBaseline() const override;
- bool InitTextParams() override;
+ bool InitTextParams() override;
- void update_progress_locked() override;
+ void update_progress_locked() override;
- void PrintV(const char*, bool, va_list) override;
+ void PrintV(const char*, bool, va_list) override;
- private:
- GRSurface* backgroundIcon[5];
+ private:
+ GRSurface* backgroundIcon[5];
- static const int kMaxCols = 96;
- static const int kMaxRows = 96;
+ static const int kMaxCols = 96;
+ static const int kMaxRows = 96;
- // Number of text rows seen on screen
- int visible_text_rows;
+ // Number of text rows seen on screen
+ int visible_text_rows;
- const char* const* menu_headers_;
- int menu_start, menu_end;
+ const char* const* menu_headers_;
+ int menu_start, menu_end;
- pthread_t progress_t;
+ pthread_t progress_t;
- void draw_background_locked() override;
- void draw_screen_locked() override;
- void draw_progress_locked();
+ void draw_background_locked() override;
+ void draw_screen_locked() override;
- void PutChar(char);
- void ClearText();
+ void PutChar(char);
};
#endif // RECOVERY_WEAR_UI_H