aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk5
-rw-r--r--backup.cpp8
-rw-r--r--messagesocket.cpp116
-rw-r--r--messagesocket.h40
-rw-r--r--minui/events.cpp17
-rw-r--r--minui/minui.h1
-rw-r--r--res-hdpi/images/icon_error.pngbin19306 -> 4011 bytes
-rw-r--r--res/images/icon_info.pngbin0 -> 3745 bytes
-rw-r--r--restore.cpp8
-rw-r--r--screen_ui.cpp80
-rw-r--r--screen_ui.h16
-rw-r--r--ui.cpp85
-rw-r--r--ui.h11
-rw-r--r--verifier_test.cpp6
-rw-r--r--wear_ui.cpp2
-rw-r--r--wear_ui.h2
16 files changed, 389 insertions, 8 deletions
diff --git a/Android.mk b/Android.mk
index 55adbaa..f7fbfd8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -41,6 +41,7 @@ LOCAL_SRC_FILES := \
recovery.cpp \
roots.cpp \
screen_ui.cpp \
+ messagesocket.cpp \
ui.cpp \
verifier.cpp \
wear_ui.cpp \
@@ -181,6 +182,7 @@ LOCAL_SRC_FILES := \
bu.cpp \
backup.cpp \
restore.cpp \
+ messagesocket.cpp \
roots.cpp \
voldclient.cpp
LOCAL_CFLAGS += -DMINIVOLD
@@ -283,7 +285,8 @@ LOCAL_SRC_FILES := \
verifier_test.cpp \
asn1_decoder.cpp \
verifier.cpp \
- ui.cpp
+ ui.cpp \
+ messagesocket.cpp
LOCAL_STATIC_LIBRARIES := \
libmincrypt \
libminui \
diff --git a/backup.cpp b/backup.cpp
index ad23b17..5849490 100644
--- a/backup.cpp
+++ b/backup.cpp
@@ -18,6 +18,8 @@
#include "voldclient.h"
+#include "messagesocket.h"
+
using namespace android;
static int append_sod(const char* opt_hash)
@@ -248,6 +250,10 @@ int do_backup(int argc, char **argv)
}
}
+ MessageSocket ms;
+ ms.ClientInit();
+ ms.Show("Backup in progress...");
+
rc = create_tar(adb_ofd, opt_compress, "w");
if (rc != 0) {
logmsg("do_backup: cannot open tar stream\n");
@@ -293,6 +299,8 @@ int do_backup(int argc, char **argv)
if (opt_compress)
gzflush(gzf, Z_FINISH);
+ ms.Dismiss();
+
logmsg("backup complete: rc=%d\n", rc);
return rc;
diff --git a/messagesocket.cpp b/messagesocket.cpp
new file mode 100644
index 0000000..355a667
--- /dev/null
+++ b/messagesocket.cpp
@@ -0,0 +1,116 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include "messagesocket.h"
+
+static const char * const SOCKET_PATH = "/tmp/.dialog_sock";
+
+bool MessageSocket::ServerInit()
+{
+ int fd, rc;
+ unlink(SOCKET_PATH);
+ fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ return false;
+ }
+ struct sockaddr_un sa;
+ socklen_t salen;
+ memset(&sa, 0, sizeof(sa));
+ sa.sun_family = AF_UNIX;
+ strcpy(sa.sun_path, SOCKET_PATH);
+ rc = ::bind(fd, (struct sockaddr *)&sa, sizeof(sa));
+ if (rc != 0) {
+ ::close(fd);
+ return false;
+ }
+ rc = ::listen(fd, 5);
+ if (rc != 0) {
+ ::close(fd);
+ return false;
+ }
+ _sock = fd;
+ return true;
+}
+
+MessageSocket* MessageSocket::Accept()
+{
+ int clientfd;
+ struct sockaddr_un sa;
+ socklen_t salen;
+ memset(&sa, 0, sizeof(sa));
+ salen = sizeof(sa);
+ clientfd = ::accept(_sock, (struct sockaddr*)&sa, &salen);
+ if (clientfd < 0) {
+ return NULL;
+ }
+ return new MessageSocket(clientfd);
+}
+
+ssize_t MessageSocket::Read(void* buf, size_t len)
+{
+ //XXX: use fdopen/getline
+ ssize_t nread = ::read(_sock, buf, len);
+ if (nread > 0) {
+ char* p = (char*)memchr(buf, '\n', nread);
+ if (p) {
+ *p = '\0';
+ }
+ }
+ return nread;
+}
+
+bool MessageSocket::ClientInit()
+{
+ int fd, rc;
+ fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ return false;
+ }
+ struct sockaddr_un sa;
+ socklen_t salen;
+ memset(&sa, 0, sizeof(sa));
+ sa.sun_family = AF_UNIX;
+ strcpy(sa.sun_path, SOCKET_PATH);
+ rc = ::connect(fd, (struct sockaddr*)&sa, sizeof(sa));
+ if (rc != 0) {
+ ::close(fd);
+ return false;
+ }
+ _sock = fd;
+ return true;
+}
+
+bool MessageSocket::Show(const char* message)
+{
+ char buf[256];
+ sprintf(buf, "show %s", message);
+ return send_command(buf);
+}
+
+bool MessageSocket::Dismiss()
+{
+ return send_command("dismiss");
+}
+
+void MessageSocket::Close()
+{
+ if (_sock != -1) {
+ ::close(_sock);
+ _sock = -1;
+ }
+}
+
+bool MessageSocket::send_command(const char* command)
+{
+ char buf[256];
+ int len;
+ ssize_t written;
+ len = sprintf(buf, "dialog %s\n", command);
+ written = ::write(_sock, buf, len);
+ return (written == len);
+}
diff --git a/messagesocket.h b/messagesocket.h
new file mode 100644
index 0000000..5a4c67d
--- /dev/null
+++ b/messagesocket.h
@@ -0,0 +1,40 @@
+#ifndef MESSAGESOCKET_H
+#define MESSAGESOCKET_H
+
+class MessageSocket
+{
+private:
+ // Unimplemented
+ MessageSocket(const MessageSocket&);
+ MessageSocket& operator=(const MessageSocket&);
+
+public:
+ MessageSocket() : _sock(-1) {}
+ ~MessageSocket() { Close(); }
+ int fd() const { return _sock; }
+
+ bool ServerInit();
+ MessageSocket* Accept();
+ ssize_t Read(void* buf, size_t len);
+
+ bool ClientInit();
+ bool Show(const char* message);
+ bool Dismiss();
+
+ void Close();
+
+private:
+ explicit MessageSocket(int fd) : _sock(fd) {}
+
+ bool send_command(const char* command);
+
+ int _sock;
+};
+
+extern int dialog_server_init();
+extern int dialog_client_init();
+extern int dialog_accept(int fd);
+extern int dialog_show(int fd);
+extern int dialog_dismiss(int fd);
+
+#endif
diff --git a/minui/events.cpp b/minui/events.cpp
index 3b2262a..4e9d80b 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -137,6 +137,23 @@ int ev_add_fd(int fd, ev_callback cb, void* data) {
return ret;
}
+int ev_del_fd(int fd)
+{
+ unsigned n;
+ for (n = 0; n < ev_count; ++n) {
+ if (ev_fdinfo[n].fd == fd) {
+ epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, fd, NULL);
+ if (n != ev_count-1) {
+ ev_fdinfo[n] = ev_fdinfo[ev_count-1];
+ }
+ ev_count--;
+ ev_misc_count--;
+ return 0;
+ }
+ }
+ return -1;
+}
+
void ev_exit(void) {
while (ev_count > 0) {
close(ev_fdinfo[--ev_count].fd);
diff --git a/minui/minui.h b/minui/minui.h
index d714632..7dec2d7 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -67,6 +67,7 @@ typedef int (*ev_set_key_callback)(int code, int value, void* data);
int ev_init(ev_callback input_cb, void* data);
void ev_exit();
int ev_add_fd(int fd, ev_callback cb, void* data);
+int ev_del_fd(int fd);
void ev_iterate_available_keys(std::function<void(int)> f);
int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data);
diff --git a/res-hdpi/images/icon_error.png b/res-hdpi/images/icon_error.png
index cb3d1ab..a803b24 100644
--- a/res-hdpi/images/icon_error.png
+++ b/res-hdpi/images/icon_error.png
Binary files differ
diff --git a/res/images/icon_info.png b/res/images/icon_info.png
new file mode 100644
index 0000000..3993941
--- /dev/null
+++ b/res/images/icon_info.png
Binary files differ
diff --git a/restore.cpp b/restore.cpp
index 8c15f6f..edfeff8 100644
--- a/restore.cpp
+++ b/restore.cpp
@@ -19,6 +19,8 @@
#include "bu.h"
+#include "messagesocket.h"
+
using namespace android;
static int verify_sod()
@@ -294,9 +296,15 @@ int do_restore(int argc, char **argv)
int len;
int written;
+ MessageSocket ms;
+ ms.ClientInit();
+ ms.Show("Restore in progress...");
+
rc = do_restore_tree();
logmsg("do_restore: rc=%d\n", rc);
+ ms.Dismiss();
+
free(hash_name);
hash_name = NULL;
diff --git a/screen_ui.cpp b/screen_ui.cpp
index f23affa..a64bad6 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -68,6 +68,8 @@ ScreenRecoveryUI::ScreenRecoveryUI() :
text_top_(0),
show_text(false),
show_text_ever(false),
+ dialog_icon(NONE),
+ dialog_text(nullptr),
menu_(nullptr),
show_menu(false),
menu_items(0),
@@ -80,7 +82,7 @@ ScreenRecoveryUI::ScreenRecoveryUI() :
rainbow(false),
wrap_count(0) {
- for (int i = 0; i < 5; i++) {
+ for (int i = 0; i < NR_ICONS; i++) {
backgroundIcon[i] = nullptr;
}
pthread_mutex_init(&updateMutex, nullptr);
@@ -202,6 +204,9 @@ void ScreenRecoveryUI::SetColor(UIElement e) {
case TEXT_FILL:
gr_color(0, 0, 0, 160);
break;
+ case ERROR_TEXT:
+ gr_color(255, 0, 0, 255);
+ break;
default:
gr_color(255, 255, 255, 255);
break;
@@ -237,6 +242,43 @@ static const char* LONG_PRESS_HELP[] = {
NULL
};
+void ScreenRecoveryUI::draw_dialog()
+{
+ int x, y, w, h;
+
+ draw_background_locked(dialog_icon);
+
+ int iconHeight = gr_get_height(backgroundIcon[dialog_icon]);
+
+ x = (gr_fb_width()/2 - (char_width*strlen(dialog_text))/2);
+ y = (gr_fb_height()/2 + iconHeight/2);
+
+ SetColor(ERROR_TEXT);
+ gr_text(x, y, dialog_text, 0);
+
+ if (dialog_icon == ERROR) {
+ /*
+ * This could be improved...
+ *
+ * Draw rect around text "Okay".
+ * Text is centered horizontally.
+ * Bottom of text is 4 lines from bottom of screen.
+ * Rect width 4px
+ * Rect padding 8px
+ */
+ w = char_width*4;
+ h = char_height;
+ x = gr_fb_width()/2 - w/2;
+ y = gr_fb_height() - h - 4*char_height;
+ SetColor(HEADER);
+ gr_fill(x-(4+8), y-(4+8), x+w+(4+8), y+h+(4+8));
+ SetColor(MENU_SEL_BG);
+ gr_fill(x-8, y-8, x+w+8, y+h+8);
+ SetColor(MENU_SEL_FG);
+ gr_text(x, y, "Okay", 0);
+ }
+}
+
// Redraw everything on the screen. Does not flip pages.
// Should only be called with updateMutex locked.
void ScreenRecoveryUI::draw_screen_locked() {
@@ -244,6 +286,12 @@ void ScreenRecoveryUI::draw_screen_locked() {
draw_background_locked(currentIcon);
draw_progress_locked();
} else {
+
+ if (DialogShowing()) {
+ draw_dialog();
+ return;
+ }
+
gr_color(0, 0, 0, 255);
gr_clear();
@@ -416,6 +464,7 @@ void ScreenRecoveryUI::Init() {
LoadBitmapArray("icon_installing", &installing_frames, &installation);
backgroundIcon[INSTALLING_UPDATE] = installing_frames ? installation[0] : nullptr;
backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];
+ LoadBitmap("icon_info", &backgroundIcon[INFO]);
LoadBitmap("icon_error", &backgroundIcon[ERROR]);
backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];
@@ -653,6 +702,35 @@ void ScreenRecoveryUI::ShowFile(const char* filename) {
text_top_ = old_text_top;
}
+void ScreenRecoveryUI::DialogShowInfo(const char* text)
+{
+ pthread_mutex_lock(&updateMutex);
+ free(dialog_text);
+ dialog_text = strdup(text);
+ dialog_icon = INFO;
+ update_screen_locked();
+ pthread_mutex_unlock(&updateMutex);
+}
+
+void ScreenRecoveryUI::DialogShowError(const char* text)
+{
+ pthread_mutex_lock(&updateMutex);
+ free(dialog_text);
+ dialog_text = strdup(text);
+ dialog_icon = ERROR;
+ update_screen_locked();
+ pthread_mutex_unlock(&updateMutex);
+}
+
+void ScreenRecoveryUI::DialogDismiss()
+{
+ pthread_mutex_lock(&updateMutex);
+ free(dialog_text);
+ dialog_text = NULL;
+ update_screen_locked();
+ pthread_mutex_unlock(&updateMutex);
+}
+
void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const * items,
int initial_selection) {
pthread_mutex_lock(&updateMutex);
diff --git a/screen_ui.h b/screen_ui.h
index 2ec5f5d..e198503 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -52,6 +52,12 @@ class ScreenRecoveryUI : public RecoveryUI {
void PrintOnScreenOnly(const char* fmt, ...) __printflike(2, 3);
void ShowFile(const char* filename);
+ void DialogShowInfo(const char* text);
+ void DialogShowError(const char* text);
+ int DialogShowing() const { return (dialog_text != NULL); }
+ bool DialogDismissable() const { return (dialog_icon == ERROR); }
+ void DialogDismiss();
+
// menu display
void StartMenu(const char* const * headers, const char* const * items,
int initial_selection);
@@ -63,7 +69,7 @@ class ScreenRecoveryUI : public RecoveryUI {
void Redraw();
enum UIElement {
- HEADER, MENU, MENU_SEL_BG, MENU_SEL_BG_ACTIVE, MENU_SEL_FG, LOG, TEXT_FILL, INFO
+ HEADER, MENU, MENU_SEL_BG, MENU_SEL_BG_ACTIVE, MENU_SEL_FG, LOG, TEXT_FILL, INFO, ERROR_TEXT
};
void SetColor(UIElement e);
@@ -74,8 +80,8 @@ class ScreenRecoveryUI : public RecoveryUI {
bool rtl_locale;
pthread_mutex_t updateMutex;
- GRSurface* backgroundIcon[5];
- GRSurface* backgroundText[5];
+ GRSurface* backgroundIcon[NR_ICONS];
+ GRSurface* backgroundText[NR_ICONS];
GRSurface** installation;
GRSurface* progressBarEmpty;
GRSurface* progressBarFill;
@@ -99,6 +105,9 @@ class ScreenRecoveryUI : public RecoveryUI {
bool show_text;
bool show_text_ever; // has show_text ever been true?
+ Icon dialog_icon;
+ char *dialog_text;
+
char** menu_;
const char* const* menu_headers_;
bool show_menu;
@@ -121,6 +130,7 @@ class ScreenRecoveryUI : public RecoveryUI {
void draw_background_locked(Icon icon);
void draw_progress_locked();
+ void draw_dialog();
void draw_screen_locked();
void update_screen_locked();
void update_progress_locked();
diff --git a/ui.cpp b/ui.cpp
index 38a8099..a5896ce 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -27,6 +27,7 @@
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
+#include <sys/epoll.h>
#include <cutils/properties.h>
#include <cutils/android_reboot.h>
@@ -40,8 +41,83 @@
#include "voldclient.h"
+#include "messagesocket.h"
+
#define UI_WAIT_KEY_TIMEOUT_SEC 120
+static int string_split(char* s, char** fields, int maxfields)
+{
+ int n = 0;
+ while (n+1 < maxfields) {
+ char* p = strchr(s, ' ');
+ if (!p)
+ break;
+ *p = '\0';
+ printf("string_split: field[%d]=%s\n", n, s);
+ fields[n++] = s;
+ s = p+1;
+ }
+ fields[n] = s;
+ printf("string_split: last field[%d]=%s\n", n, s);
+ return n+1;
+}
+
+static int message_socket_client_event(int fd, uint32_t epevents, void *data)
+{
+ MessageSocket* client = (MessageSocket*)data;
+
+ printf("message_socket client event\n");
+ if (!(epevents & EPOLLIN)) {
+ return 0;
+ }
+
+ char buf[256];
+ ssize_t nread;
+ nread = client->Read(buf, sizeof(buf));
+ if (nread <= 0) {
+ ev_del_fd(fd);
+ self->DialogDismiss();
+ client->Close();
+ delete client;
+ return 0;
+ }
+
+ printf("message_socket client message <%s>\n", buf);
+
+ // Parse the message. Right now we support:
+ // dialog show <string>
+ // dialog dismiss
+ char* fields[3];
+ int nfields;
+ nfields = string_split(buf, fields, 3);
+ printf("fields=%d\n", nfields);
+ if (nfields < 2)
+ return 0;
+ printf("field[0]=%s, field[1]=%s\n", fields[0], fields[1]);
+ if (strcmp(fields[0], "dialog") == 0) {
+ if (strcmp(fields[1], "show") == 0 && nfields > 2) {
+ self->DialogShowInfo(fields[2]);
+ }
+ if (strcmp(fields[1], "dismiss") == 0) {
+ self->DialogDismiss();
+ }
+ }
+
+ return 0;
+}
+
+static int message_socket_listen_event(int fd, uint32_t epevents, void *data)
+{
+ MessageSocket* ms = (MessageSocket*)data;
+ MessageSocket* client = ms->Accept();
+ printf("message_socket_listen_event: event on %d\n", fd);
+ if (client) {
+ printf("message_socket client connected\n");
+ ev_add_fd(client->fd(), message_socket_client_event, client);
+ }
+ return 0;
+}
+
RecoveryUI::RecoveryUI()
: key_queue_len(0),
key_last_down(-1),
@@ -86,6 +162,9 @@ static void* InputThreadLoop(void*) {
void RecoveryUI::Init() {
ev_init(InputCallback, this);
+ message_socket.ServerInit();
+ ev_add_fd(message_socket.fd(), message_socket_listen_event, &message_socket);
+
ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1));
pthread_create(&input_thread_, nullptr, InputThreadLoop, nullptr);
@@ -212,6 +291,12 @@ void RecoveryUI::time_key(int key_code, int count) {
}
void RecoveryUI::EnqueueKey(int key_code) {
+ if (DialogShowing()) {
+ if (DialogDismissable()) {
+ DialogDismiss();
+ }
+ return;
+ }
pthread_mutex_lock(&key_queue_mutex);
const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
if (key_queue_len < queue_max) {
diff --git a/ui.h b/ui.h
index ecf221b..123dc34 100644
--- a/ui.h
+++ b/ui.h
@@ -21,6 +21,7 @@
#include <pthread.h>
#include <time.h>
+#include "messagesocket.h"
#include "voldclient.h"
// Abstract class for controlling the user interface during recovery.
@@ -39,7 +40,7 @@ class RecoveryUI {
virtual void SetLocale(const char* locale) = 0;
// Set the overall recovery state ("background image").
- enum Icon { NONE, INSTALLING_UPDATE, ERASING, NO_COMMAND, ERROR };
+ enum Icon { NONE, INSTALLING_UPDATE, ERASING, NO_COMMAND, INFO, ERROR, NR_ICONS };
virtual void SetBackground(Icon icon) = 0;
// --- progress indicator ---
@@ -71,6 +72,12 @@ class RecoveryUI {
virtual void ShowFile(const char* filename) = 0;
+ virtual void DialogShowInfo(const char* text) = 0;
+ virtual void DialogShowError(const char* text) = 0;
+ virtual int DialogShowing() const = 0;
+ virtual bool DialogDismissable() const = 0;
+ virtual void DialogDismiss() = 0;
+
// --- key handling ---
// Wait for a key and return it. May return -1 after timeout.
@@ -160,6 +167,8 @@ private:
pthread_t input_thread_;
+ MessageSocket message_socket;
+
void OnKeyDetected(int key_code);
static int InputCallback(int fd, uint32_t epevents, void* data);
diff --git a/verifier_test.cpp b/verifier_test.cpp
index 21633dc..ed3dce1 100644
--- a/verifier_test.cpp
+++ b/verifier_test.cpp
@@ -149,6 +149,12 @@ class FakeUI : public RecoveryUI {
}
void ShowFile(const char*) { }
+ virtual void DialogShowInfo(const char* text) {}
+ virtual void DialogShowError(const char* text) {}
+ virtual int DialogShowing() const { return 0; }
+ bool DialogDismissable() const { return false; }
+ virtual void DialogDismiss() {}
+
void StartMenu(const char* const * headers, const char* const * items,
int initial_selection) { }
int SelectMenu(int sel) { return 0; }
diff --git a/wear_ui.cpp b/wear_ui.cpp
index 55b7afc..4a07f39 100644
--- a/wear_ui.cpp
+++ b/wear_ui.cpp
@@ -81,7 +81,7 @@ WearRecoveryUI::WearRecoveryUI() :
menu_items(0),
menu_sel(0) {
- for (size_t i = 0; i < 5; i++)
+ for (size_t i = 0; i < NR_ICONS; i++)
backgroundIcon[i] = NULL;
pthread_mutex_init(&updateMutex, NULL);
diff --git a/wear_ui.h b/wear_ui.h
index 839a264..d7624fe 100644
--- a/wear_ui.h
+++ b/wear_ui.h
@@ -91,7 +91,7 @@ class WearRecoveryUI : public RecoveryUI {
bool rtl_locale;
pthread_mutex_t updateMutex;
- GRSurface* backgroundIcon[5];
+ GRSurface* backgroundIcon[NR_ICONS];
GRSurface* *introFrames;
GRSurface* *loopFrames;