Merge "Fix google-explicit-constructor warnings in binder."
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 4769974..4dde125 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -218,7 +218,7 @@
  */
 class DurationReporter {
 public:
-    DurationReporter(const char *title);
+    explicit DurationReporter(const char *title);
     DurationReporter(const char *title, FILE* out);
 
     ~DurationReporter();
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 6cd0689..d29e5ba 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -45,8 +45,8 @@
 LOCAL_MODULE_CLASS := EXECUTABLES
 LOCAL_SRC_FILES := otapreopt_script.sh
 
-# Let this depend on otapreopt and the chroot tool, so we just have to mention one in a
-# configuration.
-LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot
+# Let this depend on otapreopt, the chroot tool and the slot script, so we just have to mention one
+# in a configuration.
+LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot otapreopt_slot
 
 include $(BUILD_PREBUILT)
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index e6680ed..cbd8a09 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -18,6 +18,7 @@
 
 #include <errno.h>
 #include <inttypes.h>
+#include <regex>
 #include <stdlib.h>
 #include <sys/capability.h>
 #include <sys/file.h>
@@ -28,9 +29,9 @@
 #include <sys/xattr.h>
 #include <unistd.h>
 
+#include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <cutils/fs.h>
 #include <cutils/log.h>               // TODO: Move everything to base/logging.
@@ -43,12 +44,14 @@
 
 #include <globals.h>
 #include <installd_deps.h>
+#include <otapreopt_utils.h>
 #include <utils.h>
 
 #ifndef LOG_TAG
 #define LOG_TAG "installd"
 #endif
 
+using android::base::EndsWith;
 using android::base::StringPrintf;
 
 namespace android {
@@ -57,6 +60,26 @@
 static constexpr const char* kCpPath = "/system/bin/cp";
 static constexpr const char* kXattrDefault = "user.default";
 
+static constexpr const char* PKG_LIB_POSTFIX = "/lib";
+static constexpr const char* CACHE_DIR_POSTFIX = "/cache";
+static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
+
+static constexpr const char* IDMAP_PREFIX = "/data/resource-cache/";
+static constexpr const char* IDMAP_SUFFIX = "@idmap";
+
+// NOTE: keep in sync with StorageManager
+static constexpr int FLAG_STORAGE_DE = 1 << 0;
+static constexpr int FLAG_STORAGE_CE = 1 << 1;
+
+// NOTE: keep in sync with Installer
+static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
+static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
+
+/* dexopt needed flags matching those in dalvik.system.DexFile */
+static constexpr int DEXOPT_DEX2OAT_NEEDED       = 1;
+static constexpr int DEXOPT_PATCHOAT_NEEDED      = 2;
+static constexpr int DEXOPT_SELF_PATCHOAT_NEEDED = 3;
+
 #define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M
 
 typedef int fd_t;
@@ -648,8 +671,10 @@
   return count;
 }
 
-static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name,
-    const char* output_file_name, const char *pkgname ATTRIBUTE_UNUSED, const char *instruction_set)
+static void run_patchoat(int input_oat_fd, int input_vdex_fd, int out_oat_fd, int out_vdex_fd,
+    const char* input_oat_file_name, const char* input_vdex_file_name,
+    const char* output_oat_file_name, const char* output_vdex_file_name,
+    const char *pkgname ATTRIBUTE_UNUSED, const char *instruction_set)
 {
     static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
@@ -663,35 +688,44 @@
 
     /* input_file_name/input_fd should be the .odex/.oat file that is precompiled. I think*/
     char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
-    char output_oat_fd_arg[strlen("--output-oat-fd=") + MAX_INT_LEN];
     char input_oat_fd_arg[strlen("--input-oat-fd=") + MAX_INT_LEN];
+    char input_vdex_fd_arg[strlen("--input-vdex-fd=") + MAX_INT_LEN];
+    char output_oat_fd_arg[strlen("--output-oat-fd=") + MAX_INT_LEN];
+    char output_vdex_fd_arg[strlen("--output-vdex-fd=") + MAX_INT_LEN];
     const char* patched_image_location_arg = "--patched-image-location=/system/framework/boot.art";
     // The caller has already gotten all the locks we need.
     const char* no_lock_arg = "--no-lock-output";
     sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
-    sprintf(output_oat_fd_arg, "--output-oat-fd=%d", oat_fd);
-    sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_fd);
-    ALOGV("Running %s isa=%s in-fd=%d (%s) out-fd=%d (%s)\n",
-          PATCHOAT_BIN, instruction_set, input_fd, input_file_name, oat_fd, output_file_name);
+    sprintf(output_oat_fd_arg, "--output-oat-fd=%d", out_oat_fd);
+    sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_oat_fd);
+    ALOGV("Running %s isa=%s in-oat-fd=%d (%s) in-vdex-fd=%d (%s) "
+          "out-oat-fd=%d (%s) out-vdex-fd=%d (%s)\n",
+          PATCHOAT_BIN, instruction_set,
+          input_oat_fd, input_oat_file_name,
+          input_vdex_fd, input_vdex_file_name,
+          out_oat_fd, output_oat_file_name,
+          out_vdex_fd, output_vdex_file_name);
 
     /* patchoat, patched-image-location, no-lock, isa, input-fd, output-fd */
-    char* argv[7];
+    char* argv[9];
     argv[0] = (char*) PATCHOAT_BIN;
     argv[1] = (char*) patched_image_location_arg;
     argv[2] = (char*) no_lock_arg;
     argv[3] = instruction_set_arg;
-    argv[4] = output_oat_fd_arg;
-    argv[5] = input_oat_fd_arg;
-    argv[6] = NULL;
+    argv[4] = input_oat_fd_arg;
+    argv[5] = input_vdex_fd_arg;
+    argv[6] = output_oat_fd_arg;
+    argv[7] = output_vdex_fd_arg;
+    argv[8] = NULL;
 
     execv(PATCHOAT_BIN, (char* const *)argv);
     ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno));
 }
 
-static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_file_name,
-        const char* output_file_name, int swap_fd, const char *instruction_set,
-        const char* compiler_filter, bool vm_safe_mode, bool debuggable, bool post_bootcomplete,
-        int profile_fd, const char* shared_libraries) {
+static void run_dex2oat(int zip_fd, int oat_fd, int vdex_fd, int image_fd,
+        const char* input_file_name, const char* output_file_name, int swap_fd,
+        const char *instruction_set, const char* compiler_filter, bool vm_safe_mode,
+        bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) {
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -754,6 +788,16 @@
         sprintf(image_format_arg, "--image-format=%s", app_image_format);
     }
 
+    char dex2oat_large_app_threshold[kPropertyValueMax];
+    bool have_dex2oat_large_app_threshold =
+            get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, NULL) > 0;
+    char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
+    if (have_dex2oat_large_app_threshold) {
+        sprintf(dex2oat_large_app_threshold_arg,
+                "--very-large-app-threshold=%s",
+                dex2oat_large_app_threshold);
+    }
+
     static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
 
     static const char* RUNTIME_ARG = "--runtime-arg";
@@ -762,6 +806,7 @@
 
     char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
     char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
+    char vdex_fd_arg[strlen("--vdex-fd=") + MAX_INT_LEN];
     char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
     char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX];
     char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
@@ -777,6 +822,7 @@
 
     sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
     sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
+    sprintf(vdex_fd_arg, "--vdex-fd=%d", vdex_fd);
     sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
     sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
     sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
@@ -839,7 +885,7 @@
 
     ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
 
-    const char* argv[7  // program name, mandatory arguments and the final NULL
+    const char* argv[8  // program name, mandatory arguments and the final NULL
                      + (have_dex2oat_isa_variant ? 1 : 0)
                      + (have_dex2oat_isa_features ? 1 : 0)
                      + (have_dex2oat_Xms_flag ? 2 : 0)
@@ -854,11 +900,13 @@
                      + (have_app_image_format ? 1 : 0)
                      + dex2oat_flags_count
                      + (profile_fd == -1 ? 0 : 1)
-                     + (shared_libraries != nullptr ? 4 : 0)];
+                     + (shared_libraries != nullptr ? 4 : 0)
+                     + (have_dex2oat_large_app_threshold ? 1 : 0)];
     int i = 0;
     argv[i++] = DEX2OAT_BIN;
     argv[i++] = zip_fd_arg;
     argv[i++] = zip_location_arg;
+    argv[i++] = vdex_fd_arg;
     argv[i++] = oat_fd_arg;
     argv[i++] = oat_location_arg;
     argv[i++] = instruction_set_arg;
@@ -897,6 +945,9 @@
     if (have_app_image_format) {
         argv[i++] = image_format_arg;
     }
+    if (have_dex2oat_large_app_threshold) {
+        argv[i++] = dex2oat_large_app_threshold_arg;
+    }
     if (dex2oat_flags_count) {
         i += split(dex2oat_flags, argv + i);
     }
@@ -1313,13 +1364,38 @@
     return true;
 }
 
-static void trim_extension(char* path) {
-  // Trim the extension.
-  int pos = strlen(path);
-  for (; pos >= 0 && path[pos] != '.'; --pos) {}
-  if (pos >= 0) {
-      path[pos] = '\0';  // Trim extension
+static std::string replace_file_extension(const std::string& oat_path, const std::string& new_ext) {
+  // A standard dalvik-cache entry. Replace ".dex" with `new_ext`.
+  if (EndsWith(oat_path, ".dex")) {
+    std::string new_path = oat_path;
+    new_path.replace(new_path.length() - strlen(".dex"), strlen(".dex"), new_ext);
+    CHECK(EndsWith(new_path, new_ext.c_str()));
+    return new_path;
   }
+
+  // An odex entry. Not that this may not be an extension, e.g., in the OTA
+  // case (where the base name will have an extension for the B artifact).
+  size_t odex_pos = oat_path.rfind(".odex");
+  if (odex_pos != std::string::npos) {
+    std::string new_path = oat_path;
+    new_path.replace(odex_pos, strlen(".odex"), new_ext);
+    CHECK_NE(new_path.find(new_ext), std::string::npos);
+    return new_path;
+  }
+
+  // Don't know how to handle this.
+  return "";
+}
+
+// Translate the given oat path to an art (app image) path. An empty string
+// denotes an error.
+static std::string create_image_filename(const std::string& oat_path) {
+    return replace_file_extension(oat_path, ".art");
+}
+
+// Translate the given oat path to a vdex path. An empty string denotes an error.
+static std::string create_vdex_filename(const std::string& oat_path) {
+    return replace_file_extension(oat_path, ".vdex");
 }
 
 static bool add_extension_to_file_name(char* file_name, const char* extension) {
@@ -1330,7 +1406,7 @@
     return true;
 }
 
-static int open_output_file(char* file_name, bool recreate, int permissions) {
+static int open_output_file(const char* file_name, bool recreate, int permissions) {
     int flags = O_RDWR | O_CREAT;
     if (recreate) {
         if (unlink(file_name) < 0) {
@@ -1357,7 +1433,7 @@
 }
 
 static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
-            const char* oat_dir, /*out*/ char* out_path) {
+            const char* oat_dir, /*out*/ char* out_oat_path) {
     // Early best-effort check whether we can fit the the path into our buffers.
     // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
     // without a swap file, if necessary. Reference profiles file also add an extra ".prof"
@@ -1372,11 +1448,11 @@
             ALOGE("invalid oat_dir '%s'\n", oat_dir);
             return false;
         }
-        if (!calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) {
+        if (!calculate_oat_file_path(out_oat_path, oat_dir, apk_path, instruction_set)) {
             return false;
         }
     } else {
-        if (!create_cache_path(out_path, apk_path, instruction_set)) {
+        if (!create_cache_path(out_oat_path, apk_path, instruction_set)) {
             return false;
         }
     }
@@ -1388,19 +1464,110 @@
     return analyse_profiles(uid, pkgname);
 }
 
+static const char* parse_null(const char* arg) {
+    if (strcmp(arg, "!") == 0) {
+        return nullptr;
+    } else {
+        return arg;
+    }
+}
+
+int dexopt(const char* const params[DEXOPT_PARAM_COUNT]) {
+    return dexopt(params[0],                    // apk_path
+                  atoi(params[1]),              // uid
+                  params[2],                    // pkgname
+                  params[3],                    // instruction_set
+                  atoi(params[4]),              // dexopt_needed
+                  params[5],                    // oat_dir
+                  atoi(params[6]),              // dexopt_flags
+                  params[7],                    // compiler_filter
+                  parse_null(params[8]),        // volume_uuid
+                  parse_null(params[9]));       // shared_libraries
+    static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param count");
+}
+
+// Helper for fd management. This is similar to a unique_fd in that it closes the file descriptor
+// on destruction. It will also run the given cleanup (unless told not to) after closing.
+//
+// Usage example:
+//
+//   Dex2oatFileWrapper<std::function<void ()>> file(open(...),
+//                                                   [name]() {
+//                                                       unlink(name.c_str());
+//                                                   });
+//   // Note: care needs to be taken about name, as it needs to have a lifetime longer than the
+//            wrapper if captured as a reference.
+//
+//   if (file.get() == -1) {
+//       // Error opening...
+//   }
+//
+//   ...
+//   if (error) {
+//       // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will run
+//       // and delete the file (after the fd is closed).
+//       return -1;
+//   }
+//
+//   (Success case)
+//   file.SetCleanup(false);
+//   // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
+//   // (leaving the file around; after the fd is closed).
+//
+template <typename Cleanup>
+class Dex2oatFileWrapper {
+ public:
+    Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true) {
+    }
+
+    Dex2oatFileWrapper(int value, Cleanup cleanup)
+            : value_(value), cleanup_(cleanup), do_cleanup_(true) {}
+
+    ~Dex2oatFileWrapper() {
+        reset(-1);
+    }
+
+    int get() {
+        return value_;
+    }
+
+    void SetCleanup(bool cleanup) {
+        do_cleanup_ = cleanup;
+    }
+
+    void reset(int new_value) {
+        if (value_ >= 0) {
+            close(value_);
+        }
+        if (do_cleanup_ && cleanup_ != nullptr) {
+            cleanup_();
+        }
+
+        value_ = new_value;
+    }
+
+    void reset(int new_value, Cleanup new_cleanup) {
+        if (value_ >= 0) {
+            close(value_);
+        }
+        if (do_cleanup_ && cleanup_ != nullptr) {
+            cleanup_();
+        }
+
+        value_ = new_value;
+        cleanup_ = new_cleanup;
+    }
+
+ private:
+    int value_;
+    Cleanup cleanup_;
+    bool do_cleanup_;
+};
+
 int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set,
            int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
            const char* volume_uuid ATTRIBUTE_UNUSED, const char* shared_libraries)
 {
-    struct utimbuf ut;
-    struct stat input_stat;
-    char out_path[PKG_PATH_MAX];
-    char swap_file_name[PKG_PATH_MAX];
-    char image_path[PKG_PATH_MAX];
-    const char *input_file;
-    char in_odex_path[PKG_PATH_MAX];
-    int res;
-    fd_t input_fd=-1, out_fd=-1, image_fd=-1, swap_fd=-1;
     bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
     bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
     bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
@@ -1410,12 +1577,16 @@
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
 
-    fd_t reference_profile_fd = -1;
     // Public apps should not be compiled with profile information ever. Same goes for the special
     // package '*' used for the system server.
+    Dex2oatFileWrapper<std::function<void ()>> reference_profile_fd;
     if (!is_public && pkgname[0] != '*') {
         // Open reference profile in read only mode as dex2oat does not get write permissions.
-        reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ false);
+        const std::string pkgname_str(pkgname);
+        reference_profile_fd.reset(open_reference_profile(uid, pkgname, /*read_write*/ false),
+                                   [pkgname_str]() {
+                                       clear_reference_profile(pkgname_str.c_str());
+                                   });
         // Note: it's OK to not find a profile here.
     }
 
@@ -1423,10 +1594,13 @@
         LOG_FATAL("dexopt flags contains unknown fields\n");
     }
 
-    if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) {
+    char out_oat_path[PKG_PATH_MAX];
+    if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_oat_path)) {
         return false;
     }
 
+    const char *input_file;
+    char in_odex_path[PKG_PATH_MAX];
     switch (dexopt_needed) {
         case DEXOPT_DEX2OAT_NEEDED:
             input_file = apk_path;
@@ -1440,40 +1614,82 @@
             break;
 
         case DEXOPT_SELF_PATCHOAT_NEEDED:
-            input_file = out_path;
+            input_file = out_oat_path;
             break;
 
         default:
             ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
-            exit(72);
+            return 72;
     }
 
+    struct stat input_stat;
     memset(&input_stat, 0, sizeof(input_stat));
     stat(input_file, &input_stat);
 
-    input_fd = open(input_file, O_RDONLY, 0);
-    if (input_fd < 0) {
+    // Open the input file. If running dex2oat, `input_file` is the APK. If running
+    // patchoat, it is the OAT file to be relocated.
+    base::unique_fd input_fd(open(input_file, O_RDONLY, 0));
+    if (input_fd.get() < 0) {
         ALOGE("installd cannot open '%s' for input during dexopt\n", input_file);
         return -1;
     }
 
-    out_fd = open_output_file(out_path, /*recreate*/true, /*permissions*/0644);
-    if (out_fd < 0) {
-        ALOGE("installd cannot open '%s' for output during dexopt\n", out_path);
-        goto fail;
+    // If invoking patchoat, open the VDEX associated with the OAT too.
+    std::string in_vdex_path_str;
+    base::unique_fd input_vdex_fd;
+    if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED
+        || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) {
+        in_vdex_path_str = create_vdex_filename(input_file);
+        if (in_vdex_path_str.empty()) {
+            return -1;
+        }
+        input_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+        if (input_vdex_fd.get() < 0) {
+            ALOGE("installd cannot open '%s' for input during dexopt\n", in_vdex_path_str.c_str());
+            return -1;
+        }
     }
-    if (!set_permissions_and_ownership(out_fd, is_public, uid, out_path)) {
-        goto fail;
+
+    // Create the output OAT file.
+    const std::string out_oat_path_str(out_oat_path);
+    Dex2oatFileWrapper<std::function<void ()>> out_oat_fd(
+            open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
+            [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
+    if (out_oat_fd.get() < 0) {
+        ALOGE("installd cannot open '%s' for output during dexopt\n", out_oat_path);
+        return -1;
+    }
+    if (!set_permissions_and_ownership(out_oat_fd.get(), is_public, uid, out_oat_path)) {
+        return -1;
+    }
+
+    // Infer the name of the output VDEX and create it.
+    const std::string out_vdex_path_str = create_vdex_filename(out_oat_path_str);
+    if (out_vdex_path_str.empty()) {
+        return -1;
+    }
+    Dex2oatFileWrapper<std::function<void ()>> out_vdex_fd(
+            open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644),
+            [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
+    if (out_vdex_fd.get() < 0) {
+        ALOGE("installd cannot open '%s' for output during dexopt\n", out_vdex_path_str.c_str());
+        return -1;
+    }
+    if (!set_permissions_and_ownership(out_vdex_fd.get(), is_public,
+                uid, out_vdex_path_str.c_str())) {
+        return -1;
     }
 
     // Create a swap file if necessary.
+    base::unique_fd swap_fd;
     if (ShouldUseSwapFileForDexopt()) {
         // Make sure there really is enough space.
-        strcpy(swap_file_name, out_path);
+        char swap_file_name[PKG_PATH_MAX];
+        strcpy(swap_file_name, out_oat_path);
         if (add_extension_to_file_name(swap_file_name, ".swap")) {
-            swap_fd = open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600);
+            swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600));
         }
-        if (swap_fd < 0) {
+        if (swap_fd.get() < 0) {
             // Could not create swap file. Optimistically go on and hope that we can compile
             // without it.
             ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
@@ -1486,111 +1702,114 @@
     }
 
     // Avoid generating an app image for extract only since it will not contain any classes.
-    strcpy(image_path, out_path);
-    trim_extension(image_path);
-    if (add_extension_to_file_name(image_path, ".art")) {
-      char app_image_format[kPropertyValueMax];
-      bool have_app_image_format =
-              get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
-      // Use app images only if it is enabled (by a set image format) and we are compiling
-      // profile-guided (so the app image doesn't conservatively contain all classes).
-      if (profile_guided && have_app_image_format) {
-          // Recreate is true since we do not want to modify a mapped image. If the app is already
-          // running and we modify the image file, it can cause crashes (b/27493510).
-          image_fd = open_output_file(image_path, /*recreate*/true, /*permissions*/0600);
-          if (image_fd < 0) {
-              // Could not create application image file. Go on since we can compile without it.
-              ALOGE("installd could not create '%s' for image file during dexopt\n", image_path);
-          } else if (!set_permissions_and_ownership(image_fd, is_public, uid, image_path)) {
-              image_fd = -1;
-          }
-      }
-      // If we have a valid image file path but no image fd, erase the image file.
-      if (image_fd < 0) {
-          if (unlink(image_path) < 0) {
-              if (errno != ENOENT) {
-                  PLOG(ERROR) << "Couldn't unlink image file " << image_path;
-              }
-          }
-      }
+    Dex2oatFileWrapper<std::function<void ()>> image_fd;
+    const std::string image_path = create_image_filename(out_oat_path);
+    if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED && !image_path.empty()) {
+        char app_image_format[kPropertyValueMax];
+        bool have_app_image_format =
+                get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+        // Use app images only if it is enabled (by a set image format) and we are compiling
+        // profile-guided (so the app image doesn't conservatively contain all classes).
+        if (profile_guided && have_app_image_format) {
+            // Recreate is true since we do not want to modify a mapped image. If the app is
+            // already running and we modify the image file, it can cause crashes (b/27493510).
+            image_fd.reset(open_output_file(image_path.c_str(),
+                                            true /*recreate*/,
+                                            0600 /*permissions*/),
+                           [image_path]() { unlink(image_path.c_str()); }
+                           );
+            if (image_fd.get() < 0) {
+                // Could not create application image file. Go on since we can compile without
+                // it.
+                LOG(ERROR) << "installd could not create '"
+                        << image_path
+                        << "' for image file during dexopt";
+            } else if (!set_permissions_and_ownership(image_fd.get(),
+                                                      is_public,
+                                                      uid,
+                                                      image_path.c_str())) {
+                image_fd.reset(-1);
+            }
+        }
+        // If we have a valid image file path but no image fd, explicitly erase the image file.
+        if (image_fd.get() < 0) {
+            if (unlink(image_path.c_str()) < 0) {
+                if (errno != ENOENT) {
+                    PLOG(ERROR) << "Couldn't unlink image file " << image_path;
+                }
+            }
+        }
     }
 
     ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file);
 
-    pid_t pid;
-    pid = fork();
+    pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
 
         SetDex2OatAndPatchOatScheduling(boot_complete);
-        if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) {
-            ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno));
-            exit(67);
+        if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
+            ALOGE("flock(%s) failed: %s\n", out_oat_path, strerror(errno));
+            _exit(67);
         }
 
         if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED
             || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) {
-            run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set);
+            run_patchoat(input_fd.get(),
+                         input_vdex_fd.get(),
+                         out_oat_fd.get(),
+                         out_vdex_fd.get(),
+                         input_file,
+                         in_vdex_path_str.c_str(),
+                         out_oat_path,
+                         out_vdex_path_str.c_str(),
+                         pkgname,
+                         instruction_set);
         } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) {
             // Pass dex2oat the relative path to the input file.
             const char *input_file_name = get_location_from_path(input_file);
-            run_dex2oat(input_fd, out_fd, image_fd, input_file_name, out_path, swap_fd,
-                        instruction_set, compiler_filter, vm_safe_mode, debuggable, boot_complete,
-                        reference_profile_fd, shared_libraries);
+            run_dex2oat(input_fd.get(),
+                        out_oat_fd.get(),
+                        out_vdex_fd.get(),
+                        image_fd.get(),
+                        input_file_name,
+                        out_oat_path,
+                        swap_fd.get(),
+                        instruction_set,
+                        compiler_filter,
+                        vm_safe_mode,
+                        debuggable,
+                        boot_complete,
+                        reference_profile_fd.get(),
+                        shared_libraries);
         } else {
             ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
-            exit(73);
+            _exit(73);
         }
-        exit(68);   /* only get here on exec failure */
+        _exit(68);   /* only get here on exec failure */
     } else {
-        res = wait_child(pid);
+        int res = wait_child(pid);
         if (res == 0) {
             ALOGV("DexInv: --- END '%s' (success) ---\n", input_file);
         } else {
             ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", input_file, res);
-            goto fail;
+            return -1;
         }
     }
 
+    struct utimbuf ut;
     ut.actime = input_stat.st_atime;
     ut.modtime = input_stat.st_mtime;
-    utime(out_path, &ut);
+    utime(out_oat_path, &ut);
 
-    close(out_fd);
-    close(input_fd);
-    if (swap_fd >= 0) {
-        close(swap_fd);
-    }
-    if (reference_profile_fd >= 0) {
-        close(reference_profile_fd);
-    }
-    if (image_fd >= 0) {
-        close(image_fd);
-    }
+    // We've been successful, don't delete output.
+    out_oat_fd.SetCleanup(false);
+    out_vdex_fd.SetCleanup(false);
+    image_fd.SetCleanup(false);
+    reference_profile_fd.SetCleanup(false);
+
     return 0;
-
-fail:
-    if (out_fd >= 0) {
-        close(out_fd);
-        unlink(out_path);
-    }
-    if (input_fd >= 0) {
-        close(input_fd);
-    }
-    if (reference_profile_fd >= 0) {
-        close(reference_profile_fd);
-        // We failed to compile. Unlink the reference profile. Current profiles are already unlinked
-        // when profmoan advises compilation.
-        clear_reference_profile(pkgname);
-    }
-    if (swap_fd >= 0) {
-        close(swap_fd);
-    }
-    if (image_fd >= 0) {
-        close(image_fd);
-    }
-    return -1;
 }
 
 int mark_boot_complete(const char* instruction_set)
@@ -1925,11 +2144,59 @@
     return true;
 }
 
+// Move/rename a B artifact (from) to an A artifact (to).
+static bool move_ab_path(const std::string& b_path, const std::string& a_path) {
+    // Check whether B exists.
+    {
+        struct stat s;
+        if (stat(b_path.c_str(), &s) != 0) {
+            // Silently ignore for now. The service calling this isn't smart enough to understand
+            // lack of artifacts at the moment.
+            return false;
+        }
+        if (!S_ISREG(s.st_mode)) {
+            LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
+            // Try to unlink, but swallow errors.
+            unlink(b_path.c_str());
+            return false;
+        }
+    }
+
+    // Rename B to A.
+    if (!unlink_and_rename(b_path.c_str(), a_path.c_str())) {
+        // Delete the b_path so we don't try again (or fail earlier).
+        if (unlink(b_path.c_str()) != 0) {
+            PLOG(ERROR) << "Could not unlink " << b_path;
+        }
+
+        return false;
+    }
+
+    return true;
+}
+
 int move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
     if (apk_path == nullptr || instruction_set == nullptr || oat_dir == nullptr) {
         LOG(ERROR) << "Cannot move_ab with null input";
         return -1;
     }
+
+    // Get the current slot suffix. No suffix, no A/B.
+    std::string slot_suffix;
+    {
+        char buf[kPropertyValueMax];
+        if (get_property("ro.boot.slot_suffix", buf, nullptr) <= 0) {
+            return -1;
+        }
+        slot_suffix = buf;
+
+        if (!ValidateTargetSlotSuffix(slot_suffix)) {
+            LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
+            return -1;
+        }
+    }
+
+    // Validate other inputs.
     if (validate_apk_path(apk_path) != 0) {
         LOG(ERROR) << "invalid apk_path " << apk_path;
         return -1;
@@ -1943,37 +2210,44 @@
     if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) {
         return -1;
     }
+    const std::string a_vdex_path = create_vdex_filename(a_path);
+    const std::string a_image_path = create_image_filename(a_path);
 
-    // B path = A path + ".b"
-    std::string b_path = StringPrintf("%s.b", a_path);
+    // B path = A path + slot suffix.
+    const std::string b_path = StringPrintf("%s.%s", a_path, slot_suffix.c_str());
+    const std::string b_vdex_path = StringPrintf("%s.%s", a_vdex_path.c_str(), slot_suffix.c_str());
+    const std::string b_image_path = StringPrintf("%s.%s",
+                                                  a_image_path.c_str(),
+                                                  slot_suffix.c_str());
 
-    // Check whether B exists.
-    {
-        struct stat s;
-        if (stat(b_path.c_str(), &s) != 0) {
-            // Silently ignore for now. The service calling this isn't smart enough to understand
-            // lack of artifacts at the moment.
-            return -1;
+    bool success = true;
+    if (move_ab_path(b_path, a_path)) {
+        if (move_ab_path(b_vdex_path, a_vdex_path)) {
+            // Note: we can live without an app image. As such, ignore failure to move the image file.
+            //       If we decide to require the app image, or the app image being moved correctly,
+            //       then change accordingly.
+            constexpr bool kIgnoreAppImageFailure = true;
+
+            if (!a_image_path.empty()) {
+                if (!move_ab_path(b_image_path, a_image_path)) {
+                    if (!kIgnoreAppImageFailure) {
+                        success = false;
+                    }
+                }
+            }
+        } else {
+            // Cleanup: delete B image, ignore errors.
+            unlink(b_image_path.c_str());
+            success = false;
         }
-        if (!S_ISREG(s.st_mode)) {
-            LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
-            // Try to unlink, but swallow errors.
-            unlink(b_path.c_str());
-            return -1;
-        }
+    } else {
+        // Cleanup: delete B image, ignore errors.
+        unlink(b_vdex_path.c_str());
+        unlink(b_image_path.c_str());
+        success = false;
     }
 
-    // Rename B to A.
-    if (!unlink_and_rename(b_path.c_str(), a_path)) {
-        // Delete the b_path so we don't try again (or fail earlier).
-        if (unlink(b_path.c_str()) != 0) {
-            PLOG(ERROR) << "Could not unlink " << b_path;
-        }
-
-        return -1;
-    }
-
-    return 0;
+    return success ? 0 : -1;
 }
 
 }  // namespace installd
diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h
index 7a42c5c..e990f1b 100644
--- a/cmds/installd/commands.h
+++ b/cmds/installd/commands.h
@@ -28,6 +28,8 @@
 namespace android {
 namespace installd {
 
+static constexpr size_t DEXOPT_PARAM_COUNT = 10U;
+
 int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
         appid_t appid, const char* seinfo, int target_sdk_version);
 int restorecon_app_data(const char* uuid, const char* pkgName, userid_t userid, int flags,
@@ -56,9 +58,21 @@
 
 bool dump_profile(uid_t uid, const char *pkgname, const char *dex_files);
 
-int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
-           int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
-           const char* volume_uuid, const char* shared_libraries);
+int dexopt(const char *apk_path,
+           uid_t uid,
+           const char *pkgName,
+           const char *instruction_set,
+           int dexopt_needed,
+           const char* oat_dir,
+           int dexopt_flags,
+           const char* compiler_filter,
+           const char* volume_uuid,
+           const char* shared_libraries);
+static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param size");
+
+// Helper for the above, converting arguments.
+int dexopt(const char* const params[DEXOPT_PARAM_COUNT]);
+
 int mark_boot_complete(const char *instruction_set);
 int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId);
 int idmap(const char *target_path, const char *overlay_path, uid_t uid);
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index 6a67e29..93e1ce5 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -30,6 +30,22 @@
 namespace android {
 namespace installd {
 
+static constexpr const char* APP_SUBDIR = "app/"; // sub-directory under ANDROID_DATA
+
+static constexpr const char* PRIV_APP_SUBDIR = "priv-app/"; // sub-directory under ANDROID_DATA
+
+static constexpr const char* EPHEMERAL_APP_SUBDIR = "app-ephemeral/"; // sub-directory under
+                                                                      // ANDROID_DATA
+
+static constexpr const char* APP_LIB_SUBDIR = "app-lib/"; // sub-directory under ANDROID_DATA
+
+static constexpr const char* MEDIA_SUBDIR = "media/"; // sub-directory under ANDROID_DATA
+
+static constexpr const char* PROFILES_SUBDIR = "misc/profiles"; // sub-directory under ANDROID_DATA
+
+static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
+                                                                  // ANDROID_DATA
+
 /* Directory records that are used in execution of commands. */
 dir_rec_t android_app_dir;
 dir_rec_t android_app_ephemeral_dir;
@@ -77,7 +93,7 @@
 
     // Get the android ephemeral app directory.
     if (copy_and_append(&android_app_ephemeral_dir, &android_data_dir, EPHEMERAL_APP_SUBDIR) < 0) {
-        return -1;
+        return false;
     }
 
     // Get the android app native library directory.
@@ -86,7 +102,7 @@
     }
 
     // Get the sd-card ASEC mount point.
-    if (get_path_from_env(&android_asec_dir, "ASEC_MOUNTPOINT") < 0) {
+    if (get_path_from_env(&android_asec_dir, ASEC_MOUNTPOINT_ENV_NAME) < 0) {
         return false;
     }
 
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index 3e52346..c90beec 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -23,6 +23,11 @@
 namespace android {
 namespace installd {
 
+/* constants */
+
+// Name of the environment variable that contains the asec mountpoint.
+static constexpr const char* ASEC_MOUNTPOINT_ENV_NAME = "ASEC_MOUNTPOINT";
+
 /* data structures */
 
 struct dir_rec_t {
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 1583f86..531c6df 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -151,12 +151,11 @@
         return false;
     }
 
-    sprintf(path,"%s%s/%s/%s%s",
+    sprintf(path,"%s%s/%s/%s",
             android_data_dir.path,
             DALVIK_CACHE,
             instruction_set,
-            src + 1, /* skip the leading / */
-            DALVIK_CACHE_POSTFIX);
+            src + 1 /* skip the leading / */);
 
     char* tmp =
             path +
@@ -171,6 +170,7 @@
         }
     }
 
+    strcat(path, DALVIK_CACHE_POSTFIX);
     return true;
 }
 
@@ -219,7 +219,8 @@
 // We use otapreopt_chroot to get into the chroot.
 static constexpr const char* kOtaPreopt = "/system/bin/otapreopt_chroot";
 
-static int do_ota_dexopt(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
+static int do_ota_dexopt(const char* args[DEXOPT_PARAM_COUNT],
+                         char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
     // Time to fork and run otapreopt.
 
     // Check that the tool exists.
@@ -231,12 +232,14 @@
 
     pid_t pid = fork();
     if (pid == 0) {
-        const char* argv[1 + 9 + 1];
+        const char* argv[1 + DEXOPT_PARAM_COUNT + 1];
         argv[0] = kOtaPreopt;
-        for (size_t i = 1; i <= 9; ++i) {
-            argv[i] = arg[i - 1];
+
+        for (size_t i = 0; i < DEXOPT_PARAM_COUNT; ++i) {
+            argv[i + 1] = args[i];
         }
-        argv[10] = nullptr;
+
+        argv[DEXOPT_PARAM_COUNT + 1] = nullptr;
 
         execv(argv[0], (char * const *)argv);
         PLOG(ERROR) << "execv(OTAPREOPT_CHROOT) failed";
@@ -252,22 +255,30 @@
     }
 }
 
+static int do_regular_dexopt(const char* args[DEXOPT_PARAM_COUNT],
+                             char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
+    return dexopt(args);
+}
+
+using DexoptFn = int (*)(const char* args[DEXOPT_PARAM_COUNT],
+                         char reply[REPLY_MAX]);
+
 static int do_dexopt(char **arg, char reply[REPLY_MAX])
 {
-    int dexopt_flags = atoi(arg[6]);
-    if ((dexopt_flags & DEXOPT_OTA) != 0) {
-      return do_ota_dexopt(arg, reply);
+    const char* args[DEXOPT_PARAM_COUNT];
+    for (size_t i = 0; i < DEXOPT_PARAM_COUNT; ++i) {
+        CHECK(arg[i] != nullptr);
+        args[i] = arg[i];
     }
-    return dexopt(arg[0],                      // apk_path
-                  atoi(arg[1]),                // uid
-                  arg[2],                      // pkgname
-                  arg[3],                      // instruction_set
-                  atoi(arg[4]),                // dexopt_needed
-                  arg[5],                      // oat_dir
-                  dexopt_flags,
-                  arg[7],                      // compiler_filter
-                  parse_null(arg[8]),          // volume_uuid
-                  parse_null(arg[9]));         // shared_libraries
+
+    int dexopt_flags = atoi(arg[6]);
+    DexoptFn dexopt_fn;
+    if ((dexopt_flags & DEXOPT_OTA) != 0) {
+        dexopt_fn = do_ota_dexopt;
+    } else {
+        dexopt_fn = do_regular_dexopt;
+    }
+    return dexopt_fn(args, reply);
 }
 
 static int do_merge_profiles(char **arg, char reply[REPLY_MAX])
@@ -546,7 +557,7 @@
     return 0;
 }
 
-bool initialize_globals() {
+static bool initialize_globals() {
     const char* data_path = getenv("ANDROID_DATA");
     if (data_path == nullptr) {
         ALOGE("Could not find ANDROID_DATA");
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 8513695..b0bcce9 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -26,51 +26,13 @@
 constexpr const char* PRIMARY_USER_PREFIX = "data/";
 constexpr const char* SECONDARY_USER_PREFIX = "user/";
 
-constexpr const char* PKG_DIR_POSTFIX = "";
-
-constexpr const char* PKG_LIB_POSTFIX = "/lib";
-
-constexpr const char* CACHE_DIR_POSTFIX = "/cache";
-constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
-
-constexpr const char* APP_SUBDIR = "app/"; // sub-directory under ANDROID_DATA
-constexpr const char* PRIV_APP_SUBDIR = "priv-app/"; // sub-directory under ANDROID_DATA
-constexpr const char* EPHEMERAL_APP_SUBDIR = "app-ephemeral/"; // sub-directory under ANDROID_DATA
-
-constexpr const char* APP_LIB_SUBDIR = "app-lib/"; // sub-directory under ANDROID_DATA
-
-constexpr const char* MEDIA_SUBDIR = "media/"; // sub-directory under ANDROID_DATA
-
-constexpr const char* PROFILES_SUBDIR = "misc/profiles"; // sub-directory under ANDROID_DATA
-
-/* other handy constants */
-
-constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under ANDROID_DATA
-
 // This is used as a string literal, can't be constants. TODO: std::string...
 #define DALVIK_CACHE "dalvik-cache"
-constexpr const char* DALVIK_CACHE_POSTFIX = "/classes.dex";
-constexpr const char* DALVIK_CACHE_POSTFIX2 = "@classes.dex";
-
-constexpr const char* IDMAP_PREFIX = "/data/resource-cache/";
-constexpr const char* IDMAP_SUFFIX = "@idmap";
+constexpr const char* DALVIK_CACHE_POSTFIX = "@classes.dex";
 
 constexpr size_t PKG_NAME_MAX = 128u;   /* largest allowed package name */
 constexpr size_t PKG_PATH_MAX = 256u;   /* max size of any path we use */
 
-// NOTE: keep in sync with StorageManager
-constexpr int FLAG_STORAGE_DE = 1 << 0;
-constexpr int FLAG_STORAGE_CE = 1 << 1;
-
-// NOTE: keep in sync with Installer
-constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
-constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
-
-/* dexopt needed flags matching those in dalvik.system.DexFile */
-constexpr int DEXOPT_DEX2OAT_NEEDED       = 1;
-constexpr int DEXOPT_PATCHOAT_NEEDED      = 2;
-constexpr int DEXOPT_SELF_PATCHOAT_NEEDED = 3;
-
 /****************************************************************************
  * IMPORTANT: These values are passed from Java code. Keep them in sync with
  * frameworks/base/services/core/java/com/android/server/pm/Installer.java
diff --git a/cmds/installd/installd_deps.h b/cmds/installd/installd_deps.h
index 5ff46e6..5093178 100644
--- a/cmds/installd/installd_deps.h
+++ b/cmds/installd/installd_deps.h
@@ -57,9 +57,6 @@
                               const char *src,
                               const char *instruction_set);
 
-// Initialize globals. May be implemented with the helper in globals.h.
-extern bool initialize_globals();
-
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 3f76770..7e02b6b 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -30,6 +30,7 @@
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <cutils/fs.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
@@ -39,7 +40,7 @@
 #include <file_parsing.h>
 #include <globals.h>
 #include <installd_deps.h>  // Need to fill in requirements of commands.
-#include <string_helpers.h>
+#include <otapreopt_utils.h>
 #include <system_properties.h>
 #include <utils.h>
 
@@ -51,16 +52,15 @@
 #define TOKEN_MAX     16    /* max number of arguments in buffer */
 #define REPLY_MAX     256   /* largest reply allowed */
 
+using android::base::EndsWith;
+using android::base::Join;
+using android::base::Split;
+using android::base::StartsWith;
 using android::base::StringPrintf;
 
 namespace android {
 namespace installd {
 
-static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH";
-static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT";
-static constexpr const char* kOTARootDirectory = "/system-b";
-static constexpr size_t kISAIndex = 3;
-
 template<typename T>
 static constexpr T RoundDown(T x, typename std::decay<T>::type n) {
     return DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0))(x & -n);
@@ -73,8 +73,6 @@
 
 class OTAPreoptService {
  public:
-    static constexpr const char* kOTADataDirectory = "/data/ota";
-
     // Main driver. Performs the following steps.
     //
     // 1) Parse options (read system properties etc from B partition).
@@ -87,26 +85,31 @@
     //
     // 5) Run update.
     int Main(int argc, char** argv) {
+        if (!ReadArguments(argc, argv)) {
+            LOG(ERROR) << "Failed reading command line.";
+            return 1;
+        }
+
         if (!ReadSystemProperties()) {
             LOG(ERROR)<< "Failed reading system properties.";
-            return 1;
+            return 2;
         }
 
         if (!ReadEnvironment()) {
             LOG(ERROR) << "Failed reading environment properties.";
-            return 2;
+            return 3;
         }
 
-        if (!ReadPackage(argc, argv)) {
-            LOG(ERROR) << "Failed reading command line file.";
-            return 3;
+        if (!CheckAndInitializeInstalldGlobals()) {
+            LOG(ERROR) << "Failed initializing globals.";
+            return 4;
         }
 
         PrepareEnvironment();
 
-        if (!PrepareBootImage()) {
+        if (!PrepareBootImage(/* force */ false)) {
             LOG(ERROR) << "Failed preparing boot image.";
-            return 4;
+            return 5;
         }
 
         int dexopt_retcode = RunPreopt();
@@ -114,7 +117,7 @@
         return dexopt_retcode;
     }
 
-    int GetProperty(const char* key, char* value, const char* default_value) {
+    int GetProperty(const char* key, char* value, const char* default_value) const {
         const std::string* prop_value = system_properties_.GetProperty(key);
         if (prop_value == nullptr) {
             if (default_value == nullptr) {
@@ -131,7 +134,16 @@
         return static_cast<int>(size);
     }
 
+    std::string GetOTADataDirectory() const {
+        return StringPrintf("%s/%s", GetOtaDirectoryPrefix().c_str(), target_slot_.c_str());
+    }
+
+    const std::string& GetTargetSlot() const {
+        return target_slot_;
+    }
+
 private:
+
     bool ReadSystemProperties() {
         static constexpr const char* kPropertyFiles[] = {
                 "/default.prop", "/system/build.prop"
@@ -173,27 +185,106 @@
             return false;
         }
 
-        // Check that we found important properties.
-        constexpr const char* kRequiredProperties[] = {
-                kBootClassPathPropertyName, kAndroidRootPathPropertyName
-        };
-        for (size_t i = 0; i < arraysize(kRequiredProperties); ++i) {
-            if (system_properties_.GetProperty(kRequiredProperties[i]) == nullptr) {
-                return false;
-            }
+        if (system_properties_.GetProperty(kAndroidDataPathPropertyName) == nullptr) {
+            return false;
+        }
+        android_data_ = *system_properties_.GetProperty(kAndroidDataPathPropertyName);
+
+        if (system_properties_.GetProperty(kAndroidRootPathPropertyName) == nullptr) {
+            return false;
+        }
+        android_root_ = *system_properties_.GetProperty(kAndroidRootPathPropertyName);
+
+        if (system_properties_.GetProperty(kBootClassPathPropertyName) == nullptr) {
+            return false;
+        }
+        boot_classpath_ = *system_properties_.GetProperty(kBootClassPathPropertyName);
+
+        if (system_properties_.GetProperty(ASEC_MOUNTPOINT_ENV_NAME) == nullptr) {
+            return false;
+        }
+        asec_mountpoint_ = *system_properties_.GetProperty(ASEC_MOUNTPOINT_ENV_NAME);
+
+        return true;
+    }
+
+    const std::string& GetAndroidData() const {
+        return android_data_;
+    }
+
+    const std::string& GetAndroidRoot() const {
+        return android_root_;
+    }
+
+    const std::string GetOtaDirectoryPrefix() const {
+        return GetAndroidData() + "/ota";
+    }
+
+    bool CheckAndInitializeInstalldGlobals() {
+        // init_globals_from_data_and_root requires "ASEC_MOUNTPOINT" in the environment. We
+        // do not use any datapath that includes this, but we'll still have to set it.
+        CHECK(system_properties_.GetProperty(ASEC_MOUNTPOINT_ENV_NAME) != nullptr);
+        int result = setenv(ASEC_MOUNTPOINT_ENV_NAME, asec_mountpoint_.c_str(), 0);
+        if (result != 0) {
+            LOG(ERROR) << "Could not set ASEC_MOUNTPOINT environment variable";
+            return false;
+        }
+
+        if (!init_globals_from_data_and_root(GetAndroidData().c_str(), GetAndroidRoot().c_str())) {
+            LOG(ERROR) << "Could not initialize globals; exiting.";
+            return false;
+        }
+
+        // This is different from the normal installd. We only do the base
+        // directory, the rest will be created on demand when each app is compiled.
+        if (access(GetOtaDirectoryPrefix().c_str(), R_OK) < 0) {
+            LOG(ERROR) << "Could not access " << GetOtaDirectoryPrefix();
+            return false;
         }
 
         return true;
     }
 
-    bool ReadPackage(int argc ATTRIBUTE_UNUSED, char** argv) {
+    bool ReadArguments(int argc ATTRIBUTE_UNUSED, char** argv) {
+        // Expected command line:
+        //   target-slot dexopt {DEXOPT_PARAMETERS}
+        // The DEXOPT_PARAMETERS are passed on to dexopt(), so we expect DEXOPT_PARAM_COUNT
+        // of them. We store them in package_parameters_ (size checks are done when
+        // parsing the special parameters and when copying into package_parameters_.
+
+        static_assert(DEXOPT_PARAM_COUNT == ARRAY_SIZE(package_parameters_),
+                      "Unexpected dexopt param count");
+
+        const char* target_slot_arg = argv[1];
+        if (target_slot_arg == nullptr) {
+            LOG(ERROR) << "Missing parameters";
+            return false;
+        }
+        // Sanitize value. Only allow (a-zA-Z0-9_)+.
+        target_slot_ = target_slot_arg;
+        if (!ValidateTargetSlotSuffix(target_slot_)) {
+            LOG(ERROR) << "Target slot suffix not legal: " << target_slot_;
+            return false;
+        }
+
+        // Check for "dexopt" next.
+        if (argv[2] == nullptr) {
+            LOG(ERROR) << "Missing parameters";
+            return false;
+        }
+        if (std::string("dexopt").compare(argv[2]) != 0) {
+            LOG(ERROR) << "Second parameter not dexopt: " << argv[2];
+            return false;
+        }
+
+        // Copy the rest into package_parameters_, but be careful about over- and underflow.
         size_t index = 0;
-        while (index < ARRAY_SIZE(package_parameters_) &&
-                argv[index + 1] != nullptr) {
-            package_parameters_[index] = argv[index + 1];
+        while (index < DEXOPT_PARAM_COUNT &&
+                argv[index + 3] != nullptr) {
+            package_parameters_[index] = argv[index + 3];
             index++;
         }
-        if (index != ARRAY_SIZE(package_parameters_)) {
+        if (index != ARRAY_SIZE(package_parameters_) || argv[index + 3] != nullptr) {
             LOG(ERROR) << "Wrong number of parameters";
             return false;
         }
@@ -202,15 +293,9 @@
     }
 
     void PrepareEnvironment() {
-        CHECK(system_properties_.GetProperty(kBootClassPathPropertyName) != nullptr);
-        const std::string& boot_cp =
-                *system_properties_.GetProperty(kBootClassPathPropertyName);
-        environ_.push_back(StringPrintf("BOOTCLASSPATH=%s", boot_cp.c_str()));
-        environ_.push_back(StringPrintf("ANDROID_DATA=%s", kOTADataDirectory));
-        CHECK(system_properties_.GetProperty(kAndroidRootPathPropertyName) != nullptr);
-        const std::string& android_root =
-                *system_properties_.GetProperty(kAndroidRootPathPropertyName);
-        environ_.push_back(StringPrintf("ANDROID_ROOT=%s", android_root.c_str()));
+        environ_.push_back(StringPrintf("BOOTCLASSPATH=%s", boot_classpath_.c_str()));
+        environ_.push_back(StringPrintf("ANDROID_DATA=%s", GetOTADataDirectory().c_str()));
+        environ_.push_back(StringPrintf("ANDROID_ROOT=%s", android_root_.c_str()));
 
         for (const std::string& e : environ_) {
             putenv(const_cast<char*>(e.c_str()));
@@ -219,7 +304,7 @@
 
     // Ensure that we have the right boot image. The first time any app is
     // compiled, we'll try to generate it.
-    bool PrepareBootImage() {
+    bool PrepareBootImage(bool force) const {
         if (package_parameters_[kISAIndex] == nullptr) {
             LOG(ERROR) << "Instruction set missing.";
             return false;
@@ -227,44 +312,114 @@
         const char* isa = package_parameters_[kISAIndex];
 
         // Check whether the file exists where expected.
-        std::string dalvik_cache = std::string(kOTADataDirectory) + "/" + DALVIK_CACHE;
+        std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
         std::string isa_path = dalvik_cache + "/" + isa;
         std::string art_path = isa_path + "/system@framework@boot.art";
         std::string oat_path = isa_path + "/system@framework@boot.oat";
-        if (access(art_path.c_str(), F_OK) == 0 &&
-                access(oat_path.c_str(), F_OK) == 0) {
-            // Files exist, assume everything is alright.
-            return true;
+        bool cleared = false;
+        if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
+            // Files exist, assume everything is alright if not forced. Otherwise clean up.
+            if (!force) {
+                return true;
+            }
+            ClearDirectory(isa_path);
+            cleared = true;
         }
 
+        // Reset umask in otapreopt, so that we control the the access for the files we create.
+        umask(0);
+
         // Create the directories, if necessary.
         if (access(dalvik_cache.c_str(), F_OK) != 0) {
-            if (mkdir(dalvik_cache.c_str(), 0711) != 0) {
-                PLOG(ERROR) << "Could not create dalvik-cache dir";
+            if (!CreatePath(dalvik_cache)) {
+                PLOG(ERROR) << "Could not create dalvik-cache dir " << dalvik_cache;
                 return false;
             }
         }
         if (access(isa_path.c_str(), F_OK) != 0) {
-            if (mkdir(isa_path.c_str(), 0711) != 0) {
+            if (!CreatePath(isa_path)) {
                 PLOG(ERROR) << "Could not create dalvik-cache isa dir";
                 return false;
             }
         }
 
         // Prepare to create.
-        // TODO: Delete files, just for a blank slate.
-        const std::string& boot_cp = *system_properties_.GetProperty(kBootClassPathPropertyName);
+        if (!cleared) {
+            ClearDirectory(isa_path);
+        }
 
         std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
         if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
           return PatchoatBootImage(art_path, isa);
         } else {
           // No preopted boot image. Try to compile.
-          return Dex2oatBootImage(boot_cp, art_path, oat_path, isa);
+          return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
         }
     }
 
-    bool PatchoatBootImage(const std::string& art_path, const char* isa) {
+    static bool CreatePath(const std::string& path) {
+        // Create the given path. Use string processing instead of dirname, as dirname's need for
+        // a writable char buffer is painful.
+
+        // First, try to use the full path.
+        if (mkdir(path.c_str(), 0711) == 0) {
+            return true;
+        }
+        if (errno != ENOENT) {
+            PLOG(ERROR) << "Could not create path " << path;
+            return false;
+        }
+
+        // Now find the parent and try that first.
+        size_t last_slash = path.find_last_of('/');
+        if (last_slash == std::string::npos || last_slash == 0) {
+            PLOG(ERROR) << "Could not create " << path;
+            return false;
+        }
+
+        if (!CreatePath(path.substr(0, last_slash))) {
+            return false;
+        }
+
+        if (mkdir(path.c_str(), 0711) == 0) {
+            return true;
+        }
+        PLOG(ERROR) << "Could not create " << path;
+        return false;
+    }
+
+    static void ClearDirectory(const std::string& dir) {
+        DIR* c_dir = opendir(dir.c_str());
+        if (c_dir == nullptr) {
+            PLOG(WARNING) << "Unable to open " << dir << " to delete it's contents";
+            return;
+        }
+
+        for (struct dirent* de = readdir(c_dir); de != nullptr; de = readdir(c_dir)) {
+            const char* name = de->d_name;
+            if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
+                continue;
+            }
+            // We only want to delete regular files and symbolic links.
+            std::string file = StringPrintf("%s/%s", dir.c_str(), name);
+            if (de->d_type != DT_REG && de->d_type != DT_LNK) {
+                LOG(WARNING) << "Unexpected file "
+                             << file
+                             << " of type "
+                             << std::hex
+                             << de->d_type
+                             << " encountered.";
+            } else {
+                // Try to unlink the file.
+                if (unlink(file.c_str()) != 0) {
+                    PLOG(ERROR) << "Unable to unlink " << file;
+                }
+            }
+        }
+        CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory.";
+    }
+
+    bool PatchoatBootImage(const std::string& art_path, const char* isa) const {
         // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
 
         std::vector<std::string> cmd;
@@ -290,12 +445,12 @@
     bool Dex2oatBootImage(const std::string& boot_cp,
                           const std::string& art_path,
                           const std::string& oat_path,
-                          const char* isa) {
+                          const char* isa) const {
         // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
         std::vector<std::string> cmd;
         cmd.push_back("/system/bin/dex2oat");
         cmd.push_back(StringPrintf("--image=%s", art_path.c_str()));
-        for (const std::string& boot_part : Split(boot_cp, ':')) {
+        for (const std::string& boot_part : Split(boot_cp, ":")) {
             cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str()));
         }
         cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str()));
@@ -324,7 +479,7 @@
         const std::string* extra_opts =
                 system_properties_.GetProperty("dalvik.vm.image-dex2oat-flags");
         if (extra_opts != nullptr) {
-            std::vector<std::string> extra_vals = Split(*extra_opts, ' ');
+            std::vector<std::string> extra_vals = Split(*extra_opts, " ");
             cmd.insert(cmd.end(), extra_vals.begin(), extra_vals.end());
         }
         // TODO: Should we lower this? It's usually set close to max, because
@@ -356,18 +511,81 @@
         return (strcmp(arg, "!") == 0) ? nullptr : arg;
     }
 
+    bool ShouldSkipPreopt() const {
+        // There's one thing we have to be careful about: we may/will be asked to compile an app
+        // living in the system image. This may be a valid request - if the app wasn't compiled,
+        // e.g., if the system image wasn't large enough to include preopted files. However, the
+        // data we have is from the old system, so the driver (the OTA service) can't actually
+        // know. Thus, we will get requests for apps that have preopted components. To avoid
+        // duplication (we'd generate files that are not used and are *not* cleaned up), do two
+        // simple checks:
+        //
+        // 1) Does the apk_path start with the value of ANDROID_ROOT? (~in the system image)
+        //    (For simplicity, assume the value of ANDROID_ROOT does not contain a symlink.)
+        //
+        // 2) If you replace the name in the apk_path with "oat," does the path exist?
+        //    (=have a subdirectory for preopted files)
+        //
+        // If the answer to both is yes, skip the dexopt.
+        //
+        // Note: while one may think it's OK to call dexopt and it will fail (because APKs should
+        //       be stripped), that's not true for APKs signed outside the build system (so the
+        //       jar content must be exactly the same).
+
+        //       (This is ugly as it's the only thing where we need to understand the contents
+        //        of package_parameters_, but it beats postponing the decision or using the call-
+        //        backs to do weird things.)
+        constexpr size_t kApkPathIndex = 0;
+        CHECK_GT(DEXOPT_PARAM_COUNT, kApkPathIndex);
+        CHECK(package_parameters_[kApkPathIndex] != nullptr);
+        if (StartsWith(package_parameters_[kApkPathIndex], android_root_.c_str())) {
+            const char* last_slash = strrchr(package_parameters_[kApkPathIndex], '/');
+            if (last_slash != nullptr) {
+                std::string path(package_parameters_[kApkPathIndex],
+                                 last_slash - package_parameters_[kApkPathIndex] + 1);
+                CHECK(EndsWith(path, "/"));
+                path = path + "oat";
+                if (access(path.c_str(), F_OK) == 0) {
+                    return true;
+                }
+            }
+        }
+
+        // Another issue is unavailability of files in the new system. If the partition
+        // layout changes, otapreopt_chroot may not know about this. Then files from that
+        // partition will not be available and fail to build. This is problematic, as
+        // this tool will wipe the OTA artifact cache and try again (for robustness after
+        // a failed OTA with remaining cache artifacts).
+        if (access(package_parameters_[kApkPathIndex], F_OK) != 0) {
+            LOG(WARNING) << "Skipping preopt of non-existing package "
+                         << package_parameters_[kApkPathIndex];
+            return true;
+        }
+
+        return false;
+    }
+
     int RunPreopt() {
-        int ret = dexopt(package_parameters_[0],          // apk_path
-                atoi(package_parameters_[1]),             // uid
-                package_parameters_[2],                   // pkgname
-                package_parameters_[3],                   // instruction_set
-                atoi(package_parameters_[4]),             // dexopt_needed
-                package_parameters_[5],                   // oat_dir
-                atoi(package_parameters_[6]),             // dexopt_flags
-                package_parameters_[7],                   // compiler_filter
-                ParseNull(package_parameters_[8]),        // volume_uuid
-                ParseNull(package_parameters_[9]));       // shared_libraries
-        return ret;
+        if (ShouldSkipPreopt()) {
+            return 0;
+        }
+
+        int dexopt_result = dexopt(package_parameters_);
+        if (dexopt_result == 0) {
+            return 0;
+        }
+
+        // If the dexopt failed, we may have a stale boot image from a previous OTA run.
+        // Try to delete and retry.
+
+        if (!PrepareBootImage(/* force */ true)) {
+            LOG(ERROR) << "Forced boot image creating failed. Original error return was "
+                         << dexopt_result;
+            return dexopt_result;
+        }
+
+        LOG(WARNING) << "Original dexopt failed, re-trying after boot image was regenerated.";
+        return dexopt(package_parameters_);
     }
 
     ////////////////////////////////////
@@ -375,8 +593,8 @@
     ////////////////////////////////////
 
     // Wrapper on fork/execv to run a command in a subprocess.
-    bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
-        const std::string command_line(Join(arg_vector, ' '));
+    static bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
+        const std::string command_line = Join(arg_vector, ' ');
 
         CHECK_GE(arg_vector.size(), 1U) << command_line;
 
@@ -465,9 +683,8 @@
     void AddCompilerOptionFromSystemProperty(const char* system_property,
             const char* prefix,
             bool runtime,
-            std::vector<std::string>& out) {
-        const std::string* value =
-        system_properties_.GetProperty(system_property);
+            std::vector<std::string>& out) const {
+        const std::string* value = system_properties_.GetProperty(system_property);
         if (value != nullptr) {
             if (runtime) {
                 out.push_back("--runtime-arg");
@@ -480,11 +697,25 @@
         }
     }
 
+    static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH";
+    static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT";
+    static constexpr const char* kAndroidDataPathPropertyName = "ANDROID_DATA";
+    // The index of the instruction-set string inside the package parameters. Needed for
+    // some special-casing that requires knowledge of the instruction-set.
+    static constexpr size_t kISAIndex = 3;
+
     // Stores the system properties read out of the B partition. We need to use these properties
     // to compile, instead of the A properties we could get from init/get_property.
     SystemProperties system_properties_;
 
-    const char* package_parameters_[10];
+    // Some select properties that are always needed.
+    std::string target_slot_;
+    std::string android_root_;
+    std::string android_data_;
+    std::string boot_classpath_;
+    std::string asec_mountpoint_;
+
+    const char* package_parameters_[DEXOPT_PARAM_COUNT];
 
     // Store environment values we need to set.
     std::vector<std::string> environ_;
@@ -497,7 +728,6 @@
 ////////////////////////
 
 int get_property(const char *key, char *value, const char *default_value) {
-    // TODO: Replace with system-properties map.
     return gOps.GetProperty(key, value, default_value);
 }
 
@@ -505,7 +735,6 @@
 bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir,
                              const char *apk_path,
                              const char *instruction_set) {
-    // TODO: Insert B directory.
     const char *file_name_start;
     const char *file_name_end;
 
@@ -526,8 +755,13 @@
     std::string file_name(file_name_start, file_name_len);
 
     // <apk_parent_dir>/oat/<isa>/<file_name>.odex.b
-    snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex.b", oat_dir, instruction_set,
-             file_name.c_str());
+    snprintf(path,
+             PKG_PATH_MAX,
+             "%s/%s/%s.odex.%s",
+             oat_dir,
+             instruction_set,
+             file_name.c_str(),
+             gOps.GetTargetSlot().c_str());
     return true;
 }
 
@@ -539,11 +773,6 @@
  */
 bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
                               const char *instruction_set) {
-    if (StringPrintf("%soat/%s/odex.b", apk_path, instruction_set).length() + 1 > PKG_PATH_MAX) {
-        ALOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
-        return false;
-    }
-
     const char *path_end = strrchr(apk_path, '/');
     if (path_end == nullptr) {
         ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
@@ -559,11 +788,15 @@
     }
     std::string name_component(name_begin, extension_start - name_begin);
 
-    std::string new_path = StringPrintf("%s/oat/%s/%s.odex.b",
+    std::string new_path = StringPrintf("%s/oat/%s/%s.odex.%s",
                                         path_component.c_str(),
                                         instruction_set,
-                                        name_component.c_str());
-    CHECK_LT(new_path.length(), PKG_PATH_MAX);
+                                        name_component.c_str(),
+                                        gOps.GetTargetSlot().c_str());
+    if (new_path.length() >= PKG_PATH_MAX) {
+        LOG(ERROR) << "apk_path of " << apk_path << " is too long: " << new_path;
+        return false;
+    }
     strcpy(path, new_path.c_str());
     return true;
 }
@@ -586,11 +819,11 @@
     std::replace(from_src.begin(), from_src.end(), '/', '@');
 
     std::string assembled_path = StringPrintf("%s/%s/%s/%s%s",
-                                              OTAPreoptService::kOTADataDirectory,
+                                              gOps.GetOTADataDirectory().c_str(),
                                               DALVIK_CACHE,
                                               instruction_set,
                                               from_src.c_str(),
-                                              DALVIK_CACHE_POSTFIX2);
+                                              DALVIK_CACHE_POSTFIX);
 
     if (assembled_path.length() + 1 > PKG_PATH_MAX) {
         return false;
@@ -600,27 +833,6 @@
     return true;
 }
 
-bool initialize_globals() {
-    const char* data_path = getenv("ANDROID_DATA");
-    if (data_path == nullptr) {
-        ALOGE("Could not find ANDROID_DATA");
-        return false;
-    }
-    return init_globals_from_data_and_root(data_path, kOTARootDirectory);
-}
-
-static bool initialize_directories() {
-    // This is different from the normal installd. We only do the base
-    // directory, the rest will be created on demand when each app is compiled.
-    mode_t old_umask = umask(0);
-    LOG(INFO) << "Old umask: " << old_umask;
-    if (access(OTAPreoptService::kOTADataDirectory, R_OK) < 0) {
-        ALOGE("Could not access %s\n", OTAPreoptService::kOTADataDirectory);
-        return false;
-    }
-    return true;
-}
-
 static int log_callback(int type, const char *fmt, ...) {
     va_list ap;
     int priority;
@@ -648,8 +860,6 @@
     setenv("ANDROID_LOG_TAGS", "*:v", 1);
     android::base::InitLogging(argv);
 
-    ALOGI("otapreopt firing up\n");
-
     if (argc < 2) {
         ALOGE("Expecting parameters");
         exit(1);
@@ -659,16 +869,6 @@
     cb.func_log = log_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
-    if (!initialize_globals()) {
-        ALOGE("Could not initialize globals; exiting.\n");
-        exit(1);
-    }
-
-    if (!initialize_directories()) {
-        ALOGE("Could not create directories; exiting.\n");
-        exit(1);
-    }
-
     if (selinux_enabled && selinux_status_open(true) < 0) {
         ALOGE("Could not open selinux status; exiting.\n");
         exit(1);
diff --git a/cmds/installd/otapreopt.rc b/cmds/installd/otapreopt.rc
new file mode 100644
index 0000000..059ae75
--- /dev/null
+++ b/cmds/installd/otapreopt.rc
@@ -0,0 +1,8 @@
+# When /data is available, look for A/B artifacts for the current slot and move them
+# into the dalvik-cache (relabeling them).
+on post-fs-data
+    exec - root -- /system/bin/otapreopt_slot
+    # The dalvik-cache was not moved itself, so as to restrict the rights of otapreopt_slot.
+    # But now the relabeling is annoying as there is no force option available here. So
+    # explicitly list all the ISAs we know.
+    restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/mips /data/dalvik-cache/mips64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index f7f69a9..5ea89e6 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -14,14 +14,20 @@
  ** limitations under the License.
  */
 
+#include <fcntl.h>
 #include <linux/unistd.h>
 #include <sys/mount.h>
 #include <sys/wait.h>
 
+#include <sstream>
+
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 
+#include <commands.h>
+#include <otapreopt_utils.h>
+
 #ifndef LOG_TAG
 #define LOG_TAG "otapreopt"
 #endif
@@ -31,7 +37,37 @@
 namespace android {
 namespace installd {
 
+static void CloseDescriptor(int fd) {
+    if (fd >= 0) {
+        int result = close(fd);
+        UNUSED(result);  // Ignore result. Printing to logcat will open a new descriptor
+                         // that we do *not* want.
+    }
+}
+
+static void CloseDescriptor(const char* descriptor_string) {
+    int fd = -1;
+    std::istringstream stream(descriptor_string);
+    stream >> fd;
+    if (!stream.fail()) {
+        CloseDescriptor(fd);
+    }
+}
+
+// Entry for otapreopt_chroot. Expected parameters are:
+//   [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
+// The file descriptor denoted by status-fd will be closed. The rest of the parameters will
+// be passed on to otapreopt in the chroot.
 static int otapreopt_chroot(const int argc, char **arg) {
+    // Close all file descriptors. They are coming from the caller, we do not want to pass them
+    // on across our fork/exec into a different domain.
+    // 1) Default descriptors.
+    CloseDescriptor(STDIN_FILENO);
+    CloseDescriptor(STDOUT_FILENO);
+    CloseDescriptor(STDERR_FILENO);
+    // 2) The status channel.
+    CloseDescriptor(arg[1]);
+
     // We need to run the otapreopt tool from the postinstall partition. As such, set up a
     // mount namespace and change root.
 
@@ -59,6 +95,28 @@
         }
     }
 
+    // Try to mount the vendor partition. update_engine doesn't do this for us, but we
+    // want it for vendor APKs.
+    // Notes:
+    //  1) We pretty much guess a name here and hope to find the partition by name.
+    //     It is just as complicated and brittle to scan /proc/mounts. But this requires
+    //     validating the target-slot so as not to try to mount some totally random path.
+    //  2) We're in a mount namespace here, so when we die, this will be cleaned up.
+    //  3) Ignore errors. Printing anything at this stage will open a file descriptor
+    //     for logging.
+    if (!ValidateTargetSlotSuffix(arg[2])) {
+        LOG(ERROR) << "Target slot suffix not legal: " << arg[2];
+        exit(207);
+    }
+    std::string vendor_partition = StringPrintf("/dev/block/bootdevice/by-name/vendor%s",
+                                                arg[2]);
+    int vendor_result = mount(vendor_partition.c_str(),
+                              "/postinstall/vendor",
+                              "ext4",
+                              MS_RDONLY,
+                              /* data */ nullptr);
+    UNUSED(vendor_result);
+
     // Chdir into /postinstall.
     if (chdir("/postinstall") != 0) {
         PLOG(ERROR) << "Unable to chdir into /postinstall.";
@@ -78,13 +136,42 @@
 
     // Now go on and run otapreopt.
 
-    const char* argv[1 + 9 + 1];
-    CHECK_EQ(argc, 10);
-    argv[0] = "/system/bin/otapreopt";
-    for (size_t i = 1; i <= 9; ++i) {
-        argv[i] = arg[i];
+    // Incoming:  cmd + status-fd + target-slot + "dexopt" + dexopt-params + null
+    // Outgoing:  cmd             + target-slot + "dexopt" + dexopt-params + null
+    constexpr size_t kInArguments =   1                       // Binary name.
+                                    + 1                       // status file descriptor.
+                                    + 1                       // target-slot.
+                                    + 1                       // "dexopt."
+                                    + DEXOPT_PARAM_COUNT      // dexopt parameters.
+                                    + 1;                      // null termination.
+    constexpr size_t kOutArguments =   1                       // Binary name.
+                                     + 1                       // target-slot.
+                                     + 1                       // "dexopt."
+                                     + DEXOPT_PARAM_COUNT      // dexopt parameters.
+                                     + 1;                      // null termination.
+    const char* argv[kOutArguments];
+    if (static_cast<size_t>(argc) !=  kInArguments - 1 /* null termination */) {
+        LOG(ERROR) << "Unexpected argument size "
+                   << argc
+                   << " vs "
+                   << (kInArguments - 1);
+        for (size_t i = 0; i < static_cast<size_t>(argc); ++i) {
+            if (arg[i] == nullptr) {
+                LOG(ERROR) << "(null)";
+            } else {
+                LOG(ERROR) << "\"" << arg[i] << "\"";
+            }
+        }
+        exit(206);
     }
-    argv[10] = nullptr;
+    argv[0] = "/system/bin/otapreopt";
+
+    // The first parameter is the status file descriptor, skip.
+
+    for (size_t i = 1; i <= kOutArguments - 2 /* cmd + null */; ++i) {
+        argv[i] = arg[i + 1];
+    }
+    argv[kOutArguments - 1] = nullptr;
 
     execv(argv[0], (char * const *)argv);
     PLOG(ERROR) << "execv(OTAPREOPT) failed.";
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
index a31734a..f950276 100644
--- a/cmds/installd/otapreopt_script.sh
+++ b/cmds/installd/otapreopt_script.sh
@@ -18,24 +18,62 @@
 
 # This script will run as a postinstall step to drive otapreopt.
 
+TARGET_SLOT="$1"
+STATUS_FD="$2"
+
 # Maximum number of packages/steps.
 MAXIMUM_PACKAGES=1000
 
-PREPARE=$(cmd otadexopt prepare)
-if [ "$PREPARE" != "Success" ] ; then
-  echo "Failed to prepare."
+# First ensure the system is booted. This is to work around issues when cmd would
+# infinitely loop trying to get a service manager (which will never come up in that
+# mode). b/30797145
+BOOT_PROPERTY_NAME="dev.bootcomplete"
+
+BOOT_COMPLETE=$(getprop $BOOT_PROPERTY_NAME)
+if [ "$BOOT_COMPLETE" != "1" ] ; then
+  echo "Error: boot-complete not detected."
+  # We must return 0 to not block sideload.
+  exit 0
+fi
+
+
+# Compute target slot suffix.
+# TODO: Once bootctl is not restricted, we should query from there. Or get this from
+#       update_engine as a parameter.
+if [ "$TARGET_SLOT" = "0" ] ; then
+  TARGET_SLOT_SUFFIX="_a"
+elif [ "$TARGET_SLOT" = "1" ] ; then
+  TARGET_SLOT_SUFFIX="_b"
+else
+  echo "Unknown target slot $TARGET_SLOT"
   exit 1
 fi
 
+
+PREPARE=$(cmd otadexopt prepare)
+# Note: Ignore preparation failures. Step and done will fail and exit this.
+#       This is necessary to support suspends - the OTA service will keep
+#       the state around for us.
+
+PROGRESS=$(cmd otadexopt progress)
+print -u${STATUS_FD} "global_progress $PROGRESS"
+
 i=0
 while ((i<MAXIMUM_PACKAGES)) ; do
-  cmd otadexopt step
+  DEXOPT_PARAMS=$(cmd otadexopt next)
+
+  /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX $DEXOPT_PARAMS >&- 2>&-
+
+  PROGRESS=$(cmd otadexopt progress)
+  print -u${STATUS_FD} "global_progress $PROGRESS"
+
   DONE=$(cmd otadexopt done)
-  if [ "$DONE" = "OTA complete." ] ; then
-    break
+  if [ "$DONE" = "OTA incomplete." ] ; then
+    sleep 1
+    i=$((i+1))
+    continue
   fi
-  sleep 1
-  i=$((i+1))
+  break
 done
 
 DONE=$(cmd otadexopt done)
@@ -45,6 +83,7 @@
   echo "Complete or error."
 fi
 
+print -u${STATUS_FD} "global_progress 1.0"
 cmd otadexopt cleanup
 
 exit 0
diff --git a/cmds/installd/otapreopt_slot.sh b/cmds/installd/otapreopt_slot.sh
new file mode 100644
index 0000000..b5786e9
--- /dev/null
+++ b/cmds/installd/otapreopt_slot.sh
@@ -0,0 +1,39 @@
+#!/system/bin/sh
+
+#
+# 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.
+#
+
+# This script will move artifacts for the currently active slot.
+
+SLOT_SUFFIX=$(getprop ro.boot.slot_suffix)
+if test -n "$SLOT_SUFFIX" ; then
+  if test -d /data/ota/$SLOT_SUFFIX/dalvik-cache ; then
+    log -p i -t otapreopt_slot "Moving A/B artifacts for slot ${SLOT_SUFFIX}."
+    OLD_SIZE=$(du -h -s /data/dalvik-cache)
+    rm -rf /data/dalvik-cache/*
+    NEW_SIZE=$(du -h -s /data/ota/$SLOT_SUFFIX/dalvik-cache)
+    mv /data/ota/$SLOT_SUFFIX/dalvik-cache/* /data/dalvik-cache/
+    rmdir /data/ota/$SLOT_SUFFIX/dalvik-cache
+    rmdir /data/ota/$SLOT_SUFFIX
+    log -p i -t otapreopt_slot "Moved ${NEW_SIZE} over ${OLD_SIZE}"
+  else
+    log -p i -t otapreopt_slot "No A/B artifacts found for slot ${SLOT_SUFFIX}."
+  fi
+  exit 0
+else
+  log -p w -t otapreopt_slot "Slot property empty."
+  exit 1
+fi
diff --git a/cmds/installd/otapreopt_utils.h b/cmds/installd/otapreopt_utils.h
new file mode 100644
index 0000000..436e554
--- /dev/null
+++ b/cmds/installd/otapreopt_utils.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef OTAPREOPT_UTILS_H_
+#define OTAPREOPT_UTILS_H_
+
+#include <regex>
+
+namespace android {
+namespace installd {
+
+static inline bool ValidateTargetSlotSuffix(const std::string& input) {
+    std::regex slot_suffix_regex("[a-zA-Z0-9_]+");
+    std::smatch slot_suffix_match;
+    return std::regex_match(input, slot_suffix_match, slot_suffix_regex);
+}
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // OTAPREOPT_UTILS_H_
diff --git a/cmds/installd/string_helpers.h b/cmds/installd/string_helpers.h
deleted file mode 100644
index e8fcdef..0000000
--- a/cmds/installd/string_helpers.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef ART_OTAPREOPT_STRING_HELPERS_H_
-#define ART_OTAPREOPT_STRING_HELPERS_H_
-
-#include <sstream>
-#include <string>
-
-#include <android-base/macros.h>
-
-namespace android {
-namespace installd {
-
-static inline bool StringStartsWith(const std::string& target,
-                                    const char* prefix) {
-    return target.compare(0, strlen(prefix), prefix) == 0;
-}
-
-// Split the input according to the separator character. Doesn't honor quotation.
-static inline std::vector<std::string> Split(const std::string& in, const char separator) {
-    if (in.empty()) {
-        return std::vector<std::string>();
-    }
-
-    std::vector<std::string> ret;
-    std::stringstream strstr(in);
-    std::string token;
-
-    while (std::getline(strstr, token, separator)) {
-        ret.push_back(token);
-    }
-
-    return ret;
-}
-
-template <typename StringT>
-static inline std::string Join(const std::vector<StringT>& strings, char separator) {
-    if (strings.empty()) {
-        return "";
-    }
-
-    std::string result(strings[0]);
-    for (size_t i = 1; i < strings.size(); ++i) {
-        result += separator;
-        result += strings[i];
-    }
-    return result;
-}
-
-}  // namespace installd
-}  // namespace android
-
-#endif  // ART_OTAPREOPT_STRING_HELPERS_H_
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index bc150cb..dc8e675 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -31,6 +31,6 @@
         "service_manager.c",
         "binder.c",
     ],
-    shared_libs: ["libselinux"],
+    shared_libs: ["libcutils", "libselinux"],
     init_rc: ["servicemanager.rc"],
 }
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 21fdff0..68e3ceb 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -8,6 +8,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <cutils/multiuser.h>
+
 #include <private/android_filesystem_config.h>
 
 #include <selinux/android.h>
@@ -121,6 +123,11 @@
 static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
 {
     const char *perm = "add";
+
+    if (multiuser_get_app_id(uid) >= AID_APP) {
+        return 0; /* Don't allow apps to register services */
+    }
+
     return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
 }
 
diff --git a/include/gui/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h
index 69fe51e..62e3877 100644
--- a/include/gui/GraphicBufferAlloc.h
+++ b/include/gui/GraphicBufferAlloc.h
@@ -35,7 +35,7 @@
     virtual ~GraphicBufferAlloc();
     virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
             uint32_t height, PixelFormat format, uint32_t usage,
-            status_t* error);
+            std::string requestorName, status_t* error) override;
 };
 
 
diff --git a/include/gui/IGraphicBufferAlloc.h b/include/gui/IGraphicBufferAlloc.h
index f3c46ec..600cf27 100644
--- a/include/gui/IGraphicBufferAlloc.h
+++ b/include/gui/IGraphicBufferAlloc.h
@@ -21,14 +21,15 @@
 #include <sys/types.h>
 
 #include <binder/IInterface.h>
+#include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 #include <utils/RefBase.h>
 
+#include <string>
+
 namespace android {
 // ----------------------------------------------------------------------------
 
-class GraphicBuffer;
-
 class IGraphicBufferAlloc : public IInterface
 {
 public:
@@ -37,7 +38,13 @@
     /* Create a new GraphicBuffer for the client to use.
      */
     virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t usage, status_t* error) = 0;
+            PixelFormat format, uint32_t usage, std::string requestorName,
+            status_t* error) = 0;
+
+    sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+            PixelFormat format, uint32_t usage, status_t* error) {
+        return createGraphicBuffer(w, h, format, usage, "<Unknown>", error);
+    }
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/ui/Gralloc1.h b/include/ui/Gralloc1.h
new file mode 100644
index 0000000..cf8c173
--- /dev/null
+++ b/include/ui/Gralloc1.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_UI_GRALLOC1_H
+#define ANDROID_UI_GRALLOC1_H
+
+#define GRALLOC1_LOG_TAG "Gralloc1"
+
+#include <ui/Gralloc1On0Adapter.h>
+
+#include <unordered_set>
+
+namespace std {
+    template <>
+    struct hash<gralloc1_capability_t> {
+        size_t operator()(gralloc1_capability_t capability) const {
+            return std::hash<int32_t>()(static_cast<int32_t>(capability));
+        }
+    };
+}
+
+namespace android {
+
+class Fence;
+class GraphicBuffer;
+
+namespace Gralloc1 {
+
+class Device;
+
+class Descriptor {
+public:
+    Descriptor(Device& device, gralloc1_buffer_descriptor_t deviceId)
+      : mShimDevice(device),
+        mDeviceId(deviceId),
+        mWidth(0),
+        mHeight(0),
+        mFormat(static_cast<android_pixel_format_t>(0)),
+        mProducerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
+        mConsumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
+
+    ~Descriptor();
+
+    gralloc1_buffer_descriptor_t getDeviceId() const { return mDeviceId; }
+
+    gralloc1_error_t setDimensions(uint32_t width, uint32_t height);
+    gralloc1_error_t setFormat(android_pixel_format_t format);
+    gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage);
+    gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage);
+
+private:
+    Device& mShimDevice;
+    const gralloc1_buffer_descriptor_t mDeviceId;
+
+    uint32_t mWidth;
+    uint32_t mHeight;
+    android_pixel_format_t mFormat;
+    gralloc1_producer_usage_t mProducerUsage;
+    gralloc1_consumer_usage_t mConsumerUsage;
+
+}; // Descriptor
+
+class Device {
+    friend class Gralloc1::Descriptor;
+
+public:
+    Device(gralloc1_device_t* device);
+
+    bool hasCapability(gralloc1_capability_t capability) const;
+
+    std::string dump();
+
+    std::shared_ptr<Descriptor> createDescriptor();
+
+    gralloc1_error_t getStride(buffer_handle_t buffer, uint32_t* outStride);
+
+    gralloc1_error_t allocate(
+            const std::vector<std::shared_ptr<const Descriptor>>& descriptors,
+            std::vector<buffer_handle_t>* outBuffers);
+    gralloc1_error_t allocate(
+            const std::shared_ptr<const Descriptor>& descriptor,
+            gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
+
+    gralloc1_error_t retain(buffer_handle_t buffer);
+    gralloc1_error_t retain(const GraphicBuffer* buffer);
+
+    gralloc1_error_t release(buffer_handle_t buffer);
+
+    gralloc1_error_t getNumFlexPlanes(buffer_handle_t buffer,
+            uint32_t* outNumPlanes);
+
+    gralloc1_error_t lock(buffer_handle_t buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t* accessRegion, void** outData,
+            const sp<Fence>& acquireFence);
+    gralloc1_error_t lockFlex(buffer_handle_t buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t* accessRegion,
+            struct android_flex_layout* outData, const sp<Fence>& acquireFence);
+    gralloc1_error_t lockYCbCr(buffer_handle_t buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t* accessRegion, struct android_ycbcr* outData,
+            const sp<Fence>& acquireFence);
+
+    gralloc1_error_t unlock(buffer_handle_t buffer, sp<Fence>* outFence);
+
+private:
+    std::unordered_set<gralloc1_capability_t> loadCapabilities();
+
+    bool loadFunctions();
+
+    template <typename LockType, typename OutType>
+    gralloc1_error_t lockHelper(LockType pfn, buffer_handle_t buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t* accessRegion, OutType* outData,
+            const sp<Fence>& acquireFence) {
+        int32_t intError = pfn(mDevice, buffer,
+                static_cast<uint64_t>(producerUsage),
+                static_cast<uint64_t>(consumerUsage), accessRegion, outData,
+                acquireFence->dup());
+        return static_cast<gralloc1_error_t>(intError);
+    }
+
+    gralloc1_device_t* const mDevice;
+
+    const std::unordered_set<gralloc1_capability_t> mCapabilities;
+
+    template <typename PFN, gralloc1_function_descriptor_t descriptor>
+    struct FunctionLoader {
+        FunctionLoader() : pfn(nullptr) {}
+
+        bool load(gralloc1_device_t* device, bool errorIfNull) {
+            gralloc1_function_pointer_t rawPointer =
+                    device->getFunction(device, descriptor);
+            pfn = reinterpret_cast<PFN>(rawPointer);
+            if (errorIfNull && !rawPointer) {
+                ALOG(LOG_ERROR, GRALLOC1_LOG_TAG,
+                        "Failed to load function pointer %d", descriptor);
+            }
+            return rawPointer != nullptr;
+        }
+
+        template <typename ...Args>
+        typename std::result_of<PFN(Args...)>::type operator()(Args... args) {
+            return pfn(args...);
+        }
+
+        PFN pfn;
+    };
+
+    // Function pointers
+    struct Functions {
+        FunctionLoader<GRALLOC1_PFN_DUMP, GRALLOC1_FUNCTION_DUMP> dump;
+        FunctionLoader<GRALLOC1_PFN_CREATE_DESCRIPTOR,
+                GRALLOC1_FUNCTION_CREATE_DESCRIPTOR> createDescriptor;
+        FunctionLoader<GRALLOC1_PFN_DESTROY_DESCRIPTOR,
+                GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR> destroyDescriptor;
+        FunctionLoader<GRALLOC1_PFN_SET_CONSUMER_USAGE,
+                GRALLOC1_FUNCTION_SET_CONSUMER_USAGE> setConsumerUsage;
+        FunctionLoader<GRALLOC1_PFN_SET_DIMENSIONS,
+                GRALLOC1_FUNCTION_SET_DIMENSIONS> setDimensions;
+        FunctionLoader<GRALLOC1_PFN_SET_FORMAT,
+                GRALLOC1_FUNCTION_SET_FORMAT> setFormat;
+        FunctionLoader<GRALLOC1_PFN_SET_PRODUCER_USAGE,
+                GRALLOC1_FUNCTION_SET_PRODUCER_USAGE> setProducerUsage;
+        FunctionLoader<GRALLOC1_PFN_GET_BACKING_STORE,
+                GRALLOC1_FUNCTION_GET_BACKING_STORE> getBackingStore;
+        FunctionLoader<GRALLOC1_PFN_GET_CONSUMER_USAGE,
+                GRALLOC1_FUNCTION_GET_CONSUMER_USAGE> getConsumerUsage;
+        FunctionLoader<GRALLOC1_PFN_GET_DIMENSIONS,
+                GRALLOC1_FUNCTION_GET_DIMENSIONS> getDimensions;
+        FunctionLoader<GRALLOC1_PFN_GET_FORMAT,
+                GRALLOC1_FUNCTION_GET_FORMAT> getFormat;
+        FunctionLoader<GRALLOC1_PFN_GET_PRODUCER_USAGE,
+                GRALLOC1_FUNCTION_GET_PRODUCER_USAGE> getProducerUsage;
+        FunctionLoader<GRALLOC1_PFN_GET_STRIDE,
+                GRALLOC1_FUNCTION_GET_STRIDE> getStride;
+        FunctionLoader<GRALLOC1_PFN_ALLOCATE,
+                GRALLOC1_FUNCTION_ALLOCATE> allocate;
+        FunctionLoader<GRALLOC1_PFN_RETAIN,
+                GRALLOC1_FUNCTION_RETAIN> retain;
+        FunctionLoader<GRALLOC1_PFN_RELEASE,
+                GRALLOC1_FUNCTION_RELEASE> release;
+        FunctionLoader<GRALLOC1_PFN_GET_NUM_FLEX_PLANES,
+                GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES> getNumFlexPlanes;
+        FunctionLoader<GRALLOC1_PFN_LOCK,
+                GRALLOC1_FUNCTION_LOCK> lock;
+        FunctionLoader<GRALLOC1_PFN_LOCK_FLEX,
+                GRALLOC1_FUNCTION_LOCK_FLEX> lockFlex;
+        FunctionLoader<GRALLOC1_PFN_LOCK_YCBCR,
+                GRALLOC1_FUNCTION_LOCK_YCBCR> lockYCbCr;
+        FunctionLoader<GRALLOC1_PFN_UNLOCK,
+                GRALLOC1_FUNCTION_UNLOCK> unlock;
+
+        // Adapter-only functions
+        FunctionLoader<GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER,
+                GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER> retainGraphicBuffer;
+        FunctionLoader<GRALLOC1_PFN_ALLOCATE_WITH_ID,
+                GRALLOC1_FUNCTION_ALLOCATE_WITH_ID> allocateWithId;
+    } mFunctions;
+
+}; // class android::Gralloc1::Device
+
+class Loader
+{
+public:
+    Loader();
+    ~Loader();
+
+    std::unique_ptr<Device> getDevice();
+
+private:
+    static std::unique_ptr<Gralloc1On0Adapter> mAdapter;
+    std::unique_ptr<Device> mDevice;
+};
+
+} // namespace android::Gralloc1
+
+} // namespace android
+
+#endif
diff --git a/include/ui/Gralloc1On0Adapter.h b/include/ui/Gralloc1On0Adapter.h
new file mode 100644
index 0000000..97c9a89
--- /dev/null
+++ b/include/ui/Gralloc1On0Adapter.h
@@ -0,0 +1,481 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_UI_GRALLOC_1_ON_0_ADAPTER_H
+#define ANDROID_UI_GRALLOC_1_ON_0_ADAPTER_H
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include <hardware/gralloc1.h>
+
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+struct gralloc_module_t;
+
+// This is not an "official" capability (i.e., it is not found in gralloc1.h),
+// but we will use it to detect that we are running through the adapter, which
+// is capable of collaborating with GraphicBuffer such that queries on a
+// buffer_handle_t succeed
+static const auto GRALLOC1_CAPABILITY_ON_ADAPTER =
+        static_cast<gralloc1_capability_t>(GRALLOC1_LAST_CAPABILITY + 1);
+
+static const auto GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER =
+        static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 1);
+static const auto GRALLOC1_FUNCTION_ALLOCATE_WITH_ID =
+        static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 2);
+static const auto GRALLOC1_FUNCTION_LOCK_YCBCR =
+        static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 3);
+static const auto GRALLOC1_LAST_ADAPTER_FUNCTION = GRALLOC1_FUNCTION_LOCK_YCBCR;
+
+typedef gralloc1_error_t (*GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER)(
+        gralloc1_device_t* device, const android::GraphicBuffer* buffer);
+typedef gralloc1_error_t (*GRALLOC1_PFN_ALLOCATE_WITH_ID)(
+        gralloc1_device_t* device, gralloc1_buffer_descriptor_t descriptor,
+        gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
+typedef int32_t /*gralloc1_error_t*/ (*GRALLOC1_PFN_LOCK_YCBCR)(
+        gralloc1_device_t* device, buffer_handle_t buffer,
+        uint64_t /*gralloc1_producer_usage_t*/ producerUsage,
+        uint64_t /*gralloc1_consumer_usage_t*/ consumerUsage,
+        const gralloc1_rect_t* accessRegion, struct android_ycbcr* outYCbCr,
+        int32_t acquireFence);
+
+namespace android {
+
+class Gralloc1On0Adapter : public gralloc1_device_t
+{
+public:
+    Gralloc1On0Adapter(const hw_module_t* module);
+    ~Gralloc1On0Adapter();
+
+    gralloc1_device_t* getDevice() {
+        return static_cast<gralloc1_device_t*>(this);
+    }
+
+private:
+    static inline Gralloc1On0Adapter* getAdapter(gralloc1_device_t* device) {
+        return static_cast<Gralloc1On0Adapter*>(device);
+    }
+
+    // getCapabilities
+
+    void doGetCapabilities(uint32_t* outCount,
+            int32_t* /*gralloc1_capability_t*/ outCapabilities);
+    static void getCapabilitiesHook(gralloc1_device_t* device,
+            uint32_t* outCount,
+            int32_t* /*gralloc1_capability_t*/ outCapabilities) {
+        getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
+    };
+
+    // getFunction
+
+    gralloc1_function_pointer_t doGetFunction(
+            int32_t /*gralloc1_function_descriptor_t*/ descriptor);
+    static gralloc1_function_pointer_t getFunctionHook(
+            gralloc1_device_t* device,
+            int32_t /*gralloc1_function_descriptor_t*/ descriptor) {
+        return getAdapter(device)->doGetFunction(descriptor);
+    }
+
+    // dump
+
+    void dump(uint32_t* outSize, char* outBuffer);
+    static void dumpHook(gralloc1_device_t* device, uint32_t* outSize,
+            char* outBuffer) {
+        return getAdapter(device)->dump(outSize, outBuffer);
+    }
+    std::string mCachedDump;
+
+    // Buffer descriptor lifecycle functions
+
+    class Descriptor;
+
+    gralloc1_error_t createDescriptor(
+            gralloc1_buffer_descriptor_t* outDescriptor);
+    static int32_t createDescriptorHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t* outDescriptor) {
+        auto error = getAdapter(device)->createDescriptor(outDescriptor);
+        return static_cast<int32_t>(error);
+    }
+
+    gralloc1_error_t destroyDescriptor(gralloc1_buffer_descriptor_t descriptor);
+    static int32_t destroyDescriptorHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptor) {
+        auto error = getAdapter(device)->destroyDescriptor(descriptor);
+        return static_cast<int32_t>(error);
+    }
+
+    // Buffer descriptor modification functions
+
+    struct Descriptor : public std::enable_shared_from_this<Descriptor> {
+        Descriptor(Gralloc1On0Adapter* adapter,
+                gralloc1_buffer_descriptor_t id)
+          : adapter(adapter),
+            id(id),
+            width(0),
+            height(0),
+            format(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+            producerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
+            consumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
+
+        gralloc1_error_t setDimensions(uint32_t w, uint32_t h) {
+            width = w;
+            height = h;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t setFormat(int32_t f) {
+            format = f;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage) {
+            producerUsage = usage;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage) {
+            consumerUsage = usage;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        Gralloc1On0Adapter* const adapter;
+        const gralloc1_buffer_descriptor_t id;
+
+        uint32_t width;
+        uint32_t height;
+        int32_t format;
+        gralloc1_producer_usage_t producerUsage;
+        gralloc1_consumer_usage_t consumerUsage;
+    };
+
+    template <typename ...Args>
+    static int32_t callDescriptorFunction(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptorId,
+            gralloc1_error_t (Descriptor::*member)(Args...), Args... args) {
+        auto descriptor = getAdapter(device)->getDescriptor(descriptorId);
+        if (!descriptor) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_DESCRIPTOR);
+        }
+        auto error = ((*descriptor).*member)(std::forward<Args>(args)...);
+        return static_cast<int32_t>(error);
+    }
+
+    static int32_t setConsumerUsageHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
+        auto usage = static_cast<gralloc1_consumer_usage_t>(intUsage);
+        return callDescriptorFunction(device, descriptorId,
+                &Descriptor::setConsumerUsage, usage);
+    }
+
+    static int32_t setDimensionsHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptorId, uint32_t width,
+            uint32_t height) {
+        return callDescriptorFunction(device, descriptorId,
+                &Descriptor::setDimensions, width, height);
+    }
+
+    static int32_t setFormatHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptorId, int32_t format) {
+        return callDescriptorFunction(device, descriptorId,
+                &Descriptor::setFormat, format);
+    }
+
+    static int32_t setProducerUsageHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
+        auto usage = static_cast<gralloc1_producer_usage_t>(intUsage);
+        return callDescriptorFunction(device, descriptorId,
+                &Descriptor::setProducerUsage, usage);
+    }
+
+    // Buffer handle query functions
+
+    class Buffer {
+    public:
+        Buffer(buffer_handle_t handle, gralloc1_backing_store_t store,
+                const Descriptor& descriptor, uint32_t stride,
+                bool wasAllocated);
+
+        buffer_handle_t getHandle() const { return mHandle; }
+
+        void retain() { ++mReferenceCount; }
+
+        // Returns true if the reference count has dropped to 0, indicating that
+        // the buffer needs to be released
+        bool release() { return --mReferenceCount == 0; }
+
+        bool wasAllocated() const { return mWasAllocated; }
+
+        gralloc1_error_t getBackingStore(
+                gralloc1_backing_store_t* outStore) const {
+            *outStore = mStore;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getConsumerUsage(
+                gralloc1_consumer_usage_t* outUsage) const {
+            *outUsage = mDescriptor.consumerUsage;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getDimensions(uint32_t* outWidth,
+                uint32_t* outHeight) const {
+            *outWidth = mDescriptor.width;
+            *outHeight = mDescriptor.height;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getFormat(int32_t* outFormat) const {
+            *outFormat = mDescriptor.format;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getNumFlexPlanes(uint32_t* outNumPlanes) const {
+            // TODO: This is conservative, and we could do better by examining
+            // the format, but it won't hurt anything for now
+            *outNumPlanes = 4;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getProducerUsage(
+                gralloc1_producer_usage_t* outUsage) const {
+            *outUsage = mDescriptor.producerUsage;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getStride(uint32_t* outStride) const {
+            *outStride = mStride;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+    private:
+
+        const buffer_handle_t mHandle;
+        size_t mReferenceCount;
+
+        // Since we're adapting to gralloc0, there will always be a 1:1
+        // correspondence between buffer handles and backing stores, and the
+        // backing store ID will be the same as the GraphicBuffer unique ID
+        const gralloc1_backing_store_t mStore;
+
+        const Descriptor mDescriptor;
+        const uint32_t mStride;
+
+        // Whether this buffer allocated in this process (as opposed to just
+        // being retained here), which determines whether to free or unregister
+        // the buffer when this Buffer is released
+        const bool mWasAllocated;
+    };
+
+    template <typename ...Args>
+    static int32_t callBufferFunction(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle,
+            gralloc1_error_t (Buffer::*member)(Args...) const, Args... args) {
+        auto buffer = getAdapter(device)->getBuffer(bufferHandle);
+        if (!buffer) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+        }
+        auto error = ((*buffer).*member)(std::forward<Args>(args)...);
+        return static_cast<int32_t>(error);
+    }
+
+    template <typename MF, MF memFunc, typename ...Args>
+    static int32_t bufferHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle, Args... args) {
+        return Gralloc1On0Adapter::callBufferFunction(device, bufferHandle,
+                memFunc, std::forward<Args>(args)...);
+    }
+
+    static int32_t getConsumerUsageHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle, uint64_t* outUsage) {
+        auto usage = GRALLOC1_CONSUMER_USAGE_NONE;
+        auto error = callBufferFunction(device, bufferHandle,
+                &Buffer::getConsumerUsage, &usage);
+        if (error != GRALLOC1_ERROR_NONE) {
+            *outUsage = static_cast<uint64_t>(usage);
+        }
+        return error;
+    }
+
+    static int32_t getProducerUsageHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle, uint64_t* outUsage) {
+        auto usage = GRALLOC1_PRODUCER_USAGE_NONE;
+        auto error = callBufferFunction(device, bufferHandle,
+                &Buffer::getProducerUsage, &usage);
+        if (error != GRALLOC1_ERROR_NONE) {
+            *outUsage = static_cast<uint64_t>(usage);
+        }
+        return error;
+    }
+
+    // Buffer management functions
+
+    // We don't provide GRALLOC1_FUNCTION_ALLOCATE, since this should always be
+    // called through GRALLOC1_FUNCTION_ALLOCATE_WITH_ID
+    gralloc1_error_t allocate(
+            const std::shared_ptr<Descriptor>& descriptor,
+            gralloc1_backing_store_t id,
+            buffer_handle_t* outBufferHandle);
+    static gralloc1_error_t allocateWithIdHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptors,
+            gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
+
+    gralloc1_error_t retain(const std::shared_ptr<Buffer>& buffer);
+    gralloc1_error_t release(const std::shared_ptr<Buffer>& buffer);
+
+    // Member function pointer 'member' will either be retain or release
+    template <gralloc1_error_t (Gralloc1On0Adapter::*member)(
+            const std::shared_ptr<Buffer>& buffer)>
+    static int32_t managementHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle) {
+        auto adapter = getAdapter(device);
+
+        auto buffer = adapter->getBuffer(bufferHandle);
+        if (!buffer) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+        }
+
+        auto error = ((*adapter).*member)(buffer);
+        return static_cast<int32_t>(error);
+    }
+
+    gralloc1_error_t retain(const GraphicBuffer* buffer);
+    static gralloc1_error_t retainGraphicBufferHook(gralloc1_device_t* device,
+            const GraphicBuffer* buffer) {
+        auto adapter = getAdapter(device);
+        return adapter->retain(buffer);
+    }
+
+    // Buffer access functions
+
+    gralloc1_error_t lock(const std::shared_ptr<Buffer>& buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t& accessRegion, void** outData,
+            const sp<Fence>& acquireFence);
+    gralloc1_error_t lockFlex(const std::shared_ptr<Buffer>& buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t& accessRegion,
+            struct android_flex_layout* outFlex,
+            const sp<Fence>& acquireFence);
+    gralloc1_error_t lockYCbCr(const std::shared_ptr<Buffer>& buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t& accessRegion,
+            struct android_ycbcr* outFlex,
+            const sp<Fence>& acquireFence);
+
+    template <typename OUT, gralloc1_error_t (Gralloc1On0Adapter::*member)(
+            const std::shared_ptr<Buffer>&, gralloc1_producer_usage_t,
+            gralloc1_consumer_usage_t, const gralloc1_rect_t&, OUT*,
+            const sp<Fence>&)>
+    static int32_t lockHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle,
+            uint64_t /*gralloc1_producer_usage_t*/ uintProducerUsage,
+            uint64_t /*gralloc1_consumer_usage_t*/ uintConsumerUsage,
+            const gralloc1_rect_t* accessRegion, OUT* outData,
+            int32_t acquireFenceFd) {
+        auto adapter = getAdapter(device);
+
+        // Exactly one of producer and consumer usage must be *_USAGE_NONE,
+        // but we can't check this until the upper levels of the framework
+        // correctly distinguish between producer and consumer usage
+        /*
+        bool hasProducerUsage =
+                uintProducerUsage != GRALLOC1_PRODUCER_USAGE_NONE;
+        bool hasConsumerUsage =
+                uintConsumerUsage != GRALLOC1_CONSUMER_USAGE_NONE;
+        if (hasProducerUsage && hasConsumerUsage ||
+                !hasProducerUsage && !hasConsumerUsage) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+        }
+        */
+
+        auto producerUsage =
+                static_cast<gralloc1_producer_usage_t>(uintProducerUsage);
+        auto consumerUsage =
+                static_cast<gralloc1_consumer_usage_t>(uintConsumerUsage);
+
+        if (!outData) {
+            const auto producerCpuUsage = GRALLOC1_PRODUCER_USAGE_CPU_READ |
+                    GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
+            if (producerUsage & producerCpuUsage != 0) {
+                return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+            }
+            if (consumerUsage & GRALLOC1_CONSUMER_USAGE_CPU_READ != 0) {
+                return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+            }
+        }
+
+        auto buffer = adapter->getBuffer(bufferHandle);
+        if (!buffer) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+        }
+
+        if (!accessRegion) {
+            ALOGE("accessRegion is null");
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+        }
+
+        sp<Fence> acquireFence{new Fence(acquireFenceFd)};
+        auto error = ((*adapter).*member)(buffer, producerUsage, consumerUsage,
+                *accessRegion, outData, acquireFence);
+        return static_cast<int32_t>(error);
+    }
+
+    gralloc1_error_t unlock(const std::shared_ptr<Buffer>& buffer,
+            sp<Fence>* outReleaseFence);
+    static int32_t unlockHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle, int32_t* outReleaseFenceFd) {
+        auto adapter = getAdapter(device);
+
+        auto buffer = adapter->getBuffer(bufferHandle);
+        if (!buffer) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+        }
+
+        sp<Fence> releaseFence = Fence::NO_FENCE;
+        auto error = adapter->unlock(buffer, &releaseFence);
+        if (error == GRALLOC1_ERROR_NONE) {
+            *outReleaseFenceFd = releaseFence->dup();
+        }
+        return static_cast<int32_t>(error);
+    }
+
+    // Adapter internals
+    const gralloc_module_t* mModule;
+    uint8_t mMinorVersion;
+    alloc_device_t* mDevice;
+
+    std::shared_ptr<Descriptor> getDescriptor(
+            gralloc1_buffer_descriptor_t descriptorId);
+    std::shared_ptr<Buffer> getBuffer(buffer_handle_t bufferHandle);
+
+    static std::atomic<gralloc1_buffer_descriptor_t> sNextBufferDescriptorId;
+    std::mutex mDescriptorMutex;
+    std::unordered_map<gralloc1_buffer_descriptor_t,
+            std::shared_ptr<Descriptor>> mDescriptors;
+    std::mutex mBufferMutex;
+    std::unordered_map<buffer_handle_t, std::shared_ptr<Buffer>> mBuffers;
+};
+
+} // namespace android
+
+#endif
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 3da720f..3e127a1 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -26,6 +26,7 @@
 #include <utils/Flattenable.h>
 #include <utils/RefBase.h>
 
+#include <string>
 
 struct ANativeWindowBuffer;
 
@@ -73,7 +74,7 @@
 
     // creates w * h buffer
     GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
-            uint32_t inUsage);
+            uint32_t inUsage, std::string requestorName = "<Unknown>");
 
     // create a buffer from an existing handle
     GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
@@ -159,7 +160,7 @@
     const GraphicBuffer& operator = (const GraphicBuffer& rhs) const;
 
     status_t initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
-            uint32_t inUsage);
+            uint32_t inUsage, std::string requestorName);
 
     void free_handle();
 
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index 5443f09..28d0238 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -27,42 +27,41 @@
 #include <utils/threads.h>
 #include <utils/Singleton.h>
 
+#include <ui/Gralloc1.h>
 #include <ui/PixelFormat.h>
 
-#include <hardware/gralloc.h>
-
-
 namespace android {
-// ---------------------------------------------------------------------------
 
+class Gralloc1Loader;
 class String8;
 
 class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
 {
 public:
     enum {
-        USAGE_SW_READ_NEVER     = GRALLOC_USAGE_SW_READ_NEVER,
-        USAGE_SW_READ_RARELY    = GRALLOC_USAGE_SW_READ_RARELY,
-        USAGE_SW_READ_OFTEN     = GRALLOC_USAGE_SW_READ_OFTEN,
-        USAGE_SW_READ_MASK      = GRALLOC_USAGE_SW_READ_MASK,
+        USAGE_SW_READ_NEVER     = GRALLOC1_CONSUMER_USAGE_CPU_READ_NEVER,
+        USAGE_SW_READ_RARELY    = GRALLOC1_CONSUMER_USAGE_CPU_READ,
+        USAGE_SW_READ_OFTEN     = GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN,
+        USAGE_SW_READ_MASK      = GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN,
 
-        USAGE_SW_WRITE_NEVER    = GRALLOC_USAGE_SW_WRITE_NEVER,
-        USAGE_SW_WRITE_RARELY   = GRALLOC_USAGE_SW_WRITE_RARELY,
-        USAGE_SW_WRITE_OFTEN    = GRALLOC_USAGE_SW_WRITE_OFTEN,
-        USAGE_SW_WRITE_MASK     = GRALLOC_USAGE_SW_WRITE_MASK,
+        USAGE_SW_WRITE_NEVER    = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_NEVER,
+        USAGE_SW_WRITE_RARELY   = GRALLOC1_PRODUCER_USAGE_CPU_WRITE,
+        USAGE_SW_WRITE_OFTEN    = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
+        USAGE_SW_WRITE_MASK     = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
 
         USAGE_SOFTWARE_MASK     = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK,
 
-        USAGE_HW_TEXTURE        = GRALLOC_USAGE_HW_TEXTURE,
-        USAGE_HW_RENDER         = GRALLOC_USAGE_HW_RENDER,
-        USAGE_HW_2D             = GRALLOC_USAGE_HW_2D,
-        USAGE_HW_MASK           = GRALLOC_USAGE_HW_MASK
+        USAGE_HW_TEXTURE        = GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE,
+        USAGE_HW_RENDER         = GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET,
+        USAGE_HW_2D             = 0x00000400, // Deprecated
+        USAGE_HW_MASK           = 0x00071F00, // Deprecated
     };
 
     static inline GraphicBufferAllocator& get() { return getInstance(); }
 
-    status_t alloc(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
-            buffer_handle_t* handle, uint32_t* stride);
+    status_t allocate(uint32_t w, uint32_t h, PixelFormat format,
+            uint32_t usage, buffer_handle_t* handle, uint32_t* stride,
+            uint64_t graphicBufferId, std::string requestorName);
 
     status_t free(buffer_handle_t handle);
 
@@ -77,6 +76,7 @@
         PixelFormat format;
         uint32_t usage;
         size_t size;
+        std::string requestorName;
     };
 
     static Mutex sLock;
@@ -86,7 +86,8 @@
     GraphicBufferAllocator();
     ~GraphicBufferAllocator();
 
-    alloc_device_t  *mAllocDev;
+    std::unique_ptr<Gralloc1::Loader> mLoader;
+    std::unique_ptr<Gralloc1::Device> mDevice;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h
index 6099548..a25809c 100644
--- a/include/ui/GraphicBufferMapper.h
+++ b/include/ui/GraphicBufferMapper.h
@@ -20,13 +20,10 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <ui/Gralloc1.h>
+
 #include <utils/Singleton.h>
 
-#include <hardware/gralloc.h>
-
-
-struct gralloc_module_t;
-
 namespace android {
 
 // ---------------------------------------------------------------------------
@@ -39,6 +36,7 @@
     static inline GraphicBufferMapper& get() { return getInstance(); }
 
     status_t registerBuffer(buffer_handle_t handle);
+    status_t registerBuffer(const GraphicBuffer* buffer);
 
     status_t unregisterBuffer(buffer_handle_t handle);
 
@@ -59,13 +57,13 @@
 
     status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
 
-    // dumps information about the mapping of this handle
-    void dump(buffer_handle_t handle);
-
 private:
     friend class Singleton<GraphicBufferMapper>;
+
     GraphicBufferMapper();
-    gralloc_module_t const *mAllocMod;
+
+    std::unique_ptr<Gralloc1::Loader> mLoader;
+    std::unique_ptr<Gralloc1::Device> mDevice;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index be3b6c3..88df6d2 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -496,7 +496,8 @@
         status_t error;
         BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
         sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
-                width, height, format, usage, &error));
+                width, height, format, usage,
+                {mConsumerName.string(), mConsumerName.size()}, &error));
         { // Autolock scope
             Mutex::Autolock lock(mCore->mMutex);
 
@@ -1255,7 +1256,8 @@
         for (size_t i = 0; i <  newBufferCount; ++i) {
             status_t result = NO_ERROR;
             sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
-                    allocWidth, allocHeight, allocFormat, allocUsage, &result));
+                    allocWidth, allocHeight, allocFormat, allocUsage,
+                    {mConsumerName.string(), mConsumerName.size()}, &result));
             if (result != NO_ERROR) {
                 BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
                         " %u, usage %u)", width, height, format, usage);
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 553b65c..aa0db45 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -345,7 +345,8 @@
         // continues to use it.
         sp<GraphicBuffer> buffer = new GraphicBuffer(
                 kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
-                GraphicBuffer::USAGE_SW_WRITE_RARELY);
+                GraphicBuffer::USAGE_SW_WRITE_RARELY,
+                "[GLConsumer debug texture]");
         uint32_t* bits;
         buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
         uint32_t stride = buffer->getStride();
diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
index 9643402..e6150f4 100644
--- a/libs/gui/GraphicBufferAlloc.cpp
+++ b/libs/gui/GraphicBufferAlloc.cpp
@@ -32,9 +32,10 @@
 }
 
 sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
-        uint32_t height, PixelFormat format, uint32_t usage, status_t* error) {
-    sp<GraphicBuffer> graphicBuffer(
-            new GraphicBuffer(width, height, format, usage));
+        uint32_t height, PixelFormat format, uint32_t usage,
+        std::string requestorName, status_t* error) {
+    sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(
+            width, height, format, usage, std::move(requestorName)));
     status_t err = graphicBuffer->initCheck();
     *error = err;
     if (err != 0 || graphicBuffer->handle == 0) {
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index d4d4702..2fb380c 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -46,13 +46,19 @@
 
     virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
             uint32_t height, PixelFormat format, uint32_t usage,
-            status_t* error) {
+            std::string requestorName, status_t* error) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
         data.writeUint32(width);
         data.writeUint32(height);
         data.writeInt32(static_cast<int32_t>(format));
         data.writeUint32(usage);
+        if (requestorName.empty()) {
+            requestorName += "[PID ";
+            requestorName += std::to_string(getpid());
+            requestorName += ']';
+        }
+        data.writeUtf8AsUtf16(requestorName);
         remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply);
         sp<GraphicBuffer> graphicBuffer;
         status_t result = reply.readInt32();
@@ -101,9 +107,11 @@
             uint32_t height = data.readUint32();
             PixelFormat format = static_cast<PixelFormat>(data.readInt32());
             uint32_t usage = data.readUint32();
-            status_t error;
-            sp<GraphicBuffer> result =
-                    createGraphicBuffer(width, height, format, usage, &error);
+            status_t error = NO_ERROR;
+            std::string requestorName;
+            data.readUtf8FromUtf16(&requestorName);
+            sp<GraphicBuffer> result = createGraphicBuffer(width, height,
+                    format, usage, requestorName, &error);
             reply->writeInt32(error);
             if (result != 0) {
                 reply->write(*result);
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 28df1cf..bd28af1 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -58,3 +58,5 @@
         },
     },
 }
+
+subdirs = ["tests"]
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
deleted file mode 100644
index e7dbe79..0000000
--- a/libs/input/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
new file mode 100644
index 0000000..f0b5eda
--- /dev/null
+++ b/libs/input/tests/Android.bp
@@ -0,0 +1,29 @@
+// Build the unit tests.
+cc_test {
+    name: "libinput_tests",
+    test_per_src: true,
+    srcs: [
+        "InputChannel_test.cpp",
+        "InputEvent_test.cpp",
+        "InputPublisherAndConsumer_test.cpp",
+    ],
+    shared_libs: [
+        "libinput",
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libui",
+    ]
+}
+
+// NOTE: This is a compile time test, and does not need to be
+// run. All assertions are static_asserts and will fail during
+// buildtime if something's wrong.
+cc_library_static {
+    name: "StructLayout_test",
+    srcs: ["StructLayout_test.cpp"],
+    cflags: [
+        "-std=c++11",
+        "-O0",
+    ],
+}
diff --git a/libs/input/tests/Android.mk b/libs/input/tests/Android.mk
deleted file mode 100644
index 5bfa3d4..0000000
--- a/libs/input/tests/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-
-# Build the unit tests.
-test_src_files := \
-    InputChannel_test.cpp \
-    InputEvent_test.cpp \
-    InputPublisherAndConsumer_test.cpp
-
-shared_libraries := \
-    libinput \
-    libcutils \
-    libutils \
-    libbinder \
-    libui \
-
-$(foreach file,$(test_src_files), \
-    $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk) \
-    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
-    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
-    $(eval LOCAL_SRC_FILES := $(file)) \
-    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
-    $(eval include $(BUILD_NATIVE_TEST)) \
-)
-
-# NOTE: This is a compile time test, and does not need to be
-# run. All assertions are static_asserts and will fail during
-# buildtime if something's wrong.
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SRC_FILES := StructLayout_test.cpp
-LOCAL_MODULE := StructLayout_test
-LOCAL_CFLAGS := -std=c++11 -O0
-LOCAL_MULTILIB := both
-include $(BUILD_STATIC_LIBRARY)
-
-
-# Build the manual test programs.
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
new file mode 100644
index 0000000..0777468
--- /dev/null
+++ b/libs/ui/Android.bp
@@ -0,0 +1,69 @@
+// Copyright (C) 2010 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.
+
+cc_library_shared {
+    name: "libui",
+
+    clang: true,
+    cppflags: [
+        "-std=c++1y",
+        "-Weverything",
+        "-Werror",
+
+        // The static constructors and destructors in this library have not been noted to
+        // introduce significant overheads
+        "-Wno-exit-time-destructors",
+        "-Wno-global-constructors",
+
+        // We only care about compiling as C++14
+        "-Wno-c++98-compat-pedantic",
+
+        // We use four-character constants for the GraphicBuffer header, and don't care
+        // that they're non-portable as long as they're consistent within one execution
+        "-Wno-four-char-constants",
+
+        // Don't warn about struct padding
+        "-Wno-padded",
+    ],
+
+    sanitize: {
+        //misc_undefined: ["integer"],
+    },
+
+    srcs: [
+        "Fence.cpp",
+        "FrameStats.cpp",
+        "Gralloc1.cpp",
+        "Gralloc1On0Adapter.cpp",
+        "GraphicBuffer.cpp",
+        "GraphicBufferAllocator.cpp",
+        "GraphicBufferMapper.cpp",
+        "HdrCapabilities.cpp",
+        "PixelFormat.cpp",
+        "Rect.cpp",
+        "Region.cpp",
+        "UiConfig.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libhardware",
+        "libsync",
+        "libutils",
+        "liblog",
+    ],
+}
+
+subdirs = ["tests"]
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
deleted file mode 100644
index 69ee949..0000000
--- a/libs/ui/Android.mk
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright (C) 2010 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror
-LOCAL_SANITIZE := integer
-
-# The static constructors and destructors in this library have not been noted to
-# introduce significant overheads
-LOCAL_CPPFLAGS += -Wno-exit-time-destructors
-LOCAL_CPPFLAGS += -Wno-global-constructors
-
-# We only care about compiling as C++14
-LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic
-
-# We use four-character constants for the GraphicBuffer header, and don't care
-# that they're non-portable as long as they're consistent within one execution
-LOCAL_CPPFLAGS += -Wno-four-char-constants
-
-# Don't warn about struct padding
-LOCAL_CPPFLAGS += -Wno-padded
-
-LOCAL_SRC_FILES := \
-	Fence.cpp \
-	FrameStats.cpp \
-	GraphicBuffer.cpp \
-	GraphicBufferAllocator.cpp \
-	GraphicBufferMapper.cpp \
-	HdrCapabilities.cpp \
-	PixelFormat.cpp \
-	Rect.cpp \
-	Region.cpp \
-	UiConfig.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libbinder \
-	libcutils \
-	libhardware \
-	libsync \
-	libutils \
-	liblog
-
-LOCAL_MODULE := libui
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/ui/Gralloc1.cpp b/libs/ui/Gralloc1.cpp
new file mode 100644
index 0000000..4c73ce4
--- /dev/null
+++ b/libs/ui/Gralloc1.cpp
@@ -0,0 +1,402 @@
+/*
+ * Copyright 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.
+ */
+
+//#define LOG_NDEBUG 0
+
+#include <ui/Gralloc1.h>
+
+#include <vector>
+
+#undef LOG_TAG
+#define LOG_TAG GRALLOC1_LOG_TAG
+
+namespace android {
+
+namespace Gralloc1 {
+
+Descriptor::~Descriptor()
+{
+    int32_t intError = mShimDevice.mFunctions.destroyDescriptor(
+            mShimDevice.mDevice, mDeviceId);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("destroyDescriptor failed: %d", intError);
+    }
+}
+
+gralloc1_error_t Descriptor::setDimensions(uint32_t width, uint32_t height)
+{
+    int32_t intError = mShimDevice.mFunctions.setDimensions(mShimDevice.mDevice,
+            mDeviceId, width, height);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return error;
+    }
+    mWidth = width;
+    mHeight = height;
+    return error;
+}
+
+template <typename ApiType>
+struct Setter {
+    typedef int32_t (*Type)(gralloc1_device_t*, gralloc1_buffer_descriptor_t,
+            ApiType);
+};
+
+template <typename ApiType, typename ValueType>
+static inline gralloc1_error_t setHelper(
+        typename Setter<ApiType>::Type setter, gralloc1_device_t* device,
+        gralloc1_buffer_descriptor_t id, ValueType newValue,
+        ValueType* cacheVariable)
+{
+    int32_t intError = setter(device, id, static_cast<ApiType>(newValue));
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return error;
+    }
+    *cacheVariable = newValue;
+    return error;
+}
+
+gralloc1_error_t Descriptor::setFormat(android_pixel_format_t format)
+{
+    return setHelper<int32_t>(mShimDevice.mFunctions.setFormat.pfn,
+            mShimDevice.mDevice, mDeviceId, format, &mFormat);
+}
+
+gralloc1_error_t Descriptor::setProducerUsage(gralloc1_producer_usage_t usage)
+{
+    return setHelper<uint64_t>(mShimDevice.mFunctions.setProducerUsage.pfn,
+            mShimDevice.mDevice, mDeviceId, usage, &mProducerUsage);
+}
+
+gralloc1_error_t Descriptor::setConsumerUsage(gralloc1_consumer_usage_t usage)
+{
+    return setHelper<uint64_t>(mShimDevice.mFunctions.setConsumerUsage.pfn,
+            mShimDevice.mDevice, mDeviceId, usage, &mConsumerUsage);
+}
+
+Device::Device(gralloc1_device_t* device)
+  : mDevice(device),
+    mCapabilities(loadCapabilities()),
+    mFunctions()
+{
+    if (!loadFunctions()) {
+        ALOGE("Failed to load a required function, aborting");
+        abort();
+    }
+}
+
+bool Device::hasCapability(gralloc1_capability_t capability) const
+{
+    return mCapabilities.count(capability) > 0;
+}
+
+std::string Device::dump()
+{
+    uint32_t length = 0;
+    mFunctions.dump(mDevice, &length, nullptr);
+
+    std::vector<char> output;
+    output.resize(length);
+    mFunctions.dump(mDevice, &length, output.data());
+
+    return std::string(output.cbegin(), output.cend());
+}
+
+std::shared_ptr<Descriptor> Device::createDescriptor()
+{
+    gralloc1_buffer_descriptor_t descriptorId;
+    int32_t intError = mFunctions.createDescriptor(mDevice, &descriptorId);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return nullptr;
+    }
+    auto descriptor = std::make_shared<Descriptor>(*this, descriptorId);
+    return descriptor;
+}
+
+gralloc1_error_t Device::getStride(buffer_handle_t buffer, uint32_t* outStride)
+{
+    int32_t intError = mFunctions.getStride(mDevice, buffer, outStride);
+    return static_cast<gralloc1_error_t>(intError);
+}
+
+static inline bool allocationSucceded(gralloc1_error_t error)
+{
+    return error == GRALLOC1_ERROR_NONE || error == GRALLOC1_ERROR_NOT_SHARED;
+}
+
+gralloc1_error_t Device::allocate(
+        const std::vector<std::shared_ptr<const Descriptor>>& descriptors,
+        std::vector<buffer_handle_t>* outBuffers)
+{
+    if (mFunctions.allocate.pfn == nullptr) {
+        // Allocation is not supported on this device
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    std::vector<gralloc1_buffer_descriptor_t> deviceIds;
+    for (const auto& descriptor : descriptors) {
+        deviceIds.emplace_back(descriptor->getDeviceId());
+    }
+
+    std::vector<buffer_handle_t> buffers(descriptors.size());
+    int32_t intError = mFunctions.allocate(mDevice,
+            static_cast<uint32_t>(descriptors.size()), deviceIds.data(),
+            buffers.data());
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (allocationSucceded(error)) {
+        *outBuffers = std::move(buffers);
+    }
+
+    return error;
+}
+
+gralloc1_error_t Device::allocate(
+        const std::shared_ptr<const Descriptor>& descriptor,
+        gralloc1_backing_store_t id, buffer_handle_t* outBuffer)
+{
+    gralloc1_error_t error = GRALLOC1_ERROR_NONE;
+
+    if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        buffer_handle_t buffer = nullptr;
+        int32_t intError = mFunctions.allocateWithId(mDevice,
+                descriptor->getDeviceId(), id, &buffer);
+        error = static_cast<gralloc1_error_t>(intError);
+        if (allocationSucceded(error)) {
+            *outBuffer = buffer;
+        }
+    } else {
+        std::vector<std::shared_ptr<const Descriptor>> descriptors;
+        descriptors.emplace_back(descriptor);
+        std::vector<buffer_handle_t> buffers;
+        error = allocate(descriptors, &buffers);
+        if (allocationSucceded(error)) {
+            *outBuffer = buffers[0];
+        }
+    }
+
+    return error;
+}
+
+gralloc1_error_t Device::retain(buffer_handle_t buffer)
+{
+    int32_t intError = mFunctions.retain(mDevice, buffer);
+    return static_cast<gralloc1_error_t>(intError);
+}
+
+gralloc1_error_t Device::retain(const GraphicBuffer* buffer)
+{
+    if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        return mFunctions.retainGraphicBuffer(mDevice, buffer);
+    } else {
+        return retain(buffer->getNativeBuffer()->handle);
+    }
+}
+
+gralloc1_error_t Device::release(buffer_handle_t buffer)
+{
+    int32_t intError = mFunctions.release(mDevice, buffer);
+    return static_cast<gralloc1_error_t>(intError);
+}
+
+gralloc1_error_t Device::getNumFlexPlanes(buffer_handle_t buffer,
+        uint32_t* outNumPlanes)
+{
+    uint32_t numPlanes = 0;
+    int32_t intError = mFunctions.getNumFlexPlanes(mDevice, buffer, &numPlanes);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outNumPlanes = numPlanes;
+    }
+    return error;
+}
+
+gralloc1_error_t Device::lock(buffer_handle_t buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t* accessRegion, void** outData,
+        const sp<Fence>& acquireFence)
+{
+    ALOGV("Calling lock(%p)", buffer);
+    return lockHelper(mFunctions.lock.pfn, buffer, producerUsage,
+            consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::lockFlex(buffer_handle_t buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t* accessRegion,
+        struct android_flex_layout* outData,
+        const sp<Fence>& acquireFence)
+{
+    ALOGV("Calling lockFlex(%p)", buffer);
+    return lockHelper(mFunctions.lockFlex.pfn, buffer, producerUsage,
+            consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::lockYCbCr(buffer_handle_t buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t* accessRegion,
+        struct android_ycbcr* outData,
+        const sp<Fence>& acquireFence)
+{
+    ALOGV("Calling lockYCbCr(%p)", buffer);
+    return lockHelper(mFunctions.lockYCbCr.pfn, buffer, producerUsage,
+            consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::unlock(buffer_handle_t buffer, sp<Fence>* outFence)
+{
+    int32_t fenceFd = -1;
+    int32_t intError = mFunctions.unlock(mDevice, buffer, &fenceFd);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outFence = new Fence(fenceFd);
+    }
+    return error;
+}
+
+std::unordered_set<gralloc1_capability_t> Device::loadCapabilities()
+{
+    std::vector<int32_t> intCapabilities;
+    uint32_t numCapabilities = 0;
+    mDevice->getCapabilities(mDevice, &numCapabilities, nullptr);
+
+    intCapabilities.resize(numCapabilities);
+    mDevice->getCapabilities(mDevice, &numCapabilities, intCapabilities.data());
+
+    std::unordered_set<gralloc1_capability_t> capabilities;
+    for (const auto intCapability : intCapabilities) {
+        capabilities.emplace(static_cast<gralloc1_capability_t>(intCapability));
+    }
+    return capabilities;
+}
+
+bool Device::loadFunctions()
+{
+    // Functions which must always be present
+    if (!mFunctions.dump.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.createDescriptor.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.destroyDescriptor.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setConsumerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setDimensions.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setFormat.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setProducerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getBackingStore.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getConsumerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getDimensions.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getFormat.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getProducerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getStride.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.retain.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.release.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getNumFlexPlanes.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.lock.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.lockFlex.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.unlock.load(mDevice, true)) {
+        return false;
+    }
+
+    if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        // These should always be present on the adapter
+        if (!mFunctions.retainGraphicBuffer.load(mDevice, true)) {
+            return false;
+        }
+        if (!mFunctions.lockYCbCr.load(mDevice, true)) {
+            return false;
+        }
+
+        // allocateWithId may not be present if we're only able to map in this
+        // process
+        mFunctions.allocateWithId.load(mDevice, false);
+    } else {
+        // allocate may not be present if we're only able to map in this process
+        mFunctions.allocate.load(mDevice, false);
+    }
+
+    return true;
+}
+
+std::unique_ptr<Gralloc1On0Adapter> Loader::mAdapter = nullptr;
+
+Loader::Loader()
+  : mDevice(nullptr)
+{
+    hw_module_t const* module;
+    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+    uint8_t majorVersion = (module->module_api_version >> 8) & 0xFF;
+    uint8_t minorVersion = module->module_api_version & 0xFF;
+    gralloc1_device_t* device = nullptr;
+    if (majorVersion == 1) {
+        gralloc1_open(module, &device);
+    } else {
+        if (!mAdapter) {
+            mAdapter = std::make_unique<Gralloc1On0Adapter>(module);
+        }
+        device = mAdapter->getDevice();
+    }
+    mDevice = std::make_unique<Gralloc1::Device>(device);
+}
+
+Loader::~Loader() {}
+
+std::unique_ptr<Device> Loader::getDevice()
+{
+    return std::move(mDevice);
+}
+
+} // namespace android::Gralloc1
+
+} // namespace android
diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp
new file mode 100644
index 0000000..d5b88de
--- /dev/null
+++ b/libs/ui/Gralloc1On0Adapter.cpp
@@ -0,0 +1,478 @@
+/*
+ * Copyright 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "Gralloc1On0Adapter"
+//#define LOG_NDEBUG 0
+
+#include <hardware/gralloc.h>
+
+#include <ui/Gralloc1On0Adapter.h>
+
+#include <utils/Log.h>
+
+#include <inttypes.h>
+
+template <typename PFN, typename T>
+static gralloc1_function_pointer_t asFP(T function)
+{
+    static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+    return reinterpret_cast<gralloc1_function_pointer_t>(function);
+}
+
+namespace android {
+
+Gralloc1On0Adapter::Gralloc1On0Adapter(const hw_module_t* module)
+  : mModule(reinterpret_cast<const gralloc_module_t*>(module)),
+    mMinorVersion(mModule->common.module_api_version & 0xFF),
+    mDevice(nullptr)
+{
+    ALOGV("Constructing");
+    getCapabilities = getCapabilitiesHook;
+    getFunction = getFunctionHook;
+    int error = ::gralloc_open(&(mModule->common), &mDevice);
+    if (error) {
+        ALOGE("Failed to open gralloc0 module: %d", error);
+    }
+    ALOGV("Opened gralloc0 device %p", mDevice);
+}
+
+Gralloc1On0Adapter::~Gralloc1On0Adapter()
+{
+    ALOGV("Destructing");
+    if (mDevice) {
+        ALOGV("Closing gralloc0 device %p", mDevice);
+        ::gralloc_close(mDevice);
+    }
+}
+
+void Gralloc1On0Adapter::doGetCapabilities(uint32_t* outCount,
+        int32_t* outCapabilities)
+{
+    if (outCapabilities == nullptr) {
+        *outCount = 1;
+        return;
+    }
+    if (*outCount >= 1) {
+        *outCapabilities = GRALLOC1_CAPABILITY_ON_ADAPTER;
+        *outCount = 1;
+    }
+}
+
+gralloc1_function_pointer_t Gralloc1On0Adapter::doGetFunction(
+        int32_t intDescriptor)
+{
+    constexpr auto lastDescriptor =
+            static_cast<int32_t>(GRALLOC1_LAST_ADAPTER_FUNCTION);
+    if (intDescriptor < 0 || intDescriptor > lastDescriptor) {
+        ALOGE("Invalid function descriptor");
+        return nullptr;
+    }
+
+    auto descriptor =
+            static_cast<gralloc1_function_descriptor_t>(intDescriptor);
+    switch (descriptor) {
+        case GRALLOC1_FUNCTION_DUMP:
+            return asFP<GRALLOC1_PFN_DUMP>(dumpHook);
+        case GRALLOC1_FUNCTION_CREATE_DESCRIPTOR:
+            return asFP<GRALLOC1_PFN_CREATE_DESCRIPTOR>(createDescriptorHook);
+        case GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR:
+            return asFP<GRALLOC1_PFN_DESTROY_DESCRIPTOR>(destroyDescriptorHook);
+        case GRALLOC1_FUNCTION_SET_CONSUMER_USAGE:
+            return asFP<GRALLOC1_PFN_SET_CONSUMER_USAGE>(setConsumerUsageHook);
+        case GRALLOC1_FUNCTION_SET_DIMENSIONS:
+            return asFP<GRALLOC1_PFN_SET_DIMENSIONS>(setDimensionsHook);
+        case GRALLOC1_FUNCTION_SET_FORMAT:
+            return asFP<GRALLOC1_PFN_SET_FORMAT>(setFormatHook);
+        case GRALLOC1_FUNCTION_SET_PRODUCER_USAGE:
+            return asFP<GRALLOC1_PFN_SET_PRODUCER_USAGE>(setProducerUsageHook);
+        case GRALLOC1_FUNCTION_GET_BACKING_STORE:
+            return asFP<GRALLOC1_PFN_GET_BACKING_STORE>(
+                    bufferHook<decltype(&Buffer::getBackingStore),
+                    &Buffer::getBackingStore, gralloc1_backing_store_t*>);
+        case GRALLOC1_FUNCTION_GET_CONSUMER_USAGE:
+            return asFP<GRALLOC1_PFN_GET_CONSUMER_USAGE>(getConsumerUsageHook);
+        case GRALLOC1_FUNCTION_GET_DIMENSIONS:
+            return asFP<GRALLOC1_PFN_GET_DIMENSIONS>(
+                    bufferHook<decltype(&Buffer::getDimensions),
+                    &Buffer::getDimensions, uint32_t*, uint32_t*>);
+        case GRALLOC1_FUNCTION_GET_FORMAT:
+            return asFP<GRALLOC1_PFN_GET_FORMAT>(
+                    bufferHook<decltype(&Buffer::getFormat),
+                    &Buffer::getFormat, int32_t*>);
+        case GRALLOC1_FUNCTION_GET_PRODUCER_USAGE:
+            return asFP<GRALLOC1_PFN_GET_PRODUCER_USAGE>(getProducerUsageHook);
+        case GRALLOC1_FUNCTION_GET_STRIDE:
+            return asFP<GRALLOC1_PFN_GET_STRIDE>(
+                    bufferHook<decltype(&Buffer::getStride),
+                    &Buffer::getStride, uint32_t*>);
+        case GRALLOC1_FUNCTION_ALLOCATE:
+            // Not provided, since we'll use ALLOCATE_WITH_ID
+            return nullptr;
+        case GRALLOC1_FUNCTION_ALLOCATE_WITH_ID:
+            if (mDevice != nullptr) {
+                return asFP<GRALLOC1_PFN_ALLOCATE_WITH_ID>(allocateWithIdHook);
+            } else {
+                return nullptr;
+            }
+        case GRALLOC1_FUNCTION_RETAIN:
+            return asFP<GRALLOC1_PFN_RETAIN>(
+                    managementHook<&Gralloc1On0Adapter::retain>);
+        case GRALLOC1_FUNCTION_RELEASE:
+            return asFP<GRALLOC1_PFN_RELEASE>(
+                    managementHook<&Gralloc1On0Adapter::release>);
+        case GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER:
+            return asFP<GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER>(
+                    retainGraphicBufferHook);
+        case GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES:
+            return asFP<GRALLOC1_PFN_GET_NUM_FLEX_PLANES>(
+                    bufferHook<decltype(&Buffer::getNumFlexPlanes),
+                    &Buffer::getNumFlexPlanes, uint32_t*>);
+        case GRALLOC1_FUNCTION_LOCK:
+            return asFP<GRALLOC1_PFN_LOCK>(
+                    lockHook<void*, &Gralloc1On0Adapter::lock>);
+        case GRALLOC1_FUNCTION_LOCK_FLEX:
+            return asFP<GRALLOC1_PFN_LOCK_FLEX>(
+                    lockHook<struct android_flex_layout,
+                    &Gralloc1On0Adapter::lockFlex>);
+        case GRALLOC1_FUNCTION_LOCK_YCBCR:
+            return asFP<GRALLOC1_PFN_LOCK_YCBCR>(
+                    lockHook<struct android_ycbcr,
+                    &Gralloc1On0Adapter::lockYCbCr>);
+        case GRALLOC1_FUNCTION_UNLOCK:
+            return asFP<GRALLOC1_PFN_UNLOCK>(unlockHook);
+        case GRALLOC1_FUNCTION_INVALID:
+            ALOGE("Invalid function descriptor");
+            return nullptr;
+    }
+
+    ALOGE("Unknown function descriptor: %d", intDescriptor);
+    return nullptr;
+}
+
+void Gralloc1On0Adapter::dump(uint32_t* outSize, char* outBuffer)
+{
+    ALOGV("dump(%u (%p), %p", outSize ? *outSize : 0, outSize, outBuffer);
+
+    if (!mDevice->dump) {
+        // dump is optional on gralloc0 implementations
+        *outSize = 0;
+        return;
+    }
+
+    if (!outBuffer) {
+        constexpr int32_t BUFFER_LENGTH = 4096;
+        char buffer[BUFFER_LENGTH] = {};
+        mDevice->dump(mDevice, buffer, BUFFER_LENGTH);
+        buffer[BUFFER_LENGTH - 1] = 0; // Ensure the buffer is null-terminated
+        size_t actualLength = std::strlen(buffer);
+        mCachedDump.resize(actualLength);
+        std::copy_n(buffer, actualLength, mCachedDump.begin());
+        *outSize = static_cast<uint32_t>(actualLength);
+    } else {
+        *outSize = std::min(*outSize,
+                static_cast<uint32_t>(mCachedDump.size()));
+        outBuffer = std::copy_n(mCachedDump.cbegin(), *outSize, outBuffer);
+    }
+}
+
+gralloc1_error_t Gralloc1On0Adapter::createDescriptor(
+        gralloc1_buffer_descriptor_t* outDescriptor)
+{
+    auto descriptorId = sNextBufferDescriptorId++;
+    std::lock_guard<std::mutex> lock(mDescriptorMutex);
+    mDescriptors.emplace(descriptorId,
+            std::make_shared<Descriptor>(this, descriptorId));
+
+    ALOGV("Created descriptor %" PRIu64, descriptorId);
+
+    *outDescriptor = descriptorId;
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::destroyDescriptor(
+        gralloc1_buffer_descriptor_t descriptor)
+{
+    ALOGV("Destroying descriptor %" PRIu64, descriptor);
+
+    std::lock_guard<std::mutex> lock(mDescriptorMutex);
+    if (mDescriptors.count(descriptor) == 0) {
+        return GRALLOC1_ERROR_BAD_DESCRIPTOR;
+    }
+
+    mDescriptors.erase(descriptor);
+    return GRALLOC1_ERROR_NONE;
+}
+
+Gralloc1On0Adapter::Buffer::Buffer(buffer_handle_t handle,
+        gralloc1_backing_store_t store, const Descriptor& descriptor,
+        uint32_t stride, bool wasAllocated)
+  : mHandle(handle),
+    mReferenceCount(1),
+    mStore(store),
+    mDescriptor(descriptor),
+    mStride(stride),
+    mWasAllocated(wasAllocated) {}
+
+gralloc1_error_t Gralloc1On0Adapter::allocate(
+        const std::shared_ptr<Descriptor>& descriptor,
+        gralloc1_backing_store_t store,
+        buffer_handle_t* outBufferHandle)
+{
+    ALOGV("allocate(%" PRIu64 ", %#" PRIx64 ")", descriptor->id, store);
+
+    // If this function is being called, it's because we handed out its function
+    // pointer, which only occurs when mDevice has been loaded successfully and
+    // we are permitted to allocate
+
+    int usage = static_cast<int>(descriptor->producerUsage) |
+            static_cast<int>(descriptor->consumerUsage);
+    buffer_handle_t handle = nullptr;
+    int stride = 0;
+    ALOGV("Calling alloc(%p, %u, %u, %i, %u)", mDevice, descriptor->width,
+            descriptor->height, descriptor->format, usage);
+    auto error = mDevice->alloc(mDevice,
+            static_cast<int>(descriptor->width),
+            static_cast<int>(descriptor->height), descriptor->format,
+            usage, &handle, &stride);
+    if (error != 0) {
+        ALOGE("gralloc0 allocation failed: %d (%s)", error,
+                strerror(-error));
+        return GRALLOC1_ERROR_NO_RESOURCES;
+    }
+
+    *outBufferHandle = handle;
+    auto buffer = std::make_shared<Buffer>(handle, store, *descriptor, stride,
+            true);
+
+    std::lock_guard<std::mutex> lock(mBufferMutex);
+    mBuffers.emplace(handle, std::move(buffer));
+
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::allocateWithIdHook(
+        gralloc1_device_t* device, gralloc1_buffer_descriptor_t descriptorId,
+        gralloc1_backing_store_t store, buffer_handle_t* outBuffer)
+{
+    auto adapter = getAdapter(device);
+
+    auto descriptor = adapter->getDescriptor(descriptorId);
+    if (!descriptor) {
+        return GRALLOC1_ERROR_BAD_DESCRIPTOR;
+    }
+
+    buffer_handle_t bufferHandle = nullptr;
+    auto error = adapter->allocate(descriptor, store, &bufferHandle);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return error;
+    }
+
+    *outBuffer = bufferHandle;
+    return error;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::retain(
+        const std::shared_ptr<Buffer>& buffer)
+{
+    buffer->retain();
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::release(
+        const std::shared_ptr<Buffer>& buffer)
+{
+    if (!buffer->release()) {
+        return GRALLOC1_ERROR_NONE;
+    }
+
+    buffer_handle_t handle = buffer->getHandle();
+    if (buffer->wasAllocated()) {
+        ALOGV("Calling free(%p)", handle);
+        int result = mDevice->free(mDevice, handle);
+        if (result != 0) {
+            ALOGE("gralloc0 free failed: %d", result);
+        }
+    } else {
+        ALOGV("Calling unregisterBuffer(%p)", handle);
+        int result = mModule->unregisterBuffer(mModule, handle);
+        if (result != 0) {
+            ALOGE("gralloc0 unregister failed: %d", result);
+        }
+    }
+
+    std::lock_guard<std::mutex> lock(mBufferMutex);
+    mBuffers.erase(handle);
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::retain(
+        const android::GraphicBuffer* graphicBuffer)
+{
+    ALOGV("retainGraphicBuffer(%p, %#" PRIx64 ")",
+            graphicBuffer->getNativeBuffer()->handle, graphicBuffer->getId());
+
+    buffer_handle_t handle = graphicBuffer->getNativeBuffer()->handle;
+    std::lock_guard<std::mutex> lock(mBufferMutex);
+    if (mBuffers.count(handle) != 0) {
+        mBuffers[handle]->retain();
+        return GRALLOC1_ERROR_NONE;
+    }
+
+    ALOGV("Calling registerBuffer(%p)", handle);
+    int result = mModule->registerBuffer(mModule, handle);
+    if (result != 0) {
+        ALOGE("gralloc0 register failed: %d", result);
+        return GRALLOC1_ERROR_NO_RESOURCES;
+    }
+
+    Descriptor descriptor{this, sNextBufferDescriptorId++};
+    descriptor.setDimensions(graphicBuffer->getWidth(),
+            graphicBuffer->getHeight());
+    descriptor.setFormat(graphicBuffer->getPixelFormat());
+    descriptor.setProducerUsage(
+            static_cast<gralloc1_producer_usage_t>(graphicBuffer->getUsage()));
+    descriptor.setConsumerUsage(
+            static_cast<gralloc1_consumer_usage_t>(graphicBuffer->getUsage()));
+    auto buffer = std::make_shared<Buffer>(handle,
+            static_cast<gralloc1_backing_store_t>(graphicBuffer->getId()),
+            descriptor, graphicBuffer->getStride(), false);
+    mBuffers.emplace(handle, std::move(buffer));
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lock(
+        const std::shared_ptr<Buffer>& buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t& accessRegion, void** outData,
+        const sp<Fence>& acquireFence)
+{
+    if (mMinorVersion >= 3) {
+        int result = mModule->lockAsync(mModule, buffer->getHandle(),
+                static_cast<int32_t>(producerUsage | consumerUsage),
+                accessRegion.left, accessRegion.top, accessRegion.width,
+                accessRegion.height, outData, acquireFence->dup());
+        if (result != 0) {
+            return GRALLOC1_ERROR_UNSUPPORTED;
+        }
+    } else {
+        acquireFence->waitForever("Gralloc1On0Adapter::lock");
+        int result = mModule->lock(mModule, buffer->getHandle(),
+                static_cast<int32_t>(producerUsage | consumerUsage),
+                accessRegion.left, accessRegion.top, accessRegion.width,
+                accessRegion.height, outData);
+        ALOGV("gralloc0 lock returned %d", result);
+        if (result != 0) {
+            return GRALLOC1_ERROR_UNSUPPORTED;
+        }
+    }
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lockFlex(
+        const std::shared_ptr<Buffer>& /*buffer*/,
+        gralloc1_producer_usage_t /*producerUsage*/,
+        gralloc1_consumer_usage_t /*consumerUsage*/,
+        const gralloc1_rect_t& /*accessRegion*/,
+        struct android_flex_layout* /*outData*/,
+        const sp<Fence>& /*acquireFence*/)
+{
+    // TODO
+    return GRALLOC1_ERROR_UNSUPPORTED;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lockYCbCr(
+        const std::shared_ptr<Buffer>& buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t& accessRegion, struct android_ycbcr* outData,
+        const sp<Fence>& acquireFence)
+{
+    if (mMinorVersion >= 3 && mModule->lockAsync_ycbcr) {
+        int result = mModule->lockAsync_ycbcr(mModule, buffer->getHandle(),
+                static_cast<int>(producerUsage | consumerUsage),
+                accessRegion.left, accessRegion.top, accessRegion.width,
+                accessRegion.height, outData, acquireFence->dup());
+        if (result != 0) {
+            return GRALLOC1_ERROR_UNSUPPORTED;
+        }
+    } else if (mModule->lock_ycbcr) {
+        acquireFence->waitForever("Gralloc1On0Adapter::lockYCbCr");
+        int result = mModule->lock_ycbcr(mModule, buffer->getHandle(),
+                static_cast<int>(producerUsage | consumerUsage),
+                accessRegion.left, accessRegion.top, accessRegion.width,
+                accessRegion.height, outData);
+        ALOGV("gralloc0 lockYCbCr returned %d", result);
+        if (result != 0) {
+            return GRALLOC1_ERROR_UNSUPPORTED;
+        }
+    } else {
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::unlock(
+        const std::shared_ptr<Buffer>& buffer,
+        sp<Fence>* outReleaseFence)
+{
+    if (mMinorVersion >= 3) {
+        int fenceFd = -1;
+        int result = mModule->unlockAsync(mModule, buffer->getHandle(),
+                &fenceFd);
+        if (result != 0) {
+            close(fenceFd);
+            ALOGE("gralloc0 unlockAsync failed: %d", result);
+        } else {
+            *outReleaseFence = new Fence(fenceFd);
+        }
+    } else {
+        int result = mModule->unlock(mModule, buffer->getHandle());
+        if (result != 0) {
+            ALOGE("gralloc0 unlock failed: %d", result);
+        }
+    }
+    return GRALLOC1_ERROR_NONE;
+}
+
+std::shared_ptr<Gralloc1On0Adapter::Descriptor>
+Gralloc1On0Adapter::getDescriptor(gralloc1_buffer_descriptor_t descriptorId)
+{
+    std::lock_guard<std::mutex> lock(mDescriptorMutex);
+    if (mDescriptors.count(descriptorId) == 0) {
+        return nullptr;
+    }
+
+    return mDescriptors[descriptorId];
+}
+
+std::shared_ptr<Gralloc1On0Adapter::Buffer> Gralloc1On0Adapter::getBuffer(
+        buffer_handle_t bufferHandle)
+{
+    std::lock_guard<std::mutex> lock(mBufferMutex);
+    if (mBuffers.count(bufferHandle) == 0) {
+        return nullptr;
+    }
+
+    return mBuffers[bufferHandle];
+}
+
+std::atomic<gralloc1_buffer_descriptor_t>
+        Gralloc1On0Adapter::sNextBufferDescriptorId(1);
+
+} // namespace android
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 4fe0946..97b948d 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -54,7 +54,7 @@
 }
 
 GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
-        PixelFormat inFormat, uint32_t inUsage)
+        PixelFormat inFormat, uint32_t inUsage, std::string requestorName)
     : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
 {
@@ -64,7 +64,8 @@
     format =
     usage  = 0;
     handle = NULL;
-    mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage);
+    mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage,
+            std::move(requestorName));
 }
 
 GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
@@ -151,7 +152,7 @@
         allocator.free(handle);
         handle = 0;
     }
-    return initSize(inWidth, inHeight, inFormat, inUsage);
+    return initSize(inWidth, inHeight, inFormat, inUsage, "[Reallocation]");
 }
 
 bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight,
@@ -165,12 +166,12 @@
 }
 
 status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
-        PixelFormat inFormat, uint32_t inUsage)
+        PixelFormat inFormat, uint32_t inUsage, std::string requestorName)
 {
     GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
     uint32_t outStride = 0;
-    status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage,
-            &handle, &outStride);
+    status_t err = allocator.allocate(inWidth, inHeight, inFormat, inUsage,
+            &handle, &outStride, mId, std::move(requestorName));
     if (err == NO_ERROR) {
         width = static_cast<int>(inWidth);
         height = static_cast<int>(inHeight);
@@ -390,7 +391,7 @@
     mOwner = ownHandle;
 
     if (handle != 0) {
-        status_t err = mBufferMapper.registerBuffer(handle);
+        status_t err = mBufferMapper.registerBuffer(this);
         if (err != NO_ERROR) {
             width = height = stride = format = usage = 0;
             handle = NULL;
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 9b265af..edfff4d 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -25,6 +25,7 @@
 #include <utils/Trace.h>
 
 #include <ui/GraphicBufferAllocator.h>
+#include <ui/Gralloc1On0Adapter.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -36,20 +37,10 @@
     GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
 
 GraphicBufferAllocator::GraphicBufferAllocator()
-    : mAllocDev(0)
-{
-    hw_module_t const* module;
-    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
-    ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
-    if (err == 0) {
-        gralloc_open(module, &mAllocDev);
-    }
-}
+  : mLoader(std::make_unique<Gralloc1::Loader>()),
+    mDevice(mLoader->getDevice()) {}
 
-GraphicBufferAllocator::~GraphicBufferAllocator()
-{
-    gralloc_close(mAllocDev);
-}
+GraphicBufferAllocator::~GraphicBufferAllocator() {}
 
 void GraphicBufferAllocator::dump(String8& result) const
 {
@@ -64,23 +55,23 @@
     for (size_t i=0 ; i<c ; i++) {
         const alloc_rec_t& rec(list.valueAt(i));
         if (rec.size) {
-            snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n",
+            snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x | %s\n",
                     list.keyAt(i), rec.size/1024.0f,
-                    rec.width, rec.stride, rec.height, rec.format, rec.usage);
+                    rec.width, rec.stride, rec.height, rec.format, rec.usage,
+                    rec.requestorName.c_str());
         } else {
-            snprintf(buffer, SIZE, "%10p: unknown     | %4u (%4u) x %4u | %8X | 0x%08x\n",
+            snprintf(buffer, SIZE, "%10p: unknown     | %4u (%4u) x %4u | %8X | 0x%08x | %s\n",
                     list.keyAt(i),
-                    rec.width, rec.stride, rec.height, rec.format, rec.usage);
+                    rec.width, rec.stride, rec.height, rec.format, rec.usage,
+                    rec.requestorName.c_str());
         }
         result.append(buffer);
         total += rec.size;
     }
     snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0f);
     result.append(buffer);
-    if (mAllocDev->common.version >= 1 && mAllocDev->dump) {
-        mAllocDev->dump(mAllocDev, buffer, SIZE);
-        result.append(buffer);
-    }
+    std::string deviceDump = mDevice->dump();
+    result.append(deviceDump.c_str(), deviceDump.size());
 }
 
 void GraphicBufferAllocator::dumpToSystemLog()
@@ -90,9 +81,9 @@
     ALOGD("%s", s.string());
 }
 
-status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,
+status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,
         PixelFormat format, uint32_t usage, buffer_handle_t* handle,
-        uint32_t* stride)
+        uint32_t* stride, uint64_t graphicBufferId, std::string requestorName)
 {
     ATRACE_CALL();
 
@@ -101,22 +92,46 @@
     if (!width || !height)
         width = height = 1;
 
-    // we have a h/w allocator and h/w buffer is requested
-    status_t err;
-
     // Filter out any usage bits that should not be passed to the gralloc module
     usage &= GRALLOC_USAGE_ALLOC_MASK;
 
-    int outStride = 0;
-    err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),
-            static_cast<int>(height), format, static_cast<int>(usage), handle,
-            &outStride);
-    *stride = static_cast<uint32_t>(outStride);
+    auto descriptor = mDevice->createDescriptor();
+    auto error = descriptor->setDimensions(width, height);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to set dimensions to (%u, %u): %d", width, height, error);
+        return BAD_VALUE;
+    }
+    error = descriptor->setFormat(static_cast<android_pixel_format_t>(format));
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to set format to %d: %d", format, error);
+        return BAD_VALUE;
+    }
+    error = descriptor->setProducerUsage(
+            static_cast<gralloc1_producer_usage_t>(usage));
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to set producer usage to %u: %d", usage, error);
+        return BAD_VALUE;
+    }
+    error = descriptor->setConsumerUsage(
+            static_cast<gralloc1_consumer_usage_t>(usage));
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to set consumer usage to %u: %d", usage, error);
+        return BAD_VALUE;
+    }
 
-    ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
-            width, height, format, usage, err, strerror(-err));
+    error = mDevice->allocate(descriptor, graphicBufferId, handle);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to allocate (%u x %u) format %d usage %u: %d",
+                width, height, format, usage, error);
+        return NO_MEMORY;
+    }
 
-    if (err == NO_ERROR) {
+    error = mDevice->getStride(*handle, stride);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGW("Failed to get stride from buffer: %d", error);
+    }
+
+    if (error == NO_ERROR) {
         Mutex::Autolock _l(sLock);
         KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
         uint32_t bpp = bytesPerPixel(format);
@@ -127,27 +142,27 @@
         rec.format = format;
         rec.usage = usage;
         rec.size = static_cast<size_t>(height * (*stride) * bpp);
+        rec.requestorName = std::move(requestorName);
         list.add(*handle, rec);
     }
 
-    return err;
+    return NO_ERROR;
 }
 
 status_t GraphicBufferAllocator::free(buffer_handle_t handle)
 {
     ATRACE_CALL();
-    status_t err;
 
-    err = mAllocDev->free(mAllocDev, handle);
-
-    ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
-    if (err == NO_ERROR) {
-        Mutex::Autolock _l(sLock);
-        KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
-        list.removeItem(handle);
+    auto error = mDevice->release(handle);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to free buffer: %d", error);
     }
 
-    return err;
+    Mutex::Autolock _l(sLock);
+    KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+    list.removeItem(handle);
+
+    return NO_ERROR;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 90a1c11..481d43c 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "GraphicBufferMapper"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
 
 #include <stdint.h>
 #include <errno.h>
@@ -31,11 +32,11 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
+#include <ui/Gralloc1On0Adapter.h>
 #include <ui/GraphicBufferMapper.h>
 #include <ui/Rect.h>
 
-#include <hardware/gralloc.h>
-
+#include <system/graphics.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -43,151 +44,247 @@
 ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
 
 GraphicBufferMapper::GraphicBufferMapper()
-    : mAllocMod(0)
-{
-    hw_module_t const* module;
-    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
-    ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
-    if (err == 0) {
-        mAllocMod = reinterpret_cast<gralloc_module_t const *>(module);
-    }
-}
+  : mLoader(std::make_unique<Gralloc1::Loader>()),
+    mDevice(mLoader->getDevice()) {}
+
+
 
 status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
 {
     ATRACE_CALL();
-    status_t err;
 
-    err = mAllocMod->registerBuffer(mAllocMod, handle);
+    gralloc1_error_t error = mDevice->retain(handle);
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
+            handle, error);
 
-    ALOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
-            handle, err, strerror(-err));
-    return err;
+    return error;
+}
+
+status_t GraphicBufferMapper::registerBuffer(const GraphicBuffer* buffer)
+{
+    ATRACE_CALL();
+
+    gralloc1_error_t error = mDevice->retain(buffer);
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
+            buffer->getNativeBuffer()->handle, error);
+
+    return error;
 }
 
 status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle)
 {
     ATRACE_CALL();
-    status_t err;
 
-    err = mAllocMod->unregisterBuffer(mAllocMod, handle);
+    gralloc1_error_t error = mDevice->release(handle);
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "unregisterBuffer(%p): failed %d",
+            handle, error);
 
-    ALOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)",
-            handle, err, strerror(-err));
-    return err;
+    return error;
 }
 
-status_t GraphicBufferMapper::lock(buffer_handle_t handle,
-        uint32_t usage, const Rect& bounds, void** vaddr)
-{
-    ATRACE_CALL();
-    status_t err;
-
-    err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage),
-            bounds.left, bounds.top, bounds.width(), bounds.height(),
-            vaddr);
-
-    ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
-    return err;
+static inline gralloc1_rect_t asGralloc1Rect(const Rect& rect) {
+    gralloc1_rect_t outRect{};
+    outRect.left = rect.left;
+    outRect.top = rect.top;
+    outRect.width = rect.width();
+    outRect.height = rect.height();
+    return outRect;
 }
 
-status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle,
-        uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr)
+status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
+        const Rect& bounds, void** vaddr)
 {
-    ATRACE_CALL();
-    status_t err;
+    return lockAsync(handle, usage, bounds, vaddr, -1);
+}
 
-    if (mAllocMod->lock_ycbcr == NULL) {
-        return -EINVAL; // do not log failure
-    }
-
-    err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage),
-            bounds.left, bounds.top, bounds.width(), bounds.height(),
-            ycbcr);
-
-    ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
-    return err;
+status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, uint32_t usage,
+        const Rect& bounds, android_ycbcr *ycbcr)
+{
+    return lockAsyncYCbCr(handle, usage, bounds, ycbcr, -1);
 }
 
 status_t GraphicBufferMapper::unlock(buffer_handle_t handle)
 {
-    ATRACE_CALL();
-    status_t err;
-
-    err = mAllocMod->unlock(mAllocMod, handle);
-
-    ALOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
-    return err;
+    int32_t fenceFd = -1;
+    status_t error = unlockAsync(handle, &fenceFd);
+    if (error == NO_ERROR) {
+        sync_wait(fenceFd, -1);
+        close(fenceFd);
+    }
+    return error;
 }
 
 status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
         uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd)
 {
     ATRACE_CALL();
-    status_t err;
 
-    if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) {
-        err = mAllocMod->lockAsync(mAllocMod, handle, static_cast<int>(usage),
-                bounds.left, bounds.top, bounds.width(), bounds.height(),
-                vaddr, fenceFd);
-    } else {
-        if (fenceFd >= 0) {
-            sync_wait(fenceFd, -1);
-            close(fenceFd);
-        }
-        err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage),
-                bounds.left, bounds.top, bounds.width(), bounds.height(),
-                vaddr);
+    gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
+    sp<Fence> fence = new Fence(fenceFd);
+    gralloc1_error_t error = mDevice->lock(handle,
+            static_cast<gralloc1_producer_usage_t>(usage),
+            static_cast<gralloc1_consumer_usage_t>(usage),
+            &accessRegion, vaddr, fence);
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "lock(%p, ...) failed: %d", handle,
+            error);
+
+    return error;
+}
+
+static inline bool isValidYCbCrPlane(const android_flex_plane_t& plane) {
+    if (plane.bits_per_component != 8) {
+        ALOGV("Invalid number of bits per component: %d",
+                plane.bits_per_component);
+        return false;
+    }
+    if (plane.bits_used != 8) {
+        ALOGV("Invalid number of bits used: %d", plane.bits_used);
+        return false;
     }
 
-    ALOGW_IF(err, "lockAsync(...) failed %d (%s)", err, strerror(-err));
-    return err;
+    bool hasValidIncrement = plane.h_increment == 1 ||
+            (plane.component != FLEX_COMPONENT_Y && plane.h_increment == 2);
+    hasValidIncrement = hasValidIncrement && plane.v_increment > 0;
+    if (!hasValidIncrement) {
+        ALOGV("Invalid increment: h %d v %d", plane.h_increment,
+                plane.v_increment);
+        return false;
+    }
+
+    return true;
 }
 
 status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
         uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd)
 {
     ATRACE_CALL();
-    status_t err;
 
-    if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3
-            && mAllocMod->lockAsync_ycbcr != NULL) {
-        err = mAllocMod->lockAsync_ycbcr(mAllocMod, handle,
-                static_cast<int>(usage), bounds.left, bounds.top,
-                bounds.width(), bounds.height(), ycbcr, fenceFd);
-    } else if (mAllocMod->lock_ycbcr != NULL) {
-        if (fenceFd >= 0) {
-            sync_wait(fenceFd, -1);
-            close(fenceFd);
-        }
-        err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage),
-                bounds.left, bounds.top, bounds.width(), bounds.height(),
-                ycbcr);
-    } else {
-        if (fenceFd >= 0) {
-            close(fenceFd);
-        }
-        return -EINVAL; // do not log failure
+    gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
+    sp<Fence> fence = new Fence(fenceFd);
+
+    if (mDevice->hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        gralloc1_error_t error = mDevice->lockYCbCr(handle,
+                static_cast<gralloc1_producer_usage_t>(usage),
+                static_cast<gralloc1_consumer_usage_t>(usage),
+                &accessRegion, ycbcr, fence);
+        ALOGW_IF(error != GRALLOC1_ERROR_NONE, "lockYCbCr(%p, ...) failed: %d",
+                handle, error);
+        return error;
     }
 
-    ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
-    return err;
+    uint32_t numPlanes = 0;
+    gralloc1_error_t error = mDevice->getNumFlexPlanes(handle, &numPlanes);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGV("Failed to retrieve number of flex planes: %d", error);
+        return error;
+    }
+    if (numPlanes < 3) {
+        ALOGV("Not enough planes for YCbCr (%u found)", numPlanes);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    std::vector<android_flex_plane_t> planes(numPlanes);
+    android_flex_layout_t flexLayout{};
+    flexLayout.num_planes = numPlanes;
+    flexLayout.planes = planes.data();
+
+    error = mDevice->lockFlex(handle,
+            static_cast<gralloc1_producer_usage_t>(usage),
+            static_cast<gralloc1_consumer_usage_t>(usage),
+            &accessRegion, &flexLayout, fence);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGW("lockFlex(%p, ...) failed: %d", handle, error);
+        return error;
+    }
+    if (flexLayout.format != FLEX_FORMAT_YCbCr) {
+        ALOGV("Unable to convert flex-format buffer to YCbCr");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    // Find planes
+    auto yPlane = planes.cend();
+    auto cbPlane = planes.cend();
+    auto crPlane = planes.cend();
+    for (auto planeIter = planes.cbegin(); planeIter != planes.cend();
+            ++planeIter) {
+        if (planeIter->component == FLEX_COMPONENT_Y) {
+            yPlane = planeIter;
+        } else if (planeIter->component == FLEX_COMPONENT_Cb) {
+            cbPlane = planeIter;
+        } else if (planeIter->component == FLEX_COMPONENT_Cr) {
+            crPlane = planeIter;
+        }
+    }
+    if (yPlane == planes.cend()) {
+        ALOGV("Unable to find Y plane");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (cbPlane == planes.cend()) {
+        ALOGV("Unable to find Cb plane");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (crPlane == planes.cend()) {
+        ALOGV("Unable to find Cr plane");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    // Validate planes
+    if (!isValidYCbCrPlane(*yPlane)) {
+        ALOGV("Y plane is invalid");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (!isValidYCbCrPlane(*cbPlane)) {
+        ALOGV("Cb plane is invalid");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (!isValidYCbCrPlane(*crPlane)) {
+        ALOGV("Cr plane is invalid");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (cbPlane->v_increment != crPlane->v_increment) {
+        ALOGV("Cb and Cr planes have different step (%d vs. %d)",
+                cbPlane->v_increment, crPlane->v_increment);
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (cbPlane->h_increment != crPlane->h_increment) {
+        ALOGV("Cb and Cr planes have different stride (%d vs. %d)",
+                cbPlane->h_increment, crPlane->h_increment);
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    // Pack plane data into android_ycbcr struct
+    ycbcr->y = yPlane->top_left;
+    ycbcr->cb = cbPlane->top_left;
+    ycbcr->cr = crPlane->top_left;
+    ycbcr->ystride = static_cast<size_t>(yPlane->v_increment);
+    ycbcr->cstride = static_cast<size_t>(cbPlane->v_increment);
+    ycbcr->chroma_step = static_cast<size_t>(cbPlane->h_increment);
+
+    return error;
 }
 
 status_t GraphicBufferMapper::unlockAsync(buffer_handle_t handle, int *fenceFd)
 {
     ATRACE_CALL();
-    status_t err;
 
-    if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) {
-        err = mAllocMod->unlockAsync(mAllocMod, handle, fenceFd);
-    } else {
-        *fenceFd = -1;
-        err = mAllocMod->unlock(mAllocMod, handle);
+    sp<Fence> fence = Fence::NO_FENCE;
+    gralloc1_error_t error = mDevice->unlock(handle, &fence);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("unlock(%p) failed: %d", handle, error);
+        return error;
     }
 
-    ALOGW_IF(err, "unlockAsync(...) failed %d (%s)", err, strerror(-err));
-    return err;
+    *fenceFd = fence->dup();
+    return error;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
new file mode 100644
index 0000000..8cdab8c
--- /dev/null
+++ b/libs/ui/tests/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2014 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.
+//
+
+cc_test {
+    name: "Region_test",
+    shared_libs: ["libui"],
+    srcs: ["Region_test.cpp"],
+}
+
+cc_test {
+    name: "vec_test",
+    srcs: ["vec_test.cpp"],
+}
+
+cc_test {
+    name: "mat_test",
+    srcs: ["mat_test.cpp"],
+}
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
deleted file mode 100644
index 6438b1f..0000000
--- a/libs/ui/tests/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Copyright (C) 2014 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SHARED_LIBRARIES := libui
-LOCAL_SRC_FILES := Region_test.cpp
-LOCAL_MODULE := Region_test
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SRC_FILES := vec_test.cpp
-LOCAL_MODULE := vec_test
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SRC_FILES := mat_test.cpp
-LOCAL_MODULE := mat_test
-include $(BUILD_NATIVE_TEST)
diff --git a/opengl/libagl/context.h b/opengl/libagl/context.h
index d23f435..18ef7d5 100644
--- a/opengl/libagl/context.h
+++ b/opengl/libagl/context.h
@@ -26,7 +26,8 @@
 #endif
 
 #include <private/pixelflinger/ggl_context.h>
-#include <hardware/gralloc.h>
+
+#include <system/window.h>
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
@@ -615,7 +616,7 @@
     culling_t               cull;
     lighting_t              lighting;
     user_clip_planes_t      clipPlanes;
-    compute_iterators_t     lerp;           __attribute__((aligned(32)));
+    compute_iterators_t     lerp           __attribute__((aligned(32)));
     vertex_t                current;
     vec4_t                  currentColorClamped;
     vec3_t                  currentNormal;
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 92139e9..c1efd1c 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -32,6 +32,7 @@
 #include <utils/threads.h>
 #include <ui/ANativeObjectBase.h>
 #include <ui/Fence.h>
+#include <ui/GraphicBufferMapper.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -242,7 +243,6 @@
     ANativeWindow*   nativeWindow;
     ANativeWindowBuffer*   buffer;
     ANativeWindowBuffer*   previousBuffer;
-    gralloc_module_t const*    module;
     int width;
     int height;
     void* bits;
@@ -341,16 +341,12 @@
         EGLConfig config,
         int32_t depthFormat,
         ANativeWindow* window)
-    : egl_surface_t(dpy, config, depthFormat), 
-    nativeWindow(window), buffer(0), previousBuffer(0), module(0),
-    bits(NULL)
+    : egl_surface_t(dpy, config, depthFormat),
+    nativeWindow(window), buffer(0), previousBuffer(0), bits(NULL)
 {
-    hw_module_t const* pModule;
-    hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
-    module = reinterpret_cast<gralloc_module_t const*>(pModule);
 
     pixelFormatTable = gglGetPixelFormatTable();
-    
+
     // keep a reference on the window
     nativeWindow->common.incRef(&nativeWindow->common);
     nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
@@ -440,22 +436,16 @@
 status_t egl_window_surface_v2_t::lock(
         ANativeWindowBuffer* buf, int usage, void** vaddr)
 {
-    int err;
-
-    err = module->lock(module, buf->handle,
-            usage, 0, 0, buf->width, buf->height, vaddr);
-
-    return err;
+    auto& mapper = GraphicBufferMapper::get();
+    return mapper.lock(buf->handle, usage,
+            android::Rect(buf->width, buf->height), vaddr);
 }
 
 status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
 {
     if (!buf) return BAD_VALUE;
-    int err = NO_ERROR;
-
-    err = module->unlock(module, buf->handle);
-
-    return err;
+    auto& mapper = GraphicBufferMapper::get();
+    return mapper.unlock(buf->handle);
 }
 
 void egl_window_surface_v2_t::copyBlt(
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
index 479bf7e..e7fe9d7 100644
--- a/opengl/libagl/light.cpp
+++ b/opengl/libagl/light.cpp
@@ -229,7 +229,7 @@
 #endif
         vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
     }
-    const vec4_t eyeViewer = { 0, 0, 0x10000, 0 };
+    const vec4_t eyeViewer = {{{ 0, 0, 0x10000, 0 }}};
 #if OBJECT_SPACE_LIGHTING
     c->transforms.mvui.point3(&c->transforms.mvui,
             &c->lighting.objViewer, &eyeViewer);
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
index cdeccb3..034c857 100644
--- a/opengl/libagl/matrix.cpp
+++ b/opengl/libagl/matrix.cpp
@@ -253,13 +253,13 @@
 {
     GLfloat const* const m = lhs.m;
     for (int i=0 ; i<4 ; i++) {
-        register const float rhs_i0 = rhs.m[ I(i,0) ];
-        register float ri0 = m[ I(0,0) ] * rhs_i0;
-        register float ri1 = m[ I(0,1) ] * rhs_i0;
-        register float ri2 = m[ I(0,2) ] * rhs_i0;
-        register float ri3 = m[ I(0,3) ] * rhs_i0;
+        const float rhs_i0 = rhs.m[ I(i,0) ];
+        float ri0 = m[ I(0,0) ] * rhs_i0;
+        float ri1 = m[ I(0,1) ] * rhs_i0;
+        float ri2 = m[ I(0,2) ] * rhs_i0;
+        float ri3 = m[ I(0,3) ] * rhs_i0;
         for (int j=1 ; j<4 ; j++) {
-            register const float rhs_ij = rhs.m[ I(i,j) ];
+            const float rhs_ij = rhs.m[ I(i,j) ];
             ri0 += m[ I(j,0) ] * rhs_ij;
             ri1 += m[ I(j,1) ] * rhs_ij;
             ri2 += m[ I(j,2) ] * rhs_ij;
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 9aa1c4f..3fe5ed0 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -25,6 +25,9 @@
 
 #include <ETC1/etc1.h>
 
+#include <ui/GraphicBufferMapper.h>
+#include <ui/Rect.h>
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -128,17 +131,11 @@
             ANativeWindowBuffer* native_buffer = u.texture->buffer;
             if (native_buffer) {
                 c->rasterizer.procs.activeTexture(c, i);
-                hw_module_t const* pModule;
-                if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
-                    continue;
 
-                gralloc_module_t const* module =
-                    reinterpret_cast<gralloc_module_t const*>(pModule);
-
+                auto& mapper = GraphicBufferMapper::get();
                 void* vaddr;
-                int err = module->lock(module, native_buffer->handle,
-                        GRALLOC_USAGE_SW_READ_OFTEN,
-                        0, 0, native_buffer->width, native_buffer->height,
+                mapper.lock(native_buffer->handle, GRALLOC_USAGE_SW_READ_OFTEN,
+                        Rect(native_buffer->width, native_buffer->height),
                         &vaddr);
 
                 u.texture->setImageBits(vaddr);
@@ -156,14 +153,10 @@
             ANativeWindowBuffer* native_buffer = u.texture->buffer;
             if (native_buffer) {
                 c->rasterizer.procs.activeTexture(c, i);
-                hw_module_t const* pModule;
-                if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
-                    continue;
 
-                gralloc_module_t const* module =
-                    reinterpret_cast<gralloc_module_t const*>(pModule);
+                auto& mapper = GraphicBufferMapper::get();
+                mapper.unlock(native_buffer->handle);
 
-                module->unlock(module, native_buffer->handle);
                 u.texture->setImageBits(NULL);
                 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
             }
@@ -405,7 +398,7 @@
     return 0;
 }
 
-static size_t dataSizePalette4(int numLevels, int width, int height, int format)
+static GLsizei dataSizePalette4(int numLevels, int width, int height, int format)
 {
     int indexBits = 8;
     int entrySize = 0;
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index dfe0fac..f0ba728 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -31,7 +31,7 @@
 	EGL/Loader.cpp 	       \
 #
 
-LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libui
+LOCAL_SHARED_LIBRARIES += libbinder libcutils libutils liblog libui
 LOCAL_MODULE:= libEGL
 LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL
 LOCAL_SHARED_LIBRARIES += libdl
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 5de5599..0c4b9e9 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -33,6 +33,8 @@
 #include <cutils/properties.h>
 #include <cutils/memory.h>
 
+#include <gui/ISurfaceComposer.h>
+
 #include <ui/GraphicBuffer.h>
 
 #include <utils/KeyedVector.h>
@@ -40,6 +42,10 @@
 #include <utils/String8.h>
 #include <utils/Trace.h>
 
+#include "binder/Binder.h"
+#include "binder/Parcel.h"
+#include "binder/IServiceManager.h"
+
 #include "../egl_impl.h"
 #include "../hooks.h"
 
@@ -1833,18 +1839,77 @@
         return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
     }
 
-    GraphicBuffer* gBuffer = new GraphicBuffer(width, height, format, usage);
-    const status_t err = gBuffer->initCheck();
+#define CHECK_ERROR_CONDITION(message) \
+    if (err != NO_ERROR) { \
+        ALOGE(message); \
+        goto error_condition; \
+    }
+
+    // The holder is used to destroy the buffer if an error occurs.
+    GraphicBuffer* gBuffer = new GraphicBuffer();
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> surfaceFlinger = sm->getService(String16("SurfaceFlinger"));
+    sp<IBinder> allocator;
+    Parcel sc_data, sc_reply, data, reply;
+    status_t err = NO_ERROR;
+    if (sm == NULL) {
+        ALOGE("Unable to connect to ServiceManager");
+        goto error_condition;
+    }
+
+    // Obtain an allocator.
+    if (surfaceFlinger == NULL) {
+        ALOGE("Unable to connect to SurfaceFlinger");
+        goto error_condition;
+    }
+    sc_data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+    err = surfaceFlinger->transact(
+            BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, sc_data, &sc_reply);
+    CHECK_ERROR_CONDITION("Unable to obtain allocator from SurfaceFlinger");
+    allocator = sc_reply.readStrongBinder();
+
+    if (allocator == NULL) {
+        ALOGE("Unable to obtain an ISurfaceComposer");
+        goto error_condition;
+    }
+    data.writeInterfaceToken(String16("android.ui.IGraphicBufferAlloc"));
+    err = data.writeUint32(width);
+    CHECK_ERROR_CONDITION("Unable to write width");
+    err = data.writeUint32(height);
+    CHECK_ERROR_CONDITION("Unable to write height");
+    err = data.writeInt32(static_cast<int32_t>(format));
+    CHECK_ERROR_CONDITION("Unable to write format");
+    err = data.writeUint32(usage);
+    CHECK_ERROR_CONDITION("Unable to write usage");
+    err = data.writeUtf8AsUtf16(
+            std::string("[eglCreateNativeClientBufferANDROID pid ") +
+            std::to_string(getpid()) + ']');
+    CHECK_ERROR_CONDITION("Unable to write requestor name");
+    err = allocator->transact(IBinder::FIRST_CALL_TRANSACTION, data,
+            &reply);
+    CHECK_ERROR_CONDITION(
+            "Unable to request buffer allocation from surface composer");
+    err = reply.readInt32();
+    CHECK_ERROR_CONDITION("Unable to obtain buffer from surface composer");
+    err = reply.read(*gBuffer);
+    CHECK_ERROR_CONDITION("Unable to read buffer from surface composer");
+
+    err = gBuffer->initCheck();
     if (err != NO_ERROR) {
         ALOGE("Unable to create native buffer { w=%d, h=%d, f=%d, u=%#x }: %#x",
                 width, height, format, usage, err);
-        // Destroy the buffer.
-        sp<GraphicBuffer> holder(gBuffer);
-        return setError(EGL_BAD_ALLOC, (EGLClientBuffer)0);
+        goto error_condition;
     }
     ALOGD("Created new native buffer %p { w=%d, h=%d, f=%d, u=%#x }",
             gBuffer, width, height, format, usage);
     return static_cast<EGLClientBuffer>(gBuffer->getNativeBuffer());
+
+#undef CHECK_ERROR_CONDITION
+
+error_condition:
+    // Delete the buffer.
+    sp<GraphicBuffer> holder(gBuffer);
+    return setError(EGL_BAD_ALLOC, (EGLClientBuffer)0);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 1c054f5..90c69ce 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -455,7 +455,7 @@
     };
 
     struct ConfigurationChangedEntry : EventEntry {
-        ConfigurationChangedEntry(nsecs_t eventTime);
+        explicit ConfigurationChangedEntry(nsecs_t eventTime);
         virtual void appendDescription(String8& msg) const;
 
     protected:
@@ -591,7 +591,7 @@
 
     class Connection;
     struct CommandEntry : Link<CommandEntry> {
-        CommandEntry(Command command);
+        explicit CommandEntry(Command command);
         ~CommandEntry();
 
         Command command;
diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h
index 1ec09ce..ea3dd1c 100644
--- a/services/inputflinger/InputListener.h
+++ b/services/inputflinger/InputListener.h
@@ -40,7 +40,7 @@
 
     inline NotifyConfigurationChangedArgs() { }
 
-    NotifyConfigurationChangedArgs(nsecs_t eventTime);
+    explicit NotifyConfigurationChangedArgs(nsecs_t eventTime);
 
     NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other);
 
@@ -178,7 +178,7 @@
     virtual ~QueuedInputListener();
 
 public:
-    QueuedInputListener(const sp<InputListenerInterface>& innerListener);
+    explicit QueuedInputListener(const sp<InputListenerInterface>& innerListener);
 
     virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
     virtual void notifyKey(const NotifyKeyArgs* args);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 374a5de..170d91e 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -6644,6 +6644,7 @@
     size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
     size_t outCount = 0;
     BitSet32 newPointerIdBits;
+    mHavePointerIds = true;
 
     for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
         const MultiTouchMotionAccumulator::Slot* inSlot =
@@ -6688,33 +6689,33 @@
         outPointer.isHovering = isHovering;
 
         // Assign pointer id using tracking id if available.
-        mHavePointerIds = true;
-        int32_t trackingId = inSlot->getTrackingId();
-        int32_t id = -1;
-        if (trackingId >= 0) {
-            for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
-                uint32_t n = idBits.clearFirstMarkedBit();
-                if (mPointerTrackingIdMap[n] == trackingId) {
-                    id = n;
+        if (mHavePointerIds) {
+            int32_t trackingId = inSlot->getTrackingId();
+            int32_t id = -1;
+            if (trackingId >= 0) {
+                for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
+                    uint32_t n = idBits.clearFirstMarkedBit();
+                    if (mPointerTrackingIdMap[n] == trackingId) {
+                        id = n;
+                    }
+                }
+
+                if (id < 0 && !mPointerIdBits.isFull()) {
+                    id = mPointerIdBits.markFirstUnmarkedBit();
+                    mPointerTrackingIdMap[id] = trackingId;
                 }
             }
-
-            if (id < 0 && !mPointerIdBits.isFull()) {
-                id = mPointerIdBits.markFirstUnmarkedBit();
-                mPointerTrackingIdMap[id] = trackingId;
+            if (id < 0) {
+                mHavePointerIds = false;
+                outState->rawPointerData.clearIdBits();
+                newPointerIdBits.clear();
+            } else {
+                outPointer.id = id;
+                outState->rawPointerData.idToIndex[id] = outCount;
+                outState->rawPointerData.markIdBit(id, isHovering);
+                newPointerIdBits.markBit(id);
             }
         }
-        if (id < 0) {
-            mHavePointerIds = false;
-            outState->rawPointerData.clearIdBits();
-            newPointerIdBits.clear();
-        } else {
-            outPointer.id = id;
-            outState->rawPointerData.idToIndex[id] = outCount;
-            outState->rawPointerData.markIdBit(id, isHovering);
-            newPointerIdBits.markBit(id);
-        }
-
         outCount += 1;
     }
 
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 076f3d6..8e2fe95 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -484,7 +484,7 @@
         InputReader* mReader;
 
     public:
-        ContextImpl(InputReader* reader);
+        explicit ContextImpl(InputReader* reader);
 
         virtual void updateGlobalMetaState();
         virtual int32_t getGlobalMetaState();
@@ -568,7 +568,7 @@
 /* Reads raw events from the event hub and processes them, endlessly. */
 class InputReaderThread : public Thread {
 public:
-    InputReaderThread(const sp<InputReaderInterface>& reader);
+    explicit InputReaderThread(const sp<InputReaderInterface>& reader);
     virtual ~InputReaderThread();
 
 private:
@@ -1007,7 +1007,7 @@
  */
 class InputMapper {
 public:
-    InputMapper(InputDevice* device);
+    explicit InputMapper(InputDevice* device);
     virtual ~InputMapper();
 
     inline InputDevice* getDevice() { return mDevice; }
@@ -1058,7 +1058,7 @@
 
 class SwitchInputMapper : public InputMapper {
 public:
-    SwitchInputMapper(InputDevice* device);
+    explicit SwitchInputMapper(InputDevice* device);
     virtual ~SwitchInputMapper();
 
     virtual uint32_t getSources();
@@ -1078,7 +1078,7 @@
 
 class VibratorInputMapper : public InputMapper {
 public:
-    VibratorInputMapper(InputDevice* device);
+    explicit VibratorInputMapper(InputDevice* device);
     virtual ~VibratorInputMapper();
 
     virtual uint32_t getSources();
@@ -1178,7 +1178,7 @@
 
 class CursorInputMapper : public InputMapper {
 public:
-    CursorInputMapper(InputDevice* device);
+    explicit CursorInputMapper(InputDevice* device);
     virtual ~CursorInputMapper();
 
     virtual uint32_t getSources();
@@ -1243,7 +1243,7 @@
 
 class RotaryEncoderInputMapper : public InputMapper {
 public:
-    RotaryEncoderInputMapper(InputDevice* device);
+    explicit RotaryEncoderInputMapper(InputDevice* device);
     virtual ~RotaryEncoderInputMapper();
 
     virtual uint32_t getSources();
@@ -1264,7 +1264,7 @@
 
 class TouchInputMapper : public InputMapper {
 public:
-    TouchInputMapper(InputDevice* device);
+    explicit TouchInputMapper(InputDevice* device);
     virtual ~TouchInputMapper();
 
     virtual uint32_t getSources();
@@ -1887,7 +1887,7 @@
 
 class SingleTouchInputMapper : public TouchInputMapper {
 public:
-    SingleTouchInputMapper(InputDevice* device);
+    explicit SingleTouchInputMapper(InputDevice* device);
     virtual ~SingleTouchInputMapper();
 
     virtual void reset(nsecs_t when);
@@ -1905,7 +1905,7 @@
 
 class MultiTouchInputMapper : public TouchInputMapper {
 public:
-    MultiTouchInputMapper(InputDevice* device);
+    explicit MultiTouchInputMapper(InputDevice* device);
     virtual ~MultiTouchInputMapper();
 
     virtual void reset(nsecs_t when);
@@ -1926,7 +1926,7 @@
 
 class ExternalStylusInputMapper : public InputMapper {
 public:
-    ExternalStylusInputMapper(InputDevice* device);
+    explicit ExternalStylusInputMapper(InputDevice* device);
     virtual ~ExternalStylusInputMapper() = default;
 
     virtual uint32_t getSources();
@@ -1948,7 +1948,7 @@
 
 class JoystickInputMapper : public InputMapper {
 public:
-    JoystickInputMapper(InputDevice* device);
+    explicit JoystickInputMapper(InputDevice* device);
     virtual ~JoystickInputMapper();
 
     virtual uint32_t getSources();
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index e243637..feca6cf 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -196,7 +196,7 @@
     void releaseInfo();
 
 protected:
-    InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
+    explicit InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
     virtual ~InputWindowHandle();
 
     InputWindowInfo* mInfo;
diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h
index 8d5a31e..e56673b 100644
--- a/services/inputflinger/host/InputDriver.h
+++ b/services/inputflinger/host/InputDriver.h
@@ -82,7 +82,7 @@
 
 class InputDriver : public InputDriverInterface {
 public:
-    InputDriver(const char* name);
+    explicit InputDriver(const char* name);
     virtual ~InputDriver() = default;
 
     virtual void init() override;
diff --git a/services/sensorservice/RecentEventLogger.h b/services/sensorservice/RecentEventLogger.h
index 4f9bc4a..973a247 100644
--- a/services/sensorservice/RecentEventLogger.h
+++ b/services/sensorservice/RecentEventLogger.h
@@ -35,7 +35,7 @@
 // behavior.
 class RecentEventLogger : public Dumpable {
 public:
-    RecentEventLogger(int sensorType);
+    explicit RecentEventLogger(int sensorType);
     void addEvent(const sensors_event_t& event);
     bool populateLastEvent(sensors_event_t *event) const;
     bool isEmpty() const;
@@ -46,7 +46,7 @@
 
 protected:
     struct SensorEventLog {
-        SensorEventLog(const sensors_event_t& e);
+        explicit SensorEventLog(const sensors_event_t& e);
         timespec mWallTime;
         sensors_event_t mEvent;
     };
diff --git a/services/sensorservice/RingBuffer.h b/services/sensorservice/RingBuffer.h
index ec98a01..a60eb90 100644
--- a/services/sensorservice/RingBuffer.h
+++ b/services/sensorservice/RingBuffer.h
@@ -39,7 +39,7 @@
     /**
      * Construct a RingBuffer that can grow up to the given length.
      */
-    RingBuffer(size_t length);
+    explicit RingBuffer(size_t length);
 
     /**
      * Forward iterator to this class.  Implements an std:forward_iterator.
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
index 3cc2248..265b4c4 100644
--- a/services/sensorservice/RotationVectorSensor.h
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -34,7 +34,7 @@
 
 class RotationVectorSensor : public VirtualSensor {
 public:
-    RotationVectorSensor(int mode = FUSION_9AXIS);
+    explicit RotationVectorSensor(int mode = FUSION_9AXIS);
     virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
     virtual status_t activate(void* ident, bool enabled) override;
     virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
diff --git a/services/sensorservice/SensorEventAckReceiver.h b/services/sensorservice/SensorEventAckReceiver.h
index 998597a..20fa4c7 100644
--- a/services/sensorservice/SensorEventAckReceiver.h
+++ b/services/sensorservice/SensorEventAckReceiver.h
@@ -27,7 +27,7 @@
     sp<SensorService> const mService;
 public:
     virtual bool threadLoop();
-    SensorEventAckReceiver(const sp<SensorService>& service)
+    explicit SensorEventAckReceiver(const sp<SensorService>& service)
             : mService(service) {
     }
 };
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index dafcf2d..0867dc2 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -47,7 +47,7 @@
 
 class BaseSensor : public SensorInterface {
 public:
-    BaseSensor(const sensor_t& sensor);
+    explicit BaseSensor(const sensor_t& sensor);
     BaseSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]);
 
     // Not all sensors need to support batching.
@@ -74,7 +74,7 @@
 
 class HardwareSensor : public BaseSensor {
 public:
-    HardwareSensor(const sensor_t& sensor);
+    explicit HardwareSensor(const sensor_t& sensor);
     HardwareSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]);
 
     virtual ~HardwareSensor();
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index fb83eff..319f4d4 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -931,9 +931,11 @@
 
 status_t SensorService::resetToNormalModeLocked() {
     SensorDevice& dev(SensorDevice::getInstance());
-    dev.enableAllSensors();
     status_t err = dev.setMode(NORMAL);
-    mCurrentOperatingMode = NORMAL;
+    if (err == NO_ERROR) {
+        mCurrentOperatingMode = NORMAL;
+        dev.enableAllSensors();
+    }
     return err;
 }
 
diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h
index a76fc91..495c14e 100644
--- a/services/sensorservice/mat.h
+++ b/services/sensorservice/mat.h
@@ -139,13 +139,13 @@
 
     mat() { }
     mat(const mat& rhs)  : base(rhs) { }
-    mat(const base& rhs) : base(rhs) { }
+    mat(const base& rhs) : base(rhs) { }  // NOLINT(implicit)
 
     // -----------------------------------------------------------------------
     // conversion constructors
 
     // sets the diagonal to the value, off-diagonal to zero
-    mat(pTYPE rhs) {
+    mat(pTYPE rhs) {  // NOLINT(implicit)
         helpers::doAssign(*this, rhs);
     }
 
@@ -220,7 +220,7 @@
     template<size_t PREV_COLUMN>
     struct column_builder {
         mat& matrix;
-        column_builder(mat& matrix) : matrix(matrix) { }
+        explicit column_builder(mat& matrix) : matrix(matrix) { }
     };
 
     // operator << is not a method of column_builder<> so we can
@@ -265,9 +265,9 @@
     enum { ROWS = R, COLS = 1 };
 
     mat() { }
-    mat(const base& rhs) : base(rhs) { }
+    explicit mat(const base& rhs) : base(rhs) { }
     mat(const mat& rhs) : base(rhs) { }
-    mat(const TYPE& rhs) { helpers::doAssign(*this, rhs); }
+    explicit mat(const TYPE& rhs) { helpers::doAssign(*this, rhs); }
     mat& operator=(const mat& rhs) { base::operator=(rhs); return *this; }
     mat& operator=(const base& rhs) { base::operator=(rhs); return *this; }
     mat& operator=(const TYPE& rhs) { return helpers::doAssign(*this, rhs); }
diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h
index a142bad..9e5d280 100644
--- a/services/sensorservice/vec.h
+++ b/services/sensorservice/vec.h
@@ -322,12 +322,12 @@
 
     vec() { }
     vec(const vec& rhs)  : base(rhs) { }
-    vec(const base& rhs) : base(rhs) { }
+    vec(const base& rhs) : base(rhs) { }  // NOLINT(implicit)
 
     // -----------------------------------------------------------------------
     // conversion constructors
 
-    vec(pTYPE rhs) {
+    vec(pTYPE rhs) {  // NOLINT(implicit)
         for (size_t i=0 ; i<SIZE ; i++)
             base::operator[](i) = rhs;
     }
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index b6d7381..c77651f 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -38,7 +38,7 @@
 class Client : public BnSurfaceComposerClient
 {
 public:
-        Client(const sp<SurfaceFlinger>& flinger);
+        explicit Client(const sp<SurfaceFlinger>& flinger);
         ~Client();
 
     status_t initCheck() const;
diff --git a/services/surfaceflinger/Colorizer.h b/services/surfaceflinger/Colorizer.h
index 6524481..f2e6491 100644
--- a/services/surfaceflinger/Colorizer.h
+++ b/services/surfaceflinger/Colorizer.h
@@ -34,7 +34,7 @@
         WHITE   = 37
     };
 
-    Colorizer(bool enabled)
+    explicit Colorizer(bool enabled)
         : mEnabled(enabled) {
     }
 
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 537c81b..2763e59 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -61,7 +61,7 @@
         virtual void onDispSyncEvent(nsecs_t when) = 0;
     };
 
-    DispSync(const char* name);
+    explicit DispSync(const char* name);
     ~DispSync();
 
     // reset clears the resync samples and error value.
diff --git a/services/surfaceflinger/DisplayHardware/FloatRect.h b/services/surfaceflinger/DisplayHardware/FloatRect.h
index 9ad1040..151eaaa 100644
--- a/services/surfaceflinger/DisplayHardware/FloatRect.h
+++ b/services/surfaceflinger/DisplayHardware/FloatRect.h
@@ -32,7 +32,7 @@
 
     inline FloatRect()
         : left(0), top(0), right(0), bottom(0) { }
-    inline FloatRect(const Rect& other)
+    inline FloatRect(const Rect& other)  // NOLINT(implicit)
         : left(other.left), top(other.top), right(other.right), bottom(other.bottom) { }
 
     inline float getWidth() const { return right - left; }
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 8ab61e9..1aa4205 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -56,7 +56,7 @@
 class Device
 {
 public:
-    Device(hwc2_device_t* device);
+    explicit Device(hwc2_device_t* device);
     ~Device();
 
     friend class HWC2::Display;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
index dc7c355..5debb9a 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
@@ -43,7 +43,7 @@
 class HWC2On1Adapter : public hwc2_device_t
 {
 public:
-    HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device);
+    explicit HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device);
     ~HWC2On1Adapter();
 
     struct hwc_composer_device_1* getHwc1Device() const { return mHwc1Device; }
@@ -488,7 +488,7 @@
 
     class Layer {
         public:
-            Layer(Display& display);
+            explicit Layer(Display& display);
 
             bool operator==(const Layer& other) { return mId == other.mId; }
             bool operator!=(const Layer& other) { return !(*this == other); }
diff --git a/services/surfaceflinger/EventControlThread.h b/services/surfaceflinger/EventControlThread.h
index be6c53a..9368db6 100644
--- a/services/surfaceflinger/EventControlThread.h
+++ b/services/surfaceflinger/EventControlThread.h
@@ -29,7 +29,7 @@
 class EventControlThread: public Thread {
 public:
 
-    EventControlThread(const sp<SurfaceFlinger>& flinger);
+    explicit EventControlThread(const sp<SurfaceFlinger>& flinger);
     virtual ~EventControlThread() {}
 
     void setVsyncEnabled(bool enabled);
diff --git a/services/surfaceflinger/EventLog/EventLog.h b/services/surfaceflinger/EventLog/EventLog.h
index 5207514..efc5d70 100644
--- a/services/surfaceflinger/EventLog/EventLog.h
+++ b/services/surfaceflinger/EventLog/EventLog.h
@@ -52,7 +52,7 @@
         bool mOverflow;
         char mStorage[STORAGE_MAX_SIZE];
     public:
-        TagBuffer(int32_t tag);
+        explicit TagBuffer(int32_t tag);
 
         // starts list of items
         void startList(int8_t count);
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 34654fa..b635115 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -57,7 +57,7 @@
 class EventThread : public Thread, private VSyncSource::Callback {
     class Connection : public BnDisplayEventConnection {
     public:
-        Connection(const sp<EventThread>& eventThread);
+        explicit Connection(const sp<EventThread>& eventThread);
         status_t postEvent(const DisplayEventReceiver::Event& event);
 
         // count >= 1 : continuous event. count is the vsync rate
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ba7184f..55e3b54 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -456,7 +456,7 @@
     class SyncPoint
     {
     public:
-        SyncPoint(uint64_t frameNumber) : mFrameNumber(frameNumber),
+        explicit SyncPoint(uint64_t frameNumber) : mFrameNumber(frameNumber),
                 mFrameIsAvailable(false), mTransactionIsApplied(false) {}
 
         uint64_t getFrameNumber() const {
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 1004f4c..aed0aa9 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -69,7 +69,7 @@
         MessageQueue& mQueue;
         int32_t mEventMask;
     public:
-        Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
+        explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
         virtual void handleMessage(const Message& message);
         void dispatchRefresh();
         void dispatchInvalidate();
diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h
index be9b645..3d8bd50 100644
--- a/vulkan/libvulkan/debug_report.h
+++ b/vulkan/libvulkan/debug_report.h
@@ -85,9 +85,9 @@
 
 class DebugReportLogger {
    public:
-    DebugReportLogger(const VkInstanceCreateInfo& info)
+    explicit DebugReportLogger(const VkInstanceCreateInfo& info)
         : instance_pnext_(info.pNext), callbacks_(nullptr) {}
-    DebugReportLogger(const DebugReportCallbackList& callbacks)
+    explicit DebugReportLogger(const DebugReportCallbackList& callbacks)
         : instance_pnext_(nullptr), callbacks_(&callbacks) {}
 
     void Message(VkDebugReportFlagsEXT flags,
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index a02ebd7..a1612c7 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -61,7 +61,7 @@
 VK_DEFINE_HANDLE(DeviceDispatchable)
 
 struct InstanceData {
-    InstanceData(const VkAllocationCallbacks& alloc)
+    explicit InstanceData(const VkAllocationCallbacks& alloc)
         : opaque_api_data(),
           allocator(alloc),
           driver(),
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
index 79fe59d..07ac1a3 100644
--- a/vulkan/libvulkan/layers_extensions.h
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -26,7 +26,7 @@
 
 class LayerRef {
    public:
-    LayerRef(const Layer* layer);
+    explicit LayerRef(const Layer* layer);
     LayerRef(LayerRef&& other);
     ~LayerRef();
     LayerRef(const LayerRef&) = delete;