summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--applypatch/Android.mk1
-rw-r--r--applypatch/imgdiff.cpp25
-rw-r--r--etc/init.rc2
-rw-r--r--recovery.cpp3
-rw-r--r--screen_ui.cpp234
-rw-r--r--screen_ui.h8
-rw-r--r--stub_ui.h2
-rw-r--r--tests/component/imgdiff_test.cpp80
-rw-r--r--tests/component/verifier_test.cpp70
-rw-r--r--ui.cpp67
-rw-r--r--ui.h21
-rw-r--r--updater/blockimg.cpp137
-rw-r--r--updater/install.cpp4
-rw-r--r--wear_ui.cpp73
-rw-r--r--wear_ui.h4
15 files changed, 403 insertions, 328 deletions
diff --git a/applypatch/Android.mk b/applypatch/Android.mk
index 61e110617..ec3c6ee38 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -124,6 +124,7 @@ libimgdiff_cflags := \
libimgdiff_static_libraries := \
libbsdiff \
+ libbase \
libz
# libimgdiff (static library)
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index 18a15a164..62de726a4 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -124,6 +124,7 @@
#include "applypatch/imgdiff.h"
#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -131,6 +132,9 @@
#include <sys/types.h>
#include <unistd.h>
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+
#include <bsdiff.h>
#include <zlib.h>
@@ -382,19 +386,12 @@ unsigned char* ReadImage(const char* filename, int* num_chunks, ImageChunk** chu
}
size_t sz = static_cast<size_t>(st.st_size);
- unsigned char* img = static_cast<unsigned char*>(malloc(sz + 4));
- FILE* f = fopen(filename, "rb");
- if (fread(img, 1, sz, f) != sz) {
+ unsigned char* img = static_cast<unsigned char*>(malloc(sz));
+ android::base::unique_fd fd(open(filename, O_RDONLY));
+ if (!android::base::ReadFully(fd, img, sz)) {
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
- fclose(f);
- return NULL;
+ return nullptr;
}
- fclose(f);
-
- // append 4 zero bytes to the data so we can always search for the
- // four-byte string 1f8b0800 starting at any point in the actual
- // file data, without special-casing the end of the data.
- memset(img+sz, 0, 4);
size_t pos = 0;
@@ -518,10 +515,8 @@ unsigned char* ReadImage(const char* filename, int* num_chunks, ImageChunk** chu
curr->data = p;
for (curr->len = 0; curr->len < (sz - pos); ++curr->len) {
- if (p[curr->len] == 0x1f &&
- p[curr->len+1] == 0x8b &&
- p[curr->len+2] == 0x08 &&
- p[curr->len+3] == 0x00) {
+ if (sz - pos >= 4 && p[curr->len] == 0x1f && p[curr->len + 1] == 0x8b &&
+ p[curr->len + 2] == 0x08 && p[curr->len + 3] == 0x00) {
break;
}
}
diff --git a/etc/init.rc b/etc/init.rc
index b1473ba4b..477e13d5e 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -30,6 +30,7 @@ on init
write /proc/sys/vm/max_map_count 1000000
on fs
+ write /sys/class/android_usb/android0/f_ffs/aliases adb
mkdir /dev/usb-ffs 0770 shell shell
mkdir /dev/usb-ffs/adb 0770 shell shell
mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
@@ -37,7 +38,6 @@ on fs
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18D1
write /sys/class/android_usb/android0/idProduct D001
- write /sys/class/android_usb/android0/f_ffs/aliases adb
write /sys/class/android_usb/android0/functions adb
write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer}
write /sys/class/android_usb/android0/iProduct ${ro.product.model}
diff --git a/recovery.cpp b/recovery.cpp
index b7aeaee1f..5888c542a 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -1506,11 +1506,10 @@ int main(int argc, char **argv) {
Device* device = make_device();
ui = device->GetUI();
- if (!ui->Init()) {
+ if (!ui->Init(locale)) {
printf("Failed to initialize UI, use stub UI instead.");
ui = new StubRecoveryUI();
}
- ui->SetLocale(locale.c_str());
// Set background string to "installing security update" for security update,
// otherwise set it to "installing system update".
ui->SetSystemUpdateText(security_update);
diff --git a/screen_ui.cpp b/screen_ui.cpp
index 5b9e5a5a9..706877b4d 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -29,6 +29,7 @@
#include <time.h>
#include <unistd.h>
+#include <string>
#include <vector>
#include <android-base/logging.h>
@@ -51,37 +52,34 @@ static double now() {
return tv.tv_sec + tv.tv_usec / 1000000.0;
}
-ScreenRecoveryUI::ScreenRecoveryUI() :
- currentIcon(NONE),
- locale(nullptr),
- progressBarType(EMPTY),
- progressScopeStart(0),
- progressScopeSize(0),
- progress(0),
- pagesIdentical(false),
- text_cols_(0),
- text_rows_(0),
- text_(nullptr),
- text_col_(0),
- text_row_(0),
- text_top_(0),
- show_text(false),
- show_text_ever(false),
- menu_(nullptr),
- show_menu(false),
- menu_items(0),
- menu_sel(0),
- file_viewer_text_(nullptr),
- intro_frames(0),
- loop_frames(0),
- current_frame(0),
- intro_done(false),
- animation_fps(30), // TODO: there's currently no way to infer this.
- stage(-1),
- max_stage(-1),
- updateMutex(PTHREAD_MUTEX_INITIALIZER),
- rtl_locale(false) {
-}
+ScreenRecoveryUI::ScreenRecoveryUI()
+ : currentIcon(NONE),
+ progressBarType(EMPTY),
+ progressScopeStart(0),
+ progressScopeSize(0),
+ progress(0),
+ pagesIdentical(false),
+ text_cols_(0),
+ text_rows_(0),
+ text_(nullptr),
+ text_col_(0),
+ text_row_(0),
+ text_top_(0),
+ show_text(false),
+ show_text_ever(false),
+ menu_(nullptr),
+ show_menu(false),
+ menu_items(0),
+ menu_sel(0),
+ file_viewer_text_(nullptr),
+ intro_frames(0),
+ loop_frames(0),
+ current_frame(0),
+ intro_done(false),
+ animation_fps(30), // TODO: there's currently no way to infer this.
+ stage(-1),
+ max_stage(-1),
+ updateMutex(PTHREAD_MUTEX_INITIALIZER) {}
GRSurface* ScreenRecoveryUI::GetCurrentFrame() {
if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
@@ -175,51 +173,50 @@ void ScreenRecoveryUI::draw_background_locked() {
// Does not flip pages.
// Should only be called with updateMutex locked.
void ScreenRecoveryUI::draw_foreground_locked() {
- if (currentIcon != NONE) {
- GRSurface* frame = GetCurrentFrame();
- int frame_width = gr_get_width(frame);
- int frame_height = gr_get_height(frame);
- int frame_x = (gr_fb_width() - frame_width) / 2;
- int frame_y = GetAnimationBaseline();
- gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
- }
-
- if (progressBarType != EMPTY) {
- int width = gr_get_width(progressBarEmpty);
- int height = gr_get_height(progressBarEmpty);
-
- int progress_x = (gr_fb_width() - width)/2;
- int progress_y = GetProgressBaseline();
-
- // Erase behind the progress bar (in case this was a progress-only update)
- gr_color(0, 0, 0, 255);
- gr_fill(progress_x, progress_y, width, height);
+ if (currentIcon != NONE) {
+ GRSurface* frame = GetCurrentFrame();
+ int frame_width = gr_get_width(frame);
+ int frame_height = gr_get_height(frame);
+ int frame_x = (gr_fb_width() - frame_width) / 2;
+ int frame_y = GetAnimationBaseline();
+ gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
+ }
+
+ if (progressBarType != EMPTY) {
+ int width = gr_get_width(progressBarEmpty);
+ int height = gr_get_height(progressBarEmpty);
+
+ int progress_x = (gr_fb_width() - width) / 2;
+ int progress_y = GetProgressBaseline();
+
+ // Erase behind the progress bar (in case this was a progress-only update)
+ gr_color(0, 0, 0, 255);
+ gr_fill(progress_x, progress_y, width, height);
- if (progressBarType == DETERMINATE) {
- float p = progressScopeStart + progress * progressScopeSize;
- int pos = (int) (p * width);
+ if (progressBarType == DETERMINATE) {
+ float p = progressScopeStart + progress * progressScopeSize;
+ int pos = static_cast<int>(p * width);
- if (rtl_locale) {
- // Fill the progress bar from right to left.
- if (pos > 0) {
- gr_blit(progressBarFill, width-pos, 0, pos, height,
- progress_x+width-pos, progress_y);
- }
- if (pos < width-1) {
- gr_blit(progressBarEmpty, 0, 0, width-pos, height, progress_x, progress_y);
- }
- } else {
- // Fill the progress bar from left to right.
- if (pos > 0) {
- gr_blit(progressBarFill, 0, 0, pos, height, progress_x, progress_y);
- }
- if (pos < width-1) {
- gr_blit(progressBarEmpty, pos, 0, width-pos, height,
- progress_x+pos, progress_y);
- }
- }
+ if (rtl_locale_) {
+ // Fill the progress bar from right to left.
+ if (pos > 0) {
+ gr_blit(progressBarFill, width - pos, 0, pos, height, progress_x + width - pos,
+ progress_y);
+ }
+ if (pos < width - 1) {
+ gr_blit(progressBarEmpty, 0, 0, width - pos, height, progress_x, progress_y);
+ }
+ } else {
+ // Fill the progress bar from left to right.
+ if (pos > 0) {
+ gr_blit(progressBarFill, 0, 0, pos, height, progress_x, progress_y);
}
+ if (pos < width - 1) {
+ gr_blit(progressBarEmpty, pos, 0, width - pos, height, progress_x + pos, progress_y);
+ }
+ }
}
+ }
}
void ScreenRecoveryUI::SetColor(UIElement e) {
@@ -423,10 +420,10 @@ void ScreenRecoveryUI::LoadBitmap(const char* filename, GRSurface** surface) {
}
void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** surface) {
- int result = res_create_localized_alpha_surface(filename, locale, surface);
- if (result < 0) {
- LOG(ERROR) << "couldn't load bitmap " << filename << " (error " << result << ")";
- }
+ int result = res_create_localized_alpha_surface(filename, locale_.c_str(), surface);
+ if (result < 0) {
+ LOG(ERROR) << "couldn't load bitmap " << filename << " (error " << result << ")";
+ }
}
static char** Alloc2d(size_t rows, size_t cols) {
@@ -459,47 +456,47 @@ bool ScreenRecoveryUI::InitTextParams() {
return true;
}
-bool ScreenRecoveryUI::Init() {
- RecoveryUI::Init();
- if (!InitTextParams()) {
- return false;
- }
+bool ScreenRecoveryUI::Init(const std::string& locale) {
+ RecoveryUI::Init(locale);
+ if (!InitTextParams()) {
+ return false;
+ }
- density_ = static_cast<float>(android::base::GetIntProperty("ro.sf.lcd_density", 160)) / 160.f;
+ density_ = static_cast<float>(android::base::GetIntProperty("ro.sf.lcd_density", 160)) / 160.f;
- // Are we portrait or landscape?
- layout_ = (gr_fb_width() > gr_fb_height()) ? LANDSCAPE : PORTRAIT;
- // Are we the large variant of our base layout?
- if (gr_fb_height() > PixelsFromDp(800)) ++layout_;
+ // Are we portrait or landscape?
+ layout_ = (gr_fb_width() > gr_fb_height()) ? LANDSCAPE : PORTRAIT;
+ // Are we the large variant of our base layout?
+ if (gr_fb_height() > PixelsFromDp(800)) ++layout_;
- text_ = Alloc2d(text_rows_, text_cols_ + 1);
- file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1);
- menu_ = Alloc2d(text_rows_, text_cols_ + 1);
+ text_ = Alloc2d(text_rows_, text_cols_ + 1);
+ file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1);
+ menu_ = Alloc2d(text_rows_, text_cols_ + 1);
- text_col_ = text_row_ = 0;
- text_top_ = 1;
+ text_col_ = text_row_ = 0;
+ text_top_ = 1;
- LoadBitmap("icon_error", &error_icon);
+ LoadBitmap("icon_error", &error_icon);
- LoadBitmap("progress_empty", &progressBarEmpty);
- LoadBitmap("progress_fill", &progressBarFill);
+ LoadBitmap("progress_empty", &progressBarEmpty);
+ LoadBitmap("progress_fill", &progressBarFill);
- LoadBitmap("stage_empty", &stageMarkerEmpty);
- LoadBitmap("stage_fill", &stageMarkerFill);
+ LoadBitmap("stage_empty", &stageMarkerEmpty);
+ LoadBitmap("stage_fill", &stageMarkerFill);
- // Background text for "installing_update" could be "installing update"
- // or "installing security update". It will be set after UI init according
- // to commands in BCB.
- installing_text = nullptr;
- LoadLocalizedBitmap("erasing_text", &erasing_text);
- LoadLocalizedBitmap("no_command_text", &no_command_text);
- LoadLocalizedBitmap("error_text", &error_text);
+ // Background text for "installing_update" could be "installing update"
+ // or "installing security update". It will be set after UI init according
+ // to commands in BCB.
+ installing_text = nullptr;
+ LoadLocalizedBitmap("erasing_text", &erasing_text);
+ LoadLocalizedBitmap("no_command_text", &no_command_text);
+ LoadLocalizedBitmap("error_text", &error_text);
- LoadAnimation();
+ LoadAnimation();
- pthread_create(&progress_thread_, nullptr, ProgressThreadStartRoutine, this);
+ pthread_create(&progress_thread_, nullptr, ProgressThreadStartRoutine, this);
- return true;
+ return true;
}
void ScreenRecoveryUI::LoadAnimation() {
@@ -539,31 +536,6 @@ void ScreenRecoveryUI::LoadAnimation() {
}
}
-void ScreenRecoveryUI::SetLocale(const char* new_locale) {
- this->locale = new_locale;
- this->rtl_locale = false;
-
- if (locale) {
- char* lang = strdup(locale);
- for (char* p = lang; *p; ++p) {
- if (*p == '_') {
- *p = '\0';
- break;
- }
- }
-
- // A bit cheesy: keep an explicit list of supported RTL languages.
- if (strcmp(lang, "ar") == 0 || // Arabic
- strcmp(lang, "fa") == 0 || // Persian (Farsi)
- strcmp(lang, "he") == 0 || // Hebrew (new language code)
- strcmp(lang, "iw") == 0 || // Hebrew (old language code)
- strcmp(lang, "ur") == 0) { // Urdu
- rtl_locale = true;
- }
- free(lang);
- }
-}
-
void ScreenRecoveryUI::SetBackground(Icon icon) {
pthread_mutex_lock(&updateMutex);
diff --git a/screen_ui.h b/screen_ui.h
index 38e2f0723..3ad64907e 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -20,6 +20,8 @@
#include <pthread.h>
#include <stdio.h>
+#include <string>
+
#include "ui.h"
#include "minui/minui.h"
@@ -29,8 +31,7 @@ class ScreenRecoveryUI : public RecoveryUI {
public:
ScreenRecoveryUI();
- bool Init() override;
- void SetLocale(const char* locale);
+ bool Init(const std::string& locale) override;
// overall recovery state ("background image")
void SetBackground(Icon icon);
@@ -71,8 +72,6 @@ class ScreenRecoveryUI : public RecoveryUI {
protected:
Icon currentIcon;
- const char* locale;
-
// The scale factor from dp to pixels. 1.0 for mdpi, 4.0 for xxxhdpi.
float density_;
// The layout to use.
@@ -135,7 +134,6 @@ class ScreenRecoveryUI : public RecoveryUI {
int char_width_;
int char_height_;
pthread_mutex_t updateMutex;
- bool rtl_locale;
virtual bool InitTextParams();
diff --git a/stub_ui.h b/stub_ui.h
index 1219b284c..85dbcfd89 100644
--- a/stub_ui.h
+++ b/stub_ui.h
@@ -24,8 +24,6 @@ class StubRecoveryUI : public RecoveryUI {
public:
StubRecoveryUI() = default;
- void SetLocale(const char* locale) override {}
-
void SetBackground(Icon icon) override {}
void SetSystemUpdateText(bool security_update) override {}
diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp
index 3711859de..7ad330783 100644
--- a/tests/component/imgdiff_test.cpp
+++ b/tests/component/imgdiff_test.cpp
@@ -404,6 +404,86 @@ TEST(ImgdiffTest, image_mode_spurious_magic) {
ASSERT_EQ(tgt, patched);
}
+TEST(ImgdiffTest, image_mode_short_input1) {
+ // src: "abcdefgh" + '0x1f8b0b'.
+ const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', '\x1f', '\x8b', '\x08' };
+ const std::string src(src_data.cbegin(), src_data.cend());
+ TemporaryFile src_file;
+ ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
+
+ // tgt: "abcdefgxyz".
+ const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
+ 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));
+
+ // Expect one CHUNK_RAW (header) entry.
+ size_t num_normal;
+ size_t num_raw;
+ size_t num_deflate;
+ verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
+ ASSERT_EQ(0U, num_normal);
+ ASSERT_EQ(0U, num_deflate);
+ ASSERT_EQ(1U, num_raw);
+
+ std::string patched;
+ ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
+ reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
+ MemorySink, &patched));
+ ASSERT_EQ(tgt, patched);
+}
+
+TEST(ImgdiffTest, image_mode_short_input2) {
+ // src: "abcdefgh" + '0x1f8b0b00'.
+ const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', '\x1f', '\x8b', '\x08', '\x00' };
+ const std::string src(src_data.cbegin(), src_data.cend());
+ TemporaryFile src_file;
+ ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
+
+ // tgt: "abcdefgxyz".
+ const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
+ 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));
+
+ // Expect one CHUNK_RAW (header) entry.
+ size_t num_normal;
+ size_t num_raw;
+ size_t num_deflate;
+ verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
+ ASSERT_EQ(0U, num_normal);
+ ASSERT_EQ(0U, num_deflate);
+ ASSERT_EQ(1U, num_raw);
+
+ std::string patched;
+ ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
+ reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
+ MemorySink, &patched));
+ ASSERT_EQ(tgt, patched);
+}
+
TEST(ImgdiffTest, image_mode_single_entry_long) {
// src: "abcdefgh" + '0x1f8b0b00' + some bytes.
const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp
index 33aadb3fb..b740af96b 100644
--- a/tests/component/verifier_test.cpp
+++ b/tests/component/verifier_test.cpp
@@ -40,38 +40,44 @@
RecoveryUI* ui = NULL;
class MockUI : public RecoveryUI {
- bool Init() { return true; }
- void SetStage(int, int) { }
- void SetLocale(const char*) { }
- void SetBackground(Icon /*icon*/) { }
- void SetSystemUpdateText(bool /*security_update*/) { }
-
- void SetProgressType(ProgressType /*determinate*/) { }
- void ShowProgress(float /*portion*/, float /*seconds*/) { }
- void SetProgress(float /*fraction*/) { }
-
- void ShowText(bool /*visible*/) { }
- bool IsTextVisible() { return false; }
- bool WasTextEverVisible() { return false; }
- void Print(const char* fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- }
- void PrintOnScreenOnly(const char* fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- }
- void ShowFile(const char*) { }
-
- void StartMenu(const char* const* /*headers*/,
- const char* const* /*items*/,
- int /*initial_selection*/) { }
- int SelectMenu(int /*sel*/) { return 0; }
- void EndMenu() { }
+ bool Init(const std::string&) override {
+ return true;
+ }
+ void SetStage(int, int) override {}
+ void SetBackground(Icon /*icon*/) override {}
+ void SetSystemUpdateText(bool /*security_update*/) override {}
+
+ void SetProgressType(ProgressType /*determinate*/) override {}
+ void ShowProgress(float /*portion*/, float /*seconds*/) override {}
+ void SetProgress(float /*fraction*/) override {}
+
+ void ShowText(bool /*visible*/) override {}
+ bool IsTextVisible() override {
+ return false;
+ }
+ bool WasTextEverVisible() override {
+ return false;
+ }
+ void Print(const char* fmt, ...) override {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+ void PrintOnScreenOnly(const char* fmt, ...) override {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+ void ShowFile(const char*) override {}
+
+ void StartMenu(const char* const* /*headers*/, const char* const* /*items*/,
+ int /*initial_selection*/) override {}
+ int SelectMenu(int /*sel*/) override {
+ return 0;
+ }
+ void EndMenu() override {}
};
void
diff --git a/ui.cpp b/ui.cpp
index 2d80c382f..f31660db4 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "ui.h"
+
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
@@ -28,6 +30,8 @@
#include <time.h>
#include <unistd.h>
+#include <string>
+
#include <android-base/properties.h>
#include <cutils/android_reboot.h>
@@ -35,25 +39,25 @@
#include "roots.h"
#include "device.h"
#include "minui/minui.h"
-#include "screen_ui.h"
-#include "ui.h"
#define UI_WAIT_KEY_TIMEOUT_SEC 120
RecoveryUI::RecoveryUI()
- : key_queue_len(0),
- key_last_down(-1),
- key_long_press(false),
- key_down_count(0),
- enable_reboot(true),
- consecutive_power_keys(0),
- last_key(-1),
- has_power_key(false),
- has_up_key(false),
- has_down_key(false) {
- pthread_mutex_init(&key_queue_mutex, nullptr);
- pthread_cond_init(&key_queue_cond, nullptr);
- memset(key_pressed, 0, sizeof(key_pressed));
+ : locale_(""),
+ rtl_locale_(false),
+ key_queue_len(0),
+ key_last_down(-1),
+ key_long_press(false),
+ key_down_count(0),
+ enable_reboot(true),
+ consecutive_power_keys(0),
+ last_key(-1),
+ has_power_key(false),
+ has_up_key(false),
+ has_down_key(false) {
+ pthread_mutex_init(&key_queue_mutex, nullptr);
+ pthread_cond_init(&key_queue_cond, nullptr);
+ memset(key_pressed, 0, sizeof(key_pressed));
}
void RecoveryUI::OnKeyDetected(int key_code) {
@@ -80,13 +84,16 @@ static void* InputThreadLoop(void*) {
return nullptr;
}
-bool RecoveryUI::Init() {
- ev_init(InputCallback, this);
+bool RecoveryUI::Init(const std::string& locale) {
+ // Set up the locale info.
+ SetLocale(locale);
- ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1));
+ ev_init(InputCallback, this);
- pthread_create(&input_thread_, nullptr, InputThreadLoop, nullptr);
- return true;
+ ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1));
+
+ pthread_create(&input_thread_, nullptr, InputThreadLoop, nullptr);
+ return true;
}
int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) {
@@ -338,3 +345,23 @@ void RecoveryUI::SetEnableReboot(bool enabled) {
enable_reboot = enabled;
pthread_mutex_unlock(&key_queue_mutex);
}
+
+void RecoveryUI::SetLocale(const std::string& new_locale) {
+ this->locale_ = new_locale;
+ this->rtl_locale_ = false;
+
+ if (!new_locale.empty()) {
+ size_t underscore = new_locale.find('_');
+ // lang has the language prefix prior to '_', or full string if '_' doesn't exist.
+ std::string lang = new_locale.substr(0, underscore);
+
+ // A bit cheesy: keep an explicit list of supported RTL languages.
+ if (lang == "ar" || // Arabic
+ lang == "fa" || // Persian (Farsi)
+ lang == "he" || // Hebrew (new language code)
+ lang == "iw" || // Hebrew (old language code)
+ lang == "ur") { // Urdu
+ rtl_locale_ = true;
+ }
+ }
+}
diff --git a/ui.h b/ui.h
index be95a4e23..8493c6f0a 100644
--- a/ui.h
+++ b/ui.h
@@ -21,6 +21,8 @@
#include <pthread.h>
#include <time.h>
+#include <string>
+
// Abstract class for controlling the user interface during recovery.
class RecoveryUI {
public:
@@ -28,14 +30,13 @@ class RecoveryUI {
virtual ~RecoveryUI() { }
- // Initialize the object; called before anything else. Returns true on success.
- virtual bool Init();
+ // 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);
+
// Show a stage indicator. Call immediately after Init().
virtual void SetStage(int current, int max) = 0;
- // After calling Init(), you can tell the UI what locale it is operating in.
- virtual void SetLocale(const char* locale) = 0;
-
// Set the overall recovery state ("background image").
enum Icon { NONE, INSTALLING_UPDATE, ERASING, NO_COMMAND, ERROR };
virtual void SetBackground(Icon icon) = 0;
@@ -122,10 +123,14 @@ class RecoveryUI {
// statements will be displayed.
virtual void EndMenu() = 0;
-protected:
+ protected:
void EnqueueKey(int key_code);
-private:
+ // The locale that's used to show the rendered texts.
+ std::string locale_;
+ bool rtl_locale_;
+
+ private:
// Key event input queue
pthread_mutex_t key_queue_mutex;
pthread_cond_t key_queue_cond;
@@ -162,6 +167,8 @@ private:
static void* time_key_helper(void* cookie);
void time_key(int key_code, int count);
+
+ void SetLocale(const std::string&);
};
#endif // RECOVERY_UI_H
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index 696c1bba4..6755d78cb 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -63,83 +63,82 @@ static constexpr mode_t STASH_DIRECTORY_MODE = 0700;
static constexpr mode_t STASH_FILE_MODE = 0600;
struct RangeSet {
- size_t count; // Limit is INT_MAX.
- size_t size;
- std::vector<size_t> pos; // Actual limit is INT_MAX.
+ size_t count; // Limit is INT_MAX.
+ size_t size;
+ std::vector<size_t> pos; // Actual limit is INT_MAX.
};
static CauseCode failure_type = kNoCause;
static bool is_retry = false;
static std::unordered_map<std::string, RangeSet> stash_map;
-static void parse_range(const std::string& range_text, RangeSet& rs) {
+static RangeSet parse_range(const std::string& range_text) {
+ RangeSet rs;
- std::vector<std::string> pieces = android::base::Split(range_text, ",");
- if (pieces.size() < 3) {
- goto err;
- }
-
- size_t num;
- if (!android::base::ParseUint(pieces[0].c_str(), &num, static_cast<size_t>(INT_MAX))) {
- goto err;
- }
+ std::vector<std::string> pieces = android::base::Split(range_text, ",");
+ if (pieces.size() < 3) {
+ goto err;
+ }
- if (num == 0 || num % 2) {
- goto err; // must be even
- } else if (num != pieces.size() - 1) {
- goto err;
- }
+ size_t num;
+ if (!android::base::ParseUint(pieces[0], &num, static_cast<size_t>(INT_MAX))) {
+ goto err;
+ }
- rs.pos.resize(num);
- rs.count = num / 2;
- rs.size = 0;
+ if (num == 0 || num % 2) {
+ goto err; // must be even
+ } else if (num != pieces.size() - 1) {
+ goto err;
+ }
- for (size_t i = 0; i < num; i += 2) {
- if (!android::base::ParseUint(pieces[i+1].c_str(), &rs.pos[i],
- static_cast<size_t>(INT_MAX))) {
- goto err;
- }
+ rs.pos.resize(num);
+ rs.count = num / 2;
+ rs.size = 0;
- if (!android::base::ParseUint(pieces[i+2].c_str(), &rs.pos[i+1],
- static_cast<size_t>(INT_MAX))) {
- goto err;
- }
+ for (size_t i = 0; i < num; i += 2) {
+ if (!android::base::ParseUint(pieces[i + 1], &rs.pos[i], static_cast<size_t>(INT_MAX))) {
+ goto err;
+ }
- if (rs.pos[i] >= rs.pos[i+1]) {
- goto err; // empty or negative range
- }
+ if (!android::base::ParseUint(pieces[i + 2], &rs.pos[i + 1], static_cast<size_t>(INT_MAX))) {
+ goto err;
+ }
- size_t sz = rs.pos[i+1] - rs.pos[i];
- if (rs.size > SIZE_MAX - sz) {
- goto err; // overflow
- }
+ if (rs.pos[i] >= rs.pos[i + 1]) {
+ goto err; // empty or negative range
+ }
- rs.size += sz;
+ size_t sz = rs.pos[i + 1] - rs.pos[i];
+ if (rs.size > SIZE_MAX - sz) {
+ goto err; // overflow
}
- return;
+ rs.size += sz;
+ }
+
+ return rs;
err:
- LOG(ERROR) << "failed to parse range '" << range_text << "'";
- exit(1);
+ LOG(ERROR) << "failed to parse range '" << range_text << "'";
+ exit(1);
}
static bool range_overlaps(const RangeSet& r1, const RangeSet& r2) {
- for (size_t i = 0; i < r1.count; ++i) {
- size_t r1_0 = r1.pos[i * 2];
- size_t r1_1 = r1.pos[i * 2 + 1];
+ for (size_t i = 0; i < r1.count; ++i) {
+ size_t r1_0 = r1.pos[i * 2];
+ size_t r1_1 = r1.pos[i * 2 + 1];
- for (size_t j = 0; j < r2.count; ++j) {
- size_t r2_0 = r2.pos[j * 2];
- size_t r2_1 = r2.pos[j * 2 + 1];
+ for (size_t j = 0; j < r2.count; ++j) {
+ size_t r2_0 = r2.pos[j * 2];
+ size_t r2_1 = r2.pos[j * 2 + 1];
- if (!(r2_0 >= r1_1 || r1_0 >= r2_1)) {
- return true;
- }
- }
+ if (!(r2_0 >= r1_1 || r1_0 >= r2_1)) {
+ return true;
+ }
}
+ }
- return false;
+ return false;
}
static int read_all(int fd, uint8_t* data, size_t size) {
@@ -430,11 +429,10 @@ static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t&
}
// <src_range>
- RangeSet src;
- parse_range(params.tokens[params.cpos++], src);
+ RangeSet src = parse_range(params.tokens[params.cpos++]);
// <tgt_range>
- parse_range(params.tokens[params.cpos++], tgt);
+ tgt = parse_range(params.tokens[params.cpos++]);
allocate(src.size * BLOCKSIZE, buffer);
int rc = ReadBlocks(src, buffer, fd);
@@ -790,8 +788,7 @@ static int SaveStash(CommandParameters& params, const std::string& base,
return 0;
}
- RangeSet src;
- parse_range(params.tokens[params.cpos++], src);
+ RangeSet src = parse_range(params.tokens[params.cpos++]);
allocate(src.size * BLOCKSIZE, buffer);
if (ReadBlocks(src, buffer, fd) == -1) {
@@ -875,7 +872,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
}
// <tgt_range>
- parse_range(params.tokens[params.cpos++], tgt);
+ tgt = parse_range(params.tokens[params.cpos++]);
// <src_block_count>
const std::string& token = params.tokens[params.cpos++];
@@ -891,8 +888,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
// no source ranges, only stashes
params.cpos++;
} else {
- RangeSet src;
- parse_range(params.tokens[params.cpos++], src);
+ RangeSet src = parse_range(params.tokens[params.cpos++]);
int res = ReadBlocks(src, buffer, fd);
if (overlap) {
@@ -908,8 +904,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
return 0;
}
- RangeSet locs;
- parse_range(params.tokens[params.cpos++], locs);
+ RangeSet locs = parse_range(params.tokens[params.cpos++]);
MoveRange(buffer, locs, buffer);
}
@@ -934,8 +929,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
continue;
}
- RangeSet locs;
- parse_range(tokens[1], locs);
+ RangeSet locs = parse_range(tokens[1]);
MoveRange(buffer, locs, stash);
}
@@ -1119,8 +1113,7 @@ static int PerformCommandZero(CommandParameters& params) {
return -1;
}
- RangeSet tgt;
- parse_range(params.tokens[params.cpos++], tgt);
+ RangeSet tgt = parse_range(params.tokens[params.cpos++]);
LOG(INFO) << " zeroing " << tgt.size << " blocks";
@@ -1163,8 +1156,7 @@ static int PerformCommandNew(CommandParameters& params) {
return -1;
}
- RangeSet tgt;
- parse_range(params.tokens[params.cpos++], tgt);
+ RangeSet tgt = parse_range(params.tokens[params.cpos++]);
if (params.canwrite) {
LOG(INFO) << " writing " << tgt.size << " blocks of new data";
@@ -1319,8 +1311,7 @@ static int PerformCommandErase(CommandParameters& params) {
return -1;
}
- RangeSet tgt;
- parse_range(params.tokens[params.cpos++], tgt);
+ RangeSet tgt = parse_range(params.tokens[params.cpos++]);
if (params.canwrite) {
LOG(INFO) << " erasing " << tgt.size << " blocks";
@@ -1708,8 +1699,7 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[])
return StringValue("");
}
- RangeSet rs;
- parse_range(ranges->data, rs);
+ RangeSet rs = parse_range(ranges->data);
SHA_CTX ctx;
SHA1_Init(&ctx);
@@ -1833,8 +1823,7 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[
return StringValue("");
}
- RangeSet rs;
- parse_range(ranges->data, rs);
+ RangeSet rs = parse_range(ranges->data);
uint8_t buffer[BLOCKSIZE];
diff --git a/updater/install.cpp b/updater/install.cpp
index 3cf38774e..643145447 100644
--- a/updater/install.cpp
+++ b/updater/install.cpp
@@ -46,6 +46,8 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <applypatch/applypatch.h>
+#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
#include <ext4_utils/make_ext4fs.h>
#include <ext4_utils/wipe.h>
@@ -54,8 +56,6 @@
#include <selinux/selinux.h>
#include <ziparchive/zip_archive.h>
-#include "applypatch/applypatch.h"
-#include "bootloader.h"
#include "edify/expr.h"
#include "error_code.h"
#include "mounts.h"
diff --git a/wear_ui.cpp b/wear_ui.cpp
index 11e5a7168..b4c63a5ae 100644
--- a/wear_ui.cpp
+++ b/wear_ui.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "wear_ui.h"
+
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
@@ -25,11 +27,11 @@
#include <time.h>
#include <unistd.h>
+#include <string>
#include <vector>
#include "common.h"
#include "device.h"
-#include "wear_ui.h"
#include "android-base/properties.h"
#include "android-base/strings.h"
#include "android-base/stringprintf.h"
@@ -204,49 +206,48 @@ bool WearRecoveryUI::InitTextParams() {
return true;
}
-bool WearRecoveryUI::Init() {
- if (!ScreenRecoveryUI::Init()) {
- return false;
- }
+bool WearRecoveryUI::Init(const std::string& locale) {
+ if (!ScreenRecoveryUI::Init(locale)) {
+ return false;
+ }
- LoadBitmap("icon_installing", &backgroundIcon[INSTALLING_UPDATE]);
- backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];
- LoadBitmap("icon_error", &backgroundIcon[ERROR]);
- backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];
- return true;
-}
+ LoadBitmap("icon_error", &backgroundIcon[ERROR]);
+ backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];
-void WearRecoveryUI::SetStage(int current, int max)
-{
+ // This leaves backgroundIcon[INSTALLING_UPDATE] and backgroundIcon[ERASING]
+ // as NULL which is fine since draw_background_locked() doesn't use them.
+
+ return true;
}
-void WearRecoveryUI::Print(const char *fmt, ...)
-{
- char buf[256];
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(buf, 256, fmt, ap);
- va_end(ap);
+void WearRecoveryUI::SetStage(int current, int max) {}
- fputs(buf, stdout);
+void WearRecoveryUI::Print(const char* fmt, ...) {
+ char buf[256];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, 256, fmt, ap);
+ va_end(ap);
- // This can get called before ui_init(), so be careful.
- pthread_mutex_lock(&updateMutex);
- if (text_rows_ > 0 && text_cols_ > 0) {
- char *ptr;
- for (ptr = buf; *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;
- }
+ fputs(buf, stdout);
+
+ // This can get called before ui_init(), so be careful.
+ pthread_mutex_lock(&updateMutex);
+ if (text_rows_ > 0 && text_cols_ > 0) {
+ char* ptr;
+ for (ptr = buf; *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 WearRecoveryUI::StartMenu(const char* const * headers, const char* const * items,
diff --git a/wear_ui.h b/wear_ui.h
index 5ac6f49dd..4cd852f21 100644
--- a/wear_ui.h
+++ b/wear_ui.h
@@ -19,11 +19,13 @@
#include "screen_ui.h"
+#include <string>
+
class WearRecoveryUI : public ScreenRecoveryUI {
public:
WearRecoveryUI();
- bool Init() override;
+ bool Init(const std::string& locale) override;
void SetStage(int current, int max) override;