Merge "init: move healthd to late-init"
diff --git a/edify/README b/edify/README.md
similarity index 99%
rename from edify/README
rename to edify/README.md
index 810455c..b3330e2 100644
--- a/edify/README
+++ b/edify/README.md
@@ -1,3 +1,6 @@
+edify
+=====
+
 Update scripts (from donut onwards) are written in a new little
 scripting language ("edify") that is superficially somewhat similar to
 the old one ("amend").  This is a brief overview of the new language.
diff --git a/edify/edify_parser.cpp b/edify/edify_parser.cpp
index 15342d3..1b89cf2 100644
--- a/edify/edify_parser.cpp
+++ b/edify/edify_parser.cpp
@@ -45,7 +45,6 @@
 
 int main(int argc, char** argv) {
     RegisterBuiltins();
-    FinishRegistration();
 
     if (argc != 2) {
         printf("Usage: %s <edify script>\n", argv[0]);
diff --git a/edify/expr.cpp b/edify/expr.cpp
index aa3a55a..4000bc4 100644
--- a/edify/expr.cpp
+++ b/edify/expr.cpp
@@ -14,20 +14,20 @@
  * limitations under the License.
  */
 
-#include <string.h>
-#include <stdbool.h>
+#include "expr.h"
+
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <string>
+#include <unordered_map>
 
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
-#include "expr.h"
-
 // Functions should:
 //
 //    - return a malloc()'d string
@@ -319,61 +319,22 @@
     return StringValue(strdup(name));
 }
 
-Expr* Build(Function fn, YYLTYPE loc, int count, ...) {
-    va_list v;
-    va_start(v, count);
-    Expr* e = reinterpret_cast<Expr*>(malloc(sizeof(Expr)));
-    e->fn = fn;
-    e->name = "(operator)";
-    e->argc = count;
-    e->argv = reinterpret_cast<Expr**>(malloc(count * sizeof(Expr*)));
-    int i;
-    for (i = 0; i < count; ++i) {
-        e->argv[i] = va_arg(v, Expr*);
-    }
-    va_end(v);
-    e->start = loc.start;
-    e->end = loc.end;
-    return e;
-}
-
 // -----------------------------------------------------------------
 //   the function table
 // -----------------------------------------------------------------
 
-static int fn_entries = 0;
-static int fn_size = 0;
-NamedFunction* fn_table = NULL;
+static std::unordered_map<std::string, Function> fn_table;
 
-void RegisterFunction(const char* name, Function fn) {
-    if (fn_entries >= fn_size) {
-        fn_size = fn_size*2 + 1;
-        fn_table = reinterpret_cast<NamedFunction*>(realloc(fn_table, fn_size * sizeof(NamedFunction)));
+void RegisterFunction(const std::string& name, Function fn) {
+    fn_table[name] = fn;
+}
+
+Function FindFunction(const std::string& name) {
+    if (fn_table.find(name) == fn_table.end()) {
+        return nullptr;
+    } else {
+        return fn_table[name];
     }
-    fn_table[fn_entries].name = name;
-    fn_table[fn_entries].fn = fn;
-    ++fn_entries;
-}
-
-static int fn_entry_compare(const void* a, const void* b) {
-    const char* na = ((const NamedFunction*)a)->name;
-    const char* nb = ((const NamedFunction*)b)->name;
-    return strcmp(na, nb);
-}
-
-void FinishRegistration() {
-    qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare);
-}
-
-Function FindFunction(const char* name) {
-    NamedFunction key;
-    key.name = name;
-    NamedFunction* nf = reinterpret_cast<NamedFunction*>(bsearch(&key, fn_table, fn_entries,
-            sizeof(NamedFunction), fn_entry_compare));
-    if (nf == NULL) {
-        return NULL;
-    }
-    return nf->fn;
 }
 
 void RegisterBuiltins() {
diff --git a/edify/expr.h b/edify/expr.h
index f045d93..cd6139a 100644
--- a/edify/expr.h
+++ b/edify/expr.h
@@ -21,11 +21,6 @@
 #include <string>
 
 #include "error_code.h"
-#include "yydefs.h"
-
-#define MAX_STRING_LEN 1024
-
-typedef struct Expr Expr;
 
 struct State {
     State(const std::string& script, void* cookie);
@@ -56,14 +51,15 @@
 #define VAL_STRING  1  // data will be NULL-terminated; size doesn't count null
 #define VAL_BLOB    2
 
-typedef struct {
+struct Value {
     int type;
     ssize_t size;
     char* data;
-} Value;
+};
 
-typedef Value* (*Function)(const char* name, State* state,
-                           int argc, Expr* argv[]);
+struct Expr;
+
+using Function = Value* (*)(const char* name, State* state, int argc, Expr* argv[]);
 
 struct Expr {
     Function fn;
@@ -100,43 +96,21 @@
 Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
 Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
 
-// Convenience function for building expressions with a fixed number
-// of arguments.
-Expr* Build(Function fn, YYLTYPE loc, int count, ...);
-
 // Global builtins, registered by RegisterBuiltins().
 Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]);
 Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]);
 Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]);
 
-
-// For setting and getting the global error string (when returning
-// NULL from a function).
-void SetError(const char* message);  // makes a copy
-const char* GetError();              // retains ownership
-void ClearError();
-
-
-typedef struct {
-  const char* name;
-  Function fn;
-} NamedFunction;
-
 // Register a new function.  The same Function may be registered under
 // multiple names, but a given name should only be used once.
-void RegisterFunction(const char* name, Function fn);
+void RegisterFunction(const std::string& name, Function fn);
 
 // Register all the builtins.
 void RegisterBuiltins();
 
-// Call this after all calls to RegisterFunction() but before parsing
-// any scripts to finish building the function table.
-void FinishRegistration();
-
 // Find the Function for a given name; return NULL if no such function
 // exists.
-Function FindFunction(const char* name);
-
+Function FindFunction(const std::string& name);
 
 // --- convenience functions for use in functions ---
 
diff --git a/edify/parser.yy b/edify/parser.yy
index 098a637..58a8dec 100644
--- a/edify/parser.yy
+++ b/edify/parser.yy
@@ -33,6 +33,25 @@
 void yy_switch_to_buffer(struct yy_buffer_state* new_buffer);
 struct yy_buffer_state* yy_scan_string(const char* yystr);
 
+// Convenience function for building expressions with a fixed number
+// of arguments.
+static Expr* Build(Function fn, YYLTYPE loc, size_t count, ...) {
+    va_list v;
+    va_start(v, count);
+    Expr* e = static_cast<Expr*>(malloc(sizeof(Expr)));
+    e->fn = fn;
+    e->name = "(operator)";
+    e->argc = count;
+    e->argv = static_cast<Expr**>(malloc(count * sizeof(Expr*)));
+    for (size_t i = 0; i < count; ++i) {
+        e->argv[i] = va_arg(v, Expr*);
+    }
+    va_end(v);
+    e->start = loc.start;
+    e->end = loc.end;
+    return e;
+}
+
 %}
 
 %locations
@@ -70,7 +89,7 @@
 ;
 
 expr:  STRING {
-    $$ = reinterpret_cast<Expr*>(malloc(sizeof(Expr)));
+    $$ = static_cast<Expr*>(malloc(sizeof(Expr)));
     $$->fn = Literal;
     $$->name = $1;
     $$->argc = 0;
@@ -91,9 +110,9 @@
 |  IF expr THEN expr ENDIF           { $$ = Build(IfElseFn, @$, 2, $2, $4); }
 |  IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); }
 | STRING '(' arglist ')' {
-    $$ = reinterpret_cast<Expr*>(malloc(sizeof(Expr)));
+    $$ = static_cast<Expr*>(malloc(sizeof(Expr)));
     $$->fn = FindFunction($1);
-    if ($$->fn == NULL) {
+    if ($$->fn == nullptr) {
         char buffer[256];
         snprintf(buffer, sizeof(buffer), "unknown function \"%s\"", $1);
         yyerror(root, error_count, buffer);
@@ -113,12 +132,12 @@
 }
 | expr {
     $$.argc = 1;
-    $$.argv = reinterpret_cast<Expr**>(malloc(sizeof(Expr*)));
+    $$.argv = static_cast<Expr**>(malloc(sizeof(Expr*)));
     $$.argv[0] = $1;
 }
 | arglist ',' expr {
     $$.argc = $1.argc + 1;
-    $$.argv = reinterpret_cast<Expr**>(realloc($$.argv, $$.argc * sizeof(Expr*)));
+    $$.argv = static_cast<Expr**>(realloc($$.argv, $$.argc * sizeof(Expr*)));
     $$.argv[$$.argc-1] = $3;
 }
 ;
diff --git a/install.cpp b/install.cpp
index 427bea1..72c922d 100644
--- a/install.cpp
+++ b/install.cpp
@@ -377,8 +377,8 @@
         std::string uncrypt_status;
         if (!android::base::ReadFileToString(UNCRYPT_STATUS, &uncrypt_status)) {
             PLOG(WARNING) << "failed to read uncrypt status";
-        } else if (!android::base::StartsWith(uncrypt_status, "uncrypt_:")) {
-            PLOG(WARNING) << "corrupted uncrypt_status: " << uncrypt_status;
+        } else if (!android::base::StartsWith(uncrypt_status, "uncrypt_")) {
+            LOG(WARNING) << "corrupted uncrypt_status: " << uncrypt_status;
         } else {
             log_buffer.push_back(android::base::Trim(uncrypt_status));
         }
diff --git a/tests/Android.mk b/tests/Android.mk
index 19cb809..ef822d1 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -41,25 +41,41 @@
 LOCAL_MODULE := recovery_component_test
 LOCAL_C_INCLUDES := bootable/recovery
 LOCAL_SRC_FILES := \
+    component/applypatch_test.cpp \
     component/edify_test.cpp \
-    component/verifier_test.cpp \
-    component/applypatch_test.cpp
+    component/updater_test.cpp \
+    component/verifier_test.cpp
 LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+tune2fs_static_libraries := \
+    libext2_com_err \
+    libext2_blkid \
+    libext2_quota \
+    libext2_uuid_static \
+    libext2_e2p \
+    libext2fs
+
 LOCAL_STATIC_LIBRARIES := \
     libapplypatch \
     libedify \
     libotafault \
+    libupdater \
     libverifier \
-    libcrypto_utils \
-    libcrypto \
     libminui \
     libminzip \
+    libmounts \
+    liblog \
+    libselinux \
+    libext4_utils_static \
+    libsparse_static \
+    libcrypto_utils \
+    libcrypto \
     libcutils \
     libbz \
     libz \
-    libc \
     libbase \
-    liblog
+    libtune2fs \
+    $(tune2fs_static_libraries)
 
 testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery
 testdata_files := $(call find-subdir-files, testdata/*)
diff --git a/tests/component/edify_test.cpp b/tests/component/edify_test.cpp
index ede2ecb..a4dbb9f 100644
--- a/tests/component/edify_test.cpp
+++ b/tests/component/edify_test.cpp
@@ -22,17 +22,18 @@
 
 static void expect(const char* expr_str, const char* expected) {
     Expr* e;
-    int error_count;
-    EXPECT_EQ(parse_string(expr_str, &e, &error_count), 0);
+    int error_count = 0;
+    EXPECT_EQ(0, parse_string(expr_str, &e, &error_count));
+    EXPECT_EQ(0, error_count);
 
     State state(expr_str, nullptr);
 
     char* result = Evaluate(&state, e);
 
     if (expected == nullptr) {
-        EXPECT_EQ(result, nullptr);
+        EXPECT_EQ(nullptr, result);
     } else {
-        EXPECT_STREQ(result, expected);
+        EXPECT_STREQ(expected, result);
     }
 
     free(result);
@@ -42,7 +43,6 @@
   protected:
     virtual void SetUp() {
         RegisterBuiltins();
-        FinishRegistration();
     }
 };
 
@@ -149,3 +149,21 @@
     expect(std::string(8192, 's').c_str(), std::string(8192, 's').c_str());
 }
 
+TEST_F(EdifyTest, unknown_function) {
+    // unknown function
+    const char* script1 = "unknown_function()";
+    Expr* expr;
+    int error_count = 0;
+    EXPECT_EQ(1, parse_string(script1, &expr, &error_count));
+    EXPECT_EQ(1, error_count);
+
+    const char* script2 = "abc; unknown_function()";
+    error_count = 0;
+    EXPECT_EQ(1, parse_string(script2, &expr, &error_count));
+    EXPECT_EQ(1, error_count);
+
+    const char* script3 = "unknown_function1() || yes";
+    error_count = 0;
+    EXPECT_EQ(1, parse_string(script3, &expr, &error_count));
+    EXPECT_EQ(1, error_count);
+}
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
new file mode 100644
index 0000000..64a6b37
--- /dev/null
+++ b/tests/component/updater_test.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <android-base/properties.h>
+#include <gtest/gtest.h>
+
+#include "edify/expr.h"
+#include "error_code.h"
+#include "updater/install.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);
+
+    State state(expr_str, nullptr);
+
+    char* result = Evaluate(&state, e);
+
+    if (expected == nullptr) {
+        EXPECT_EQ(nullptr, result);
+    } else {
+        EXPECT_STREQ(expected, result);
+    }
+
+    // Error code is set in updater/updater.cpp only, by parsing State.errmsg.
+    EXPECT_EQ(kNoError, state.error_code);
+
+    // Cause code should always be available.
+    EXPECT_EQ(cause_code, state.cause_code);
+
+    free(result);
+}
+
+class UpdaterTest : public ::testing::Test {
+  protected:
+    virtual void SetUp() {
+        RegisterBuiltins();
+        RegisterInstallFunctions();
+    }
+};
+
+TEST_F(UpdaterTest, getprop) {
+    expect(android::base::GetProperty("ro.product.device", "").c_str(),
+           "getprop(\"ro.product.device\")",
+           kNoCause);
+
+    expect(android::base::GetProperty("ro.build.fingerprint", "").c_str(),
+           "getprop(\"ro.build.fingerprint\")",
+           kNoCause);
+
+    // getprop() accepts only one parameter.
+    expect(nullptr, "getprop()", kArgsParsingFailure);
+    expect(nullptr, "getprop(\"arg1\", \"arg2\")", kArgsParsingFailure);
+}
+
+TEST_F(UpdaterTest, sha1_check) {
+    // sha1_check(data) returns the SHA-1 of the data.
+    expect("81fe8bfe87576c3ecb22426f8e57847382917acf", "sha1_check(\"abcd\")", kNoCause);
+    expect("da39a3ee5e6b4b0d3255bfef95601890afd80709", "sha1_check(\"\")", kNoCause);
+
+    // sha1_check(data, sha1_hex, [sha1_hex, ...]) returns the matched SHA-1.
+    expect("81fe8bfe87576c3ecb22426f8e57847382917acf",
+           "sha1_check(\"abcd\", \"81fe8bfe87576c3ecb22426f8e57847382917acf\")",
+           kNoCause);
+
+    expect("81fe8bfe87576c3ecb22426f8e57847382917acf",
+           "sha1_check(\"abcd\", \"wrong_sha1\", \"81fe8bfe87576c3ecb22426f8e57847382917acf\")",
+           kNoCause);
+
+    // Or "" if there's no match.
+    expect("",
+           "sha1_check(\"abcd\", \"wrong_sha1\")",
+           kNoCause);
+
+    expect("",
+           "sha1_check(\"abcd\", \"wrong_sha1\", \"wrong_sha2\")",
+           kNoCause);
+
+    // sha1_check() expects at least one argument.
+    expect(nullptr, "sha1_check()", kArgsParsingFailure);
+}
diff --git a/updater/Android.mk b/updater/Android.mk
index d9fc72c..33e9738 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -14,41 +14,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-# updater (static executable)
-# ===============================
-# Build a statically-linked binary to include in OTA packages.
-include $(CLEAR_VARS)
-
-updater_src_files := \
-    install.cpp \
-    blockimg.cpp \
-    updater.cpp
-
-LOCAL_CLANG := true
-LOCAL_SRC_FILES := $(updater_src_files)
-
-LOCAL_STATIC_LIBRARIES += \
-    $(TARGET_RECOVERY_UPDATER_LIBS) \
-    $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) \
-    libfec \
-    libfec_rs \
-    libext4_utils_static \
-    libsquashfs_utils \
-    libcrypto_utils \
-    libcrypto \
-    libapplypatch \
-    libotafault \
-    libedify \
-    libminzip \
-    libmounts \
-    libz \
-    libbz \
-    libcutils \
-    liblog \
-    libselinux \
-    libbase \
-    liblog
-
 tune2fs_static_libraries := \
     libext2_com_err \
     libext2_blkid \
@@ -57,17 +22,77 @@
     libext2_e2p \
     libext2fs
 
-LOCAL_STATIC_LIBRARIES += \
+updater_common_static_libraries := \
+    libapplypatch \
+    libedify \
+    libminzip \
+    libmounts \
+    libotafault \
+    libext4_utils_static \
+    libfec \
+    libfec_rs \
+    liblog \
+    libselinux \
+    libsparse_static \
+    libsquashfs_utils \
+    libbz \
+    libz \
+    libbase \
+    libcrypto \
+    libcrypto_utils \
+    libcutils \
     libtune2fs \
     $(tune2fs_static_libraries)
 
-LOCAL_CFLAGS += -Wno-unused-parameter -Werror
-LOCAL_STATIC_LIBRARIES += \
-    libsparse_static \
-    libz
+# libupdater (static library)
+# ===============================
+include $(CLEAR_VARS)
 
-LOCAL_C_INCLUDES += external/e2fsprogs/misc
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
+LOCAL_MODULE := libupdater
+
+LOCAL_SRC_FILES := \
+    install.cpp \
+    blockimg.cpp
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/.. \
+    $(LOCAL_PATH)/include \
+    external/e2fsprogs/misc
+
+LOCAL_CFLAGS := \
+    -Wno-unused-parameter \
+    -Werror
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+    $(LOCAL_PATH)/include
+
+LOCAL_STATIC_LIBRARIES := \
+    $(updater_common_static_libraries)
+
+include $(BUILD_STATIC_LIBRARY)
+
+# updater (static executable)
+# ===============================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := updater
+
+LOCAL_SRC_FILES := \
+    updater.cpp
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/.. \
+    $(LOCAL_PATH)/include
+
+LOCAL_CFLAGS := \
+    -Wno-unused-parameter \
+    -Werror
+
+LOCAL_STATIC_LIBRARIES := \
+    libupdater \
+    $(TARGET_RECOVERY_UPDATER_LIBS) \
+    $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) \
+    $(updater_common_static_libraries)
 
 # Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function
 # named "Register_<libname>()".  Here we emit a little C function that
@@ -108,8 +133,6 @@
 inc :=
 inc_dep_file :=
 
-LOCAL_MODULE := updater
-
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 
 include $(BUILD_EXECUTABLE)
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index 0caa1ac..433d980 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -45,12 +45,12 @@
 #include "applypatch/applypatch.h"
 #include "edify/expr.h"
 #include "error_code.h"
-#include "install.h"
+#include "updater/install.h"
 #include "openssl/sha.h"
 #include "minzip/Hash.h"
 #include "ota_io.h"
 #include "print_sha1.h"
-#include "updater.h"
+#include "updater/updater.h"
 
 #define BLOCKSIZE 4096
 
diff --git a/updater/blockimg.h b/updater/include/updater/blockimg.h
similarity index 100%
rename from updater/blockimg.h
rename to updater/include/updater/blockimg.h
diff --git a/updater/install.h b/updater/include/updater/install.h
similarity index 89%
rename from updater/install.h
rename to updater/include/updater/install.h
index b3b8a4d..8d6ca47 100644
--- a/updater/install.h
+++ b/updater/include/updater/install.h
@@ -17,11 +17,12 @@
 #ifndef _UPDATER_INSTALL_H_
 #define _UPDATER_INSTALL_H_
 
+struct State;
+
 void RegisterInstallFunctions();
 
 // uiPrintf function prints msg to screen as well as logs
-void uiPrintf(State* _Nonnull state, const char* _Nonnull format, ...) __attribute__((__format__(printf, 2, 3)));
-
-static int make_parents(char* _Nonnull name);
+void uiPrintf(State* _Nonnull state, const char* _Nonnull format, ...)
+    __attribute__((__format__(printf, 2, 3)));
 
 #endif
diff --git a/updater/updater.h b/updater/include/updater/updater.h
similarity index 100%
rename from updater/updater.h
rename to updater/include/updater/updater.h
diff --git a/updater/install.cpp b/updater/install.cpp
index 24e35cf..3546968 100644
--- a/updater/install.cpp
+++ b/updater/install.cpp
@@ -14,50 +14,51 @@
  * limitations under the License.
  */
 
+#include "updater/install.h"
+
 #include <ctype.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <inttypes.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/capability.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <ftw.h>
-#include <sys/capability.h>
 #include <sys/xattr.h>
-#include <linux/xattr.h>
-#include <inttypes.h>
+#include <time.h>
+#include <unistd.h>
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android-base/stringprintf.h>
+#include <cutils/android_reboot.h>
 #include <ext4_utils/make_ext4fs.h>
 #include <ext4_utils/wipe.h>
+#include <openssl/sha.h>
 #include <selinux/label.h>
 #include <selinux/selinux.h>
 
-#include "bootloader.h"
 #include "applypatch/applypatch.h"
-#include "cutils/android_reboot.h"
-#include "cutils/misc.h"
+#include "bootloader.h"
 #include "edify/expr.h"
 #include "error_code.h"
 #include "minzip/DirUtil.h"
 #include "mounts.h"
-#include "openssl/sha.h"
 #include "ota_io.h"
-#include "updater.h"
-#include "install.h"
+#include "print_sha1.h"
 #include "tune2fs.h"
+#include "updater/updater.h"
 
 // Send over the buffer to recovery though the command pipe.
 static void uiPrint(State* state, const std::string& buffer) {
@@ -90,17 +91,25 @@
     uiPrint(state, error_msg);
 }
 
-// Take a sha-1 digest and return it as a newly-allocated hex string.
-char* PrintSha1(const uint8_t* digest) {
-    char* buffer = reinterpret_cast<char*>(malloc(SHA_DIGEST_LENGTH*2 + 1));
-    const char* alphabet = "0123456789abcdef";
-    size_t i;
-    for (i = 0; i < SHA_DIGEST_LENGTH; ++i) {
-        buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
-        buffer[i*2+1] = alphabet[digest[i] & 0xf];
+// Create all parent directories of name, if necessary.
+static int make_parents(char* name) {
+    char* p;
+    for (p = name + (strlen(name)-1); p > name; --p) {
+        if (*p != '/') continue;
+        *p = '\0';
+        if (make_parents(name) < 0) return -1;
+        int result = mkdir(name, 0700);
+        if (result == 0) printf("created [%s]\n", name);
+        *p = '/';
+        if (result == 0 || errno == EEXIST) {
+            // successfully created or already existed; we're done
+            return 0;
+        } else {
+            printf("failed to mkdir %s: %s\n", name, strerror(errno));
+            return -1;
+        }
     }
-    buffer[i*2] = '\0';
-    return buffer;
+    return 0;
 }
 
 // mount(fs_type, partition_type, location, mount_point)
@@ -569,27 +578,6 @@
     }
 }
 
-// Create all parent directories of name, if necessary.
-static int make_parents(char* name) {
-    char* p;
-    for (p = name + (strlen(name)-1); p > name; --p) {
-        if (*p != '/') continue;
-        *p = '\0';
-        if (make_parents(name) < 0) return -1;
-        int result = mkdir(name, 0700);
-        if (result == 0) printf("created [%s]\n", name);
-        *p = '/';
-        if (result == 0 || errno == EEXIST) {
-            // successfully created or already existed; we're done
-            return 0;
-        } else {
-            printf("failed to mkdir %s: %s\n", name, strerror(errno));
-            return -1;
-        }
-    }
-    return 0;
-}
-
 // symlink target src1 src2 ...
 //    unlinks any previously existing src1, src2, etc before creating symlinks.
 Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
@@ -1227,29 +1215,24 @@
     SHA1(reinterpret_cast<uint8_t*>(args[0]->data), args[0]->size, digest);
 
     if (argc == 1) {
-        return StringValue(PrintSha1(digest));
+        return StringValue(strdup(print_sha1(digest).c_str()));
     }
 
-    int i;
-    uint8_t arg_digest[SHA_DIGEST_LENGTH];
-    for (i = 1; i < argc; ++i) {
+    for (int i = 1; i < argc; ++i) {
+        uint8_t arg_digest[SHA_DIGEST_LENGTH];
         if (args[i]->type != VAL_STRING) {
-            printf("%s(): arg %d is not a string; skipping",
-                    name, i);
+            printf("%s(): arg %d is not a string; skipping", name, i);
         } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
             // Warn about bad args and skip them.
-            printf("%s(): error parsing \"%s\" as sha-1; skipping",
-                   name, args[i]->data);
+            printf("%s(): error parsing \"%s\" as sha-1; skipping", name, args[i]->data);
         } else if (memcmp(digest, arg_digest, SHA_DIGEST_LENGTH) == 0) {
-            break;
+            // Found a match.
+            return args[i].release();
         }
     }
-    if (i >= argc) {
-        // Didn't match any of the hex strings; return false.
-        return StringValue(strdup(""));
-    }
-    // Found a match.
-    return args[i].release();
+
+    // Didn't match any of the hex strings; return false.
+    return StringValue(strdup(""));
 }
 
 // Read a local file and return its contents (the Value* returned
diff --git a/updater/updater.cpp b/updater/updater.cpp
index 74a4048..c752ebb 100644
--- a/updater/updater.cpp
+++ b/updater/updater.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "updater.h"
+#include "updater/updater.h"
 
 #include <stdio.h>
 #include <unistd.h>
@@ -27,10 +27,10 @@
 
 #include "config.h"
 #include "edify/expr.h"
-#include "blockimg.h"
-#include "install.h"
-#include "minzip/Zip.h"
 #include "minzip/SysUtil.h"
+#include "minzip/Zip.h"
+#include "updater/blockimg.h"
+#include "updater/install.h"
 
 // Generated by the makefile, this function defines the
 // RegisterDeviceExtensions() function, which calls all the
@@ -111,7 +111,6 @@
     RegisterInstallFunctions();
     RegisterBlockImageFunctions();
     RegisterDeviceExtensions();
-    FinishRegistration();
 
     // Parse the script.