am d327c63a: am c87bab10: add the functions for multi-stage packages to updater

* commit 'd327c63af691a36fbf53866a3ae7ad27a43ebe3b':
  add the functions for multi-stage packages to updater
This commit is contained in:
Doug Zongker 2013-12-02 23:30:51 +00:00 committed by Android Git Automerger
commit a766c34f86
8 changed files with 181 additions and 9 deletions

View file

@ -38,11 +38,24 @@ extern "C" {
* The recovery field is only written by linux and used
* for the system to send a message to recovery or the
* other way around.
*
* The stage field is written by packages which restart themselves
* multiple times, so that the UI can reflect which invocation of the
* package it is. If the value is of the format "#/#" (eg, "1/3"),
* the UI will add a simple indicator of that status.
*/
struct bootloader_message {
char command[32];
char status[32];
char recovery[1024];
char recovery[768];
// The 'recovery' field used to be 1024 bytes. It has only ever
// been used to store the recovery command line, so 768 bytes
// should be plenty. We carve off the last 256 bytes to store the
// stage string (for multistage packages) and possible future
// expansion.
char stage[32];
char reserved[224];
};
/* Read and write the bootloader command from the "misc" partition.

View file

@ -56,6 +56,7 @@ static const struct option OPTIONS[] = {
{ "show_text", no_argument, NULL, 't' },
{ "just_exit", no_argument, NULL, 'x' },
{ "locale", required_argument, NULL, 'l' },
{ "stages", required_argument, NULL, 'g' },
{ NULL, 0, NULL, 0 },
};
@ -76,6 +77,7 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
RecoveryUI* ui = NULL;
char* locale = NULL;
char recovery_version[PROPERTY_VALUE_MAX+1];
char* stage = NULL;
/*
* The recovery tool communicates with the main system through /cache files.
@ -172,6 +174,7 @@ get_args(int *argc, char ***argv) {
struct bootloader_message boot;
memset(&boot, 0, sizeof(boot));
get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
stage = strndup(boot.stage, sizeof(boot.stage));
if (boot.command[0] != 0 && boot.command[0] != 255) {
LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command);
@ -959,6 +962,14 @@ main(int argc, char **argv) {
case 't': show_text = 1; break;
case 'x': just_exit = true; break;
case 'l': locale = optarg; break;
case 'g': {
if (stage == NULL || *stage == '\0') {
char buffer[20] = "1/";
strncat(buffer, optarg, sizeof(buffer)-3);
stage = strdup(buffer);
}
break;
}
case '?':
LOGE("Invalid command argument\n");
continue;
@ -969,12 +980,19 @@ main(int argc, char **argv) {
load_locale_from_cache();
}
printf("locale is [%s]\n", locale);
printf("stage is [%s]\n", stage, stage);
Device* device = make_device();
ui = device->GetUI();
gCurrentUI = ui;
ui->Init();
int st_cur, st_max;
if (stage != NULL && sscanf(stage, "%d/%d", &st_cur, &st_max) == 2) {
ui->SetStage(st_cur, st_max);
}
ui->SetLocale(locale);
ui->SetBackground(RecoveryUI::NONE);
if (show_text) ui->ShowText(true);

BIN
res/images/stage_empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

BIN
res/images/stage_fill.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

View file

@ -81,7 +81,9 @@ ScreenRecoveryUI::ScreenRecoveryUI() :
install_overlay_offset_x(13),
install_overlay_offset_y(190),
overlay_offset_x(-1),
overlay_offset_y(-1) {
overlay_offset_y(-1),
stage(-1),
max_stage(-1) {
for (int i = 0; i < 5; i++)
backgroundIcon[i] = NULL;
@ -120,14 +122,28 @@ void ScreenRecoveryUI::draw_background_locked(Icon icon)
int iconHeight = gr_get_height(surface);
int textWidth = gr_get_width(text_surface);
int textHeight = gr_get_height(text_surface);
int stageHeight = gr_get_height(stageMarkerEmpty);
int sh = (max_stage >= 0) ? stageHeight : 0;
int iconX = (gr_fb_width() - iconWidth) / 2;
int iconY = (gr_fb_height() - (iconHeight+textHeight+40)) / 2;
int iconY = (gr_fb_height() - (iconHeight+textHeight+40+sh)) / 2;
int textX = (gr_fb_width() - textWidth) / 2;
int textY = ((gr_fb_height() - (iconHeight+textHeight+40)) / 2) + iconHeight + 40;
int textY = ((gr_fb_height() - (iconHeight+textHeight+40+sh)) / 2) + iconHeight + 40;
gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY);
if (stageHeight > 0) {
int sw = gr_get_width(stageMarkerEmpty);
int x = (gr_fb_width() - max_stage * gr_get_width(stageMarkerEmpty)) / 2;
int y = iconY + iconHeight + 20;
for (int i = 0; i < max_stage; ++i) {
gr_blit((i < stage) ? stageMarkerFill : stageMarkerEmpty,
0, 0, sw, stageHeight, x, y);
x += sw;
}
}
if (icon == INSTALLING_UPDATE || icon == ERASING) {
draw_install_overlay_locked(installingFrame);
}
@ -384,6 +400,8 @@ void ScreenRecoveryUI::Init()
LoadBitmap("progress_empty", &progressBarEmpty);
LoadBitmap("progress_fill", &progressBarFill);
LoadBitmap("stage_empty", &stageMarkerEmpty);
LoadBitmap("stage_fill", &stageMarkerFill);
LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]);
LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]);
@ -454,7 +472,10 @@ void ScreenRecoveryUI::SetBackground(Icon icon)
gr_surface text = backgroundText[icon];
overlay_offset_x = install_overlay_offset_x + (gr_fb_width() - gr_get_width(bg)) / 2;
overlay_offset_y = install_overlay_offset_y +
(gr_fb_height() - (gr_get_height(bg) + gr_get_height(text) + 40)) / 2;
(gr_fb_height() - (gr_get_height(bg) +
gr_get_height(text) +
40 +
((max_stage >= 0) ? gr_get_height(stageMarkerEmpty) : 0))) / 2;
}
currentIcon = icon;
@ -506,6 +527,13 @@ void ScreenRecoveryUI::SetProgress(float fraction)
pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::SetStage(int current, int max) {
pthread_mutex_lock(&updateMutex);
stage = current;
max_stage = max;
pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::Print(const char *fmt, ...)
{
char buf[256];

View file

@ -39,6 +39,8 @@ class ScreenRecoveryUI : public RecoveryUI {
void ShowProgress(float portion, float seconds);
void SetProgress(float fraction);
void SetStage(int current, int max);
// text log
void ShowText(bool visible);
bool IsTextVisible();
@ -58,9 +60,6 @@ class ScreenRecoveryUI : public RecoveryUI {
enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL };
virtual void SetColor(UIElement e);
protected:
int install_overlay_offset_x, install_overlay_offset_y;
private:
Icon currentIcon;
int installingFrame;
@ -73,6 +72,8 @@ class ScreenRecoveryUI : public RecoveryUI {
gr_surface *progressBarIndeterminate;
gr_surface progressBarEmpty;
gr_surface progressBarFill;
gr_surface stageMarkerEmpty;
gr_surface stageMarkerFill;
ProgressType progressBarType;
@ -102,8 +103,13 @@ class ScreenRecoveryUI : public RecoveryUI {
int animation_fps;
int indeterminate_frames;
int installing_frames;
protected:
int install_overlay_offset_x, install_overlay_offset_y;
private:
int overlay_offset_x, overlay_offset_y;
int stage, max_stage;
void draw_install_overlay_locked(int frame);
void draw_background_locked(Icon icon);
void draw_progress_locked();

2
ui.h
View file

@ -30,6 +30,8 @@ class RecoveryUI {
// Initialize the object; called before anything else.
virtual void Init();
// Show a stage indicator. Call immediately after Init().
virtual void SetStage(int current, int max) { }
// After calling Init(), you can tell the UI what locale it is operating in.
virtual void SetLocale(const char* locale) { }

View file

@ -34,6 +34,9 @@
#include <linux/xattr.h>
#include <inttypes.h>
#include "bootloader.h"
#include "applypatch/applypatch.h"
#include "cutils/android_reboot.h"
#include "cutils/misc.h"
#include "cutils/properties.h"
#include "edify/expr.h"
@ -42,7 +45,6 @@
#include "mtdutils/mounts.h"
#include "mtdutils/mtdutils.h"
#include "updater.h"
#include "applypatch/applypatch.h"
#ifdef USE_EXT4
#include "make_ext4fs.h"
@ -1337,6 +1339,105 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
return v;
}
// Immediately reboot the device. Recovery is not finished normally,
// so if you reboot into recovery it will re-start applying the
// current package (because nothing has cleared the copy of the
// arguments stored in the BCB).
//
// The argument is the partition name passed to the android reboot
// property. It can be "recovery" to boot from the recovery
// partition, or "" (empty string) to boot from the regular boot
// partition.
Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2) {
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
}
char* filename;
char* property;
if (ReadArgs(state, argv, 2, &filename, &property) < 0) return NULL;
char buffer[80];
// zero out the 'command' field of the bootloader message.
memset(buffer, 0, sizeof(((struct bootloader_message*)0)->command));
FILE* f = fopen(filename, "r+b");
fseek(f, offsetof(struct bootloader_message, command), SEEK_SET);
fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f);
fclose(f);
free(filename);
strcpy(buffer, "reboot,");
if (property != NULL) {
strncat(buffer, property, sizeof(buffer)-10);
}
property_set(ANDROID_RB_PROPERTY, buffer);
sleep(5);
free(property);
ErrorAbort(state, "%s() failed to reboot", name);
return NULL;
}
// Store a string value somewhere that future invocations of recovery
// can access it. This value is called the "stage" and can be used to
// drive packages that need to do reboots in the middle of
// installation and keep track of where they are in the multi-stage
// install.
//
// The first argument is the block device for the misc partition
// ("/misc" in the fstab), which is where this value is stored. The
// second argument is the string to store; it should not exceed 31
// bytes.
Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2) {
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
}
char* filename;
char* stagestr;
if (ReadArgs(state, argv, 2, &filename, &stagestr) < 0) return NULL;
// Store this value in the misc partition, immediately after the
// bootloader message that the main recovery uses to save its
// arguments in case of the device restarting midway through
// package installation.
FILE* f = fopen(filename, "r+b");
fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET);
int to_write = strlen(stagestr)+1;
int max_size = sizeof(((struct bootloader_message*)0)->stage);
if (to_write > max_size) {
to_write = max_size;
stagestr[max_size-1] = 0;
}
fwrite(stagestr, to_write, 1, f);
fclose(f);
free(stagestr);
return StringValue(filename);
}
// Return the value most recently saved with SetStageFn. The argument
// is the block device for the misc partition.
Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2) {
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
}
char* filename;
if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
char buffer[sizeof(((struct bootloader_message*)0)->stage)];
FILE* f = fopen(filename, "rb");
fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET);
fread(buffer, sizeof(buffer), 1, f);
fclose(f);
buffer[sizeof(buffer)-1] = '\0';
return StringValue(strdup(buffer));
}
void RegisterInstallFunctions() {
RegisterFunction("mount", MountFn);
RegisterFunction("is_mounted", IsMountedFn);
@ -1379,4 +1480,8 @@ void RegisterInstallFunctions() {
RegisterFunction("ui_print", UIPrintFn);
RegisterFunction("run_program", RunProgramFn);
RegisterFunction("reboot_now", RebootNowFn);
RegisterFunction("get_stage", GetStageFn);
RegisterFunction("set_stage", SetStageFn);
}