Merge "Add preloadPassthroughService."
diff --git a/base/include/hidl/HidlSupport.h b/base/include/hidl/HidlSupport.h
index d7c3b83..3f45afd 100644
--- a/base/include/hidl/HidlSupport.h
+++ b/base/include/hidl/HidlSupport.h
@@ -316,6 +316,27 @@
         *this = other;
     }
 
+    template <typename InputIterator,
+              typename = typename std::enable_if<std::is_convertible<
+                  typename std::iterator_traits<InputIterator>::iterator_category,
+                  std::input_iterator_tag>::value>::type>
+    hidl_vec(InputIterator first, InputIterator last) : mOwnsBuffer(true) {
+        auto size = std::distance(first, last);
+        if (size > static_cast<int64_t>(UINT32_MAX)) {
+            details::logAlwaysFatal("hidl_vec can't hold more than 2^32 elements.");
+        }
+        if (size < 0) {
+            details::logAlwaysFatal("size can't be negative.");
+        }
+        mSize = static_cast<uint32_t>(size);
+        mBuffer = new T[mSize];
+
+        size_t idx = 0;
+        for (; first != last; ++first) {
+            mBuffer[idx++] = static_cast<T>(*first);
+        }
+    }
+
     ~hidl_vec() {
         if (mOwnsBuffer) {
             delete[] mBuffer;
diff --git a/test_main.cpp b/test_main.cpp
index bce9294..1f2f845 100644
--- a/test_main.cpp
+++ b/test_main.cpp
@@ -262,6 +262,30 @@
     EXPECT_TRUE(hv1 != hv3);
 }
 
+TEST_F(LibHidlTest, VecRangeCtorTest) {
+    struct ConvertibleType {
+        int val;
+
+        explicit ConvertibleType(int val) : val(val) {}
+        explicit operator int() const { return val; }
+        bool operator==(const int& other) const { return val == other; }
+    };
+
+    std::vector<ConvertibleType> input{
+        ConvertibleType(1), ConvertibleType(2), ConvertibleType(3),
+    };
+
+    android::hardware::hidl_vec<int> hv(input.begin(), input.end());
+
+    EXPECT_EQ(input.size(), hv.size());
+    int sum = 0;
+    for (unsigned i = 0; i < input.size(); i++) {
+        EXPECT_EQ(input[i], hv[i]);
+        sum += hv[i];
+    }
+    EXPECT_EQ(sum, 1 + 2 + 3);
+}
+
 TEST_F(LibHidlTest, ArrayTest) {
     using android::hardware::hidl_array;
     int32_t array[] = {5, 6, 7};
diff --git a/transport/allocator/1.0/IAllocator.hal b/transport/allocator/1.0/IAllocator.hal
index 814c69d..6f531dd 100644
--- a/transport/allocator/1.0/IAllocator.hal
+++ b/transport/allocator/1.0/IAllocator.hal
@@ -29,4 +29,14 @@
      * @return memory Unmapped memory object.
      */
     allocate(uint64_t size) generates (bool success, memory mem);
+
+    /**
+     * Return memory must have instance name corresponding to this type of memory.
+     *
+     * @param size Size of memory to allocate in bytes.
+     * @param count Number of memory instances to allocate.
+     * @return success Whether allocation succeeded (returns false if any allocation failed).
+     * @return batch Unmapped memory objects.
+     */
+    batchAllocate(uint64_t size, uint64_t count) generates (bool success, vec<memory> batch);
 };
\ No newline at end of file
diff --git a/transport/allocator/1.0/default/AshmemAllocator.cpp b/transport/allocator/1.0/default/AshmemAllocator.cpp
index ce6dbf7..0bd4f81 100644
--- a/transport/allocator/1.0/default/AshmemAllocator.cpp
+++ b/transport/allocator/1.0/default/AshmemAllocator.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AshmemAllocator"
+#include <android-base/logging.h>
+
 #include "AshmemAllocator.h"
 
 #include <cutils/ashmem.h>
@@ -24,21 +27,70 @@
 namespace V1_0 {
 namespace implementation {
 
-// Methods from ::android::hidl::allocator::V1_0::IAllocator follow.
-Return<void> AshmemAllocator::allocate(uint64_t size, allocate_cb _hidl_cb) {
+static hidl_memory allocateOne(uint64_t size) {
     int fd = ashmem_create_region("AshmemAllocator_hidl", size);
     if (fd < 0) {
-        _hidl_cb(false /* success */, hidl_memory());
-        return Void();
+        LOG(WARNING) << "ashmem_create_region(" << size << ") fails with " << fd;
+        return hidl_memory();
     }
 
     native_handle_t* handle = native_handle_create(1, 0);
     handle->data[0] = fd;
-    hidl_memory memory("ashmem", handle, size);
+    LOG(WARNING) << "ashmem_create_region(" << size << ") returning hidl_memory(" << handle
+            << ", " << size << ")";
+    return hidl_memory("ashmem", handle, size);
+}
 
-    _hidl_cb(true /* success */, memory);
-    native_handle_close(handle);
-    native_handle_delete(handle);
+static void cleanup(hidl_memory&& memory) {
+    if (memory.handle() == nullptr) {
+        return;
+    }
+
+    native_handle_close(const_cast<native_handle_t *>(memory.handle()));
+    native_handle_delete(const_cast<native_handle_t *>(memory.handle()));
+}
+
+Return<void> AshmemAllocator::allocate(uint64_t size, allocate_cb _hidl_cb) {
+    hidl_memory memory = allocateOne(size);
+    _hidl_cb(memory.handle() != nullptr /* success */, memory);
+    cleanup(std::move(memory));
+
+    return Void();
+}
+
+Return<void> AshmemAllocator::batchAllocate(uint64_t size, uint64_t count, batchAllocate_cb _hidl_cb) {
+    // resize fails if count > 2^32
+    if (count > UINT32_MAX) {
+        _hidl_cb(false /* success */, {});
+        return Void();
+    }
+
+    hidl_vec<hidl_memory> batch;
+    batch.resize(count);
+
+    uint64_t allocated;
+    for (allocated = 0; allocated < count; allocated++) {
+        batch[allocated] = allocateOne(size);
+
+        if (batch[allocated].handle() == nullptr) {
+            LOG(WARNING) << "batchAllocate(" << size << ", " << count << ") fails @ #" << allocated;
+            break;
+        }
+    }
+
+    // batch[i].handle() != nullptr for i in [0, allocated - 1].
+    // batch[i].handle() == nullptr for i in [allocated, count - 1].
+
+    if (allocated < count) {
+        _hidl_cb(false /* success */, {});
+    } else {
+        _hidl_cb(true /* success */, batch);
+    }
+
+    for (uint64_t i = 0; i < allocated; i++) {
+        cleanup(std::move(batch[i]));
+    }
+
     return Void();
 }
 
diff --git a/transport/allocator/1.0/default/AshmemAllocator.h b/transport/allocator/1.0/default/AshmemAllocator.h
index 307cb5a..131417d 100644
--- a/transport/allocator/1.0/default/AshmemAllocator.h
+++ b/transport/allocator/1.0/default/AshmemAllocator.h
@@ -39,7 +39,7 @@
 struct AshmemAllocator : public IAllocator {
     // Methods from ::android::hidl::allocator::V1_0::IAllocator follow.
     Return<void> allocate(uint64_t size, allocate_cb _hidl_cb) override;
-
+    Return<void> batchAllocate(uint64_t size, uint64_t count, batchAllocate_cb _hidl_cb) override;
 };
 
 }  // namespace implementation