Merge "Convert update_verifier to boot HIDL HAL"
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index 7c5bb86..f6087de 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -189,7 +189,7 @@
   }
 
   size_t sz = static_cast<size_t>(st.st_size);
-  unsigned char* img = reinterpret_cast<unsigned char*>(malloc(sz));
+  unsigned char* img = static_cast<unsigned char*>(malloc(sz));
   FILE* f = fopen(filename, "rb");
   if (fread(img, 1, sz, f) != sz) {
     printf("failed to read \"%s\" %s\n", filename, strerror(errno));
@@ -216,7 +216,7 @@
   int cdcount = Read2(img+i+8);
   int cdoffset = Read4(img+i+16);
 
-  ZipFileEntry* temp_entries = reinterpret_cast<ZipFileEntry*>(malloc(
+  ZipFileEntry* temp_entries = static_cast<ZipFileEntry*>(malloc(
       cdcount * sizeof(ZipFileEntry)));
   int entrycount = 0;
 
@@ -234,7 +234,7 @@
     int mlen = Read2(cd+32);   // file comment len
     int hoffset = Read4(cd+42);   // local header offset
 
-    char* filename = reinterpret_cast<char*>(malloc(nlen+1));
+    char* filename = static_cast<char*>(malloc(nlen+1));
     memcpy(filename, cd+46, nlen);
     filename[nlen] = '\0';
 
@@ -283,7 +283,7 @@
 #endif
 
   *num_chunks = 0;
-  *chunks = reinterpret_cast<ImageChunk*>(malloc((entrycount*2+2) * sizeof(ImageChunk)));
+  *chunks = static_cast<ImageChunk*>(malloc((entrycount*2+2) * sizeof(ImageChunk)));
   ImageChunk* curr = *chunks;
 
   if (include_pseudo_chunk) {
@@ -308,7 +308,7 @@
       curr->filename = temp_entries[nextentry].filename;
 
       curr->len = temp_entries[nextentry].uncomp_len;
-      curr->data = reinterpret_cast<unsigned char*>(malloc(curr->len));
+      curr->data = static_cast<unsigned char*>(malloc(curr->len));
 
       z_stream strm;
       strm.zalloc = Z_NULL;
@@ -378,7 +378,7 @@
   }
 
   size_t sz = static_cast<size_t>(st.st_size);
-  unsigned char* img = reinterpret_cast<unsigned char*>(malloc(sz + 4));
+  unsigned char* img = static_cast<unsigned char*>(malloc(sz + 4));
   FILE* f = fopen(filename, "rb");
   if (fread(img, 1, sz, f) != sz) {
     printf("failed to read \"%s\" %s\n", filename, strerror(errno));
@@ -408,7 +408,7 @@
       size_t chunk_offset = pos;
 
       *num_chunks += 3;
-      *chunks = reinterpret_cast<ImageChunk*>(realloc(*chunks,
+      *chunks = static_cast<ImageChunk*>(realloc(*chunks,
           *num_chunks * sizeof(ImageChunk)));
       ImageChunk* curr = *chunks + (*num_chunks-3);
 
@@ -431,7 +431,7 @@
 
       size_t allocated = 32768;
       curr->len = 0;
-      curr->data = reinterpret_cast<unsigned char*>(malloc(allocated));
+      curr->data = static_cast<unsigned char*>(malloc(allocated));
       curr->start = pos;
       curr->deflate_data = p;
 
@@ -459,7 +459,7 @@
         curr->len = allocated - strm.avail_out;
         if (strm.avail_out == 0) {
           allocated *= 2;
-          curr->data = reinterpret_cast<unsigned char*>(realloc(curr->data, allocated));
+          curr->data = static_cast<unsigned char*>(realloc(curr->data, allocated));
         }
       } while (ret != Z_STREAM_END);
 
@@ -502,7 +502,7 @@
       // Reallocate the list for every chunk; we expect the number of
       // chunks to be small (5 for typical boot and recovery images).
       ++*num_chunks;
-      *chunks = reinterpret_cast<ImageChunk*>(realloc(*chunks, *num_chunks * sizeof(ImageChunk)));
+      *chunks = static_cast<ImageChunk*>(realloc(*chunks, *num_chunks * sizeof(ImageChunk)));
       ImageChunk* curr = *chunks + (*num_chunks-1);
       curr->start = pos;
 
@@ -585,7 +585,7 @@
     return -1;
   }
 
-  unsigned char* out = reinterpret_cast<unsigned char*>(malloc(BUFFER_SIZE));
+  unsigned char* out = static_cast<unsigned char*>(malloc(BUFFER_SIZE));
 
   // We only check two combinations of encoder parameters:  level 6
   // (the default) and level 9 (the maximum).
@@ -646,7 +646,7 @@
 
   size_t sz = static_cast<size_t>(st.st_size);
   // TODO: Memory leak on error return.
-  unsigned char* data = reinterpret_cast<unsigned char*>(malloc(sz));
+  unsigned char* data = static_cast<unsigned char*>(malloc(sz));
 
   if (tgt->type == CHUNK_NORMAL && tgt->len <= sz) {
     unlink(ptemp);
@@ -813,7 +813,7 @@
       return 1;
     }
     bonus_size = st.st_size;
-    bonus_data = reinterpret_cast<unsigned char*>(malloc(bonus_size));
+    bonus_data = static_cast<unsigned char*>(malloc(bonus_size));
     FILE* f = fopen(argv[2], "rb");
     if (f == NULL) {
       printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno));
@@ -959,9 +959,9 @@
   DumpChunks(src_chunks, num_src_chunks);
 
   printf("Construct patches for %d chunks...\n", num_tgt_chunks);
-  unsigned char** patch_data = reinterpret_cast<unsigned char**>(malloc(
+  unsigned char** patch_data = static_cast<unsigned char**>(malloc(
       num_tgt_chunks * sizeof(unsigned char*)));
-  size_t* patch_size = reinterpret_cast<size_t*>(malloc(num_tgt_chunks * sizeof(size_t)));
+  size_t* patch_size = static_cast<size_t*>(malloc(num_tgt_chunks * sizeof(size_t)));
   for (i = 0; i < num_tgt_chunks; ++i) {
     if (zip_mode) {
       ImageChunk* src;
@@ -975,7 +975,7 @@
     } else {
       if (i == 1 && bonus_data) {
         printf("  using %zu bytes of bonus data for chunk %d\n", bonus_size, i);
-        src_chunks[i].data = reinterpret_cast<unsigned char*>(realloc(src_chunks[i].data,
+        src_chunks[i].data = static_cast<unsigned char*>(realloc(src_chunks[i].data,
             src_chunks[i].len + bonus_size));
         memcpy(src_chunks[i].data+src_chunks[i].len, bonus_data, bonus_size);
         src_chunks[i].len += bonus_size;
diff --git a/error_code.h b/error_code.h
index 92e93bd..92b1574 100644
--- a/error_code.h
+++ b/error_code.h
@@ -18,52 +18,53 @@
 #define _ERROR_CODE_H_
 
 enum ErrorCode {
-    kNoError = -1,
-    kLowBattery = 20,
-    kZipVerificationFailure,
-    kZipOpenFailure,
-    kBootreasonInBlacklist
+  kNoError = -1,
+  kLowBattery = 20,
+  kZipVerificationFailure,
+  kZipOpenFailure,
+  kBootreasonInBlacklist
 };
 
 enum CauseCode {
-    kNoCause = -1,
-    kArgsParsingFailure = 100,
-    kStashCreationFailure,
-    kFileOpenFailure,
-    kLseekFailure,
-    kFreadFailure,
-    kFwriteFailure,
-    kFsyncFailure,
-    kLibfecFailure,
-    kFileGetPropFailure,
-    kFileRenameFailure,
-    kSymlinkFailure,
-    kSetMetadataFailure,
-    kTune2FsFailure,
-    kRebootFailure,
-    kVendorFailure = 200
+  kNoCause = -1,
+  kArgsParsingFailure = 100,
+  kStashCreationFailure,
+  kFileOpenFailure,
+  kLseekFailure,
+  kFreadFailure,
+  kFwriteFailure,
+  kFsyncFailure,
+  kLibfecFailure,
+  kFileGetPropFailure,
+  kFileRenameFailure,
+  kSymlinkFailure,
+  kSetMetadataFailure,
+  kTune2FsFailure,
+  kRebootFailure,
+  kPackageExtractFileFailure,
+  kVendorFailure = 200
 };
 
 enum UncryptErrorCode {
-    kUncryptNoError = -1,
-    kUncryptErrorHolder = 50,
-    kUncryptTimeoutError = 100,
-    kUncryptFileRemoveError,
-    kUncryptFileOpenError,
-    kUncryptSocketOpenError,
-    kUncryptSocketWriteError,
-    kUncryptSocketListenError,
-    kUncryptSocketAcceptError,
-    kUncryptFstabReadError,
-    kUncryptFileStatError,
-    kUncryptBlockOpenError,
-    kUncryptIoctlError,
-    kUncryptReadError,
-    kUncryptWriteError,
-    kUncryptFileSyncError,
-    kUncryptFileCloseError,
-    kUncryptFileRenameError,
-    kUncryptPackageMissingError,
+  kUncryptNoError = -1,
+  kUncryptErrorHolder = 50,
+  kUncryptTimeoutError = 100,
+  kUncryptFileRemoveError,
+  kUncryptFileOpenError,
+  kUncryptSocketOpenError,
+  kUncryptSocketWriteError,
+  kUncryptSocketListenError,
+  kUncryptSocketAcceptError,
+  kUncryptFstabReadError,
+  kUncryptFileStatError,
+  kUncryptBlockOpenError,
+  kUncryptIoctlError,
+  kUncryptReadError,
+  kUncryptWriteError,
+  kUncryptFileSyncError,
+  kUncryptFileCloseError,
+  kUncryptFileRenameError,
+  kUncryptPackageMissingError,
 };
 
-#endif
+#endif // _ERROR_CODE_H_
diff --git a/minadbd/minadbd_services.cpp b/minadbd/minadbd_services.cpp
index 003b519..426d982 100644
--- a/minadbd/minadbd_services.cpp
+++ b/minadbd/minadbd_services.cpp
@@ -66,7 +66,7 @@
         return -1;
     }
 
-    stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
+    stinfo* sti = static_cast<stinfo*>(malloc(sizeof(stinfo)));
     if(sti == 0) fatal("cannot allocate stinfo");
     sti->func = func;
     sti->cookie = cookie;
diff --git a/minui/font_10x18.h b/minui/font_10x18.h
index 29d7053..30dfb9c 100644
--- a/minui/font_10x18.h
+++ b/minui/font_10x18.h
@@ -1,14 +1,14 @@
 struct {
   unsigned width;
   unsigned height;
-  unsigned cwidth;
-  unsigned cheight;
+  unsigned char_width;
+  unsigned char_height;
   unsigned char rundata[2973];
 } font = {
   .width = 960,
   .height = 18,
-  .cwidth = 10,
-  .cheight = 18,
+  .char_width = 10,
+  .char_height = 18,
   .rundata = {
 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x55,0x82,0x06,0x82,0x02,0x82,0x10,0x82,
 0x11,0x83,0x08,0x82,0x0a,0x82,0x04,0x82,0x46,0x82,0x08,0x82,0x07,0x84,0x06,
diff --git a/minui/graphics.cpp b/minui/graphics.cpp
index c0eea9e..dcca3ec 100644
--- a/minui/graphics.cpp
+++ b/minui/graphics.cpp
@@ -35,12 +35,6 @@
 #include "minui.h"
 #include "graphics.h"
 
-struct GRFont {
-    GRSurface* texture;
-    int cwidth;
-    int cheight;
-};
-
 static GRFont* gr_font = NULL;
 static minui_backend* gr_backend = NULL;
 
@@ -60,15 +54,20 @@
     return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height;
 }
 
-int gr_measure(const char *s)
+const GRFont* gr_sys_font()
 {
-    return gr_font->cwidth * strlen(s);
+    return gr_font;
 }
 
-void gr_font_size(int *x, int *y)
+int gr_measure(const GRFont* font, const char *s)
 {
-    *x = gr_font->cwidth;
-    *y = gr_font->cheight;
+    return font->char_width * strlen(s);
+}
+
+void gr_font_size(const GRFont* font, int *x, int *y)
+{
+    *x = font->char_width;
+    *y = font->char_height;
 }
 
 static void text_blend(unsigned char* src_p, int src_row_bytes,
@@ -103,34 +102,32 @@
     }
 }
 
-void gr_text(int x, int y, const char *s, bool bold)
+void gr_text(const GRFont* font, int x, int y, const char *s, bool bold)
 {
-    GRFont* font = gr_font;
-
     if (!font->texture || gr_current_a == 0) return;
 
-    bold = bold && (font->texture->height != font->cheight);
+    bold = bold && (font->texture->height != font->char_height);
 
     x += overscan_offset_x;
     y += overscan_offset_y;
 
     unsigned char ch;
     while ((ch = *s++)) {
-        if (outside(x, y) || outside(x+font->cwidth-1, y+font->cheight-1)) break;
+        if (outside(x, y) || outside(x+font->char_width-1, y+font->char_height-1)) break;
 
         if (ch < ' ' || ch > '~') {
             ch = '?';
         }
 
-        unsigned char* src_p = font->texture->data + ((ch - ' ') * font->cwidth) +
-                               (bold ? font->cheight * font->texture->row_bytes : 0);
+        unsigned char* src_p = font->texture->data + ((ch - ' ') * font->char_width) +
+                               (bold ? font->char_height * font->texture->row_bytes : 0);
         unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
 
         text_blend(src_p, font->texture->row_bytes,
                    dst_p, gr_draw->row_bytes,
-                   font->cwidth, font->cheight);
+                   font->char_width, font->char_height);
 
-        x += font->cwidth;
+        x += font->char_width;
     }
 }
 
@@ -267,40 +264,59 @@
     return surface->height;
 }
 
+int gr_init_font(const char* name, GRFont** dest) {
+    GRFont* font = reinterpret_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
+    if (font == nullptr) {
+        return -1;
+    }
+
+    int res = res_create_alpha_surface(name, &(font->texture));
+    if (res < 0) {
+        free(font);
+        return res;
+    }
+
+    // The font image should be a 96x2 array of character images.  The
+    // columns are the printable ASCII characters 0x20 - 0x7f.  The
+    // top row is regular text; the bottom row is bold.
+    font->char_width = font->texture->width / 96;
+    font->char_height = font->texture->height / 2;
+
+    *dest = font;
+
+    return 0;
+}
+
 static void gr_init_font(void)
 {
-    gr_font = reinterpret_cast<GRFont*>(calloc(sizeof(*gr_font), 1));
-
-    int res = res_create_alpha_surface("font", &(gr_font->texture));
+    int res = gr_init_font("font", &gr_font);
     if (res == 0) {
-        // The font image should be a 96x2 array of character images.  The
-        // columns are the printable ASCII characters 0x20 - 0x7f.  The
-        // top row is regular text; the bottom row is bold.
-        gr_font->cwidth = gr_font->texture->width / 96;
-        gr_font->cheight = gr_font->texture->height / 2;
-    } else {
-        printf("failed to read font: res=%d\n", res);
-
-        // fall back to the compiled-in font.
-        gr_font->texture = reinterpret_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
-        gr_font->texture->width = font.width;
-        gr_font->texture->height = font.height;
-        gr_font->texture->row_bytes = font.width;
-        gr_font->texture->pixel_bytes = 1;
-
-        unsigned char* bits = reinterpret_cast<unsigned char*>(malloc(font.width * font.height));
-        gr_font->texture->data = reinterpret_cast<unsigned char*>(bits);
-
-        unsigned char data;
-        unsigned char* in = font.rundata;
-        while((data = *in++)) {
-            memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
-            bits += (data & 0x7f);
-        }
-
-        gr_font->cwidth = font.cwidth;
-        gr_font->cheight = font.cheight;
+        return;
     }
+
+    printf("failed to read font: res=%d\n", res);
+
+
+    // fall back to the compiled-in font.
+    gr_font = static_cast<GRFont*>(calloc(sizeof(*gr_font), 1));
+    gr_font->texture = static_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
+    gr_font->texture->width = font.width;
+    gr_font->texture->height = font.height;
+    gr_font->texture->row_bytes = font.width;
+    gr_font->texture->pixel_bytes = 1;
+
+    unsigned char* bits = static_cast<unsigned char*>(malloc(font.width * font.height));
+    gr_font->texture->data = bits;
+
+    unsigned char data;
+    unsigned char* in = font.rundata;
+    while((data = *in++)) {
+        memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
+        bits += (data & 0x7f);
+    }
+
+    gr_font->char_width = font.char_width;
+    gr_font->char_height = font.char_height;
 }
 
 #if 0
diff --git a/minui/graphics_adf.cpp b/minui/graphics_adf.cpp
index 3c35410..9e262b0 100644
--- a/minui/graphics_adf.cpp
+++ b/minui/graphics_adf.cpp
@@ -68,9 +68,9 @@
     surf->base.row_bytes = surf->pitch;
     surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4;
 
-    surf->base.data = reinterpret_cast<uint8_t*>(mmap(NULL,
-                                                      surf->pitch * surf->base.height, PROT_WRITE,
-                                                      MAP_SHARED, surf->fd, surf->offset));
+    surf->base.data = static_cast<uint8_t*>(mmap(NULL,
+                                                 surf->pitch * surf->base.height, PROT_WRITE,
+                                                 MAP_SHARED, surf->fd, surf->offset));
     if (surf->base.data == MAP_FAILED) {
         close(surf->fd);
         return -errno;
@@ -259,7 +259,7 @@
 
 minui_backend *open_adf()
 {
-    adf_pdata* pdata = reinterpret_cast<adf_pdata*>(calloc(1, sizeof(*pdata)));
+    adf_pdata* pdata = static_cast<adf_pdata*>(calloc(1, sizeof(*pdata)));
     if (!pdata) {
         perror("allocating adf backend failed");
         return NULL;
diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp
index 0788f75..631ef4e 100644
--- a/minui/graphics_fbdev.cpp
+++ b/minui/graphics_fbdev.cpp
@@ -133,7 +133,7 @@
     gr_framebuffer[0].height = vi.yres;
     gr_framebuffer[0].row_bytes = fi.line_length;
     gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8;
-    gr_framebuffer[0].data = reinterpret_cast<uint8_t*>(bits);
+    gr_framebuffer[0].data = static_cast<uint8_t*>(bits);
     memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes);
 
     /* check if we can use double buffering */
diff --git a/minui/minui.h b/minui/minui.h
index 5362d3f..78890b8 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -33,6 +33,12 @@
     unsigned char* data;
 };
 
+struct GRFont {
+    GRSurface* texture;
+    int char_width;
+    int char_height;
+};
+
 int gr_init();
 void gr_exit();
 
@@ -45,10 +51,14 @@
 void gr_clear();  // clear entire surface to current color
 void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
 void gr_fill(int x1, int y1, int x2, int y2);
-void gr_text(int x, int y, const char *s, bool bold);
+
 void gr_texticon(int x, int y, GRSurface* icon);
-int gr_measure(const char *s);
-void gr_font_size(int *x, int *y);
+
+const GRFont* gr_sys_font();
+int gr_init_font(const char* name, GRFont** dest);
+void gr_text(const GRFont* font, int x, int y, const char *s, bool bold);
+int gr_measure(const GRFont* font, const char *s);
+void gr_font_size(const GRFont* font, int *x, int *y);
 
 void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy);
 unsigned int gr_get_width(GRSurface* surface);
diff --git a/minui/resources.cpp b/minui/resources.cpp
index 455ef27..9ccbf4b 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -37,7 +37,7 @@
 
 static GRSurface* malloc_surface(size_t data_size) {
     size_t size = sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT;
-    unsigned char* temp = reinterpret_cast<unsigned char*>(malloc(size));
+    unsigned char* temp = static_cast<unsigned char*>(malloc(size));
     if (temp == NULL) return NULL;
     GRSurface* surface = reinterpret_cast<GRSurface*>(temp);
     surface->data = temp + sizeof(GRSurface) +
@@ -221,7 +221,7 @@
     png_set_bgr(png_ptr);
 #endif
 
-    p_row = reinterpret_cast<unsigned char*>(malloc(width * 4));
+    p_row = static_cast<unsigned char*>(malloc(width * 4));
     for (y = 0; y < height; ++y) {
         png_read_row(png_ptr, p_row, NULL);
         transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width);
@@ -281,7 +281,7 @@
         goto exit;
     }
 
-    surface = reinterpret_cast<GRSurface**>(calloc(*frames, sizeof(GRSurface*)));
+    surface = static_cast<GRSurface**>(calloc(*frames, sizeof(GRSurface*)));
     if (surface == NULL) {
         result = -8;
         goto exit;
@@ -298,7 +298,7 @@
     png_set_bgr(png_ptr);
 #endif
 
-    p_row = reinterpret_cast<unsigned char*>(malloc(width * 4));
+    p_row = static_cast<unsigned char*>(malloc(width * 4));
     for (y = 0; y < height; ++y) {
         png_read_row(png_ptr, p_row, NULL);
         int frame = y % *frames;
@@ -308,7 +308,7 @@
     }
     free(p_row);
 
-    *pSurface = reinterpret_cast<GRSurface**>(surface);
+    *pSurface = surface;
 
 exit:
     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
@@ -436,7 +436,7 @@
                 memcpy(surface->data + i*w, row.data(), w);
             }
 
-            *pSurface = reinterpret_cast<GRSurface*>(surface);
+            *pSurface = surface;
             break;
         } else {
             int i;
diff --git a/screen_ui.cpp b/screen_ui.cpp
index c617272..fab3489 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -248,7 +248,7 @@
 }
 
 void ScreenRecoveryUI::DrawTextLine(int x, int* y, const char* line, bool bold) {
-    gr_text(x, *y, line, bold);
+    gr_text(gr_sys_font(), x, *y, line, bold);
     *y += char_height_ + 4;
 }
 
@@ -304,10 +304,10 @@
                     gr_fill(0, y - 2, gr_fb_width(), y + char_height_ + 2);
                     // Bold white text for the selected item.
                     SetColor(MENU_SEL_FG);
-                    gr_text(4, y, menu_[i], true);
+                    gr_text(gr_sys_font(), 4, y, menu_[i], true);
                     SetColor(MENU);
                 } else {
-                    gr_text(4, y, menu_[i], false);
+                    gr_text(gr_sys_font(), 4, y, menu_[i], false);
                 }
                 y += char_height_ + 4;
             }
@@ -323,7 +323,7 @@
         for (int ty = gr_fb_height() - char_height_;
              ty >= y && count < text_rows_;
              ty -= char_height_, ++count) {
-            gr_text(0, ty, text_[row], false);
+            gr_text(gr_sys_font(), 0, ty, text_[row], false);
             --row;
             if (row < 0) row = text_rows_ - 1;
         }
@@ -442,7 +442,7 @@
     density_ = static_cast<float>(android::base::GetIntProperty("ro.sf.lcd_density", 160)) / 160.f;
     is_large_ = gr_fb_height() > PixelsFromDp(800);
 
-    gr_font_size(&char_width_, &char_height_);
+    gr_font_size(gr_sys_font(), &char_width_, &char_height_);
     text_rows_ = gr_fb_height() / char_height_;
     text_cols_ = gr_fb_width() / char_width_;
 
diff --git a/tests/Android.mk b/tests/Android.mk
index e87a229..fdc9470 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -92,6 +92,8 @@
     libcrypto \
     libcutils \
     libbz \
+    libziparchive \
+    libutils \
     libz \
     libbase \
     libtune2fs \
diff --git a/tests/common/test_constants.h b/tests/common/test_constants.h
index 97e74a3..93e4ab5 100644
--- a/tests/common/test_constants.h
+++ b/tests/common/test_constants.h
@@ -19,6 +19,15 @@
 
 #include <stdlib.h>
 
+// Zip entries in ziptest_valid.zip.
+static const std::string kATxtContents("abcdefghabcdefgh\n");
+static const std::string kBTxtContents("abcdefgh\n");
+
+// echo -n -e "abcdefghabcdefgh\n" | sha1sum
+static const std::string kATxtSha1Sum("32c96a03dc8cd20097940f351bca6261ee5a1643");
+// echo -n -e "abcdefgh\n" | sha1sum
+static const std::string kBTxtSha1Sum("e414af7161c9554089f4106d6f1797ef14a73666");
+
 static const char* data_root = getenv("ANDROID_DATA");
 
 static std::string from_testdata_base(const std::string& fname) {
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index 973c19d..a029cf4 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -24,35 +24,40 @@
 #include <android-base/properties.h>
 #include <android-base/test_utils.h>
 #include <gtest/gtest.h>
+#include <ziparchive/zip_archive.h>
 
+#include "common/test_constants.h"
 #include "edify/expr.h"
 #include "error_code.h"
 #include "updater/install.h"
+#include "updater/updater.h"
 
 struct selabel_handle *sehandle = nullptr;
 
-static void expect(const char* expected, const char* expr_str, CauseCode cause_code) {
-    Expr* e;
-    int error_count;
-    EXPECT_EQ(parse_string(expr_str, &e, &error_count), 0);
+static void expect(const char* expected, const char* expr_str, CauseCode cause_code,
+                   UpdaterInfo* info = nullptr) {
+  Expr* e;
+  int error_count = 0;
+  ASSERT_EQ(0, parse_string(expr_str, &e, &error_count));
+  ASSERT_EQ(0, error_count);
 
-    State state(expr_str, nullptr);
+  State state(expr_str, info);
 
-    std::string result;
-    bool status = Evaluate(&state, e, &result);
+  std::string result;
+  bool status = Evaluate(&state, e, &result);
 
-    if (expected == nullptr) {
-        EXPECT_FALSE(status);
-    } else {
-        EXPECT_STREQ(expected, result.c_str());
-    }
+  if (expected == nullptr) {
+    ASSERT_FALSE(status);
+  } else {
+    ASSERT_TRUE(status);
+    ASSERT_STREQ(expected, result.c_str());
+  }
 
-    // Error code is set in updater/updater.cpp only, by parsing State.errmsg.
-    EXPECT_EQ(kNoError, state.error_code);
+  // Error code is set in updater/updater.cpp only, by parsing State.errmsg.
+  ASSERT_EQ(kNoError, state.error_code);
 
-    // Cause code should always be available.
-    EXPECT_EQ(cause_code, state.cause_code);
-
+  // Cause code should always be available.
+  ASSERT_EQ(cause_code, state.cause_code);
 }
 
 class UpdaterTest : public ::testing::Test {
@@ -264,3 +269,56 @@
     ASSERT_EQ(0, unlink(src1.c_str()));
     ASSERT_EQ(0, unlink(src2.c_str()));
 }
+
+// TODO: Test extracting to block device.
+TEST_F(UpdaterTest, package_extract_file) {
+  // package_extract_file expects 1 or 2 arguments.
+  expect(nullptr, "package_extract_file()", kArgsParsingFailure);
+  expect(nullptr, "package_extract_file(\"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;
+
+  // Two-argument version.
+  TemporaryFile temp_file1;
+  std::string script("package_extract_file(\"a.txt\", \"" + std::string(temp_file1.path) + "\")");
+  expect("t", script.c_str(), kNoCause, &updater_info);
+
+  // Verify the extracted entry.
+  std::string data;
+  ASSERT_TRUE(android::base::ReadFileToString(temp_file1.path, &data));
+  ASSERT_EQ(kATxtContents, data);
+
+  // Now extract another entry to the same location, which should overwrite.
+  script = "package_extract_file(\"b.txt\", \"" + std::string(temp_file1.path) + "\")";
+  expect("t", script.c_str(), kNoCause, &updater_info);
+
+  ASSERT_TRUE(android::base::ReadFileToString(temp_file1.path, &data));
+  ASSERT_EQ(kBTxtContents, data);
+
+  // Missing zip entry. The two-argument version doesn't abort.
+  script = "package_extract_file(\"doesntexist\", \"" + std::string(temp_file1.path) + "\")";
+  expect("", script.c_str(), kNoCause, &updater_info);
+
+  // Extract to /dev/full should fail.
+  script = "package_extract_file(\"a.txt\", \"/dev/full\")";
+  expect("", script.c_str(), kNoCause, &updater_info);
+
+  // One-argument version.
+  script = "sha1_check(package_extract_file(\"a.txt\"))";
+  expect(kATxtSha1Sum.c_str(), script.c_str(), kNoCause, &updater_info);
+
+  script = "sha1_check(package_extract_file(\"b.txt\"))";
+  expect(kBTxtSha1Sum.c_str(), script.c_str(), kNoCause, &updater_info);
+
+  // Missing entry. The one-argument version aborts the evaluation.
+  script = "package_extract_file(\"doesntexist\")";
+  expect(nullptr, script.c_str(), kPackageExtractFileFailure, &updater_info);
+
+  CloseArchive(handle);
+}
diff --git a/tests/unit/zip_test.cpp b/tests/unit/zip_test.cpp
index 4972946..ef0ee4c 100644
--- a/tests/unit/zip_test.cpp
+++ b/tests/unit/zip_test.cpp
@@ -30,9 +30,6 @@
 
 #include "common/test_constants.h"
 
-static const std::string kATxtContents("abcdefghabcdefgh\n");
-static const std::string kBTxtContents("abcdefgh\n");
-
 TEST(ZipTest, ExtractPackageRecursive) {
   std::string zip_path = from_testdata_base("ziptest_valid.zip");
   ZipArchiveHandle handle;
diff --git a/updater/install.cpp b/updater/install.cpp
index 59c54dd..b885f86 100644
--- a/updater/install.cpp
+++ b/updater/install.cpp
@@ -477,93 +477,86 @@
     return StringValue(success ? "t" : "");
 }
 
+// package_extract_file(package_file[, dest_file])
+//   Extracts a single package_file from the update package and writes it to dest_file,
+//   overwriting existing files if necessary. Without the dest_file argument, returns the
+//   contents of the package file as a binary blob.
+Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv[]) {
+  if (argc < 1 || argc > 2) {
+    return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 or 2 args, got %d", name, argc);
+  }
 
-// package_extract_file(package_path, destination_path)
-//   or
-// package_extract_file(package_path)
-//   to return the entire contents of the file as the result of this
-//   function (the char* returned is actually a FileContents*).
-Value* PackageExtractFileFn(const char* name, State* state,
-                           int argc, Expr* argv[]) {
-    if (argc < 1 || argc > 2) {
-        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 or 2 args, got %d",
-                          name, argc);
+  if (argc == 2) {
+    // The two-argument version extracts to a file.
+
+    std::vector<std::string> args;
+    if (!ReadArgs(state, 2, argv, &args)) {
+      return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, argc);
     }
-    bool success = false;
+    const std::string& zip_path = args[0];
+    const std::string& dest_path = args[1];
 
-    if (argc == 2) {
-        // The two-argument version extracts to a file.
-
-        ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
-
-        std::vector<std::string> args;
-        if (!ReadArgs(state, 2, argv, &args)) {
-            return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name,
-                              argc);
-        }
-        const std::string& zip_path = args[0];
-        const std::string& dest_path = args[1];
-
-        ZipString zip_string_path(zip_path.c_str());
-        ZipEntry entry;
-        if (FindEntry(za, zip_string_path, &entry) != 0) {
-            printf("%s: no %s in package\n", name, zip_path.c_str());
-            return StringValue("");
-        }
-
-        int fd = TEMP_FAILURE_RETRY(ota_open(dest_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC,
-              S_IRUSR | S_IWUSR));
-        if (fd == -1) {
-            printf("%s: can't open %s for write: %s\n", name, dest_path.c_str(), strerror(errno));
-            return StringValue("");
-        }
-        success = ExtractEntryToFile(za, &entry, fd);
-        if (ota_fsync(fd) == -1) {
-            printf("fsync of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno));
-            success = false;
-        }
-        if (ota_close(fd) == -1) {
-            printf("close of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno));
-            success = false;
-        }
-
-        return StringValue(success ? "t" : "");
-    } else {
-        // The one-argument version returns the contents of the file
-        // as the result.
-
-        std::vector<std::string> args;
-        if (!ReadArgs(state, 1, argv, &args)) {
-            return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name,
-                              argc);
-        }
-        const std::string& zip_path = args[0];
-
-        Value* v = new Value(VAL_INVALID, "");
-
-        ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
-        ZipString zip_string_path(zip_path.c_str());
-        ZipEntry entry;
-        if (FindEntry(za, zip_string_path, &entry) != 0) {
-            printf("%s: no %s in package\n", name, zip_path.c_str());
-            return v;
-        }
-
-        v->data.resize(entry.uncompressed_length);
-        if (ExtractToMemory(za, &entry, reinterpret_cast<uint8_t*>(&v->data[0]),
-                            v->data.size()) != 0) {
-            printf("%s: faled to extract %zu bytes to memory\n", name, v->data.size());
-        } else {
-            success = true;
-        }
-
-        if (!success) {
-            v->data.clear();
-        } else {
-            v->type = VAL_BLOB;
-        }
-        return v;
+    ZipArchiveHandle za = static_cast<UpdaterInfo*>(state->cookie)->package_zip;
+    ZipString zip_string_path(zip_path.c_str());
+    ZipEntry entry;
+    if (FindEntry(za, zip_string_path, &entry) != 0) {
+      printf("%s: no %s in package\n", name, zip_path.c_str());
+      return StringValue("");
     }
+
+    int fd = TEMP_FAILURE_RETRY(
+        ota_open(dest_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR));
+    if (fd == -1) {
+      printf("%s: can't open %s for write: %s\n", name, dest_path.c_str(), strerror(errno));
+      return StringValue("");
+    }
+
+    bool success = true;
+    int32_t ret = ExtractEntryToFile(za, &entry, fd);
+    if (ret != 0) {
+      printf("%s: Failed to extract entry \"%s\" (%u bytes) to \"%s\": %s\n", name,
+             zip_path.c_str(), entry.uncompressed_length, dest_path.c_str(), ErrorCodeString(ret));
+      success = false;
+    }
+    if (ota_fsync(fd) == -1) {
+      printf("fsync of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno));
+      success = false;
+    }
+    if (ota_close(fd) == -1) {
+      printf("close of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno));
+      success = false;
+    }
+
+    return StringValue(success ? "t" : "");
+  } else {
+    // The one-argument version returns the contents of the file as the result.
+
+    std::vector<std::string> args;
+    if (!ReadArgs(state, 1, argv, &args)) {
+      return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, argc);
+    }
+    const std::string& zip_path = args[0];
+
+    ZipArchiveHandle za = static_cast<UpdaterInfo*>(state->cookie)->package_zip;
+    ZipString zip_string_path(zip_path.c_str());
+    ZipEntry entry;
+    if (FindEntry(za, zip_string_path, &entry) != 0) {
+      return ErrorAbort(state, kPackageExtractFileFailure, "%s(): no %s in package", name,
+                        zip_path.c_str());
+    }
+
+    std::string buffer;
+    buffer.resize(entry.uncompressed_length);
+
+    int32_t ret = ExtractToMemory(za, &entry, reinterpret_cast<uint8_t*>(&buffer[0]), buffer.size());
+    if (ret != 0) {
+      return ErrorAbort(state, kPackageExtractFileFailure,
+                        "%s: Failed to extract entry \"%s\" (%zu bytes) to memory: %s", name,
+                        zip_path.c_str(), buffer.size(), ErrorCodeString(ret));
+    }
+
+    return new Value(VAL_BLOB, buffer);
+  }
 }
 
 // symlink(target, [src1, src2, ...])
diff --git a/wear_ui.cpp b/wear_ui.cpp
index 1788907..5433d11 100644
--- a/wear_ui.cpp
+++ b/wear_ui.cpp
@@ -177,7 +177,7 @@
             // 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(x+4, y, cur_selection_str, 1);
+                gr_text(gr_sys_font(), x+4, y, cur_selection_str, 1);
                 y += char_height_+4;
             }
 
@@ -192,10 +192,10 @@
                     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(x+4, y, menu[i], 1);
+                    if (menu[i][0]) gr_text(gr_sys_font(), x+4, y, menu[i], 1);
                     SetColor(MENU);
-                } else {
-                    if (menu[i][0]) gr_text(x+4, y, menu[i], 0);
+                } else if (menu[i][0]) {
+                    gr_text(gr_sys_font(), x+4, y, menu[i], 0);
                 }
                 y += char_height_+4;
             }
@@ -216,7 +216,7 @@
         for (int ty = gr_fb_height() - char_height_ - outer_height;
              ty > y+2 && count < text_rows;
              ty -= char_height_, ++count) {
-            gr_text(x+4, ty, text[row], 0);
+            gr_text(gr_sys_font(), x+4, ty, text[row], 0);
             --row;
             if (row < 0) row = text_rows-1;
         }
@@ -285,7 +285,7 @@
 {
     gr_init();
 
-    gr_font_size(&char_width_, &char_height_);
+    gr_font_size(gr_sys_font(), &char_width_, &char_height_);
 
     text_col = text_row = 0;
     text_rows = (gr_fb_height()) / char_height_;