Merge "Fix IMemoryBlock::validRange(),read(),update()"
diff --git a/base/include/hidl/HidlSupport.h b/base/include/hidl/HidlSupport.h
index 7a5183b..2d0dc25 100644
--- a/base/include/hidl/HidlSupport.h
+++ b/base/include/hidl/HidlSupport.h
@@ -116,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();
 
diff --git a/transport/HidlBinderSupport.cpp b/transport/HidlBinderSupport.cpp
index a221b46..cd05c3d 100644
--- a/transport/HidlBinderSupport.cpp
+++ b/transport/HidlBinderSupport.cpp
@@ -47,6 +47,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");
@@ -54,6 +78,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,
@@ -73,6 +98,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,
diff --git a/transport/HidlTransportSupport.cpp b/transport/HidlTransportSupport.cpp
index d0871f6..9c2bf25 100644
--- a/transport/HidlTransportSupport.cpp
+++ b/transport/HidlTransportSupport.cpp
@@ -58,7 +58,23 @@
         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.
+    // TODO(b/37794345): if ever we update the HIDL ABI for launches in an Android
+    // release in the meta-version sense, we should remove this.
+    std::unique_lock<std::mutex> lock = details::gServicePrioMap.lock();
+
+    std::vector<wp<::android::hidl::base::V1_0::IBase>> toDelete;
+    for (const auto& kv : details::gServicePrioMap) {
+        if (kv.first.promote() == nullptr) {
+            toDelete.push_back(kv.first);
+        }
+    }
+    for (const auto& k : toDelete) {
+        details::gServicePrioMap.eraseLocked(k);
+    }
+    details::gServicePrioMap.setLocked(service, {policy, priority});
 
     return true;
 }
diff --git a/transport/include/hidl/ConcurrentMap.h b/transport/include/hidl/ConcurrentMap.h
index 4066869..54c1a32 100644
--- a/transport/include/hidl/ConcurrentMap.h
+++ b/transport/include/hidl/ConcurrentMap.h
@@ -76,6 +76,14 @@
         return iter->second;
     }
 
+    size_type eraseLocked(const K& k) { return mMap.erase(k); }
+
+    // the concurrent map must be locked in order to iterate over it
+    iterator begin() { return mMap.begin(); }
+    iterator end() { return mMap.end(); }
+    const_iterator begin() const { return mMap.begin(); }
+    const_iterator end() const { return mMap.end(); }
+
    private:
     mutable std::mutex mMutex;
     std::map<K, V> mMap;
diff --git a/transport/include/hidl/HidlBinderSupport.h b/transport/include/hidl/HidlBinderSupport.h
index 6d45f39..97d185e 100644
--- a/transport/include/hidl/HidlBinderSupport.h
+++ b/transport/include/hidl/HidlBinderSupport.h
@@ -49,6 +49,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,