[automerger skipped] Zero-init HIDL core types (all) am: 38db64566e -s ours
am: 6015a706d9 -s ours
am skip reason: change_id I3979232879bb437d17d3a6f6013b53b2951a2138 with SHA1 aa79ac59c8 is in history

Change-Id: I92a044ec6a6ecc3bc3ac264280e0cb4e8a1b006c
diff --git a/.clang-format b/.clang-format
new file mode 120000
index 0000000..ddcf5a2
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1 @@
+../../build/soong/scripts/system-clang-format
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 032a61a..97ed108 100644
--- a/Android.bp
+++ b/Android.bp
@@ -16,7 +16,9 @@
     name: "libhidl-defaults",
     cflags: [
         "-Wall",
+        "-Wdocumentation", // since some users use this
         "-Werror",
+        "-Wextra-semi",
     ],
 }
 
@@ -25,9 +27,10 @@
     defaults: ["libhidl-defaults"],
     gtest: false,
     srcs: ["test_main.cpp"],
+    test_suites: ["device-tests"],
 
     shared_libs: [
-        "android.hardware.tests.inheritance@1.0",
+        "android.hidl.memory@1.0",
         "libbase",
         "libhidlbase",
         "libhidltransport",
@@ -38,10 +41,6 @@
     ],
     static_libs: ["libgtest", "libgmock"],
 
-    required: [
-        "android.hardware.tests.inheritance@1.0-impl",
-    ],
-
     cflags: [
         "-O0",
         "-g",
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..3e17fc4
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+  "presubmit": [
+    {
+      "name": "libhidl_test"
+    }
+  ]
+}
+
diff --git a/adapter/HidlBinderAdapter.cpp b/adapter/HidlBinderAdapter.cpp
index b6aa58e..ed6dad1 100644
--- a/adapter/HidlBinderAdapter.cpp
+++ b/adapter/HidlBinderAdapter.cpp
@@ -36,42 +36,92 @@
 
 const static std::string kDeactivateProp = "test.hidl.adapters.deactivated";
 
-void usage(const std::string& me) {
-    std::cerr << "usage: " << me << " [-p] interface-name instance-name number-of-threads."
+int usage(const std::string& me) {
+    std::cerr << "usage: " << me
+              << " [-p|P] [-n instance-name] interface-name instance-name number-of-threads."
               << std::endl;
     std::cerr << "    -p: stop based on property " << kDeactivateProp << "and reset it."
               << std::endl;
+    std::cerr << "    -P: stop based on interface specific property " << kDeactivateProp
+              << ".<fq-name>.<instance-name>" << std::endl;
+    std::cerr
+        << "    -n instance-name: register as a different instance name (does not de-register)"
+        << std::endl;
+    return EINVAL;
 }
 
-bool processArguments(int* argc, char*** argv, bool* propertyStop) {
+enum class StopMethod {
+    NONE,
+    ALL,
+    SPECIFIC,
+};
+
+struct Args {
+    StopMethod stopMethod = StopMethod::NONE;
+    std::string interface;     // e.x. IFoo
+    std::string instanceName;  // e.x. default
+    int threadNumber;
+    std::string registerInstanceName;  // e.x. default
+};
+
+bool processArguments(int argc, char** argv, Args* args) {
     int c;
-    while ((c = getopt(*argc, *argv, "p")) != -1) {
+    while ((c = getopt(argc, argv, "pPn:")) != -1) {
         switch (c) {
             case 'p': {
-                *propertyStop = true;
+                args->stopMethod = StopMethod::ALL;
+                break;
+            }
+            case 'P': {
+                args->stopMethod = StopMethod::SPECIFIC;
+                break;
+            }
+            case 'n': {
+                args->registerInstanceName = optarg;
                 break;
             }
             default: { return false; }
         }
     }
 
-    *argc -= optind;
-    *argv += optind;
+    argc -= optind;
+    argv += optind;
+
+    if (argc != 3) {
+        std::cerr << "ERROR: requires exactly three positional arguments for "
+                     "interface, instance name, and number of threads, but "
+                  << argc << " provided." << std::endl;
+        return false;
+    }
+
+    args->interface = argv[0];
+    args->instanceName = argv[1];
+    args->threadNumber = std::stoi(argv[2]);
+
+    if (args->threadNumber <= 0) {
+        std::cerr << "ERROR: invalid thread number " << args->threadNumber
+                  << " must be a positive integer." << std::endl;
+        return false;
+    }
+
+    if (args->registerInstanceName.empty()) {
+        args->registerInstanceName = args->instanceName;
+    }
+
     return true;
 }
 
 // only applies for -p argument
-void waitForAdaptersDeactivated() {
+void waitForAdaptersDeactivated(const std::string& property) {
     using std::literals::chrono_literals::operator""s;
 
-    while (!WaitForProperty(kDeactivateProp, "true", 30s)) {
+    while (!WaitForProperty(property, "true", 30s)) {
         // Log this so that when using this option on testing devices, there is
         // a clear indication if adapters are not properly stopped
-        LOG(WARNING) << "Adapter use in progress. Waiting for stop based on 'true' "
-                     << kDeactivateProp;
+        LOG(WARNING) << "Adapter use in progress. Waiting for stop based on 'true' " << property;
     }
 
-    SetProperty(kDeactivateProp, "false");
+    SetProperty(property, "false");
 }
 
 int adapterMain(const std::string& package, int argc, char** argv,
@@ -82,25 +132,12 @@
 
     const std::string& me = argc > 0 ? argv[0] : "(error)";
 
-    bool propertyStop = false;
-    if (!processArguments(&argc, &argv, &propertyStop)) {
-        usage(me);
-        return EINVAL;
+    Args args;
+    if (!processArguments(argc, argv, &args)) {
+        return usage(me);
     }
 
-    if (argc != 3) {
-        usage(me);
-        return EINVAL;
-    }
-
-    std::string interfaceName = package + "::" + argv[0];
-    std::string instanceName = argv[1];
-    int threadNumber = std::stoi(argv[2]);
-
-    if (threadNumber <= 0) {
-        std::cerr << "ERROR: invalid thread number " << threadNumber
-                  << " must be a positive integer.";
-    }
+    std::string interfaceName = package + "::" + args.interface;
 
     auto it = adapters.find(interfaceName);
     if (it == adapters.end()) {
@@ -108,9 +145,10 @@
         return 1;
     }
 
-    std::cout << "Trying to adapt down " << interfaceName << "/" << instanceName << std::endl;
+    std::cout << "Trying to adapt down " << interfaceName << "/" << args.instanceName << " to "
+              << args.registerInstanceName << std::endl;
 
-    configureRpcThreadpool(threadNumber, false /* callerWillJoin */);
+    configureRpcThreadpool(args.threadNumber, false /* callerWillJoin */);
 
     sp<IServiceManager> manager = IServiceManager::getService();
     if (manager == nullptr) {
@@ -118,7 +156,7 @@
         return 1;
     }
 
-    sp<IBase> implementation = manager->get(interfaceName, instanceName).withDefault(nullptr);
+    sp<IBase> implementation = manager->get(interfaceName, args.instanceName).withDefault(nullptr);
     if (implementation == nullptr) {
         std::cerr << "ERROR: could not retrieve desired implementation" << std::endl;
         return 1;
@@ -130,25 +168,40 @@
         return 1;
     }
 
-    bool replaced = manager->add(instanceName, adapter).withDefault(false);
+    bool replaced = manager->add(args.registerInstanceName, adapter).withDefault(false);
     if (!replaced) {
         std::cerr << "ERROR: could not register the service with the service manager." << std::endl;
         return 1;
     }
 
-    if (propertyStop) {
-        std::cout << "Set " << kDeactivateProp << " to true to deactivate." << std::endl;
-        waitForAdaptersDeactivated();
-    } else {
-        std::cout << "Press any key to disassociate adapter." << std::endl;
-        getchar();
+    switch (args.stopMethod) {
+        case StopMethod::NONE: {
+            std::cout << "Press any key to disassociate adapter." << std::endl;
+            getchar();
+            break;
+        };
+        case StopMethod::SPECIFIC: {
+            const std::string property =
+                kDeactivateProp + "." + interfaceName + "." + args.registerInstanceName;
+            std::cout << "Set " << property << " to true to deactivate." << std::endl;
+            waitForAdaptersDeactivated(property);
+            break;
+        };
+        case StopMethod::ALL: {
+            std::cout << "Set " << kDeactivateProp << " to true to deactivate." << std::endl;
+            waitForAdaptersDeactivated(kDeactivateProp);
+            break;
+        };
     }
 
-    bool restored = manager->add(instanceName, implementation).withDefault(false);
-    if (!restored) {
-        std::cerr << "ERROR: could not re-register interface with the service manager."
-                  << std::endl;
-        return 1;
+    // automatically unregistered on process exit if it is a new instance name
+    if (args.registerInstanceName == args.instanceName) {
+        bool restored = manager->add(args.instanceName, implementation).withDefault(false);
+        if (!restored) {
+            std::cerr << "ERROR: could not re-register interface with the service manager."
+                      << std::endl;
+            return 1;
+        }
     }
 
     std::cout << "Success." << std::endl;
diff --git a/base/Android.bp b/base/Android.bp
index 22f5ee1..359ac91 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -14,6 +14,7 @@
 
 cc_library {
     name: "libhidlbase",
+    recovery_available: true,
     vendor_available: true,
     vndk: {
         enabled: true,
diff --git a/base/HidlInternal.cpp b/base/HidlInternal.cpp
index babdac1..440b30f 100644
--- a/base/HidlInternal.cpp
+++ b/base/HidlInternal.cpp
@@ -31,16 +31,17 @@
 #include <regex>
 
 extern "C" __attribute__((weak)) void __sanitizer_cov_dump();
-const char* kGcovPrefixEnvVar = "GCOV_PREFIX";
-const char* kGcovPrefixOverrideEnvVar = "GCOV_PREFIX_OVERRIDE";
-const char* kGcovPrefixPath = "/data/misc/trace/";
-const char* kSysPropHalCoverage = "hal.coverage.enable";
+
+const char kGcovPrefixEnvVar[] = "GCOV_PREFIX";
+const char kGcovPrefixOverrideEnvVar[] = "GCOV_PREFIX_OVERRIDE";
+const char kGcovPrefixPath[] = "/data/misc/trace/";
+const char kSysPropHalCoverage[] = "hal.coverage.enable";
 #if defined(__LP64__)
-const char* kSysPropInstrumentationPath = "hal.instrumentation.lib.path.64";
+const char kSysPropInstrumentationPath[] = "hal.instrumentation.lib.path.64";
 #else
-const char* kSysPropInstrumentationPath = "hal.instrumentation.lib.path.32";
+const char kSysPropInstrumentationPath[] = "hal.instrumentation.lib.path.32";
 #endif
-#endif
+#endif  // LIBHIDL_TARGET_DEBUGGABLE
 
 namespace android {
 namespace hardware {
@@ -145,7 +146,9 @@
     } else {
         static std::string halLibPathVndkSp = android::base::StringPrintf(
             HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION, getVndkVersionStr().c_str());
+#ifndef __ANDROID_VNDK__
         instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_SYSTEM);
+#endif
         instrumentationLibPaths.push_back(halLibPathVndkSp);
         instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_VENDOR);
         instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_ODM);
@@ -153,7 +156,7 @@
 
     for (const auto& path : instrumentationLibPaths) {
         DIR *dir = opendir(path.c_str());
-        if (dir == 0) {
+        if (dir == nullptr) {
             LOG(WARNING) << path << " does not exist. ";
             return;
         }
diff --git a/base/HidlSupport.cpp b/base/HidlSupport.cpp
index e08bf93..f97f216 100644
--- a/base/HidlSupport.cpp
+++ b/base/HidlSupport.cpp
@@ -57,7 +57,7 @@
 }
 
 // move constructor.
-hidl_handle::hidl_handle(hidl_handle&& other) : hidl_handle() {
+hidl_handle::hidl_handle(hidl_handle&& other) noexcept : hidl_handle() {
     mOwnsHandle = false;
     *this = std::move(other);
 }
@@ -88,7 +88,7 @@
     return *this;
 }
 
-hidl_handle &hidl_handle::operator=(hidl_handle &&other) {
+hidl_handle& hidl_handle::operator=(hidl_handle&& other) noexcept {
     if (this != &other) {
         freeHandle();
         mHandle = other.mHandle;
@@ -169,11 +169,11 @@
     copyFrom(s.c_str(), s.size());
 }
 
-hidl_string::hidl_string(hidl_string &&other): hidl_string() {
+hidl_string::hidl_string(hidl_string&& other) noexcept : hidl_string() {
     moveFrom(std::forward<hidl_string>(other));
 }
 
-hidl_string &hidl_string::operator=(hidl_string &&other) {
+hidl_string& hidl_string::operator=(hidl_string&& other) noexcept {
     if (this != &other) {
         clear();
         moveFrom(std::forward<hidl_string>(other));
@@ -256,6 +256,14 @@
     if (size > UINT32_MAX) {
         LOG(FATAL) << "string size can't exceed 2^32 bytes: " << size;
     }
+
+    // When the binder driver copies this data into its buffer, it must
+    // have a zero byte there because the remote process will have a pointer
+    // directly into the read-only binder buffer. If we manually copy the
+    // data now to add a zero, then we lose the efficiency of this method.
+    // Checking here (it's also checked in the parceling code later).
+    CHECK(data[size] == '\0');
+
     clear();
 
     mBuffer = data;
@@ -309,9 +317,7 @@
         : hidl_memory(name, std::move(handle), size) {}
 
 // it's required to have at least one out-of-line method to avoid weak vtable
-HidlMemory::~HidlMemory() {
-    hidl_memory::~hidl_memory();
-}
+HidlMemory::~HidlMemory() {}
 
 }  // namespace hardware
 }  // namespace android
diff --git a/base/Status.cpp b/base/Status.cpp
index 1ba91c3..90474a0 100644
--- a/base/Status.cpp
+++ b/base/Status.cpp
@@ -18,6 +18,7 @@
 #include <android-base/logging.h>
 
 #include <hidl/Status.h>
+#include <utils/CallStack.h>
 
 #include <unordered_map>
 
@@ -82,11 +83,17 @@
 }
 
 Status Status::fromExceptionCode(int32_t exceptionCode) {
+    if (exceptionCode == EX_TRANSACTION_FAILED) {
+        return Status(exceptionCode, FAILED_TRANSACTION);
+    }
     return Status(exceptionCode, OK);
 }
 
 Status Status::fromExceptionCode(int32_t exceptionCode,
                                  const char *message) {
+    if (exceptionCode == EX_TRANSACTION_FAILED) {
+        return Status(exceptionCode, FAILED_TRANSACTION, message);
+    }
     return Status(exceptionCode, OK, message);
 }
 
@@ -107,7 +114,7 @@
 
 void Status::setException(int32_t ex, const char *message) {
     mException = ex;
-    mErrorCode = NO_ERROR;  // an exception, not a transaction failure.
+    mErrorCode = ex == EX_TRANSACTION_FAILED ? FAILED_TRANSACTION : NO_ERROR;
     mMessage = message;
 }
 
@@ -136,6 +143,11 @@
     return stream;
 }
 
+static HidlReturnRestriction gReturnRestriction = HidlReturnRestriction::NONE;
+void setProcessHidlReturnRestriction(HidlReturnRestriction restriction) {
+    gReturnRestriction = restriction;
+}
+
 namespace details {
     void return_status::assertOk() const {
         if (!isOk()) {
@@ -145,12 +157,25 @@
 
     return_status::~return_status() {
         // mCheckedStatus must be checked before isOk since isOk modifies mCheckedStatus
-        if (!mCheckedStatus && !isOk()) {
+        if (mCheckedStatus) return;
+
+        if (!isOk()) {
             LOG(FATAL) << "Failed HIDL return status not checked: " << description();
         }
+
+        if (gReturnRestriction == HidlReturnRestriction::NONE) {
+            return;
+        }
+
+        if (gReturnRestriction == HidlReturnRestriction::ERROR_IF_UNCHECKED) {
+            LOG(ERROR) << "Failed to check status of HIDL Return.";
+            CallStack::logStack("unchecked HIDL return", CallStack::getCurrent(10).get(), ANDROID_LOG_ERROR);
+        } else {
+            LOG(FATAL) << "Failed to check status of HIDL Return.";
+        }
     }
 
-    return_status &return_status::operator=(return_status &&other) {
+    return_status& return_status::operator=(return_status&& other) noexcept {
         if (!mCheckedStatus && !isOk()) {
             LOG(FATAL) << "Failed HIDL return status not checked: " << description();
         }
diff --git a/base/include/hidl/HidlInternal.h b/base/include/hidl/HidlInternal.h
index ed9f02c..0b80cd4 100644
--- a/base/include/hidl/HidlInternal.h
+++ b/base/include/hidl/HidlInternal.h
@@ -48,6 +48,15 @@
 // If "ro.vndk.version" is not set or set to "current", it returns empty string.
 std::string getVndkVersionStr();
 
+// Explicitly invokes the parameterized element's destructor;
+// intended to be used alongside the placement new operator.
+template<typename T>
+void destructElement(T* element) {
+    if (element != nullptr) {
+        element->~T();
+    }
+}
+
 // HIDL client/server code should *NOT* use this class.
 //
 // hidl_pointer wraps a pointer without taking ownership,
@@ -63,13 +72,13 @@
     }
     hidl_pointer(T* ptr) : hidl_pointer() { mPointer = ptr; }
     hidl_pointer(const hidl_pointer<T>& other) : hidl_pointer() { mPointer = other.mPointer; }
-    hidl_pointer(hidl_pointer<T>&& other) : hidl_pointer() { *this = std::move(other); }
+    hidl_pointer(hidl_pointer<T>&& other) noexcept : hidl_pointer() { *this = std::move(other); }
 
     hidl_pointer &operator=(const hidl_pointer<T>& other) {
         mPointer = other.mPointer;
         return *this;
     }
-    hidl_pointer &operator=(hidl_pointer<T>&& other) {
+    hidl_pointer& operator=(hidl_pointer<T>&& other) noexcept {
         mPointer = other.mPointer;
         other.mPointer = nullptr;
         return *this;
diff --git a/base/include/hidl/HidlSupport.h b/base/include/hidl/HidlSupport.h
index f8f79a5..93a6251 100644
--- a/base/include/hidl/HidlSupport.h
+++ b/base/include/hidl/HidlSupport.h
@@ -40,18 +40,22 @@
 namespace hidl {
 namespace memory {
 namespace V1_0 {
-    struct IMemory;
-}; // namespace V1_0
-}; // namespace manager
-}; // namespace hidl
+
+struct IMemory;
+
+}  // namespace V1_0
+}  // namespace memory
+}  // namespace hidl
 
 namespace hidl {
 namespace base {
 namespace V1_0 {
-    struct IBase;
-}; // namespace V1_0
-}; // namespace base
-}; // namespace hidl
+
+struct IBase;
+
+}  // namespace V1_0
+}  // namespace base
+}  // namespace hidl
 
 namespace hardware {
 
@@ -112,6 +116,10 @@
 
     // explicit conversion
     const native_handle_t *getNativeHandle() const;
+
+    // offsetof(hidl_handle, mHandle) exposed since mHandle is private.
+    static const size_t kOffsetOfNativeHandle;
+
 private:
     void freeHandle();
 
@@ -155,6 +163,8 @@
     // Reference an external char array. Ownership is _not_ transferred.
     // Caller is responsible for ensuring that underlying memory is valid
     // for the lifetime of this hidl_string.
+    //
+    // size == strlen(data)
     void setToExternal(const char *data, size_t size);
 
     // offsetof(hidl_string, mBuffer) exposed since mBuffer is private.
@@ -338,19 +348,7 @@
         *this = std::move(other);
     }
 
-    hidl_vec(const std::initializer_list<T> list) : hidl_vec() {
-        if (list.size() > UINT32_MAX) {
-            details::logAlwaysFatal("hidl_vec can't hold more than 2^32 elements.");
-        }
-        mSize = static_cast<uint32_t>(list.size());
-        mBuffer = new T[mSize]();
-        mOwnsBuffer = true;
-
-        size_t idx = 0;
-        for (auto it = list.begin(); it != list.end(); ++it) {
-            mBuffer[idx++] = *it;
-        }
-    }
+    hidl_vec(const std::initializer_list<T> list) : hidl_vec() { *this = list; }
 
     hidl_vec(const std::vector<T> &other) : hidl_vec() {
         *this = other;
@@ -447,6 +445,24 @@
         return *this;
     }
 
+    hidl_vec& operator=(const std::initializer_list<T> list) {
+        if (list.size() > UINT32_MAX) {
+            details::logAlwaysFatal("hidl_vec can't hold more than 2^32 elements.");
+        }
+        if (mOwnsBuffer) {
+            delete[] mBuffer;
+        }
+        mSize = static_cast<uint32_t>(list.size());
+        mBuffer = new T[mSize]();
+        mOwnsBuffer = true;
+
+        size_t idx = 0;
+        for (auto it = list.begin(); it != list.end(); ++it) {
+            mBuffer[idx++] = *it;
+        }
+        return *this;
+    }
+
     // cast to an std::vector.
     operator std::vector<T>() const {
         std::vector<T> v(mSize);
@@ -845,6 +861,10 @@
         return (mMajor == other.get_major() && mMinor == other.get_minor());
     }
 
+    bool operator!=(const hidl_version& other) const {
+        return !(*this == other);
+    }
+
     bool operator<(const hidl_version& other) const {
         return (mMajor < other.get_major() ||
                 (mMajor == other.get_major() && mMinor < other.get_minor()));
@@ -989,12 +1009,38 @@
             + details::toString(details::const_accessor<T, SIZE1, SIZE2, SIZES...>(a.data()));
 }
 
+namespace details {
+// Never instantiated. Used as a placeholder for template variables.
+template <typename T>
+struct hidl_invalid_type;
+
+// HIDL generates specializations of this for enums. See hidl_enum_range.
+template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
+constexpr hidl_invalid_type<T> hidl_enum_values;
+}  // namespace details
+
 /**
- * Every HIDL generated enum generates an implementation of this function.
- * E.x.: for(const auto v : hidl_enum_iterator<Enum>) { ... }
+ * Every HIDL generated enum supports this function.
+ * E.x.: for(const auto v : hidl_enum_range<Enum>) { ... }
  */
-template <typename>
-struct hidl_enum_iterator;
+template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
+struct hidl_enum_range {
+    constexpr auto begin() const { return std::begin(details::hidl_enum_values<T>); }
+    constexpr auto cbegin() const { return begin(); }
+    constexpr auto rbegin() const { return std::rbegin(details::hidl_enum_values<T>); }
+    constexpr auto crbegin() const { return rbegin(); }
+    constexpr auto end() const { return std::end(details::hidl_enum_values<T>); }
+    constexpr auto cend() const { return end(); }
+    constexpr auto rend() const { return std::rend(details::hidl_enum_values<T>); }
+    constexpr auto crend() const { return rend(); }
+};
+
+template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
+struct hidl_enum_iterator {
+    static_assert(!std::is_enum<T>::value,
+                  "b/78573628: hidl_enum_iterator was renamed to hidl_enum_range because it is not "
+                  "actually an iterator. Please use that type instead.");
+};
 
 /**
  * Bitfields in HIDL are the underlying type of the enumeration.
diff --git a/base/include/hidl/MQDescriptor.h b/base/include/hidl/MQDescriptor.h
index 23be971..0f61cb5 100644
--- a/base/include/hidl/MQDescriptor.h
+++ b/base/include/hidl/MQDescriptor.h
@@ -59,18 +59,20 @@
 
 template <typename T, MQFlavor flavor>
 struct MQDescriptor {
+    // Takes ownership of handle
     MQDescriptor(
             const std::vector<GrantorDescriptor>& grantors,
             native_handle_t* nHandle, size_t size);
 
+    // Takes ownership of handle
     MQDescriptor(size_t bufferSize, native_handle_t* nHandle,
                  size_t messageSize, bool configureEventFlag = false);
 
     MQDescriptor();
     ~MQDescriptor();
 
-    explicit MQDescriptor(const MQDescriptor &other);
-    MQDescriptor &operator=(const MQDescriptor &other) = delete;
+    explicit MQDescriptor(const MQDescriptor& other) : MQDescriptor() { *this = other; }
+    MQDescriptor& operator=(const MQDescriptor& other);
 
     size_t getSize() const;
 
@@ -213,12 +215,17 @@
     }
 }
 
-template<typename T, MQFlavor flavor>
-MQDescriptor<T, flavor>::MQDescriptor(const MQDescriptor<T, flavor> &other)
-    : mGrantors(other.mGrantors),
-      mHandle(nullptr),
-      mQuantum(other.mQuantum),
-      mFlags(other.mFlags) {
+template <typename T, MQFlavor flavor>
+MQDescriptor<T, flavor>& MQDescriptor<T, flavor>::operator=(const MQDescriptor& other) {
+    mGrantors = other.mGrantors;
+    if (mHandle != nullptr) {
+        native_handle_close(mHandle);
+        native_handle_delete(mHandle);
+        mHandle = nullptr;
+    }
+    mQuantum = other.mQuantum;
+    mFlags = other.mFlags;
+
     if (other.mHandle != nullptr) {
         mHandle = native_handle_create(
                 other.mHandle->numFds, other.mHandle->numInts);
@@ -231,6 +238,8 @@
                &other.mHandle->data[other.mHandle->numFds],
                other.mHandle->numInts * sizeof(int));
     }
+
+    return *this;
 }
 
 template<typename T, MQFlavor flavor>
diff --git a/base/include/hidl/Status.h b/base/include/hidl/Status.h
index 1a2ef6d..817277f 100644
--- a/base/include/hidl/Status.h
+++ b/base/include/hidl/Status.h
@@ -27,32 +27,36 @@
 namespace android {
 namespace hardware {
 
-// An object similar in function to a status_t except that it understands
-// how exceptions are encoded in the prefix of a Parcel. Used like:
+// HIDL formally separates transport error codes from interface error codes. When developing a HIDL
+// interface, errors relevant to a service should be placed in the interface design for that HAL.
 //
-//     Parcel data;
-//     Parcel reply;
-//     status_t status;
-//     binder::Status remote_exception;
-//     if ((status = data.writeInterfaceToken(interface_descriptor)) != OK ||
-//         (status = data.writeInt32(function_input)) != OK) {
-//         // We failed to write into the memory of our local parcel?
-//     }
-//     if ((status = remote()->transact(transaction, data, &reply)) != OK) {
-//        // Something has gone wrong in the binder driver or libbinder.
-//     }
-//     if ((status = remote_exception.readFromParcel(reply)) != OK) {
-//         // The remote didn't correctly write the exception header to the
-//         // reply.
-//     }
-//     if (!remote_exception.isOk()) {
-//         // The transaction went through correctly, but the remote reported an
-//         // exception during handling.
-//     }
+// For instance:
 //
+//     interface I* {
+//         enum FooStatus { NO_FOO, NO_BAR }; // service-specific errors
+//         doFoo(...) generates (FooStatus foo);
+//     };
+//
+// When calling into this interface, a Return<*> (in this case Return<FooStatus> object will be
+// returned). For most clients, it's expected that they'll just get the result from this function
+// and use it directly. If there is a transport error, the process will just abort. In general,
+// transport errors are expected only in extremely rare circumstances (bug in the
+// code/cosmic radiation/etc..). Aborting allows process to restart using their normal happy path
+// code.
+//
+// For certain processes though which are critical to the functionality of the phone (e.g.
+// hwservicemanager/init), these errors must be handled. Return<*>::isOk and
+// Return<*>::isDeadObject are provided for these cases. Whenever this is done, special attention
+// should be paid to testing the unhappy paths to make sure that error handling is handled
+// properly.
+
+// Transport implementation detail. HIDL implementors, see Return below. HAL implementations should
+// return HIDL-defined errors rather than use this.
 class Status final {
 public:
-    // Keep the exception codes in sync with android/os/Parcel.java.
+    // Note: forked from
+    // - frameworks/base/core/java/android/os/android/os/Parcel.java.
+    // - frameworks/native/libs/binder/include/binder/Status.h
     enum Exception {
         EX_NONE = 0,
         EX_SECURITY = -1,
@@ -139,19 +143,16 @@
 
         template <typename T, typename U>
         friend Return<U> StatusOf(const Return<T> &other);
-    protected:
-        void assertOk() const;
     public:
+        void assertOk() const;
         return_status() {}
         return_status(const Status& s) : mStatus(s) {}
 
         return_status(const return_status &) = delete;
         return_status &operator=(const return_status &) = delete;
 
-        return_status(return_status &&other) {
-            *this = std::move(other);
-        }
-        return_status &operator=(return_status &&other);
+        return_status(return_status&& other) noexcept { *this = std::move(other); }
+        return_status& operator=(return_status&& other) noexcept;
 
         ~return_status();
 
@@ -187,6 +188,26 @@
     };
 }  // namespace details
 
+enum class HidlReturnRestriction {
+    // Okay to ignore checking transport errors. This would instead rely on init to reset state
+    // after an error in the underlying transport. This is the default and expected for most
+    // usecases.
+    NONE,
+    // Log when there is an unchecked error.
+    ERROR_IF_UNCHECKED,
+    // Fatal when there is an unchecked error.
+    FATAL_IF_UNCHECKED,
+};
+
+/**
+ * This should be called during process initialization (e.g. before binder threadpool is created).
+ *
+ * Note: default of HidlReturnRestriction::NONE should be good for most usecases. See above.
+ *
+ * The restriction will be applied when Return objects are deconstructed.
+ */
+void setProcessHidlReturnRestriction(HidlReturnRestriction restriction);
+
 template<typename T> class Return : public details::return_status {
 private:
     T mVal {};
@@ -197,8 +218,8 @@
     // move-able.
     // precondition: "this" has checked status
     // postcondition: other is safe to destroy after moving to *this.
-    Return(Return &&other) = default;
-    Return &operator=(Return &&) = default;
+    Return(Return&& other) noexcept = default;
+    Return& operator=(Return&&) noexcept = default;
 
     ~Return() = default;
 
@@ -226,8 +247,8 @@
     // move-able.
     // precondition: "this" has checked status
     // postcondition: other is safe to destroy after moving to *this.
-    Return(Return &&other) = default;
-    Return &operator=(Return &&) = default;
+    Return(Return&& other) noexcept = default;
+    Return& operator=(Return&&) noexcept = default;
 
     ~Return() = default;
 
diff --git a/libhidlcache/HidlCache.h b/libhidlcache/HidlCache.h
index db778d3..39a7b3a 100644
--- a/libhidlcache/HidlCache.h
+++ b/libhidlcache/HidlCache.h
@@ -97,7 +97,7 @@
 template <class Key, class Value, class Compare>
 sp<Value> HidlCache<Key, Value, Compare>::unlock(const Key& key) {
     Lock lock(mMutex);
-    if (locked(key) > 0) {
+    if (locked(key)) {
         sp<Value> v = mLocked[key];
         mLocked.erase(key);
         return v;
diff --git a/libhidlcache/HidlMemoryCache.cpp b/libhidlcache/HidlMemoryCache.cpp
index 6f9c25c..a23c388 100644
--- a/libhidlcache/HidlMemoryCache.cpp
+++ b/libhidlcache/HidlMemoryCache.cpp
@@ -28,12 +28,12 @@
 using IMemoryToken = ::android::hidl::memory::token::V1_0::IMemoryToken;
 using IMemory = ::android::hidl::memory::V1_0::IMemory;
 
-class IMemoryDecorator : public virtual IMemory {
+class MemoryDecorator : public virtual IMemory {
    public:
-    IMemoryDecorator(sp<IMemory> heap) : mHeap(heap) {}
-    virtual ~IMemoryDecorator(){};
+    MemoryDecorator(const sp<IMemory>& heap) : mHeap(heap) {}
+    virtual ~MemoryDecorator() {}
     Return<void> update() override { return mHeap->update(); }
-    Return<void> read() override { return mHeap->read(); };
+    Return<void> read() override { return mHeap->read(); }
     Return<void> updateRange(uint64_t start, uint64_t length) override {
         return mHeap->updateRange(start, length);
     }
@@ -49,29 +49,28 @@
     sp<IMemory> mHeap;
 };
 
-class IMemoryCacheable : public virtual IMemoryDecorator {
+class MemoryCacheable : public virtual MemoryDecorator {
    public:
-    IMemoryCacheable(sp<IMemory> heap, sp<IMemoryToken> key) : IMemoryDecorator(heap), mKey(key) {}
-    virtual ~IMemoryCacheable() { HidlMemoryCache::getInstance()->flush(mKey); }
+    MemoryCacheable(const sp<IMemory>& heap, sp<IMemoryToken> key)
+        : MemoryDecorator(heap), mKey(key) {}
+    virtual ~MemoryCacheable() { HidlMemoryCache::getInstance()->flush(mKey); }
 
    protected:
     sp<IMemoryToken> mKey;
 };
 
-class IMemoryBlock : public virtual IMemoryDecorator {
+class MemoryBlockImpl : public virtual IMemory {
    public:
-    IMemoryBlock(sp<IMemory> heap, uint64_t size, uint64_t offset)
-        : IMemoryDecorator(heap), mSize(size), mOffset(offset), mHeapSize(heap->getSize()) {}
+    MemoryBlockImpl(const sp<IMemory>& heap, uint64_t size, uint64_t offset)
+        : mHeap(heap), mSize(size), mOffset(offset), mHeapSize(heap->getSize()) {}
     bool validRange(uint64_t start, uint64_t length) {
-        return (start + length < mSize) && (start + length >= start) &&
-               (mOffset + mSize < mHeapSize);
+        return (start + length <= mSize) && (start + length >= start) &&
+               (mOffset + mSize <= mHeapSize);
     }
-    Return<void> readRange(uint64_t start, uint64_t length) {
+    Return<void> readRange(uint64_t start, uint64_t length) override {
         if (!validRange(start, length)) {
             ALOGE("IMemoryBlock::readRange: out of range");
-            Status status;
-            status.setException(Status::EX_ILLEGAL_ARGUMENT, "out of range");
-            return Return<void>(status);
+            return Void();
         }
         return mHeap->readRange(mOffset + start, length);
     }
@@ -82,6 +81,9 @@
         }
         return mHeap->updateRange(mOffset + start, length);
     }
+    Return<void> read() override { return this->readRange(0, mSize); }
+    Return<void> update() override { return this->updateRange(0, mSize); }
+    Return<void> commit() override { return mHeap->commit(); }
     Return<uint64_t> getSize() override { return mSize; }
     Return<void*> getPointer() override {
         void* p = mHeap->getPointer();
@@ -89,6 +91,7 @@
     }
 
    protected:
+    sp<IMemory> mHeap;
     uint64_t mSize;
     uint64_t mOffset;
     uint64_t mHeapSize;
@@ -102,7 +105,7 @@
 sp<IMemory> HidlMemoryCache::fillLocked(const sp<IMemoryToken>& key) {
     sp<IMemory> memory = nullptr;
     Return<void> ret = key->get(
-        [&](const hidl_memory& mem) { memory = new IMemoryCacheable(mapMemory(mem), key); });
+        [&](const hidl_memory& mem) { memory = new MemoryCacheable(mapMemory(mem), key); });
     if (!ret.isOk()) {
         ALOGE("HidlMemoryCache::fill: cannot IMemoryToken::get.");
         return nullptr;
@@ -117,7 +120,7 @@
     if (heap == nullptr) {
         return nullptr;
     }
-    return new IMemoryBlock(heap, memblk.size, memblk.offset);
+    return new MemoryBlockImpl(heap, memblk.size, memblk.offset);
 }
 
 }  // namespace hardware
diff --git a/libhidlcache/MemoryDealer.cpp b/libhidlcache/MemoryDealer.cpp
index e9196a1..e5686a7 100644
--- a/libhidlcache/MemoryDealer.cpp
+++ b/libhidlcache/MemoryDealer.cpp
@@ -123,7 +123,7 @@
         // and generates a false positive warning about accessing
         // memory that is already freed.
         // Add an "assert" to avoid the confusion.
-        LOG_ALWAYS_FATAL_IF(mList.head() == removed);
+        LOG_ALWAYS_FATAL_IF(mList.front() == removed);
 #endif
         delete removed;
     }
@@ -221,8 +221,9 @@
                     if (p->free || !cur->size) {
                         freed = p;
                         p->size += cur->size;
-                        mList.erase(pos);
+                        pos = mList.erase(pos);
                         delete cur;
+                        if (pos == mList.end()) break;
                     }
                 }
                 if (++pos == mList.end()) break;
@@ -240,7 +241,7 @@
             return freed;
         }
     }
-    return 0;
+    return nullptr;
 }
 
 void SimpleBestFitAllocator::dump(const char* tag) const {
diff --git a/minijail/HardwareMinijail.cpp b/minijail/HardwareMinijail.cpp
index e6b1144..990a689 100644
--- a/minijail/HardwareMinijail.cpp
+++ b/minijail/HardwareMinijail.cpp
@@ -29,7 +29,7 @@
     }
 
     struct minijail* jail = minijail_new();
-    if (jail == NULL) {
+    if (jail == nullptr) {
         LOG(FATAL) << "Failed to create minijail.";
     }
 
diff --git a/test_main.cpp b/test_main.cpp
index 0de46ec..2b9f52c 100644
--- a/test_main.cpp
+++ b/test_main.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "LibHidlTest"
 
 #include <android-base/logging.h>
-#include <android/hardware/tests/inheritance/1.0/IParent.h>
+#include <android/hidl/memory/1.0/IMemory.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <hidl/HidlSupport.h>
@@ -280,6 +280,21 @@
     EXPECT_TRUE(hv1 != hv3);
 }
 
+TEST_F(LibHidlTest, VecEqInitializerTest) {
+    std::vector<int32_t> reference{5, 6, 7};
+    android::hardware::hidl_vec<int32_t> hv1{1, 2, 3};
+    hv1 = {5, 6, 7};
+    android::hardware::hidl_vec<int32_t> hv2;
+    hv2 = {5, 6, 7};
+    android::hardware::hidl_vec<int32_t> hv3;
+    hv3 = {5, 6, 8};
+
+    // use the == and != operator intentionally here
+    EXPECT_TRUE(hv1 == hv2);
+    EXPECT_TRUE(hv1 == reference);
+    EXPECT_TRUE(hv1 != hv3);
+}
+
 TEST_F(LibHidlTest, VecRangeCtorTest) {
     struct ConvertibleType {
         int val;
@@ -390,12 +405,15 @@
     hidl_version v3_0b{3,0};
 
     EXPECT_TRUE(v1_0 < v2_0);
+    EXPECT_TRUE(v1_0 != v2_0);
     EXPECT_TRUE(v2_0 < v2_1);
     EXPECT_TRUE(v2_1 < v3_0);
     EXPECT_TRUE(v2_0 > v1_0);
+    EXPECT_TRUE(v2_0 != v1_0);
     EXPECT_TRUE(v2_1 > v2_0);
     EXPECT_TRUE(v3_0 > v2_1);
     EXPECT_TRUE(v3_0 == v3_0b);
+    EXPECT_FALSE(v3_0 != v3_0b);
     EXPECT_TRUE(v3_0 <= v3_0b);
     EXPECT_TRUE(v2_2 <= v3_0);
     EXPECT_TRUE(v3_0 >= v3_0b);
@@ -459,12 +477,14 @@
 
 TEST_F(LibHidlTest, PreloadTest) {
     using ::android::hardware::preloadPassthroughService;
-    using ::android::hardware::tests::inheritance::V1_0::IParent;
+    using ::android::hidl::memory::V1_0::IMemory;
 
-    static const std::string kLib = "android.hardware.tests.inheritance@1.0-impl.so";
+    // installed on all devices by default in both bitnesses and not otherwise a dependency of this
+    // test.
+    static const std::string kLib = "android.hidl.memory@1.0-impl.so";
 
     EXPECT_FALSE(isLibraryOpen(kLib));
-    preloadPassthroughService<IParent>();
+    preloadPassthroughService<IMemory>();
     EXPECT_TRUE(isLibraryOpen(kLib));
 }
 
diff --git a/transport/Android.bp b/transport/Android.bp
index 5b0c11c..6518177 100644
--- a/transport/Android.bp
+++ b/transport/Android.bp
@@ -14,11 +14,11 @@
 
 hidl_package_root {
     name: "android.hidl",
-    path: "system/libhidl/transport",
 }
 
 cc_library {
     name: "libhidltransport",
+    recovery_available: true,
     vendor_available: true,
     vndk: {
         enabled: true,
@@ -47,21 +47,25 @@
     generated_sources: [
         "android.hidl.manager@1.0_genc++",
         "android.hidl.manager@1.1_genc++",
+        "android.hidl.manager@1.2_genc++",
         "android.hidl.base@1.0_genc++"
     ],
     generated_headers: [
         "android.hidl.manager@1.0_genc++_headers",
         "android.hidl.manager@1.1_genc++_headers",
+        "android.hidl.manager@1.2_genc++_headers",
         "android.hidl.base@1.0_genc++_headers"
     ],
     export_generated_headers: [
         "android.hidl.manager@1.0_genc++_headers",
         "android.hidl.manager@1.1_genc++_headers",
+        "android.hidl.manager@1.2_genc++_headers",
         "android.hidl.base@1.0_genc++_headers"
     ],
 
     srcs: [
         "HidlBinderSupport.cpp",
+        "HidlLazyUtils.cpp",
         "HidlPassthroughSupport.cpp",
         "HidlTransportSupport.cpp",
         "HidlTransportUtils.cpp",
@@ -77,4 +81,10 @@
             cflags: ["-DENFORCE_VINTF_MANIFEST"]
         },
     },
+
+    target: {
+        recovery: {
+            exclude_shared_libs: ["libvndksupport"],
+        },
+    },
 }
diff --git a/transport/HidlBinderSupport.cpp b/transport/HidlBinderSupport.cpp
index 4f8d7c5..62b1755 100644
--- a/transport/HidlBinderSupport.cpp
+++ b/transport/HidlBinderSupport.cpp
@@ -18,6 +18,10 @@
 
 #include <hidl/HidlBinderSupport.h>
 
+#include <InternalStatic.h>  // TODO(b/69122224): remove this include, for getOrCreateCachedBinder
+#include <android/hidl/base/1.0/BpHwBase.h>
+#include <hwbinder/IPCThreadState.h>
+
 // C includes
 #include <inttypes.h>
 #include <unistd.h>
@@ -46,6 +50,30 @@
     return mRecipient;
 }
 
+const size_t hidl_handle::kOffsetOfNativeHandle = offsetof(hidl_handle, mHandle);
+static_assert(hidl_handle::kOffsetOfNativeHandle == 0, "wrong offset");
+
+status_t readEmbeddedFromParcel(const hidl_handle& /* handle */,
+        const Parcel &parcel, size_t parentHandle, size_t parentOffset) {
+    const native_handle_t *handle;
+    status_t _hidl_err = parcel.readNullableEmbeddedNativeHandle(
+            parentHandle,
+            parentOffset + hidl_handle::kOffsetOfNativeHandle,
+            &handle);
+
+    return _hidl_err;
+}
+
+status_t writeEmbeddedToParcel(const hidl_handle &handle,
+        Parcel *parcel, size_t parentHandle, size_t parentOffset) {
+    status_t _hidl_err = parcel->writeEmbeddedNativeHandle(
+            handle.getNativeHandle(),
+            parentHandle,
+            parentOffset + hidl_handle::kOffsetOfNativeHandle);
+
+    return _hidl_err;
+}
+
 const size_t hidl_memory::kOffsetOfHandle = offsetof(hidl_memory, mHandle);
 const size_t hidl_memory::kOffsetOfName = offsetof(hidl_memory, mName);
 static_assert(hidl_memory::kOffsetOfHandle == 0, "wrong offset");
@@ -53,6 +81,7 @@
 
 status_t readEmbeddedFromParcel(const hidl_memory& memory,
         const Parcel &parcel, size_t parentHandle, size_t parentOffset) {
+    // TODO(b/111883309): Invoke readEmbeddedFromParcel(hidl_handle, ...).
     const native_handle_t *handle;
     ::android::status_t _hidl_err = parcel.readNullableEmbeddedNativeHandle(
             parentHandle,
@@ -81,6 +110,7 @@
 
 status_t writeEmbeddedToParcel(const hidl_memory &memory,
         Parcel *parcel, size_t parentHandle, size_t parentOffset) {
+    // TODO(b/111883309): Invoke writeEmbeddedToParcel(hidl_handle, ...).
     status_t _hidl_err = parcel->writeEmbeddedNativeHandle(
             memory.handle(),
             parentHandle,
@@ -206,11 +236,63 @@
     return status;
 }
 
+sp<IBinder> getOrCreateCachedBinder(::android::hidl::base::V1_0::IBase* ifacePtr) {
+    if (ifacePtr == nullptr) {
+        return nullptr;
+    }
+
+    if (ifacePtr->isRemote()) {
+        using ::android::hidl::base::V1_0::BpHwBase;
+
+        BpHwBase* bpBase = static_cast<BpHwBase*>(ifacePtr);
+        BpHwRefBase* bpRefBase = static_cast<BpHwRefBase*>(bpBase);
+        return sp<IBinder>(bpRefBase->remote());
+    }
+
+    std::string descriptor = details::getDescriptor(ifacePtr);
+    if (descriptor.empty()) {
+        // interfaceDescriptor fails
+        return nullptr;
+    }
+
+    // for get + set
+    std::unique_lock<std::mutex> _lock = details::gBnMap->lock();
+
+    wp<BHwBinder> wBnObj = details::gBnMap->getLocked(ifacePtr, nullptr);
+    sp<IBinder> sBnObj = wBnObj.promote();
+
+    if (sBnObj == nullptr) {
+        auto func = details::getBnConstructorMap().get(descriptor, nullptr);
+        if (!func) {
+            // TODO(b/69122224): remove this static variable when prebuilts updated
+            func = details::gBnConstructorMap->get(descriptor, nullptr);
+        }
+        LOG_ALWAYS_FATAL_IF(func == nullptr, "%s gBnConstructorMap returned null for %s", __func__,
+                            descriptor.c_str());
+
+        sBnObj = sp<IBinder>(func(static_cast<void*>(ifacePtr)));
+        LOG_ALWAYS_FATAL_IF(sBnObj == nullptr, "%s Bn constructor function returned null for %s",
+                            __func__, descriptor.c_str());
+
+        details::gBnMap->setLocked(ifacePtr, static_cast<BHwBinder*>(sBnObj.get()));
+    }
+
+    return sBnObj;
+}
+
+static bool gThreadPoolConfigured = false;
+
 void configureBinderRpcThreadpool(size_t maxThreads, bool callerWillJoin) {
-    ProcessState::self()->setThreadPoolConfiguration(maxThreads, callerWillJoin /*callerJoinsPool*/);
+    status_t ret = ProcessState::self()->setThreadPoolConfiguration(
+        maxThreads, callerWillJoin /*callerJoinsPool*/);
+    LOG_ALWAYS_FATAL_IF(ret != OK, "Could not setThreadPoolConfiguration: %d", ret);
+
+    gThreadPoolConfigured = true;
 }
 
 void joinBinderRpcThreadpool() {
+    LOG_ALWAYS_FATAL_IF(!gThreadPoolConfigured,
+                        "HIDL joinRpcThreadpool without calling configureRpcThreadPool.");
     IPCThreadState::self()->joinThreadPool();
 }
 
@@ -218,9 +300,7 @@
     int fd;
     int err = IPCThreadState::self()->setupPolling(&fd);
 
-    if (err != OK) {
-        ALOGE("Failed to setup binder polling: %d (%s)", err, strerror(err));
-    }
+    LOG_ALWAYS_FATAL_IF(err != OK, "Failed to setup binder polling: %d (%s)", err, strerror(err));
 
     return err == OK ? fd : -1;
 }
@@ -229,5 +309,9 @@
     return IPCThreadState::self()->handlePolledCommands();
 }
 
+void addPostCommandTask(const std::function<void(void)> task) {
+    IPCThreadState::self()->addPostCommandTask(task);
+}
+
 }  // namespace hardware
 }  // namespace android
diff --git a/transport/HidlLazyUtils.cpp b/transport/HidlLazyUtils.cpp
new file mode 100644
index 0000000..8e3fdf3
--- /dev/null
+++ b/transport/HidlLazyUtils.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hidl/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <android-base/logging.h>
+
+#include <android/hidl/manager/1.2/IClientCallback.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+namespace android {
+namespace hardware {
+namespace details {
+
+using ::android::hidl::base::V1_0::IBase;
+
+class ClientCounterCallback : public ::android::hidl::manager::V1_2::IClientCallback {
+   public:
+    ClientCounterCallback() : mNumConnectedServices(0) {}
+
+    bool addRegisteredService(const sp<IBase>& service, const std::string& name);
+
+   protected:
+    Return<void> onClients(const sp<IBase>& service, bool clients) override;
+
+   private:
+    /**
+     * Registers or re-registers services. Returns whether successful.
+     */
+    bool registerService(const sp<IBase>& service, const std::string& name);
+
+    /**
+     * Unregisters all services that we can. If we can't unregister all, re-register other
+     * services.
+     */
+    void tryShutdown();
+
+    /**
+     * Counter of the number of services that currently have at least one client.
+     */
+    size_t mNumConnectedServices;
+
+    struct Service {
+        sp<IBase> service;
+        std::string name;
+    };
+    /**
+     * Number of services that have been registered.
+     */
+    std::vector<Service> mRegisteredServices;
+};
+
+class LazyServiceRegistrarImpl {
+   public:
+    LazyServiceRegistrarImpl() : mClientCallback(new ClientCounterCallback) {}
+
+    status_t registerService(const sp<::android::hidl::base::V1_0::IBase>& service,
+                             const std::string& name);
+
+   private:
+    sp<ClientCounterCallback> mClientCallback;
+};
+
+bool ClientCounterCallback::addRegisteredService(const sp<IBase>& service,
+                                                 const std::string& name) {
+    bool success = registerService(service, name);
+
+    if (success) {
+        mRegisteredServices.push_back({service, name});
+    }
+
+    return success;
+}
+
+bool ClientCounterCallback::registerService(const sp<IBase>& service, const std::string& name) {
+    auto manager = hardware::defaultServiceManager1_2();
+
+    const std::string descriptor = getDescriptor(service.get());
+
+    LOG(INFO) << "Registering HAL: " << descriptor << " with name: " << name;
+
+    status_t res = android::hardware::details::registerAsServiceInternal(service, name);
+    if (res != android::OK) {
+        LOG(ERROR) << "Failed to register as service.";
+        return false;
+    }
+
+    bool ret = manager->registerClientCallback(getDescriptor(service.get()), name, service, this);
+    if (!ret) {
+        LOG(ERROR) << "Failed to add client callback.";
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * onClients is oneway, so no need to worry about multi-threading. Note that this means multiple
+ * invocations could occur on different threads however.
+ */
+Return<void> ClientCounterCallback::onClients(const sp<::android::hidl::base::V1_0::IBase>& service,
+                                              bool clients) {
+    if (clients) {
+        mNumConnectedServices++;
+    } else {
+        mNumConnectedServices--;
+    }
+
+    LOG(INFO) << "Process has " << mNumConnectedServices << " (of " << mRegisteredServices.size()
+              << " available) client(s) in use after notification " << getDescriptor(service.get())
+              << " has clients: " << clients;
+
+    if (mNumConnectedServices == 0) {
+        tryShutdown();
+    }
+
+    return Status::ok();
+}
+
+void ClientCounterCallback::tryShutdown() {
+    LOG(INFO) << "Trying to exit HAL. No clients in use for any service in process.";
+
+    auto manager = hardware::defaultServiceManager1_2();
+
+    auto unRegisterIt = mRegisteredServices.begin();
+    for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
+        auto& entry = (*unRegisterIt);
+
+        const std::string descriptor = getDescriptor(entry.service.get());
+        bool success = manager->tryUnregister(descriptor, entry.name, entry.service);
+
+        if (!success) {
+            LOG(INFO) << "Failed to unregister HAL " << descriptor << "/" << entry.name;
+            break;
+        }
+    }
+
+    if (unRegisterIt == mRegisteredServices.end()) {
+        LOG(INFO) << "Unregistered all clients and exiting";
+        exit(EXIT_SUCCESS);
+    }
+
+    for (auto reRegisterIt = mRegisteredServices.begin(); reRegisterIt != unRegisterIt;
+         reRegisterIt++) {
+        auto& entry = (*reRegisterIt);
+
+        // re-register entry
+        if (!registerService(entry.service, entry.name)) {
+            // Must restart. Otherwise, clients will never be able to get ahold of this service.
+            LOG(FATAL) << "Bad state: could not re-register " << getDescriptor(entry.service.get());
+        }
+    }
+}
+
+status_t LazyServiceRegistrarImpl::registerService(
+    const sp<::android::hidl::base::V1_0::IBase>& service, const std::string& name) {
+    if (!mClientCallback->addRegisteredService(service, name)) {
+        return ::android::UNKNOWN_ERROR;
+    }
+
+    return ::android::OK;
+}
+
+}  // namespace details
+
+LazyServiceRegistrar::LazyServiceRegistrar() {
+    mImpl = std::make_shared<details::LazyServiceRegistrarImpl>();
+}
+
+status_t LazyServiceRegistrar::registerService(
+    const sp<::android::hidl::base::V1_0::IBase>& service, const std::string& name) {
+    return mImpl->registerService(service, name);
+}
+
+}  // namespace hardware
+}  // namespace android
diff --git a/transport/HidlPassthroughSupport.cpp b/transport/HidlPassthroughSupport.cpp
index e5eb164..bc67656 100644
--- a/transport/HidlPassthroughSupport.cpp
+++ b/transport/HidlPassthroughSupport.cpp
@@ -16,6 +16,8 @@
 
 #include <hidl/HidlPassthroughSupport.h>
 
+#include <InternalStatic.h>  // TODO(b/69122224): remove this include, for tryWrap
+
 #include <hidl/HidlTransportUtils.h>
 #include <hidl/Static.h>
 
@@ -28,7 +30,8 @@
 static sp<IBase> tryWrap(const std::string& descriptor, sp<IBase> iface) {
     auto func = getBsConstructorMap().get(descriptor, nullptr);
     if (!func) {
-        func = gBsConstructorMap.get(descriptor, nullptr);
+        // TODO(b/69122224): remove this when prebuilts don't reference it
+        func = gBsConstructorMap->get(descriptor, nullptr);
     }
     if (func) {
         return func(static_cast<void*>(iface.get()));
diff --git a/transport/HidlTransportSupport.cpp b/transport/HidlTransportSupport.cpp
index c3a3031..b433b70 100644
--- a/transport/HidlTransportSupport.cpp
+++ b/transport/HidlTransportSupport.cpp
@@ -13,14 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <hidl/HidlTransportSupport.h>
 #include <hidl/HidlBinderSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Static.h>
 
+#include <android-base/logging.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 
 namespace android {
 namespace hardware {
 
+using ::android::hidl::base::V1_0::IBase;
+
 void configureRpcThreadpool(size_t maxThreads, bool callerWillJoin) {
     // TODO(b/32756130) this should be transport-dependent
     configureBinderRpcThreadpool(maxThreads, callerWillJoin);
@@ -40,9 +44,7 @@
 
 // TODO(b/122472540): only store one data item per object
 template <typename V>
-static void pruneMapLocked(ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, V>& map) {
-    using ::android::hidl::base::V1_0::IBase;
-
+static void pruneMapLocked(ConcurrentMap<wp<IBase>, V>& map) {
     std::vector<wp<IBase>> toDelete;
     for (const auto& kv : map) {
         if (kv.first.promote() == nullptr) {
@@ -54,47 +56,65 @@
     }
 }
 
-bool setMinSchedulerPolicy(const sp<::android::hidl::base::V1_0::IBase>& service,
-                           int policy, int priority) {
+bool setMinSchedulerPolicy(const sp<IBase>& service, int policy, int priority) {
     if (service->isRemote()) {
-        ALOGE("Can't set scheduler policy on remote service.");
+        LOG(ERROR) << "Can't set scheduler policy on remote service.";
         return false;
     }
 
-    if (policy != SCHED_NORMAL && policy != SCHED_FIFO && policy != SCHED_RR) {
-        ALOGE("Invalid scheduler policy %d", policy);
-        return false;
+    switch (policy) {
+        case SCHED_NORMAL: {
+            if (priority < -20 || priority > 19) {
+                LOG(ERROR) << "Invalid priority for SCHED_NORMAL: " << priority;
+                return false;
+            }
+        } break;
+        case SCHED_RR:
+        case SCHED_FIFO: {
+            if (priority < 1 || priority > 99) {
+                LOG(ERROR) << "Invalid priority for " << policy << " policy: " << priority;
+                return false;
+            }
+        } break;
+        default: {
+            LOG(ERROR) << "Invalid scheduler policy " << policy;
+            return false;
+        }
     }
 
-    if (policy == SCHED_NORMAL && (priority < -20 || priority > 19)) {
-        ALOGE("Invalid priority for SCHED_NORMAL: %d", priority);
-        return false;
-    } else if (priority < 1 || priority > 99) {
-        ALOGE("Invalid priority for real-time policy: %d", priority);
-        return false;
-    }
-
-    details::gServicePrioMap.set(service, { policy, priority });
+    // Due to ABI considerations, IBase cannot have a destructor to clean this up.
+    // So, because this API is so infrequently used, (expected to be usually only
+    // one time for a process, but it can be more), we are cleaning it up here.
+    std::unique_lock<std::mutex> lock = details::gServicePrioMap->lock();
+    pruneMapLocked(details::gServicePrioMap.get());
+    details::gServicePrioMap->setLocked(service, {policy, priority});
 
     return true;
 }
 
-bool setRequestingSid(const sp<::android::hidl::base::V1_0::IBase>& service, bool requesting) {
+bool setRequestingSid(const sp<IBase>& service, bool requesting) {
     if (service->isRemote()) {
-        ALOGE("Can't set requesting sid on remote service.");
+        LOG(ERROR) << "Can't set requesting sid on remote service.";
         return false;
     }
 
     // Due to ABI considerations, IBase cannot have a destructor to clean this up.
     // So, because this API is so infrequently used, (expected to be usually only
     // one time for a process, but it can be more), we are cleaning it up here.
-    std::unique_lock<std::mutex> lock = details::gServiceSidMap.lock();
-    pruneMapLocked(details::gServiceSidMap);
-    details::gServiceSidMap.setLocked(service, requesting);
+    std::unique_lock<std::mutex> lock = details::gServiceSidMap->lock();
+    pruneMapLocked(details::gServiceSidMap.get());
+    details::gServiceSidMap->setLocked(service, requesting);
 
     return true;
 }
 
+bool interfacesEqual(const sp<IBase>& left, const sp<IBase>& right) {
+    if (left == nullptr || right == nullptr || !left->isRemote() || !right->isRemote()) {
+        return left == right;
+    }
+    return getOrCreateCachedBinder(left.get()) == getOrCreateCachedBinder(right.get());
+}
+
 namespace details {
 int32_t getPidIfSharable() {
 #if LIBHIDL_TARGET_DEBUGGABLE
diff --git a/transport/HidlTransportUtils.cpp b/transport/HidlTransportUtils.cpp
index 4e952eb..8c61281 100644
--- a/transport/HidlTransportUtils.cpp
+++ b/transport/HidlTransportUtils.cpp
@@ -56,6 +56,10 @@
 }
 
 std::string getDescriptor(IBase* interface) {
+    if (interface == nullptr) {
+        return "";
+    }
+
     std::string myDescriptor{};
     auto ret = interface->interfaceDescriptor([&](const hidl_string &types) {
         myDescriptor = types.c_str();
diff --git a/transport/InternalStatic.h b/transport/InternalStatic.h
new file mode 100644
index 0000000..1dfaae4
--- /dev/null
+++ b/transport/InternalStatic.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 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 file is for legacy static variables that we are trying to get rid of.
+// TODO(b/69122224): remove this file
+
+#ifndef ANDROID_HARDWARE_HIDL_INTERNAL_STATIC_H
+#define ANDROID_HARDWARE_HIDL_INTERNAL_STATIC_H
+
+#include <hidl/Static.h>
+
+namespace android {
+namespace hardware {
+namespace details {
+
+// TODO(b/69122224): remove this
+// deprecated; use getBnConstructorMap instead.
+extern DoNotDestruct<BnConstructorMap> gBnConstructorMap;
+// TODO(b/69122224): remove this
+// deprecated; use getBsConstructorMap instead.
+extern DoNotDestruct<BsConstructorMap> gBsConstructorMap;
+
+}  // namespace details
+}  // namespace hardware
+}  // namespace android
+
+#endif
diff --git a/transport/ServiceManagement.cpp b/transport/ServiceManagement.cpp
index 01f83bd..e7bec41 100644
--- a/transport/ServiceManagement.cpp
+++ b/transport/ServiceManagement.cpp
@@ -33,17 +33,23 @@
 #include <hidl/HidlTransportUtils.h>
 #include <hidl/ServiceManagement.h>
 #include <hidl/Status.h>
+#include <utils/SystemClock.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <hwbinder/IPCThreadState.h>
 #include <hwbinder/Parcel.h>
+#if !defined(__ANDROID_RECOVERY__)
 #include <vndksupport/linker.h>
+#endif
 
-#include <android/hidl/manager/1.1/IServiceManager.h>
-#include <android/hidl/manager/1.1/BpHwServiceManager.h>
-#include <android/hidl/manager/1.1/BnHwServiceManager.h>
+#include <android/hidl/manager/1.2/BnHwServiceManager.h>
+#include <android/hidl/manager/1.2/BpHwServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 
 #define RE_COMPONENT    "[a-zA-Z_][a-zA-Z_0-9]*"
 #define RE_PATH         RE_COMPONENT "(?:[.]" RE_COMPONENT ")*"
@@ -51,23 +57,24 @@
 
 using android::base::WaitForProperty;
 
+using ::android::hidl::base::V1_0::IBase;
 using IServiceManager1_0 = android::hidl::manager::V1_0::IServiceManager;
 using IServiceManager1_1 = android::hidl::manager::V1_1::IServiceManager;
-using android::hidl::manager::V1_0::IServiceNotification;
-using android::hidl::manager::V1_1::BpHwServiceManager;
-using android::hidl::manager::V1_1::BnHwServiceManager;
+using IServiceManager1_2 = android::hidl::manager::V1_2::IServiceManager;
+using ::android::hidl::manager::V1_0::IServiceNotification;
 
 namespace android {
 namespace hardware {
 
-namespace details {
-extern Mutex gDefaultServiceManagerLock;
-extern sp<android::hidl::manager::V1_1::IServiceManager> gDefaultServiceManager;
-}  // namespace details
-
 static const char* kHwServicemanagerReadyProperty = "hwservicemanager.ready";
 
-void waitForHwServiceManager() {
+#if defined(__ANDROID_RECOVERY__)
+static constexpr bool kIsRecovery = true;
+#else
+static constexpr bool kIsRecovery = false;
+#endif
+
+static void waitForHwServiceManager() {
     using std::literals::chrono_literals::operator""s;
 
     while (!WaitForProperty(kHwServicemanagerReadyProperty, "true", 1s)) {
@@ -75,17 +82,7 @@
     }
 }
 
-bool endsWith(const std::string &in, const std::string &suffix) {
-    return in.size() >= suffix.size() &&
-           in.substr(in.size() - suffix.size()) == suffix;
-}
-
-bool startsWith(const std::string &in, const std::string &prefix) {
-    return in.size() >= prefix.size() &&
-           in.substr(0, prefix.size()) == prefix;
-}
-
-std::string binaryName() {
+static std::string binaryName() {
     std::ifstream ifs("/proc/self/cmdline");
     std::string cmdline;
     if (!ifs.is_open()) {
@@ -101,27 +98,27 @@
     return cmdline;
 }
 
-std::string packageWithoutVersion(const std::string& packageAndVersion) {
+static std::string packageWithoutVersion(const std::string& packageAndVersion) {
     size_t at = packageAndVersion.find('@');
     if (at == std::string::npos) return packageAndVersion;
     return packageAndVersion.substr(0, at);
 }
 
-void tryShortenProcessName(const std::string& packageAndVersion) {
+static void tryShortenProcessName(const std::string& descriptor) {
     const static std::string kTasks = "/proc/self/task/";
 
     // make sure that this binary name is in the same package
     std::string processName = binaryName();
 
     // e.x. android.hardware.foo is this package
-    if (!startsWith(packageWithoutVersion(processName), packageWithoutVersion(packageAndVersion))) {
+    if (!base::StartsWith(packageWithoutVersion(processName), packageWithoutVersion(descriptor))) {
         return;
     }
 
-    // e.x. android.hardware.module.foo@1.2 -> foo@1.2
-    size_t lastDot = packageAndVersion.rfind('.');
+    // e.x. android.hardware.module.foo@1.2::IFoo -> foo@1.2
+    size_t lastDot = descriptor.rfind('.');
     if (lastDot == std::string::npos) return;
-    size_t secondDot = packageAndVersion.rfind('.', lastDot - 1);
+    size_t secondDot = descriptor.rfind('.', lastDot - 1);
     if (secondDot == std::string::npos) return;
 
     std::string newName = processName.substr(secondDot + 1, std::string::npos);
@@ -145,7 +142,7 @@
         fs >> oldComm;
 
         // don't rename if it already has an explicit name
-        if (startsWith(packageAndVersion, oldComm)) {
+        if (base::StartsWith(descriptor, oldComm)) {
             fs.seekg(0, fs.beg);
             fs << newName;
         }
@@ -154,22 +151,69 @@
 
 namespace details {
 
-void onRegistration(const std::string &packageName,
-                    const std::string& /* interfaceName */,
-                    const std::string& /* instanceName */) {
-    tryShortenProcessName(packageName);
+/*
+ * Returns the age of the current process by reading /proc/self/stat and comparing starttime to the
+ * current time. This is useful for measuring how long it took a HAL to register itself.
+ */
+static long getProcessAgeMs() {
+    constexpr const int PROCFS_STAT_STARTTIME_INDEX = 21;
+    std::string content;
+    android::base::ReadFileToString("/proc/self/stat", &content, false);
+    auto stats = android::base::Split(content, " ");
+    if (stats.size() <= PROCFS_STAT_STARTTIME_INDEX) {
+        LOG(INFO) << "Could not read starttime from /proc/self/stat";
+        return -1;
+    }
+    const std::string& startTimeString = stats[PROCFS_STAT_STARTTIME_INDEX];
+    static const int64_t ticksPerSecond = sysconf(_SC_CLK_TCK);
+    const int64_t uptime = android::uptimeMillis();
+
+    unsigned long long startTimeInClockTicks = 0;
+    if (android::base::ParseUint(startTimeString, &startTimeInClockTicks)) {
+        long startTimeMs = 1000ULL * startTimeInClockTicks / ticksPerSecond;
+        return uptime - startTimeMs;
+    }
+    return -1;
+}
+
+static void onRegistrationImpl(const std::string& descriptor, const std::string& instanceName) {
+    long halStartDelay = getProcessAgeMs();
+    if (halStartDelay >= 0) {
+        // The "start delay" printed here is an estimate of how long it took the HAL to go from
+        // process creation to registering itself as a HAL.  Actual start time could be longer
+        // because the process might not have joined the threadpool yet, so it might not be ready to
+        // process transactions.
+        LOG(INFO) << "Registered " << descriptor << "/" << instanceName << " (start delay of "
+                  << halStartDelay << "ms)";
+    }
+
+    tryShortenProcessName(descriptor);
+}
+
+void onRegistration(const std::string& packageName, const std::string& interfaceName,
+                    const std::string& instanceName) {
+    return onRegistrationImpl(packageName + "::" + interfaceName, instanceName);
 }
 
 }  // details
 
 sp<IServiceManager1_0> defaultServiceManager() {
-    return defaultServiceManager1_1();
+    return defaultServiceManager1_2();
 }
 sp<IServiceManager1_1> defaultServiceManager1_1() {
+    return defaultServiceManager1_2();
+}
+sp<IServiceManager1_2> defaultServiceManager1_2() {
+    using android::hidl::manager::V1_2::BnHwServiceManager;
+    using android::hidl::manager::V1_2::BpHwServiceManager;
+
+    static std::mutex gDefaultServiceManagerLock;
+    static sp<IServiceManager1_2> gDefaultServiceManager;
+
     {
-        AutoMutex _l(details::gDefaultServiceManagerLock);
-        if (details::gDefaultServiceManager != nullptr) {
-            return details::gDefaultServiceManager;
+        std::lock_guard<std::mutex> _l(gDefaultServiceManagerLock);
+        if (gDefaultServiceManager != nullptr) {
+            return gDefaultServiceManager;
         }
 
         if (access("/dev/hwbinder", F_OK|R_OK|W_OK) != 0) {
@@ -180,23 +224,22 @@
 
         waitForHwServiceManager();
 
-        while (details::gDefaultServiceManager == nullptr) {
-            details::gDefaultServiceManager =
-                    fromBinder<IServiceManager1_1, BpHwServiceManager, BnHwServiceManager>(
-                        ProcessState::self()->getContextObject(nullptr));
-            if (details::gDefaultServiceManager == nullptr) {
+        while (gDefaultServiceManager == nullptr) {
+            gDefaultServiceManager =
+                fromBinder<IServiceManager1_2, BpHwServiceManager, BnHwServiceManager>(
+                    ProcessState::self()->getContextObject(nullptr));
+            if (gDefaultServiceManager == nullptr) {
                 LOG(ERROR) << "Waited for hwservicemanager, but got nullptr.";
                 sleep(1);
             }
         }
     }
 
-    return details::gDefaultServiceManager;
+    return gDefaultServiceManager;
 }
 
-std::vector<std::string> search(const std::string &path,
-                              const std::string &prefix,
-                              const std::string &suffix) {
+static std::vector<std::string> findFiles(const std::string& path, const std::string& prefix,
+                                          const std::string& suffix) {
     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
     if (!dir) return {};
 
@@ -206,8 +249,7 @@
     while ((dp = readdir(dir.get())) != nullptr) {
         std::string name = dp->d_name;
 
-        if (startsWith(name, prefix) &&
-                endsWith(name, suffix)) {
+        if (base::StartsWith(name, prefix) && base::EndsWith(name, suffix)) {
             results.push_back(name);
         }
     }
@@ -226,6 +268,11 @@
 }
 
 static void registerReference(const hidl_string &interfaceName, const hidl_string &instanceName) {
+    if (kIsRecovery) {
+        // No hwservicemanager in recovery.
+        return;
+    }
+
     sp<IServiceManager1_0> binderizedManager = defaultServiceManager();
     if (binderizedManager == nullptr) {
         LOG(WARNING) << "Could not registerReference for "
@@ -309,8 +356,12 @@
 
         static std::string halLibPathVndkSp = android::base::StringPrintf(
             HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION, details::getVndkVersionStr().c_str());
-        std::vector<std::string> paths = {HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR,
-                                          halLibPathVndkSp, HAL_LIBRARY_PATH_SYSTEM};
+        std::vector<std::string> paths = {
+            HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR, halLibPathVndkSp,
+#ifndef __ANDROID_VNDK__
+            HAL_LIBRARY_PATH_SYSTEM,
+#endif
+        };
 
 #ifdef LIBHIDL_TARGET_DEBUGGABLE
         const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
@@ -336,15 +387,17 @@
 #endif
 
         for (const std::string& path : paths) {
-            std::vector<std::string> libs = search(path, prefix, ".so");
+            std::vector<std::string> libs = findFiles(path, prefix, ".so");
 
             for (const std::string &lib : libs) {
                 const std::string fullPath = path + lib;
 
-                if (path == HAL_LIBRARY_PATH_SYSTEM) {
+                if (kIsRecovery || path == HAL_LIBRARY_PATH_SYSTEM) {
                     handle = dlopen(fullPath.c_str(), dlMode);
                 } else {
+#if !defined(__ANDROID_RECOVERY__)
                     handle = android_load_sphal_library(fullPath.c_str(), dlMode);
+#endif
                 }
 
                 if (handle == nullptr) {
@@ -436,16 +489,26 @@
             HAL_LIBRARY_PATH_VNDK_SP_32BIT_FOR_VERSION, details::getVndkVersionStr().c_str());
         static std::vector<std::pair<Arch, std::vector<const char*>>> sAllPaths{
             {Arch::IS_64BIT,
-             {HAL_LIBRARY_PATH_ODM_64BIT, HAL_LIBRARY_PATH_VENDOR_64BIT,
-              halLibPathVndkSp64.c_str(), HAL_LIBRARY_PATH_SYSTEM_64BIT}},
+             {
+                 HAL_LIBRARY_PATH_ODM_64BIT, HAL_LIBRARY_PATH_VENDOR_64BIT,
+                 halLibPathVndkSp64.c_str(),
+#ifndef __ANDROID_VNDK__
+                 HAL_LIBRARY_PATH_SYSTEM_64BIT,
+#endif
+             }},
             {Arch::IS_32BIT,
-             {HAL_LIBRARY_PATH_ODM_32BIT, HAL_LIBRARY_PATH_VENDOR_32BIT,
-              halLibPathVndkSp32.c_str(), HAL_LIBRARY_PATH_SYSTEM_32BIT}}};
+             {
+                 HAL_LIBRARY_PATH_ODM_32BIT, HAL_LIBRARY_PATH_VENDOR_32BIT,
+                 halLibPathVndkSp32.c_str(),
+#ifndef __ANDROID_VNDK__
+                 HAL_LIBRARY_PATH_SYSTEM_32BIT,
+#endif
+             }}};
         std::map<std::string, InstanceDebugInfo> map;
         for (const auto &pair : sAllPaths) {
             Arch arch = pair.first;
             for (const auto &path : pair.second) {
-                std::vector<std::string> libs = search(path, "", ".so");
+                std::vector<std::string> libs = findFiles(path, "", ".so");
                 for (const std::string &lib : libs) {
                     std::string matchedName;
                     std::string implName;
@@ -563,7 +626,7 @@
         return Void();
     }
 
-    void wait() {
+    void wait(bool timeout) {
         using std::literals::chrono_literals::operator""s;
 
         if (!mRegisteredForNotifications) {
@@ -574,7 +637,7 @@
         }
 
         std::unique_lock<std::mutex> lock(mMutex);
-        while(true) {
+        do {
             mCondition.wait_for(lock, 1s, [this]{
                 return mRegistered;
             });
@@ -583,9 +646,8 @@
                 break;
             }
 
-            LOG(WARNING) << "Waited one second for " << mInterfaceName << "/" << mInstanceName
-                         << ". Waiting another...";
-        }
+            LOG(WARNING) << "Waited one second for " << mInterfaceName << "/" << mInstanceName;
+        } while (!timeout);
     }
 
     // Be careful when using this; after calling reset(), you must always try to retrieve
@@ -615,7 +677,7 @@
    private:
     const std::string mInterfaceName;
     const std::string mInstanceName;
-    const sp<IServiceManager1_1>& mSm;
+    sp<IServiceManager1_1> mSm;
     std::mutex mMutex;
     std::condition_variable mCondition;
     bool mRegistered = false;
@@ -626,7 +688,7 @@
 void waitForHwService(
         const std::string &interface, const std::string &instanceName) {
     sp<Waiter> waiter = new Waiter(interface, instanceName, defaultServiceManager1_1());
-    waiter->wait();
+    waiter->wait(false /* timeout */);
     waiter->done();
 }
 
@@ -665,24 +727,30 @@
                                                              const std::string& instance,
                                                              bool retry, bool getStub) {
     using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport;
-    using ::android::hidl::base::V1_0::IBase;
     using ::android::hidl::manager::V1_0::IServiceManager;
     sp<Waiter> waiter;
 
-    const sp<IServiceManager1_1> sm = defaultServiceManager1_1();
-    if (sm == nullptr) {
-        ALOGE("getService: defaultServiceManager() is null");
-        return nullptr;
+    sp<IServiceManager1_1> sm;
+    Transport transport = Transport::EMPTY;
+    if (kIsRecovery) {
+        transport = Transport::PASSTHROUGH;
+    } else {
+        sm = defaultServiceManager1_1();
+        if (sm == nullptr) {
+            ALOGE("getService: defaultServiceManager() is null");
+            return nullptr;
+        }
+
+        Return<Transport> transportRet = sm->getTransport(descriptor, instance);
+
+        if (!transportRet.isOk()) {
+            ALOGE("getService: defaultServiceManager()->getTransport returns %s",
+                  transportRet.description().c_str());
+            return nullptr;
+        }
+        transport = transportRet;
     }
 
-    Return<Transport> transportRet = sm->getTransport(descriptor, instance);
-
-    if (!transportRet.isOk()) {
-        ALOGE("getService: defaultServiceManager()->getTransport returns %s",
-              transportRet.description().c_str());
-        return nullptr;
-    }
-    Transport transport = transportRet;
     const bool vintfHwbinder = (transport == Transport::HWBINDER);
     const bool vintfPassthru = (transport == Transport::PASSTHROUGH);
 
@@ -736,7 +804,7 @@
 
         if (waiter != nullptr) {
             ALOGI("getService: Trying again for %s/%s...", descriptor.c_str(), instance.c_str());
-            waiter->wait();
+            waiter->wait(true /* timeout */);
         }
     }
 
@@ -758,7 +826,33 @@
     return nullptr;
 }
 
-}; // namespace details
+status_t registerAsServiceInternal(const sp<IBase>& service, const std::string& name) {
+    if (service == nullptr) {
+        return UNEXPECTED_NULL;
+    }
 
-}; // namespace hardware
-}; // namespace android
+    sp<IServiceManager1_2> sm = defaultServiceManager1_2();
+    if (sm == nullptr) {
+        return INVALID_OPERATION;
+    }
+
+    bool registered = false;
+    Return<void> ret = service->interfaceChain([&](const auto& chain) {
+        registered = sm->addWithChain(name.c_str(), service, chain).withDefault(false);
+    });
+
+    if (!ret.isOk()) {
+        LOG(ERROR) << "Could not retrieve interface chain: " << ret.description();
+    }
+
+    if (registered) {
+        onRegistrationImpl(getDescriptor(service.get()), name);
+    }
+
+    return registered ? OK : UNKNOWN_ERROR;
+}
+
+} // namespace details
+
+} // namespace hardware
+} // namespace android
diff --git a/transport/Static.cpp b/transport/Static.cpp
index a506644..af16e8f 100644
--- a/transport/Static.cpp
+++ b/transport/Static.cpp
@@ -17,6 +17,7 @@
 // All static variables go here, to control initialization and
 // destruction order in the library.
 
+#include <InternalStatic.h>
 #include <hidl/Static.h>
 
 #include <android/hidl/manager/1.0/IServiceManager.h>
@@ -26,31 +27,29 @@
 namespace hardware {
 namespace details {
 
-Mutex gDefaultServiceManagerLock;
-sp<android::hidl::manager::V1_0::IServiceManager> gDefaultServiceManager;
-
 // Deprecated; kept for ABI compatibility. Use getBnConstructorMap.
-BnConstructorMap gBnConstructorMap{};
+DoNotDestruct<BnConstructorMap> gBnConstructorMap{};
 
-ConcurrentMap<const ::android::hidl::base::V1_0::IBase*, wp<::android::hardware::BHwBinder>>
-    gBnMap{};
+DoNotDestruct<ConcurrentMap<const ::android::hidl::base::V1_0::IBase*,
+                            wp<::android::hardware::BHwBinder>>>
+        gBnMap{};
 
 // TODO(b/122472540): replace with single, hidden map
-ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, SchedPrio> gServicePrioMap{};
-ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, bool> gServiceSidMap{};
+DoNotDestruct<ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, SchedPrio>> gServicePrioMap{};
+DoNotDestruct<ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, bool>> gServiceSidMap{};
 
 // Deprecated; kept for ABI compatibility. Use getBsConstructorMap.
-BsConstructorMap gBsConstructorMap{};
+DoNotDestruct<BsConstructorMap> gBsConstructorMap{};
 
 // For static executables, it is not guaranteed that gBnConstructorMap are initialized before
 // used in HAL definition libraries.
 BnConstructorMap& getBnConstructorMap() {
-    static BnConstructorMap map{};
+    static BnConstructorMap& map = *new BnConstructorMap();
     return map;
 }
 
 BsConstructorMap& getBsConstructorMap() {
-    static BsConstructorMap map{};
+    static BsConstructorMap& map = *new BsConstructorMap();
     return map;
 }
 
diff --git a/transport/allocator/1.0/default/Android.bp b/transport/allocator/1.0/default/Android.bp
index fc352c3..1fdfb26 100644
--- a/transport/allocator/1.0/default/Android.bp
+++ b/transport/allocator/1.0/default/Android.bp
@@ -21,6 +21,7 @@
         "service.cpp"
     ],
     init_rc: ["android.hidl.allocator@1.0-service.rc"],
+    vintf_fragments: ["android.hidl.allocator@1.0-service.xml"],
 
     shared_libs: [
         "android.hidl.allocator@1.0",
diff --git a/transport/allocator/1.0/default/AshmemAllocator.cpp b/transport/allocator/1.0/default/AshmemAllocator.cpp
index 0bd4f81..5cc2eea 100644
--- a/transport/allocator/1.0/default/AshmemAllocator.cpp
+++ b/transport/allocator/1.0/default/AshmemAllocator.cpp
@@ -36,8 +36,8 @@
 
     native_handle_t* handle = native_handle_create(1, 0);
     handle->data[0] = fd;
-    LOG(WARNING) << "ashmem_create_region(" << size << ") returning hidl_memory(" << handle
-            << ", " << size << ")";
+    LOG(VERBOSE) << "ashmem_create_region(" << size << ") returning hidl_memory(" << handle << ", "
+                 << size << ")";
     return hidl_memory("ashmem", handle, size);
 }
 
diff --git a/transport/allocator/1.0/default/android.hidl.allocator@1.0-service.xml b/transport/allocator/1.0/default/android.hidl.allocator@1.0-service.xml
new file mode 100644
index 0000000..5218241
--- /dev/null
+++ b/transport/allocator/1.0/default/android.hidl.allocator@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+    <hal>
+        <name>android.hidl.allocator</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IAllocator</name>
+            <instance>ashmem</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/transport/allocator/1.0/utils/Android.bp b/transport/allocator/1.0/utils/Android.bp
index b1a3f41..9f70963 100644
--- a/transport/allocator/1.0/utils/Android.bp
+++ b/transport/allocator/1.0/utils/Android.bp
@@ -18,6 +18,7 @@
     vndk: {
         enabled: true,
     },
+    double_loadable: true,
     defaults: ["libhidl-defaults"],
     shared_libs: [
         "libbinder",
diff --git a/transport/allocator/1.0/vts/functional/Android.bp b/transport/allocator/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..797d3f8
--- /dev/null
+++ b/transport/allocator/1.0/vts/functional/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2018 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: "VtsHidlAllocatorV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHidlAllocatorV1_0TargetTest.cpp"],
+    shared_libs: [
+        "libhidlmemory",
+    ],
+    static_libs: [
+        "android.hidl.allocator@1.0",
+    ],
+}
+
diff --git a/.clang-format b/transport/allocator/1.0/vts/functional/Android.mk
similarity index 69%
rename from .clang-format
rename to transport/allocator/1.0/vts/functional/Android.mk
index 9b3f9d9..62880ed 100644
--- a/.clang-format
+++ b/transport/allocator/1.0/vts/functional/Android.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2017 The Android Open Source Project
+# Copyright (C) 2018 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.
@@ -14,11 +14,9 @@
 # limitations under the License.
 #
 
-BasedOnStyle: Google
-CommentPragmas: NOLINT:.*
-DerivePointerAlignment: false
-AllowShortFunctionsOnASingleLine: Inline
-ColumnLimit: 100
-TabWidth: 4
-UseTab: Never
-IndentWidth: 4
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsHidlAllocatorV1_0Target
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/transport/allocator/1.0/vts/functional/AndroidTest.xml b/transport/allocator/1.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..6ac167f
--- /dev/null
+++ b/transport/allocator/1.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VTS VtsHidlAllocatorV1_0Target test cases">
+    <option name="config-descriptor:metadata" key="plan" value="vts-treble" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="abort-on-push-failure" value="false"/>
+        <option name="push-group" value="HalHidlTargetTest.push"/>
+    </target_preparer>
+    <multi_target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+        <option name="test-module-name" value="VtsHidlAllocatorV1_0Target"/>
+        <option name="binary-test-working-directory" value="_32bit::/data/nativetest/" />
+        <option name="binary-test-working-directory" value="_64bit::/data/nativetest64/" />
+        <option name="binary-test-source" value="_32bit::DATA/nativetest/VtsHidlAllocatorV1_0TargetTest/VtsHidlAllocatorV1_0TargetTest" />
+        <option name="binary-test-source" value="_64bit::DATA/nativetest64/VtsHidlAllocatorV1_0TargetTest/VtsHidlAllocatorV1_0TargetTest" />
+        <option name="binary-test-type" value="hal_hidl_gtest"/>
+        <option name="test-timeout" value="5m"/>
+    </test>
+</configuration>
diff --git a/transport/allocator/1.0/vts/functional/VtsHidlAllocatorV1_0TargetTest.cpp b/transport/allocator/1.0/vts/functional/VtsHidlAllocatorV1_0TargetTest.cpp
new file mode 100644
index 0000000..39ce606
--- /dev/null
+++ b/transport/allocator/1.0/vts/functional/VtsHidlAllocatorV1_0TargetTest.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+#define ASSERT_OK(ret) ASSERT_TRUE((ret).isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE((ret).isOk())
+
+class AllocatorEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    virtual void registerTestServices() override { registerTestService<IAllocator>(); }
+
+    static AllocatorEnvironment* instance() {
+        static AllocatorEnvironment* instance = new AllocatorEnvironment();
+        return instance;
+    };
+};
+
+class AllocatorHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        allocator = getService<IAllocator>(AllocatorEnvironment::instance());
+        ASSERT_NE(allocator, nullptr);
+    }
+
+    sp<IMemory> expectAllocateSuccess(size_t size) {
+        sp<IMemory> memory;
+        EXPECT_OK(allocator->allocate(size, [&](bool success, const hidl_memory& mem) {
+            ASSERT_TRUE(success) << "Allocate failed for size: " << size;
+            EXPECT_EQ(mem.size(), size)
+                << "Allocated " << size << " but got hidl_memory with size " << mem.size();
+            memory = mapMemory(mem);
+        }));
+        EXPECT_NE(nullptr, memory.get());
+        EXPECT_EQ(memory->getSize(), size)
+            << "Allocated " << size << " but got IMemory with size " << memory->getSize();
+        return memory;
+    }
+
+    std::vector<sp<IMemory>> expectBatchAllocateSuccess(size_t size, size_t count) {
+        std::vector<sp<IMemory>> memories;
+        memories.reserve(count);
+        EXPECT_OK(allocator->batchAllocate(
+            size, count, [&](bool success, const hidl_vec<hidl_memory>& mems) {
+                EXPECT_EQ(count, mems.size());
+
+                for (const hidl_memory& mem : mems) {
+                    ASSERT_TRUE(success) << "Allocate failed for size: " << size;
+                    EXPECT_EQ(mem.size(), size)
+                        << "Allocated " << size << " but got hidl_memory with size " << mem.size();
+                    memories.push_back(mapMemory(mem));
+                }
+            }));
+        for (const sp<IMemory>& memory : memories) {
+            EXPECT_NE(nullptr, memory.get());
+            EXPECT_EQ(memory->getSize(), size)
+                << "Allocated " << size << " but got IMemory with size " << memory->getSize();
+        }
+        return memories;
+    }
+
+    sp<IAllocator> allocator;
+};
+
+TEST_F(AllocatorHidlTest, TestAllocateSizes) {
+    for (size_t size : {1, 1023, 1024, 1025, 4096}) {
+        expectAllocateSuccess(size);
+    }
+}
+
+TEST_F(AllocatorHidlTest, TestBatchAllocateSizes) {
+    for (size_t count : {1, 1, 2, 3, 10}) {
+        for (size_t size : {1, 1023, 1024, 1025, 4096}) {
+            expectBatchAllocateSuccess(size, count);
+        }
+    }
+}
+
+TEST_F(AllocatorHidlTest, TestCommit) {
+    constexpr size_t kSize = 1337;
+
+    sp<IMemory> memory = expectAllocateSuccess(kSize);
+    for (int i = 0; i < 100; i++) {
+        EXPECT_OK(memory->read());
+        EXPECT_OK(memory->update());
+        EXPECT_OK(memory->commit());
+
+        EXPECT_OK(memory->read());
+        EXPECT_OK(memory->commit());
+
+        EXPECT_OK(memory->update());
+        EXPECT_OK(memory->commit());
+    }
+
+    for (int i = 0; i < kSize; i++) {
+        EXPECT_OK(memory->readRange(i, kSize));
+        EXPECT_OK(memory->updateRange(i, kSize));
+        EXPECT_OK(memory->commit());
+
+        EXPECT_OK(memory->readRange(i, kSize));
+        EXPECT_OK(memory->commit());
+
+        EXPECT_OK(memory->updateRange(i, kSize));
+        EXPECT_OK(memory->commit());
+    }
+}
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(AllocatorEnvironment::instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    AllocatorEnvironment::instance()->init(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/transport/base/1.0/Android.bp b/transport/base/1.0/Android.bp
index bd2ae49..cebb01b 100644
--- a/transport/base/1.0/Android.bp
+++ b/transport/base/1.0/Android.bp
@@ -3,7 +3,6 @@
 hidl_interface {
     name: "android.hidl.base@1.0",
     root: "android.hidl",
-    core_interface: true,
     vndk: {
         enabled: true,
     },
@@ -11,9 +10,6 @@
         "types.hal",
         "IBase.hal",
     ],
-    types: [
-        "DebugInfo",
-    ],
     gen_java: true,
 }
 
diff --git a/transport/base/1.0/IBase.hal b/transport/base/1.0/IBase.hal
index e862ec8..22007f0 100644
--- a/transport/base/1.0/IBase.hal
+++ b/transport/base/1.0/IBase.hal
@@ -87,7 +87,10 @@
     linkToDeath(death_recipient recipient, uint64_t cookie) generates (bool success);
 
     /*
-     * Unregisters a previously registered death recipient.
+     * Unregisters the registered death recipient. If this service was registered
+     * multiple times with the same exact death recipient, this unlinks the most
+     * recently registered one.
+     *
      * @param recipient a previously registered hidl_death_recipient callback
      * @return success whether the death recipient was unregistered successfully.
      */
diff --git a/transport/current.txt b/transport/current.txt
index a48233c..2abf6f7 100644
--- a/transport/current.txt
+++ b/transport/current.txt
@@ -21,4 +21,13 @@
 2e19301ceb87fb0696cd8268fab9c41f95d23c7392d35bc575daaa6eb32807eb android.hidl.memory.token@1.0::IMemoryToken
 
 # ABI preserving changes to HALs during Android Q
+85394f8a0d15e7fb2ee45c52d1fb8b8fd3c13c333e63c78c4aa1ff86840cf6dc android.hidl.manager@1.0::IServiceManager
 fcde1d0788066a62d5766f4dc19d4c1ec76967d5ddb636f59ccc66603460bcf8 android.hidl.manager@1.0::IServiceNotification
+
+# Clarification for b/67503915
+ec7fd79ed02dfa85bc499426adae3ebe23ef0524f3cd6957139324b83b18ca4c android.hidl.base@1.0::IBase
+
+# HALs released in Android Q
+a570fd436aed5eeeea2495b9267e7f9c4808d51efd4c9ba0913b9102eb93aeed android.hidl.manager@1.2::IClientCallback
+6f3a8a3fd4bfbd02e4e61c732d2df616ff69434a1ed83cda337303adc6d714df android.hidl.manager@1.2::IServiceManager
+b1c4fbdebe6d0def9b4f63aa83a0641f694fd5732ad32881a57fe12d5310a259 android.hidl.safe_union@1.0::types
diff --git a/transport/include/hidl/ConcurrentMap.h b/transport/include/hidl/ConcurrentMap.h
index 1b06dfd..329752c 100644
--- a/transport/include/hidl/ConcurrentMap.h
+++ b/transport/include/hidl/ConcurrentMap.h
@@ -90,6 +90,23 @@
     std::map<K, V> mMap;
 };
 
+namespace details {
+
+// TODO(b/69122224): remove this type and usages of it
+// DO NOT ADD USAGES
+template <typename T>
+class DoNotDestruct {
+  public:
+    DoNotDestruct() { new (buffer) T(); }
+    T& get() { return *reinterpret_cast<T*>(buffer); }
+    T* operator->() { return reinterpret_cast<T*>(buffer); }
+
+  private:
+    alignas(T) char buffer[sizeof(T)];
+};
+
+}  // namespace details
+
 }  // namespace hardware
 }  // namespace android
 
diff --git a/transport/include/hidl/HidlBinderSupport.h b/transport/include/hidl/HidlBinderSupport.h
index 9759af1..a098805 100644
--- a/transport/include/hidl/HidlBinderSupport.h
+++ b/transport/include/hidl/HidlBinderSupport.h
@@ -24,11 +24,10 @@
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportUtils.h>
 #include <hidl/MQDescriptor.h>
-#include <hidl/Static.h>
 #include <hwbinder/IBinder.h>
-#include <hwbinder/IPCThreadState.h>
 #include <hwbinder/Parcel.h>
-#include <hwbinder/ProcessState.h>
+#include <log/log.h>  // TODO(b/65843592): remove. Too many users depending on this transitively.
+
 // Defines functions for hidl_string, hidl_version, Status, hidl_vec, MQDescriptor,
 // etc. to interact with Parcel.
 
@@ -49,6 +48,14 @@
     wp<::android::hidl::base::V1_0::IBase> mBase;
 };
 
+// ---------------------- hidl_handle
+
+status_t readEmbeddedFromParcel(const hidl_handle &handle,
+        const Parcel &parcel, size_t parentHandle, size_t parentOffset);
+
+status_t writeEmbeddedToParcel(const hidl_handle &handle,
+        Parcel *parcel, size_t parentHandle, size_t parentOffset);
+
 // ---------------------- hidl_memory
 
 status_t readEmbeddedFromParcel(const hidl_memory &memory,
@@ -301,6 +308,10 @@
 
 // ---------------------- support for casting interfaces
 
+// Constructs a binder for this interface and caches it. If it has already been created
+// then it returns it.
+sp<IBinder> getOrCreateCachedBinder(::android::hidl::base::V1_0::IBase* ifacePtr);
+
 // Construct a smallest possible binder from the given interface.
 // If it is remote, then its remote() will be retrieved.
 // Otherwise, the smallest possible BnChild is found where IChild is a subclass of IType
@@ -310,43 +321,7 @@
           typename = std::enable_if_t<std::is_same<details::i_tag, typename IType::_hidl_tag>::value>>
 sp<IBinder> toBinder(sp<IType> iface) {
     IType *ifacePtr = iface.get();
-    if (ifacePtr == nullptr) {
-        return nullptr;
-    }
-    if (ifacePtr->isRemote()) {
-        return ::android::hardware::IInterface::asBinder(
-            static_cast<BpInterface<IType>*>(ifacePtr));
-    } else {
-        std::string myDescriptor = details::getDescriptor(ifacePtr);
-        if (myDescriptor.empty()) {
-            // interfaceDescriptor fails
-            return nullptr;
-        }
-
-        // for get + set
-        std::unique_lock<std::mutex> _lock = details::gBnMap.lock();
-
-        wp<BHwBinder> wBnObj = details::gBnMap.getLocked(ifacePtr, nullptr);
-        sp<IBinder> sBnObj = wBnObj.promote();
-
-        if (sBnObj == nullptr) {
-            auto func = details::getBnConstructorMap().get(myDescriptor, nullptr);
-            if (!func) {
-                func = details::gBnConstructorMap.get(myDescriptor, nullptr);
-                if (!func) {
-                    return nullptr;
-                }
-            }
-
-            sBnObj = sp<IBinder>(func(static_cast<void*>(ifacePtr)));
-
-            if (sBnObj != nullptr) {
-                details::gBnMap.setLocked(ifacePtr, static_cast<BHwBinder*>(sBnObj.get()));
-            }
-        }
-
-        return sBnObj;
-    }
+    return getOrCreateCachedBinder(ifacePtr);
 }
 
 template <typename IType, typename ProxyType, typename StubType>
@@ -374,6 +349,8 @@
 int setupBinderPolling();
 status_t handleBinderPoll();
 
+void addPostCommandTask(const std::function<void(void)> task);
+
 }  // namespace hardware
 }  // namespace android
 
diff --git a/transport/include/hidl/HidlLazyUtils.h b/transport/include/hidl/HidlLazyUtils.h
new file mode 100644
index 0000000..2205daa
--- /dev/null
+++ b/transport/include/hidl/HidlLazyUtils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace details {
+class LazyServiceRegistrarImpl;
+}  // namespace details
+
+/** Exits when all HALs registered through this object have 0 clients */
+class LazyServiceRegistrar {
+   public:
+    LazyServiceRegistrar();
+    status_t registerService(const sp<::android::hidl::base::V1_0::IBase>& service,
+                             const std::string& name = "default");
+
+   private:
+    std::shared_ptr<details::LazyServiceRegistrarImpl> mImpl;
+};
+
+}  // namespace hardware
+}  // namespace android
diff --git a/transport/include/hidl/HidlTransportSupport.h b/transport/include/hidl/HidlTransportSupport.h
index cdcb03e..a132bfa 100644
--- a/transport/include/hidl/HidlTransportSupport.h
+++ b/transport/include/hidl/HidlTransportSupport.h
@@ -84,18 +84,6 @@
 bool setMinSchedulerPolicy(const sp<::android::hidl::base::V1_0::IBase>& service,
                            int policy, int priority);
 
-template <typename ILeft,
-          typename IRight,
-          typename = std::enable_if_t<std::is_same<details::i_tag, typename ILeft::_hidl_tag>::value>,
-          typename = std::enable_if_t<std::is_same<details::i_tag, typename IRight::_hidl_tag>::value>>
-bool interfacesEqual(sp<ILeft> left, sp<IRight> right) {
-    if (left == nullptr || right == nullptr || !left->isRemote() || !right->isRemote()) {
-        return left == right;
-    }
-
-    return toBinder<ILeft>(left) == toBinder<IRight>(right);
-}
-
 /**
  * Sets whether or not this object should request security contexts to be populatd for incoming
  * calls (e.g. with getCallingSid).
@@ -108,6 +96,14 @@
  */
 bool setRequestingSid(const sp<::android::hidl::base::V1_0::IBase>& service, bool requesting);
 
+/**
+ * Returns whether two interfaces represent the same interface. References to interfaces in the same
+ * process will always be equivalent. However, in order to compare a service that is a proxy to a
+ * different process, its underlying structure may have to be checked.
+ */
+bool interfacesEqual(const sp<::android::hidl::base::V1_0::IBase>& left,
+                     const sp<::android::hidl::base::V1_0::IBase>& right);
+
 namespace details {
 
 // Return PID on userdebug / eng builds and IServiceManager::PidConstant::NO_PID on user builds.
@@ -141,7 +137,7 @@
     // TODO b/32001926 Needs to be fixed for socket mode.
     if (parent->isRemote()) {
         // binderized mode. Got BpChild. grab the remote and wrap it.
-        return sp<IChild>(new BpChild(toBinder<IParent>(parent)));
+        return sp<IChild>(new BpChild(getOrCreateCachedBinder(parent.get())));
     }
     // Passthrough mode. Got BnChild or BsChild.
     return sp<IChild>(static_cast<IChild *>(parent.get()));
@@ -161,7 +157,7 @@
 
     if (base->isRemote()) {
         // getRawServiceInternal guarantees we get the proper class
-        return sp<IType>(new BpType(toBinder<IBase>(base)));
+        return sp<IType>(new BpType(getOrCreateCachedBinder(base.get())));
     }
 
     return IType::castFrom(base);
diff --git a/transport/include/hidl/LegacySupport.h b/transport/include/hidl/LegacySupport.h
index f03d34d..1e983eb 100644
--- a/transport/include/hidl/LegacySupport.h
+++ b/transport/include/hidl/LegacySupport.h
@@ -14,25 +14,21 @@
  * limitations under the License.
  */
 
+#include <hidl/HidlLazyUtils.h>
 #include <hidl/HidlTransportSupport.h>
 #include <sys/wait.h>
-#include <utils/Log.h>
 #include <utils/Errors.h>
+#include <utils/Log.h>
 #include <utils/StrongPointer.h>
 
-#ifndef ANDROID_HIDL_LEGACY_SUPPORT_H
-#define ANDROID_HIDL_LEGACY_SUPPORT_H
+#pragma once
 
 namespace android {
 namespace hardware {
-
-/**
- * Registers passthrough service implementation.
- */
-template<class Interface>
-__attribute__((warn_unused_result))
-status_t registerPassthroughServiceImplementation(
-        std::string name = "default") {
+namespace details {
+template <class Interface, typename Func>
+__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
+    Func registerServiceCb, const std::string& name = "default") {
     sp<Interface> service = Interface::getService(name, true /* getStub */);
 
     if (service == nullptr) {
@@ -44,7 +40,7 @@
     LOG_FATAL_IF(service->isRemote(), "Implementation of %s/%s is remote!",
             Interface::descriptor, name.c_str());
 
-    status_t status = service->registerAsService(name);
+    status_t status = registerServiceCb(service, name);
 
     if (status == OK) {
         ALOGI("Registration complete for %s/%s.",
@@ -56,16 +52,29 @@
 
     return status;
 }
+}  // namespace details
+
+/**
+ * Registers passthrough service implementation.
+ */
+template <class Interface>
+__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
+    const std::string& name = "default") {
+    return details::registerPassthroughServiceImplementation<Interface>(
+        [](const sp<Interface>& service, const std::string& name) {
+            return service->registerAsService(name);
+        },
+        name);
+}
 
 /**
  * Creates default passthrough service implementation. This method never returns.
  *
  * Return value is exit status.
  */
-template<class Interface>
-__attribute__((warn_unused_result))
-status_t defaultPassthroughServiceImplementation(std::string name,
-                                            size_t maxThreads = 1) {
+template <class Interface>
+__attribute__((warn_unused_result)) status_t defaultPassthroughServiceImplementation(
+    const std::string& name, size_t maxThreads = 1) {
     configureRpcThreadpool(maxThreads, true);
     status_t result = registerPassthroughServiceImplementation<Interface>(name);
 
@@ -82,7 +91,54 @@
     return defaultPassthroughServiceImplementation<Interface>("default", maxThreads);
 }
 
+/**
+ * Registers a passthrough service implementation that exits when there are 0 clients.
+ *
+ * If this function is called multiple times to register different services, then this process will
+ * only exit once all services have 0 clients. This function does not know about clients registered
+ * through registerPassthroughServiceImplementation, so if that function is used in conjunction with
+ * this one, the process may exit while a client is still using the HAL.
+ */
+template <class Interface>
+__attribute__((warn_unused_result)) status_t registerLazyPassthroughServiceImplementation(
+    const std::string& name = "default") {
+    // Make LazyServiceRegistrar static so that multiple calls to
+    // registerLazyPassthroughServiceImplementation work as expected: each HAL is registered and the
+    // process only exits once all HALs have 0 clients.
+    using android::hardware::LazyServiceRegistrar;
+    static auto serviceCounter(std::make_shared<LazyServiceRegistrar>());
+
+    return details::registerPassthroughServiceImplementation<Interface>(
+        [](const sp<Interface>& service, const std::string& name) {
+            return serviceCounter->registerService(service, name);
+        },
+        name);
+}
+
+/**
+ * Creates default passthrough service implementation that exits when there are 0 clients. This
+ * method never returns.
+ *
+ * Return value is exit status.
+ */
+template <class Interface>
+__attribute__((warn_unused_result)) status_t defaultLazyPassthroughServiceImplementation(
+    const std::string& name, size_t maxThreads = 1) {
+    configureRpcThreadpool(maxThreads, true);
+    status_t result = registerLazyPassthroughServiceImplementation<Interface>(name);
+
+    if (result != OK) {
+        return result;
+    }
+
+    joinRpcThreadpool();
+    return UNKNOWN_ERROR;
+}
+template <class Interface>
+__attribute__((warn_unused_result)) status_t defaultLazyPassthroughServiceImplementation(
+    size_t maxThreads = 1) {
+    return defaultLazyPassthroughServiceImplementation<Interface>("default", maxThreads);
+}
+
 }  // namespace hardware
 }  // namespace android
-
-#endif  // ANDROID_HIDL_LEGACY_SUPPORT_H
diff --git a/transport/include/hidl/ServiceManagement.h b/transport/include/hidl/ServiceManagement.h
index 4df156b..a962034 100644
--- a/transport/include/hidl/ServiceManagement.h
+++ b/transport/include/hidl/ServiceManagement.h
@@ -28,21 +28,21 @@
 namespace manager {
 namespace V1_0 {
     struct IServiceManager;
-}; // namespace V1_0
+}  // namespace V1_0
 namespace V1_1 {
-    struct IServiceManager;
-}; // namespace V1_0
-}; // namespace manager
-}; // namespace hidl
+struct IServiceManager;
+}  // namespace V1_1
+namespace V1_2 {
+struct IServiceManager;
+}  // namespace V1_2
+}  // namespace manager
+}  // namespace hidl
 
 namespace hardware {
 
 namespace details {
-// e.x.: android.hardware.foo@1.0, IFoo, default
-void onRegistration(const std::string &packageName,
-                    const std::string &interfaceName,
-                    const std::string &instanceName);
 
+// Will not attempt to start a lazy HAL
 // e.x.: android.hardware.foo@1.0::IFoo, default
 void waitForHwService(const std::string &interface, const std::string &instanceName);
 
@@ -57,12 +57,16 @@
 sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
                                                              const std::string& instance,
                                                              bool retry, bool getStub);
-};
+
+status_t registerAsServiceInternal(const sp<::android::hidl::base::V1_0::IBase>& service,
+                                   const std::string& name);
+}  // namespace details
 
 // These functions are for internal use by hidl. If you want to get ahold
 // of an interface, the best way to do this is by calling IFoo::getService()
 sp<::android::hidl::manager::V1_0::IServiceManager> defaultServiceManager();
 sp<::android::hidl::manager::V1_1::IServiceManager> defaultServiceManager1_1();
+sp<::android::hidl::manager::V1_2::IServiceManager> defaultServiceManager1_2();
 sp<::android::hidl::manager::V1_0::IServiceManager> getPassthroughServiceManager();
 sp<::android::hidl::manager::V1_1::IServiceManager> getPassthroughServiceManager1_1();
 
@@ -77,8 +81,8 @@
     details::preloadPassthroughService(I::descriptor);
 }
 
-}; // namespace hardware
-}; // namespace android
+} // namespace hardware
+} // namespace android
 
 #endif // ANDROID_HARDWARE_ISERVICE_MANAGER_H
 
diff --git a/transport/include/hidl/Static.h b/transport/include/hidl/Static.h
index b15be68..be74bae 100644
--- a/transport/include/hidl/Static.h
+++ b/transport/include/hidl/Static.h
@@ -17,6 +17,9 @@
 // All static variables go here, to control initialization and
 // destruction order in the library.
 
+#ifndef ANDROID_HARDWARE_HIDL_STATIC_H
+#define ANDROID_HARDWARE_HIDL_STATIC_H
+
 #include <functional>
 
 #include <android/hidl/base/1.0/IBase.h>
@@ -34,19 +37,22 @@
     int prio;
 };
 
-extern ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, SchedPrio> gServicePrioMap;
-extern ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, bool> gServiceSidMap;
+// TODO(b/69122224): remove this
+extern DoNotDestruct<ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, SchedPrio>>
+        gServicePrioMap;
+// TODO(b/69122224): remove this
+extern DoNotDestruct<ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, bool>> gServiceSidMap;
 
+// TODO(b/69122224): remove this
 // For HidlBinderSupport and autogenerated code
-extern ConcurrentMap<const ::android::hidl::base::V1_0::IBase*, wp<::android::hardware::BHwBinder>>
-    gBnMap;
+extern DoNotDestruct<ConcurrentMap<const ::android::hidl::base::V1_0::IBase*,
+                                   wp<::android::hardware::BHwBinder>>>
+        gBnMap;
 
 using BnConstructorMap = ConcurrentMap<std::string, std::function<sp<IBinder>(void*)>>;
 // For HidlBinderSupport and autogenerated code
 // value function receives reinterpret_cast<void *>(static_cast<IFoo *>(foo)),
 // returns sp<IBinder>
-// deprecated; use getBnConstructorMap instead.
-extern BnConstructorMap gBnConstructorMap;
 BnConstructorMap& getBnConstructorMap();
 
 using BsConstructorMap = ConcurrentMap<std::string,
@@ -54,9 +60,9 @@
 // For HidlPassthroughSupport and autogenerated code
 // value function receives reinterpret_cast<void *>(static_cast<IFoo *>(foo)),
 // returns sp<IBase>
-// deprecated; use getBsConstructorMap instead.
-extern BsConstructorMap gBsConstructorMap;
 BsConstructorMap& getBsConstructorMap();
 }  // namespace details
 }  // namespace hardware
 }  // namespace android
+
+#endif
diff --git a/transport/manager/1.0/Android.bp b/transport/manager/1.0/Android.bp
index e4a120b..869c58e 100644
--- a/transport/manager/1.0/Android.bp
+++ b/transport/manager/1.0/Android.bp
@@ -3,7 +3,6 @@
 hidl_interface {
     name: "android.hidl.manager@1.0",
     root: "android.hidl",
-    core_interface: true,
     vndk: {
         enabled: true,
     },
diff --git a/transport/manager/1.0/IServiceManager.hal b/transport/manager/1.0/IServiceManager.hal
index 2b59a56..6eddefb 100644
--- a/transport/manager/1.0/IServiceManager.hal
+++ b/transport/manager/1.0/IServiceManager.hal
@@ -43,7 +43,7 @@
      * WARNING: This function is for libhidl/HwBinder use only. You are likely
      * looking for 'IMyInterface::getService("name")' instead.
      *
-     * @param iface    Fully-qualified interface name.
+     * @param fqName   Fully-qualified interface name.
      * @param name     Instance name. Same as in IServiceManager::add.
      *
      * @return service Handle to requested service, same as provided in
diff --git a/transport/manager/1.1/Android.bp b/transport/manager/1.1/Android.bp
index cde68a7..407dfa3 100644
--- a/transport/manager/1.1/Android.bp
+++ b/transport/manager/1.1/Android.bp
@@ -3,7 +3,6 @@
 hidl_interface {
     name: "android.hidl.manager@1.1",
     root: "android.hidl",
-    core_interface: true,
     vndk: {
         enabled: true,
     },
diff --git a/transport/manager/1.2/Android.bp b/transport/manager/1.2/Android.bp
new file mode 100644
index 0000000..3f02f78
--- /dev/null
+++ b/transport/manager/1.2/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hidl.manager@1.2",
+    root: "android.hidl",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IClientCallback.hal",
+        "IServiceManager.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+        "android.hidl.manager@1.0",
+        "android.hidl.manager@1.1",
+    ],
+    gen_java: true,
+}
+
diff --git a/transport/manager/1.2/IClientCallback.hal b/transport/manager/1.2/IClientCallback.hal
new file mode 100644
index 0000000..8ebb044
--- /dev/null
+++ b/transport/manager/1.2/IClientCallback.hal
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.hidl.manager@1.2;
+
+interface IClientCallback {
+    /**
+     * This is called when there is a transition between having >= 1 clients and having 0 clients
+     * (or vice versa).
+     *
+     * Upon receiving hasClients false, if the process decides to exit, it is recommended to try to
+     * unregister using @1.2::IServiceManager's tryUnregister before quiting in case another client
+     * associates.
+     *
+     * @param registered binder 'server' registered with IServiceManager's registerClientCallback
+     * @param hasClients whether there are currently clients
+     *     true - when there are >= 1 clients. This must be called as soon as IServiceManager::get
+     *         is called (no race).
+     *     false - when there are 0 clients. This may be delayed if it is thought that another
+     *         may be used again soon.
+     */
+    oneway onClients(interface registered, bool hasClients);
+};
diff --git a/transport/manager/1.2/IServiceManager.hal b/transport/manager/1.2/IServiceManager.hal
new file mode 100644
index 0000000..d79403d
--- /dev/null
+++ b/transport/manager/1.2/IServiceManager.hal
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.hidl.manager@1.2;
+
+import @1.1::IServiceManager;
+
+import IClientCallback;
+
+interface IServiceManager extends @1.1::IServiceManager {
+    /**
+     * Adds a callback that must be called when the specified server has no clients.
+     *
+     * If the service has clients at the time of registration, the callback is called with
+     * hasClients true. After that, it is called based on the changes in clientele.
+     *
+     * @param fqName Fully-qualified interface name (used to register)
+     * @param name Instance name (of the registered service)
+     * @param server non-null service waiting to have no clients (previously registered)
+     * @param cb non-null callback to call when there are no clients
+     * @return success
+     *     true on success
+     *     false if either
+     *      - the server or cb parameters are null
+     *      - this is called by a process other than the server process
+     */
+    registerClientCallback(string fqName,
+                           string name,
+                           interface server,
+                           IClientCallback cb)
+        generates (bool success);
+
+    /**
+     * Removes a callback previously registered with registerClientCallback.
+     *
+     * If server is null, then this must remove the cb from all matching services.
+     *
+     * @param server service registered with registerClientCallback
+     * @param cb non-null callback to remove
+     * @return success
+     *     true if the server(s) have been removed
+     *     false if cb is null or if the client callback or server could not be found
+     */
+    unregisterClientCallback(interface server, IClientCallback cb) generates (bool success);
+
+    /**
+     * Exactly the same as @1.0::IServiceManager.add, but the interfaceChain of the service is
+     * provided in the same call.
+     *
+     * @param name Instance name. Must also be used to retrieve service.
+     * @param service Handle to registering service.
+     * @param chain service->interfaceChain
+     *
+     * @return success Whether or not the service was registered.
+     */
+    addWithChain(string name, interface service, vec<string> chain) generates (bool success);
+
+    /**
+     * List all instances of a particular service from the manifest. Must be sorted. These HALs
+     * may not be started if they are lazy.
+     *
+     * See also @1.0::IServiceManager's listByInterface function.
+     *
+     * @param fqName Fully-qualified interface name.
+     *
+     * @return instanceNames List of instance names running the particular service.
+     */
+    listManifestByInterface(string fqName) generates (vec<string> instanceNames);
+
+    /**
+     * Unregisters a service if there are no clients for it. This must only unregister the
+     * service if it is called from the same process that registered the service.
+     *
+     * This unregisters all instances of the service, even if they are under a different instance
+     * name.
+     *
+     * Recommended usage is when creating a lazy process, try unregistering when IClientCallback's
+     * onClients(*, false) is called. If this unregister is successful, then it is safe to exit. If
+     * it is unsuccessful, then you can assume a client re-associated with the server. If a process
+     * has multiple servers, and only some succeed in unregistration, then the unregistered services
+     * can be re-registered.
+     *
+     * See also addWithChain and @1.0::IServiceManager's add.
+     *
+     * @param fqName Fully-qualified interface name.
+     * @param name Instance name.
+     * @param service Handle to registering service.
+     *
+     * @return success Whether the service was successfully unregistered.
+     */
+    tryUnregister(string fqName, string name, interface service) generates (bool success);
+};
diff --git a/transport/safe_union/1.0/Android.bp b/transport/safe_union/1.0/Android.bp
new file mode 100644
index 0000000..88c7d5d
--- /dev/null
+++ b/transport/safe_union/1.0/Android.bp
@@ -0,0 +1,15 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hidl.safe_union@1.0",
+    root: "android.hidl",
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "types.hal",
+    ],
+    gen_java: true,
+}
+
diff --git a/transport/safe_union/1.0/types.hal b/transport/safe_union/1.0/types.hal
new file mode 100644
index 0000000..bc3dbc2
--- /dev/null
+++ b/transport/safe_union/1.0/types.hal
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.hidl.safe_union@1.0;
+
+/**
+ * Unit type easily available to be used with safe_union.
+ *
+ * Example usage:
+ *
+ * safe_union MaybeFoo {
+ *     Monostate no_init;
+ *     Foo foo;
+ * };
+ */
+struct Monostate {};
diff --git a/transport/token/1.0/utils/Android.bp b/transport/token/1.0/utils/Android.bp
index fcb1613..cdbdd97 100644
--- a/transport/token/1.0/utils/Android.bp
+++ b/transport/token/1.0/utils/Android.bp
@@ -19,17 +19,18 @@
     vndk: {
         enabled: true,
     },
+    double_loadable: true,
 
     srcs: [
         "HybridInterface.cpp",
     ],
 
     shared_libs: [
-        "libutils",
-        "libbinder",
-        "liblog",
-        "libhidlbase",
         "android.hidl.token@1.0",
+        "libbinder",
+        "libhidlbase",
+        "liblog",
+        "libutils",
     ],
 
     export_shared_lib_headers: [
diff --git a/transport/token/1.0/utils/include/hidl/HybridInterface.h b/transport/token/1.0/utils/include/hidl/HybridInterface.h
index 984555e..125d5e8 100644
--- a/transport/token/1.0/utils/include/hidl/HybridInterface.h
+++ b/transport/token/1.0/utils/include/hidl/HybridInterface.h
@@ -23,6 +23,9 @@
 #include <binder/Parcel.h>
 #include <hidl/HidlSupport.h>
 
+#include <cinttypes>
+#include <variant>
+
 /**
  * Hybrid Interfaces
  * =================
@@ -47,50 +50,130 @@
  *
  * To demonstrate how this is done, here is an example. Suppose `INTERFACE` is
  * `IFoo` and `HALINTERFACE` is `HFoo`. The required steps are:
- * 1. Use DECLARE_HYBRID_META_INTERFACE instead of DECLARE_META_INTERFACE in the
- *    definition of `IFoo`. The usage is
- *        DECLARE_HYBRID_META_INTERFACE(IFoo, HFoo)
- *    inside the body of `IFoo`.
+ * 1. Use `DECLARE_HYBRID_META_INTERFACE` instead of `DECLARE_META_INTERFACE` in
+ *    the declaration of `IFoo`. `DECLARE_HYBRID_META_INTERFACE` takes an
+ *    additional argument that is the hidl interface to be converted into a
+ *    binder interface. Example:
+ *        Change from `DECLARE_META_INTERFACE(Foo)`
+ *                 to `DECLARE_HYBRID_META_INTERFACE(Foo, HFoo)`
  * 2. Create a converter class that derives from
- *    `H2BConverter<HFoo, IFoo, BnFoo>`. Let us call this `H2BFoo`.
+ *    `H2BConverter<HFoo, BnFoo>`. Let us call this `H2BFoo`.
  * 3. Add the following constructor in `H2BFoo` that call the corresponding
  *    constructors in `H2BConverter`:
- *        H2BFoo(const sp<HalInterface>& base) : CBase(base) {}
- *    Note: `CBase = H2BConverter<HFoo, IFoo, BnFoo>` and `HalInterface = HFoo`
- *    are member typedefs of `H2BConverter<HFoo, IFoo, BnFoo>`, so the above
- *    line can be copied into `H2BFoo`.
+ *        `H2BFoo(const sp<HalInterface>& base) : CBase(base) {}`
+ *    Note: `CBase = H2BConverter<HFoo, BnFoo>` and `HalInterface = HFoo` are
+ *    member typedefs of `H2BConverter<HFoo, BnFoo>`, so the above line can be
+ *    copied verbatim into `H2BFoo`.
  * 4. Implement `IFoo` in `H2BFoo` on top of `HFoo`. `H2BConverter` provides a
  *    protected `mBase` of type `sp<HFoo>` that can be used to access the `HFoo`
- *    instance. (There is also a public function named `getHalInterface()` that
- *    returns `mBase`.)
+ *    instance. (There is also a public function named `getBase()` that returns
+ *    `mBase`.)
  * 5. Create a hardware proxy class that derives from
  *    `HpInterface<BpFoo, H2BFoo>`. Name this class `HpFoo`. (This name cannot
  *    deviate. See step 8 below.)
  * 6. Add the following constructor to `HpFoo`:
- *        HpFoo(const sp<IBinder>& base): PBase(base) {}
+ *        `HpFoo(const sp<IBinder>& base): PBase(base) {}`
  *    Note: `PBase` a member typedef of `HpInterface<BpFoo, H2BFoo>` that is
  *    equal to `HpInterface<BpFoo, H2BFoo>` itself, so the above line can be
  *    copied verbatim into `HpFoo`.
- * 7. Delegate all functions in `HpFoo` that come from `IFoo` except
- *    `getHalInterface` to the protected member `mBase`,
- *    which is defined in `HpInterface<BpFoo, H2BFoo>` (hence in `HpFoo`) with
- *    type `IFoo`. (There is also a public function named `getBaseInterface()`
- *    that returns `mBase`.)
- * 8. Replace the existing `IMPLEMENT_META_INTERFACE` for INTERFACE by
- *    `IMPLEMENT_HYBRID_META_INTERFACE`. Note that this macro relies on the
- *    exact naming of `HpFoo`, where `Foo` comes from the interface name `IFoo`.
- *    An example usage is
- *        IMPLEMENT_HYBRID_META_INTERFACE(IFoo, HFoo, "example.interface.foo");
+ * 7. Delegate all functions in `HpFoo` that come from `IFoo` (except those that
+ *    are defined by the macro `DECLARE_HYBRID_META_INTERFACE`) to the protected
+ *    member `mBase`. `mBase` is defined in `HpInterface<BpFoo, H2BFoo>` (hence
+ *    in `HpFoo`) with type `IFoo`. There is also a public function named
+ *    `getBase()` that returns `mBase`.
+ * 8. Replace the existing `IMPLEMENT_META_INTERFACE` for `IFoo` by
+ *    `IMPLEMENT_HYBRID_META_INTERFACE`. This macro assumes that the subclass of
+ *    `HpInterface` for `IFoo` is named `HpFoo`.
  *
- * `GETTOKEN` Template Argument
- * ============================
+ * After the hybrid interface has been put in place properly, it can be used to
+ * do the following tasks:
+ * 1. Create an `IFoo` instance from an `HFoo` by passing `sp<HFoo>` to
+ *    the constructor of `H2BFoo`.
+ * 2. Retrieve an `HFoo` from an `HpFoo` instance by calling
+ *    `HpFoo::getHalInterface<HFoo>()`. This function may return `nullptr` if
+ *    the `HpFoo` object is not backed by `HFoo`. The template parameter is
+ *    required because `HpFoo` in fact may be backed by multiple H2B converter
+ *    classes.
  *
- * Following the instructions above, `H2BConverter` and `HpInterface` would use
- * `transact()` to send over tokens, with `code` (the first argument of
- * `transact()`) equal to `DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE`. If this
- * value clashes with other values already in use in the `Bp` class, it can be
- * changed by supplying the last optional template argument to `H2BConverter`
- * and `HpInterface`.
+ * Multiple H2B Converters
+ * =======================
+ *
+ * Because the system may support multiple versions of hidl interfaces for the
+ * same object, one binder interface may correspond to multiple H2B converters.
+ * The hybrid interface is designed to handle this as
+ * well---`DECLARE_HYBRID_META_INTERFACE` and `HpInterface` can take a variable
+ * number of arguments.
+ *
+ * As a concrete example, suppose `IFoo` is a binder interface that corresponds
+ * to two hidl interfaces `HFoo1` and `HFoo2`. That means `HpFoo`, the hybrid
+ * interface presenting `IFoo`, may be backed by `HFoo1` or `HFoo2`. This is
+ * achievable by
+ *
+ *   - Replacing `DECLARE_META_INTERFACE(Foo)` by
+ *     `DECLARE_HYBRID_META_INTERFACE(Foo, HFoo1, HFoo2)` in the declaration of
+ *     `IFoo`.
+ *   - Creating `H2BFoo1` as a subclass of `H2BConverter<HFoo1, BnFoo>`;
+ *   - Creating `H2BFoo2` as a subclass of `H2BConverter<HFoo2, BnFoo>`; and
+ *   - Creating `HpFoo` as a subclass of `HpInterface<BpFoo, H2BFoo1, H2BFoo2>`.
+ *
+ * It is important that `HFoo1` and `HFoo2` are different hidl interfaces. [The
+ * actual requirement is that for each pair `<HFoo, IFoo>`, there can be only
+ * one subclass of `H2BConverter<HFoo, BnFoo>`.]
+ *
+ * As mentioned in the previous section, `HpFoo::getHalInterface` requires a
+ * template argument because it must be able to return different hidl
+ * interface types based on which hidl interface is being used. The user of
+ * `HpFoo` can query the type of the underlying hidl interface by calling
+ * `HpFoo::getHalIndex()`. The return value is a 1-based index into the list of
+ * all the supported hidl interfaces. In the example with 2 hidl interfaces
+ * `HFoo1` and `HFoo2`, index 1 corresponds to `HFoo1` and index 2 corresponds
+ * to `HFoo2`. A typical code block that accesses the underlying hidl interface
+ * of would look like this:
+ *
+ * void someFunction(const sp<IFoo> &foo) {
+ *
+ *     switch (foo->getHalIndex()) {
+ *     case 1: {
+ *             sp<HFoo1> hFoo1 = foo->getHalInterface<HFoo1>();
+ *             ...
+ *             break;
+ *         }
+ *     case 2: {
+ *             sp<HFoo2> hFoo2 = foo->getHalInterface<HFoo2>();
+ *             ...
+ *             break;
+ *         }
+ *     default: // Not backed by a hidl interface.
+ *              // Alternatively, "case 0:" can be used.
+ *     }
+ *
+ * }
+ *
+ * Error State
+ * ===========
+ *
+ * A corrupted transaction may cause an `HpInterface` to be in an error state.
+ * This could cause `getHalInterface<ExpectedHalInterface>()` to return
+ * `nullptr` even though `getHalIndex()` returns a non-zero index and
+ * `ExpectedHalInterface` is the corresponding hidl interface. It is therefore
+ * recommended that a null check be performed on the return value of
+ * `getHalInterface` before using it.
+ *
+ * DECLARE_HYBRID_META_INTERFACE_WITH_CODE
+ * =======================================
+ *
+ * `H2BConverter` and `HpInterface` use `transact()` to send over tokens with
+ * the transaction code (the first argument of `transact()`) equal to `_GHT`,
+ * which is defined as a global constant named
+ * `DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE`.
+ *
+ * In the rare occasion that this value clashes with other values already used
+ * by the `Bp` class and modifying the `Bp` class is difficult, the
+ * "GET_HAL_TOKEN" transaction code can be changed to a different value simply
+ * by replacing `DECLARE_HYBRID_META_INTERFACE` with
+ * `DECLARE_HYBRID_META_INTERFACE_WITH_CODE` in the declaration of the base
+ * interface and supplying the new transaction code in the first argument of
+ * this macro.
  *
  */
 
@@ -106,23 +189,19 @@
 bool createHalToken(const sp<HInterface>& interface, HalToken* token);
 bool deleteHalToken(const HalToken& token);
 
-template <
-        typename HINTERFACE,
-        typename INTERFACE,
-        typename BNINTERFACE,
-        uint32_t GETTOKEN = DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE>
+template <typename HINTERFACE,
+          typename BNINTERFACE>
 class H2BConverter : public BNINTERFACE {
 public:
-    typedef H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN> CBase; // Converter Base
-    typedef INTERFACE BaseInterface;
+    typedef H2BConverter<HINTERFACE, BNINTERFACE> CBase; // Converter Base
+    typedef typename BNINTERFACE::BaseInterface BaseInterface;
     typedef HINTERFACE HalInterface;
-    static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
+    typedef typename BaseInterface::HalVariant HalVariant;
+    using BaseInterface::sGetHalTokenTransactionCode;
 
-    H2BConverter(const sp<HalInterface>& base) : mBase(base) {}
+    H2BConverter(const sp<HalInterface>& base) : mBase{base} {}
     virtual status_t onTransact(uint32_t code,
             const Parcel& data, Parcel* reply, uint32_t flags = 0);
-    virtual sp<HalInterface> getHalInterface() { return mBase; }
-    HalInterface* getBaseInterface() { return mBase.get(); }
     virtual status_t linkToDeath(
             const sp<IBinder::DeathRecipient>& recipient,
             void* cookie = nullptr,
@@ -132,9 +211,13 @@
             void* cookie = nullptr,
             uint32_t flags = 0,
             wp<IBinder::DeathRecipient>* outRecipient = nullptr);
+    virtual HalVariant getHalVariant() const override { return { mBase }; }
+    HalInterface* getBase() { return mBase.get(); }
 
 protected:
     sp<HalInterface> mBase;
+
+private:
     struct Obituary : public hardware::hidl_death_recipient {
         wp<IBinder::DeathRecipient> recipient;
         void* cookie;
@@ -168,102 +251,210 @@
     };
     std::mutex mObituariesLock;
     std::vector<sp<Obituary> > mObituaries;
+
+    template <size_t Index = std::variant_size_v<HalVariant> - 1>
+    static constexpr size_t _findIndex() {
+        if constexpr (Index == 0) {
+            return Index;
+        } else if constexpr (
+                std::is_same_v<
+                    std::variant_alternative_t<Index, HalVariant>,
+                    sp<HalInterface>>) {
+            return Index;
+        } else {
+            return _findIndex<Index - 1>();
+        }
+    }
+
+    static constexpr size_t sHalIndex = _findIndex<>();
+    static_assert(sHalIndex != 0,
+                  "H2BConverter from an unrecognized HAL interface.");
 };
 
-template <
-        typename BPINTERFACE,
-        typename CONVERTER,
-        uint32_t GETTOKEN = DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE>
+template <typename BPINTERFACE, typename CONVERTER, typename... CONVERTERS>
 class HpInterface : public CONVERTER::BaseInterface {
 public:
-    typedef HpInterface<BPINTERFACE, CONVERTER, GETTOKEN> PBase; // Proxy Base
+    typedef HpInterface<BPINTERFACE, CONVERTER, CONVERTERS...> PBase; // Proxy Base
     typedef typename CONVERTER::BaseInterface BaseInterface;
-    typedef typename CONVERTER::HalInterface HalInterface;
-    static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
+    typedef typename BaseInterface::HalVariant HalVariant;
+    using BaseInterface::sGetHalTokenTransactionCode;
 
     explicit HpInterface(const sp<IBinder>& impl);
-    virtual sp<HalInterface> getHalInterface() { return mHal; }
-    BaseInterface* getBaseInterface() { return mBase.get(); }
+    BaseInterface* getBase() { return mBase.get(); }
+    virtual HalVariant getHalVariant() const override { return mHalVariant; }
 
 protected:
-    IBinder* mImpl;
+    IBinder* mBpBinder;
     sp<BPINTERFACE> mBp;
     sp<BaseInterface> mBase;
-    sp<HalInterface> mHal;
-    IBinder* onAsBinder() override { return mImpl; }
+    HalVariant mHalVariant;
+    bool mHasConverter{false};
+    IBinder* onAsBinder() override { return mBpBinder; }
+
+private:
+    typedef std::variant<std::monostate,
+            CONVERTER, CONVERTERS...> _ConverterVar;
+    typedef std::variant<std::monostate,
+            typename CONVERTER::HalInterface,
+            typename CONVERTERS::HalInterface...> _ConverterHalVar;
+    typedef std::variant<std::monostate,
+            sp<typename CONVERTER::HalInterface>,
+            sp<typename CONVERTERS::HalInterface>...> _ConverterHalPointerVar;
+
+    static_assert(std::is_same_v<_ConverterHalPointerVar, HalVariant>,
+                  "Converter classes do not match HAL interfaces.");
+
+    template <size_t Index = std::variant_size_v<HalVariant> - 1>
+    bool _castFromHalBaseAndConvert(size_t halIndex,
+                                    const sp<HInterface>& halBase) {
+        if constexpr (Index == 0) {
+            return false;
+        } else {
+            if (halIndex != Index) {
+                return _castFromHalBaseAndConvert<Index - 1>(halIndex, halBase);
+            }
+            typedef std::variant_alternative_t<Index, _ConverterHalVar>
+                    HalInterface;
+            sp<HalInterface> halInterface = HalInterface::castFrom(halBase);
+            mHalVariant.template emplace<Index>(halInterface);
+            if (!halInterface) {
+                return false;
+            }
+            if (mHasConverter) {
+                typedef std::variant_alternative_t<Index, _ConverterVar>
+                        Converter;
+                sp<Converter> converter = new Converter(halInterface);
+                if (converter) {
+                    mBase = converter;
+                } else {
+                    ALOGW("HpInterface: Failed to create an H2B converter -- "
+                          "index = %zu.", Index);
+                }
+            }
+            return true;
+        }
+    }
+
+    bool castFromHalBaseAndConvert(size_t halIndex,
+                                   const sp<HInterface>& halBase) {
+        if (!_castFromHalBaseAndConvert<>(halIndex, halBase)) {
+            return false;
+        }
+        return true;
+    }
+
 };
 
 // ----------------------------------------------------------------------
 
-#define DECLARE_HYBRID_META_INTERFACE(INTERFACE, HAL)                   \
-    static const ::android::String16 descriptor;                        \
-    static ::android::sp<I##INTERFACE> asInterface(                     \
-            const ::android::sp<::android::IBinder>& obj);              \
-    virtual const ::android::String16& getInterfaceDescriptor() const;  \
-    I##INTERFACE();                                                     \
-    virtual ~I##INTERFACE();                                            \
-    virtual sp<HAL> getHalInterface();                                  \
+#define DECLARE_HYBRID_META_INTERFACE(INTERFACE, ...)                     \
+        DECLARE_HYBRID_META_INTERFACE_WITH_CODE(                          \
+            ::android::DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE,            \
+            INTERFACE, __VA_ARGS__)                                       \
 
 
-#define IMPLEMENT_HYBRID_META_INTERFACE(INTERFACE, HAL, NAME)           \
-    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
-    const ::android::String16&                                          \
-            I##INTERFACE::getInterfaceDescriptor() const {              \
-        return I##INTERFACE::descriptor;                                \
-    }                                                                   \
-    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
-            const ::android::sp<::android::IBinder>& obj)               \
-    {                                                                   \
-        ::android::sp<I##INTERFACE> intr;                               \
-        if (obj != nullptr) {                                           \
-            intr = static_cast<I##INTERFACE*>(                          \
-                obj->queryLocalInterface(                               \
-                        I##INTERFACE::descriptor).get());               \
-            if (intr == nullptr) {                                      \
-                intr = new Hp##INTERFACE(obj);                          \
-            }                                                           \
-        }                                                               \
-        return intr;                                                    \
-    }                                                                   \
-    I##INTERFACE::I##INTERFACE() { }                                    \
-    I##INTERFACE::~I##INTERFACE() { }                                   \
-    sp<HAL> I##INTERFACE::getHalInterface() { return nullptr; }         \
+#define DECLARE_HYBRID_META_INTERFACE_WITH_CODE(GTKCODE, INTERFACE, ...)  \
+private:                                                                  \
+    typedef ::std::variant<::std::monostate, __VA_ARGS__> _HalVariant;    \
+    template <typename... Types>                                          \
+    using _SpVariant =                                                    \
+            ::std::variant<::std::monostate, ::android::sp<Types>...>;    \
+public:                                                                   \
+    typedef _SpVariant<__VA_ARGS__> HalVariant;                           \
+    virtual HalVariant getHalVariant() const;                             \
+    size_t getHalIndex() const;                                           \
+    template <size_t Index>                                               \
+    using HalInterface = ::std::variant_alternative_t<Index, _HalVariant>;\
+    template <typename HAL>                                               \
+    sp<HAL> getHalInterface() const {                                     \
+        HalVariant halVariant = getHalVariant();                          \
+        const sp<HAL>* hal = std::get_if<sp<HAL>>(&halVariant);           \
+        return hal ? *hal : nullptr;                                      \
+    }                                                                     \
+                                                                          \
+    static const ::android::String16 descriptor;                          \
+    static ::android::sp<I##INTERFACE> asInterface(                       \
+            const ::android::sp<::android::IBinder>& obj);                \
+    virtual const ::android::String16& getInterfaceDescriptor() const;    \
+    I##INTERFACE();                                                       \
+    virtual ~I##INTERFACE();                                              \
+    static constexpr uint32_t sGetHalTokenTransactionCode = GTKCODE;      \
+
+
+#define IMPLEMENT_HYBRID_META_INTERFACE(INTERFACE, NAME)                  \
+    I##INTERFACE::HalVariant I##INTERFACE::getHalVariant() const {        \
+        return HalVariant{std::in_place_index<0>};                        \
+    }                                                                     \
+    size_t I##INTERFACE::getHalIndex() const {                            \
+        return getHalVariant().index();                                   \
+    }                                                                     \
+    constexpr uint32_t I##INTERFACE::sGetHalTokenTransactionCode;         \
+    const ::android::String16 I##INTERFACE::descriptor(NAME);             \
+    const ::android::String16&                                            \
+            I##INTERFACE::getInterfaceDescriptor() const {                \
+        return I##INTERFACE::descriptor;                                  \
+    }                                                                     \
+    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
+            const ::android::sp<::android::IBinder>& obj)                 \
+    {                                                                     \
+        ::android::sp<I##INTERFACE> intr;                                 \
+        if (obj != nullptr) {                                             \
+            intr = static_cast<I##INTERFACE*>(                            \
+                obj->queryLocalInterface(                                 \
+                        I##INTERFACE::descriptor).get());                 \
+            if (intr == nullptr) {                                        \
+                intr = new Hp##INTERFACE(obj);                            \
+            }                                                             \
+        }                                                                 \
+        return intr;                                                      \
+    }                                                                     \
+    I##INTERFACE::I##INTERFACE() { }                                      \
+    I##INTERFACE::~I##INTERFACE() { }                                     \
 
 // ----------------------------------------------------------------------
 
-template <
-        typename HINTERFACE,
-        typename INTERFACE,
-        typename BNINTERFACE,
-        uint32_t GETTOKEN>
-status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
+template <typename HINTERFACE,
+          typename BNINTERFACE>
+status_t H2BConverter<HINTERFACE, BNINTERFACE>::
         onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
-    if (code == GET_HAL_TOKEN) {
+    if (code == sGetHalTokenTransactionCode) {
+        if (!data.enforceInterface(BaseInterface::getInterfaceDescriptor())) {
+            return BAD_TYPE;
+        }
+
         HalToken token;
         bool result;
         result = createHalToken(mBase, &token);
+        // Write whether a HAL token is present.
+        reply->writeBool(result);
         if (!result) {
             ALOGE("H2BConverter: Failed to create HAL token.");
+            return NO_ERROR;
         }
-        reply->writeBool(result);
+
+        // Write the HAL token.
         reply->writeByteArray(token.size(), token.data());
+
+        // Write the HAL index.
+        reply->writeUint32(static_cast<uint32_t>(sHalIndex));
+
+        // Write a flag indicating that a converter needs to be created.
+        reply->writeBool(true);
+
         return NO_ERROR;
     }
     return BNINTERFACE::onTransact(code, data, reply, flags);
 }
 
-template <
-        typename HINTERFACE,
-        typename INTERFACE,
-        typename BNINTERFACE,
-        uint32_t GETTOKEN>
-status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
-        linkToDeath(
+template <typename HINTERFACE,
+          typename BNINTERFACE>
+status_t H2BConverter<HINTERFACE, BNINTERFACE>::linkToDeath(
         const sp<IBinder::DeathRecipient>& recipient,
         void* cookie, uint32_t flags) {
-    LOG_ALWAYS_FATAL_IF(recipient == nullptr,
-            "linkToDeath(): recipient must be non-nullptr");
+    LOG_ALWAYS_FATAL_IF(
+            recipient == nullptr,
+            "linkToDeath(): recipient must not be null.");
     {
         std::lock_guard<std::mutex> lock(mObituariesLock);
         mObituaries.push_back(new Obituary(recipient, cookie, flags, this));
@@ -274,13 +465,9 @@
     return NO_ERROR;
 }
 
-template <
-        typename HINTERFACE,
-        typename INTERFACE,
-        typename BNINTERFACE,
-        uint32_t GETTOKEN>
-status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
-        unlinkToDeath(
+template <typename HINTERFACE,
+          typename BNINTERFACE>
+status_t H2BConverter<HINTERFACE, BNINTERFACE>::unlinkToDeath(
         const wp<IBinder::DeathRecipient>& recipient,
         void* cookie, uint32_t flags,
         wp<IBinder::DeathRecipient>* outRecipient) {
@@ -300,37 +487,70 @@
     return NAME_NOT_FOUND;
 }
 
-template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN>
-HpInterface<BPINTERFACE, CONVERTER, GETTOKEN>::HpInterface(
-        const sp<IBinder>& impl) :
-    mImpl(impl.get()),
-    mBp(new BPINTERFACE(impl)) {
+template <typename BPINTERFACE, typename CONVERTER, typename... CONVERTERS>
+HpInterface<BPINTERFACE, CONVERTER, CONVERTERS...>::HpInterface(
+        const sp<IBinder>& impl)
+      : mBpBinder{impl.get()},
+        mBp{new BPINTERFACE(impl)} {
     mBase = mBp;
-    if (mImpl->remoteBinder() == nullptr) {
+    if (!mBpBinder->remoteBinder()) {
         return;
     }
     Parcel data, reply;
     data.writeInterfaceToken(BaseInterface::getInterfaceDescriptor());
-    if (mImpl->transact(GET_HAL_TOKEN, data, &reply) == NO_ERROR) {
-        bool tokenCreated = reply.readBool();
+    if (mBpBinder->transact(sGetHalTokenTransactionCode,
+                            data, &reply) == NO_ERROR) {
+        // Read whether a HAL token is present.
+        bool tokenCreated;
+        if (reply.readBool(&tokenCreated) != OK) {
+            ALOGW("HpInterface: Corrupted parcel from GET_HAL_TOKEN "
+                  "(tokenCreated).");
+        }
 
+        if (!tokenCreated) {
+            ALOGW("HpInterface: No HAL token was created.");
+            return;
+        }
+
+        // Read the HAL token.
         std::vector<uint8_t> tokenVector;
-        reply.readByteVector(&tokenVector);
-        HalToken token = HalToken(tokenVector);
+        if (reply.readByteVector(&tokenVector) != OK) {
+            ALOGW("HpInterface: Corrupted parcel from GET_HAL_TOKEN "
+                  "(halToken).");
+            return;
+        }
 
-        if (tokenCreated) {
-            sp<HInterface> hBase = retrieveHalInterface(token);
-            if (hBase != nullptr) {
-                mHal = HalInterface::castFrom(hBase);
-                if (mHal != nullptr) {
-                    mBase = new CONVERTER(mHal);
-                } else {
-                    ALOGE("HpInterface: Wrong interface type.");
-                }
-            } else {
-                ALOGE("HpInterface: Invalid HAL token.");
-            }
-            deleteHalToken(token);
+        // Retrieve the HAL interface from the token.
+        HalToken token{tokenVector};
+        sp<HInterface> halBase = retrieveHalInterface(token);
+        deleteHalToken(token);
+
+        if (!halBase) {
+            ALOGW("HpInterface: Failed to retrieve HAL interface.");
+            return;
+        }
+
+        uint32_t halIndex;
+        // Read the hal index.
+        if (reply.readUint32(&halIndex) != OK) {
+            ALOGW("HpInterface: Corrupted parcel from GET_HAL_TOKEN "
+                  "(halIndex).");
+            return;
+        }
+
+        // Read the converter flag.
+        if (reply.readBool(&mHasConverter) != OK) {
+            ALOGW("HpInterface: Corrupted parcel from GET_HAL_TOKEN "
+                  "(hasConverter).");
+            return;
+        }
+
+        // Call castFrom from the right HAL interface and create a converter if
+        // needed.
+        if (!castFromHalBaseAndConvert(static_cast<size_t>(halIndex),
+                                       halBase)) {
+            ALOGW("HpInterface: Failed to cast to the correct HAL interface -- "
+                  "HAL index = %" PRIu32 ".", halIndex);
         }
     }
 }
diff --git a/update-makefiles.sh b/update-makefiles.sh
index fd0a23c..cf13c83 100755
--- a/update-makefiles.sh
+++ b/update-makefiles.sh
@@ -5,7 +5,9 @@
     android.hidl.base@1.0
     android.hidl.manager@1.0
     android.hidl.manager@1.1
+    android.hidl.manager@1.2
     android.hidl.memory@1.0
+    android.hidl.safe_union@1.0
     android.hidl.token@1.0
 )
 
diff --git a/vintfdata/Android.mk b/vintfdata/Android.mk
index bc7a55a..7a30668 100644
--- a/vintfdata/Android.mk
+++ b/vintfdata/Android.mk
@@ -16,6 +16,12 @@
 
 LOCAL_PATH := $(call my-dir)
 
+# DEVICE_FRAMEWORK_MANIFEST_FILE is a device-specific framework manifest file
+# that installed to the system image. HALs entries should be written to
+# DEVICE_FRAMEWORK_MANIFEST_FILE or PRODUCT_MANIFEST_FILES depend on the path of
+# the module. It is recommended that such device-specific modules to be
+# installed on product partition.
+
 FRAMEWORK_MANIFEST_INPUT_FILES := $(LOCAL_PATH)/manifest.xml
 ifdef DEVICE_FRAMEWORK_MANIFEST_FILE
   FRAMEWORK_MANIFEST_INPUT_FILES += $(DEVICE_FRAMEWORK_MANIFEST_FILE)
@@ -44,33 +50,27 @@
 GEN := $(local-generated-sources-dir)/compatibility_matrix.xml
 
 $(GEN): PRIVATE_VINTF_VNDK_VERSION := $(VINTF_VNDK_VERSION)
+$(GEN): PRIVATE_DEVICE_MATRIX_INPUT_FILE := $(DEVICE_MATRIX_INPUT_FILE)
 $(GEN): $(DEVICE_MATRIX_INPUT_FILE) $(HOST_OUT_EXECUTABLES)/assemble_vintf
 	REQUIRED_VNDK_VERSION=$(PRIVATE_VINTF_VNDK_VERSION) \
 	BOARD_SYSTEMSDK_VERSIONS="$(BOARD_SYSTEMSDK_VERSIONS)" \
-		$(HOST_OUT_EXECUTABLES)/assemble_vintf -i $< -o $@
+		$(HOST_OUT_EXECUTABLES)/assemble_vintf \
+		-i $(call normalize-path-list,$(PRIVATE_DEVICE_MATRIX_INPUT_FILE)) \
+		-o $@
 
 LOCAL_PREBUILT_MODULE_FILE := $(GEN)
 include $(BUILD_PREBUILT)
 BUILT_VENDOR_MATRIX := $(LOCAL_BUILT_MODULE)
 
-# Framework Manifest
+# System Manifest
 include $(CLEAR_VARS)
-LOCAL_MODULE        := framework_manifest.xml
+LOCAL_MODULE        := system_manifest.xml
 LOCAL_MODULE_STEM   := manifest.xml
 LOCAL_MODULE_CLASS  := ETC
 LOCAL_MODULE_PATH   := $(TARGET_OUT)/etc/vintf
 
 GEN := $(local-generated-sources-dir)/manifest.xml
 
-$(GEN): PRIVATE_FLAGS :=
-
-ifeq ($(PRODUCT_ENFORCE_VINTF_MANIFEST),true)
-ifdef BUILT_VENDOR_MATRIX
-$(GEN): $(BUILT_VENDOR_MATRIX)
-$(GEN): PRIVATE_FLAGS += -c "$(BUILT_VENDOR_MATRIX)"
-endif
-endif
-
 $(GEN): PRIVATE_VINTF_VNDK_VERSION := $(VINTF_VNDK_VERSION)
 $(GEN): PRIVATE_FRAMEWORK_MANIFEST_INPUT_FILES := $(FRAMEWORK_MANIFEST_INPUT_FILES)
 $(GEN): $(FRAMEWORK_MANIFEST_INPUT_FILES) $(HOST_OUT_EXECUTABLES)/assemble_vintf
@@ -78,12 +78,32 @@
 	PLATFORM_SYSTEMSDK_VERSIONS="$(PLATFORM_SYSTEMSDK_VERSIONS)" \
 		$(HOST_OUT_EXECUTABLES)/assemble_vintf \
 		-i $(call normalize-path-list,$(PRIVATE_FRAMEWORK_MANIFEST_INPUT_FILES)) \
-		-o $@ $(PRIVATE_FLAGS)
+		-o $@
 
 LOCAL_PREBUILT_MODULE_FILE := $(GEN)
 include $(BUILD_PREBUILT)
 BUILT_SYSTEM_MANIFEST := $(LOCAL_BUILT_MODULE)
 
+# Product Manifest
+ifneq ($(PRODUCT_MANIFEST_FILES),)
+include $(CLEAR_VARS)
+LOCAL_MODULE := product_manifest.xml
+LOCAL_MODULE_STEM := manifest.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_RELATIVE_PATH := vintf
+GEN := $(local-generated-sources-dir)/manifest.xml
+$(GEN): PRIVATE_PRODUCT_MANIFEST_FILES := $(PRODUCT_MANIFEST_FILES)
+$(GEN): $(PRODUCT_MANIFEST_FILES) $(HOST_OUT_EXECUTABLES)/assemble_vintf
+	$(HOST_OUT_EXECUTABLES)/assemble_vintf \
+		-i $(call normalize-path-list,$(PRIVATE_PRODUCT_MANIFEST_FILES)) \
+		-o $@
+
+LOCAL_PREBUILT_MODULE_FILE := $(GEN)
+include $(BUILD_PREBUILT)
+BUILT_PRODUCT_MANIFEST := $(LOCAL_BUILT_MODULE)
+endif
+
 VINTF_VNDK_VERSION :=
 FRAMEWORK_MANIFEST_INPUT_FILES :=
 DEVICE_MATRIX_INPUT_FILE :=
+PRODUCT_MANIFEST_INPUT_FILES :=
diff --git a/vintfdata/manifest.xml b/vintfdata/manifest.xml
index 51d68eb..e204671 100644
--- a/vintfdata/manifest.xml
+++ b/vintfdata/manifest.xml
@@ -2,22 +2,13 @@
     <hal>
         <name>android.hidl.manager</name>
         <transport>hwbinder</transport>
-        <version>1.1</version>
+        <version>1.2</version>
         <interface>
             <name>IServiceManager</name>
             <instance>default</instance>
         </interface>
     </hal>
     <hal>
-        <name>android.hidl.allocator</name>
-        <transport>hwbinder</transport>
-        <version>1.0</version>
-        <interface>
-            <name>IAllocator</name>
-            <instance>ashmem</instance>
-        </interface>
-    </hal>
-    <hal>
         <name>android.hidl.memory</name>
         <transport arch="32+64">passthrough</transport>
         <version>1.0</version>
@@ -62,7 +53,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-        <hal format="hidl">
+    <hal>
         <name>android.system.net.netd</name>
         <transport>hwbinder</transport>
         <version>1.1</version>
@@ -80,25 +71,6 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal>
-      <name>android.hardware.graphics.composer</name>
-      <transport>hwbinder</transport>
-      <version>2.1</version>
-      <interface>
-          <name>IComposer</name>
-          <instance>vr</instance>
-      </interface>
-    </hal>
-    <hal>
-        <name>android.hardware.health</name>
-        <transport>hwbinder</transport>
-        <version>2.0</version>
-        <interface>
-            <name>IHealth</name>
-            <!-- The backup instance provided by healthd. -->
-            <instance>backup</instance>
-        </interface>
-    </hal>
     <hal format="native">
         <name>netutils-wrapper</name>
         <!--
diff --git a/vintfdata/manifest_healthd_exclude.xml b/vintfdata/manifest_healthd_exclude.xml
deleted file mode 100644
index b4060f0..0000000
--- a/vintfdata/manifest_healthd_exclude.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<!--
-    Include this file to DEVICE_FRAMEWORK_MANIFEST_FILE to disable
-    having an healthd on the device which is not needed if you have
-    an alternative implementation like the following:
-    (1) Device has android.hardware.health@2.0-service.override
-    (2) Device has android.hardware.health@2.0-service.<device>, which
-        contains the following:
-        overrides: ["healthd"]
--->
-<manifest version="1.0" type="framework">
-    <hal format="hidl" override="true">
-        <name>android.hardware.health</name>
-        <transport>hwbinder</transport>
-    </hal>
-</manifest>