Merge "libdmabufheap: Add an API to check ION support"
diff --git a/BufferAllocator.cpp b/BufferAllocator.cpp
index 386ecc2..ce075d6 100644
--- a/BufferAllocator.cpp
+++ b/BufferAllocator.cpp
@@ -252,6 +252,38 @@
     return fd;
 }
 
+int BufferAllocator::AllocSystem(bool cpu_access_needed, size_t len, unsigned int heap_flags,
+                                 size_t legacy_align) {
+    if (!cpu_access_needed) {
+        /*
+         * CPU does not need to access allocated buffer so we try to allocate in
+         * the 'system-uncached' heap after querying for its existence.
+         */
+        static bool uncached_dmabuf_system_heap_support = [this]() -> bool {
+            auto dmabuf_heap_list = this->GetDmabufHeapList();
+            return (dmabuf_heap_list.find(kDmabufSystemUncachedHeapName) != dmabuf_heap_list.end());
+        }();
+
+        if (uncached_dmabuf_system_heap_support)
+            return DmabufAlloc(kDmabufSystemUncachedHeapName, len);
+
+        static bool uncached_ion_system_heap_support = [this]() -> bool {
+            IonHeapConfig heap_config;
+            auto ret = this->GetIonConfig(kDmabufSystemUncachedHeapName, heap_config);
+            return (ret == 0);
+        }();
+
+        if (uncached_ion_system_heap_support)
+            return IonAlloc(kDmabufSystemUncachedHeapName, len, heap_flags, legacy_align);
+    }
+
+    /*
+     * Either 1) CPU needs to access allocated buffer OR 2) CPU does not need to
+     * access allocated buffer but the "system-uncached" heap is unsupported.
+     */
+    return Alloc(kDmabufSystemHeapName, len, heap_flags, legacy_align);
+}
+
 int BufferAllocator::LegacyIonCpuSync(unsigned int dmabuf_fd,
                                       const CustomCpuSyncLegacyIon& legacy_ion_cpu_sync_custom,
                                       void *legacy_ion_custom_data) {
diff --git a/BufferAllocatorWrapper.cpp b/BufferAllocatorWrapper.cpp
index a4ef981..6e2ebed 100644
--- a/BufferAllocatorWrapper.cpp
+++ b/BufferAllocatorWrapper.cpp
@@ -30,10 +30,16 @@
 };
 
 int DmabufHeapAlloc(BufferAllocator* buffer_allocator, const char* heap_name, size_t len,
-                    unsigned int heap_flags) {
+                    unsigned int heap_flags, size_t legacy_align) {
     if (!buffer_allocator)
         return -EINVAL;
-    return buffer_allocator->Alloc(heap_name, len, heap_flags);
+    return buffer_allocator->Alloc(heap_name, len, heap_flags, legacy_align);
+}
+
+int DmabufHeapAllocSystem(BufferAllocator* buffer_allocator, bool cpu_access, size_t len,
+                          unsigned int heap_flags, size_t legacy_align) {
+    if (!buffer_allocator) return -EINVAL;
+    return buffer_allocator->AllocSystem(cpu_access, len, heap_flags, legacy_align);
 }
 
 int MapDmabufHeapNameToIonHeap(BufferAllocator* buffer_allocator, const char* heap_name,
diff --git a/include/BufferAllocator/BufferAllocator.h b/include/BufferAllocator/BufferAllocator.h
index 44c90fb..edc3143 100644
--- a/include/BufferAllocator/BufferAllocator.h
+++ b/include/BufferAllocator/BufferAllocator.h
@@ -81,6 +81,24 @@
      */
     int Alloc(const std::string& heap_name, size_t len, unsigned int heap_flags = 0, size_t legacy_align = 0);
 
+    /* *
+     * Returns a dmabuf fd if the allocation in system heap(cached/uncached) is successful and
+     * an error code otherwise. Allocates in the 'system' heap if CPU access of
+     * the buffer is expected and 'system-uncached' otherwise. If the 'system-uncached'
+     * heap is not supported, falls back to the 'system' heap.
+     * For vendor defined heaps with a legacy ION interface(no heap query support),
+     * MapNameToIonMask() must be called prior to invocation of AllocSystem() to
+     * map names 'system'(and optionally 'system-uncached' if applicable) to an
+     * equivalent heap mask and heap flag configuration;
+     * configuration.
+     * @cpu_access: indicates if CPU access of the buffer is expected.
+     * @len: size of the allocation.
+     * @heap_flags: flags passed to heap.
+     * @legacy_align: alignment value used only by legacy ION
+     */
+    int AllocSystem(bool cpu_access, size_t len, unsigned int heap_flags = 0,
+                    size_t legacy_align = 0);
+
     /**
      * Optional custom callback for legacy ion implementation that can be specified as a
      * parameter to CpuSyncStart() and CpuSyncEnd(). Its first argument is an fd to /dev/ion.
diff --git a/include/BufferAllocator/BufferAllocatorWrapper.h b/include/BufferAllocator/BufferAllocatorWrapper.h
index c1c4b0c..5d62de6 100644
--- a/include/BufferAllocator/BufferAllocatorWrapper.h
+++ b/include/BufferAllocator/BufferAllocatorWrapper.h
@@ -18,6 +18,7 @@
 #define BUFFER_ALLOCATOR_H_
 
 #include <BufferAllocator/dmabufheap-defs.h>
+#include <stdbool.h>
 #include <sys/types.h>
 
 #ifdef __cplusplus
@@ -32,7 +33,9 @@
 void FreeDmabufHeapBufferAllocator(BufferAllocator* buffer_allocator);
 
 int DmabufHeapAlloc(BufferAllocator* buffer_allocator, const char* heap_name, size_t len,
-                    unsigned int heap_flags);
+                    unsigned int heap_flags, size_t legacy_align);
+int DmabufHeapAllocSystem(BufferAllocator* buffer_allocator, bool cpu_access, size_t len,
+                          unsigned int heap_flags, size_t legacy_align);
 
 int MapDmabufHeapNameToIonHeap(BufferAllocator* buffer_allocator, const char* heap_name,
                                const char* ion_heap_name, unsigned int ion_heap_flags,
diff --git a/tests/dmabuf_heap_test.c b/tests/dmabuf_heap_test.c
index db880c8..55e6788 100644
--- a/tests/dmabuf_heap_test.c
+++ b/tests/dmabuf_heap_test.c
@@ -76,7 +76,24 @@
         return;
     }
 
-    fd = DmabufHeapAlloc(bufferAllocator, kDmabufSystemHeapName, len, 0);
+    /*
+     * Test the DmabufHeapAllocSystem() APIs.
+     */
+    fd = DmabufHeapAllocSystem(bufferAllocator, true /* cpu_access */, len, 0, 0);
+    if (fd < 0) {
+        printf("DmabufHeapAllocSystem() failed: %d cpu_access: true\n", fd);
+        return;
+    }
+    close(fd);
+
+    fd = DmabufHeapAllocSystem(bufferAllocator, false /* cpu_access */, len, 0, 0);
+    if (fd < 0) {
+        printf("DmabufHeapAllocSystem() failed: %d cpu_access: false\n", fd);
+        return;
+    }
+    close(fd);
+
+    fd = DmabufHeapAlloc(bufferAllocator, kDmabufSystemHeapName, len, 0, 0);
     if (fd < 0) {
         printf("Alloc failed: %d\n", fd);
         return;
diff --git a/tests/dmabuf_heap_test.cpp b/tests/dmabuf_heap_test.cpp
index fdb3c79..243f703 100644
--- a/tests/dmabuf_heap_test.cpp
+++ b/tests/dmabuf_heap_test.cpp
@@ -33,9 +33,9 @@
   public:
     virtual void SetUp() { allocator = new BufferAllocator(); }
 
-    void DoAlloc(const std::string& heap_name) {
+    void DoAlloc(bool cpu_access_needed) {
         static const size_t kAllocSizeInBytes = 4096;
-        int map_fd = allocator->Alloc(heap_name, kAllocSizeInBytes);
+        int map_fd = allocator->AllocSystem(cpu_access_needed, kAllocSizeInBytes);
         ASSERT_GE(map_fd, 0);
 
         void* ptr = mmap(NULL, kAllocSizeInBytes, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
@@ -52,19 +52,19 @@
     }
 
     void DoConcurrentAlloc() {
-        DoAlloc(kDmabufSystemHeapName);
-        DoAlloc(kDmabufSystemUncachedHeapName);
+        DoAlloc(true /* cpu_access_needed */);
+        DoAlloc(false /* cpu_access_needed */);
     }
 
     void DoConcurrentAllocWithMapName() {
         allocator->MapNameToIonHeap(kDmabufSystemHeapName, "" /* no mapping for non-legacy */,
                                     0 /* no mapping for non-legacy ion */,
                                     ~0 /* legacy ion heap mask */, ION_FLAG_CACHED);
-        DoAlloc(kDmabufSystemHeapName);
+        DoAlloc(true /* cpu_access_needed */);
         allocator->MapNameToIonHeap(
                 kDmabufSystemUncachedHeapName, "" /* no mapping for non-legacy */,
                 0 /* no mapping for non-legacy ion */, ~0 /* legacy ion heap mask */);
-        DoAlloc(kDmabufSystemUncachedHeapName);
+        DoAlloc(false /* cpu_access_needed */);
     }
 
     virtual void TearDown() { delete allocator; }
@@ -124,26 +124,16 @@
                                 ~0 /* legacy ion heap mask */);
 }
 
-TEST_F(DmaBufHeapTest, AllocateUncached) {
+TEST_F(DmaBufHeapTest, Allocate) {
     static const size_t allocationSizes[] = {4 * 1024, 64 * 1024, 1024 * 1024, 2 * 1024 * 1024};
-    for (size_t size : allocationSizes) {
-        SCOPED_TRACE(::testing::Message()
-                     << "heap: " << kDmabufSystemUncachedHeapName << " size: " << size);
-        int fd = allocator->Alloc(kDmabufSystemUncachedHeapName, size);
-        ASSERT_GE(fd, 0);
-        ASSERT_EQ(close(fd), 0);  // free the buffer
-    }
-}
-
-TEST_F(DmaBufHeapTest, AllocateCached) {
-    static const size_t allocationSizes[] = {4 * 1024, 64 * 1024, 1024 * 1024, 2 * 1024 * 1024};
-    for (size_t size : allocationSizes) {
-        SCOPED_TRACE(::testing::Message()
-                     << "heap: " << kDmabufSystemHeapName << " size: " << size);
-        int fd = allocator->Alloc(kDmabufSystemHeapName, size, ION_FLAG_CACHED
-                                  /* ion heap flags will be ignored if using dmabuf heaps */);
-        ASSERT_GE(fd, 0);
-        ASSERT_EQ(close(fd), 0);  // free the buffer
+    for (bool cpu_access_needed : {false, true}) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message()
+                         << "cpu_access_needed: " << cpu_access_needed << " size: " << size);
+            int fd = allocator->AllocSystem(cpu_access_needed, size);
+            ASSERT_GE(fd, 0);
+            ASSERT_EQ(close(fd), 0);  // free the buffer
+        }
     }
 }
 
@@ -159,30 +149,18 @@
     }
 }
 
-TEST_F(DmaBufHeapTest, RepeatedAllocateUncached) {
+TEST_F(DmaBufHeapTest, RepeatedAllocate) {
     static const size_t allocationSizes[] = {4 * 1024, 64 * 1024, 1024 * 1024, 2 * 1024 * 1024};
-    for (size_t size : allocationSizes) {
-        SCOPED_TRACE(::testing::Message()
-                     << "heap: " << kDmabufSystemUncachedHeapName << " size: " << size);
-        for (unsigned int i = 0; i < 1024; i++) {
-            SCOPED_TRACE(::testing::Message() << "iteration " << i);
-            int fd = allocator->Alloc(kDmabufSystemUncachedHeapName, size);
-            ASSERT_GE(fd, 0);
-            ASSERT_EQ(close(fd), 0);  // free the buffer
-        }
-    }
-}
-
-TEST_F(DmaBufHeapTest, RepeatedAllocateCached) {
-    static const size_t allocationSizes[] = {4 * 1024, 64 * 1024, 1024 * 1024, 2 * 1024 * 1024};
-    for (size_t size : allocationSizes) {
-        SCOPED_TRACE(::testing::Message()
-                     << "heap: " << kDmabufSystemHeapName << " size: " << size);
-        for (unsigned int i = 0; i < 1024; i++) {
-            SCOPED_TRACE(::testing::Message() << "iteration " << i);
-            int fd = allocator->Alloc(kDmabufSystemHeapName, size);
-            ASSERT_GE(fd, 0);
-            ASSERT_EQ(close(fd), 0);  // free the buffer
+    for (bool cpu_access_needed : {false, true}) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message()
+                         << "cpu_access_needed: " << cpu_access_needed << " size: " << size);
+            for (unsigned int i = 0; i < 1024; i++) {
+                SCOPED_TRACE(::testing::Message() << "iteration " << i);
+                int fd = allocator->AllocSystem(cpu_access_needed, size);
+                ASSERT_GE(fd, 0);
+                ASSERT_EQ(close(fd), 0);  // free the buffer
+            }
         }
     }
 }
@@ -305,7 +283,6 @@
 TEST_F(DmaBufHeapTest, TestDmabufSystemHeapCompliance) {
     using android::vintf::KernelVersion;
 
-    static const size_t kAllocSizeInBytes = 4096;
     if (android::base::GetIntProperty("ro.product.first_api_level", 0) < __ANDROID_API_S__) {
         GTEST_SKIP();
     }
@@ -322,30 +299,34 @@
     auto heap_list = allocator->GetDmabufHeapList();
     ASSERT_TRUE(heap_list.find("system") != heap_list.end());
 
-    /*
-     * Test that system heap can be allocated from.
-     */
-    int map_fd = allocator->Alloc(kDmabufSystemHeapName, kAllocSizeInBytes);
-    ASSERT_GE(map_fd, 0);
+    for (bool cpu_access_needed : {false, true}) {
+        static const size_t kAllocSizeInBytes = 4096;
+        /*
+         * Test that system heap can be allocated from.
+         */
+        SCOPED_TRACE(::testing::Message() << "cpu_access_needed: " << cpu_access_needed);
+        int map_fd = allocator->AllocSystem(cpu_access_needed, kAllocSizeInBytes);
+        ASSERT_GE(map_fd, 0);
 
-    /*
-     * Test that system heap can be mmapped by the CPU.
-     */
-    void* ptr = mmap(NULL, kAllocSizeInBytes, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
-    ASSERT_TRUE(ptr != MAP_FAILED);
+        /*
+         * Test that system heap can be mmapped by the CPU.
+         */
+        void* ptr = mmap(NULL, kAllocSizeInBytes, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != MAP_FAILED);
 
-    /*
-     * Test that the allocated memory is zeroed.
-     */
-    auto zeroes_ptr = std::make_unique<char[]>(kAllocSizeInBytes);
-    int ret = allocator->CpuSyncStart(map_fd);
-    ASSERT_EQ(0, ret);
+        /*
+         * Test that the allocated memory is zeroed.
+         */
+        auto zeroes_ptr = std::make_unique<char[]>(kAllocSizeInBytes);
+        int ret = allocator->CpuSyncStart(map_fd);
+        ASSERT_EQ(0, ret);
 
-    ASSERT_EQ(0, memcmp(ptr, zeroes_ptr.get(), kAllocSizeInBytes));
+        ASSERT_EQ(0, memcmp(ptr, zeroes_ptr.get(), kAllocSizeInBytes));
 
-    ret = allocator->CpuSyncEnd(map_fd);
-    ASSERT_EQ(0, ret);
+        ret = allocator->CpuSyncEnd(map_fd);
+        ASSERT_EQ(0, ret);
 
-    ASSERT_EQ(0, munmap(ptr, kAllocSizeInBytes));
-    ASSERT_EQ(0, close(map_fd));
+        ASSERT_EQ(0, munmap(ptr, kAllocSizeInBytes));
+        ASSERT_EQ(0, close(map_fd));
+    }
 }