diff options
-rw-r--r-- | Android.mk | 5 | ||||
-rw-r--r-- | backup.cpp | 8 | ||||
-rw-r--r-- | messagesocket.cpp | 116 | ||||
-rw-r--r-- | messagesocket.h | 40 | ||||
-rw-r--r-- | minui/events.cpp | 17 | ||||
-rw-r--r-- | minui/minui.h | 1 | ||||
-rw-r--r-- | res-hdpi/images/icon_error.png | bin | 19306 -> 4011 bytes | |||
-rw-r--r-- | res/images/icon_info.png | bin | 0 -> 3745 bytes | |||
-rw-r--r-- | restore.cpp | 8 | ||||
-rw-r--r-- | screen_ui.cpp | 80 | ||||
-rw-r--r-- | screen_ui.h | 16 | ||||
-rw-r--r-- | ui.cpp | 85 | ||||
-rw-r--r-- | ui.h | 11 | ||||
-rw-r--r-- | verifier_test.cpp | 6 | ||||
-rw-r--r-- | wear_ui.cpp | 2 | ||||
-rw-r--r-- | wear_ui.h | 2 |
16 files changed, 389 insertions, 8 deletions
@@ -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 \ @@ -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 Binary files differindex cb3d1ab..a803b24 100644 --- a/res-hdpi/images/icon_error.png +++ b/res-hdpi/images/icon_error.png diff --git a/res/images/icon_info.png b/res/images/icon_info.png Binary files differnew file mode 100644 index 0000000..3993941 --- /dev/null +++ b/res/images/icon_info.png 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(); @@ -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) { @@ -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); @@ -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; |