Ashmem HIDL Interface Implementation
am: 3e4079a9b5

Change-Id: Ib078a42238757c0439ddf1b77afdea8fd38f868c
diff --git a/Android.bp b/Android.bp
index b30ca23..bff956e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,10 +23,14 @@
 cc_defaults {
     name: "ashmemd_defaults",
     shared_libs: [
+        "android.system.ashmem@1.0",
         "ashmemd_aidl_interface-cpp",
         "libbase",
         "libbinder",
+        "libcutils",
         "libutils",
+        "libhidlbase",
+        "libhidltransport",
     ],
     cflags: [
         "-Wall",
@@ -39,6 +43,7 @@
     defaults: ["ashmemd_defaults"],
     srcs: ["ashmemd.cpp"],
     init_rc: ["ashmemd.rc"],
+    vintf_fragments: ["android.system.ashmem@1.0.xml"],
 }
 
 // This library is used to communicate with ashmemd using dlopen/dlsym. We do
diff --git a/android.system.ashmem@1.0.xml b/android.system.ashmem@1.0.xml
new file mode 100644
index 0000000..48c7e47
--- /dev/null
+++ b/android.system.ashmem@1.0.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+    <hal>
+        <name>android.system.ashmem</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IAshmem</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/ashmemd.cpp b/ashmemd.cpp
index 9d12ed3..67f407b 100644
--- a/ashmemd.cpp
+++ b/ashmemd.cpp
@@ -14,46 +14,89 @@
  * limitations under the License.
  */
 
+#include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <binder/BinderService.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <binder/Status.h>
+#include <cutils/native_handle.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
 #include <utils/String16.h>
 
 #include <android/ashmemd/BnAshmemDeviceService.h>
+#include <android/system/ashmem/1.0/IAshmem.h>
 
+using android::sp;
 using android::String16;
 using android::base::unique_fd;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::system::ashmem::V1_0::IAshmem;
 
 namespace android {
 namespace ashmemd {
 
-class AshmemDeviceService : public BnAshmemDeviceService {
-  public:
-    binder::Status open(os::ParcelFileDescriptor* ashmemFd) override {
-        ashmemFd->reset(unique_fd(TEMP_FAILURE_RETRY(::open("/dev/ashmem", O_RDWR | O_CLOEXEC))));
-        return binder::Status::ok();
-    }
+inline unique_fd openDevAshmem() {
+    int fd = TEMP_FAILURE_RETRY(::open("/dev/ashmem", O_RDWR | O_CLOEXEC));
+    return unique_fd(fd);
+}
+
+class AshmemAidlService : public BnAshmemDeviceService {
+public:
+  binder::Status open(os::ParcelFileDescriptor *ashmemFd) override {
+      ashmemFd->reset(openDevAshmem());
+      return binder::Status::ok();
+  }
 };
 
-void CreateAndRegisterService() {
-    sp<AshmemDeviceService> ashmemService = new AshmemDeviceService();
-    defaultServiceManager()->addService(String16("ashmem_device_service"), ashmemService,
-                                        true /* allowIsolated */);
-}
-
-void JoinThreadPool() {
-    sp<ProcessState> ps = ProcessState::self();
-    IPCThreadState::self()->joinThreadPool();  // should not return
-}
+class AshmemHidlService : public IAshmem {
+public:
+  Return<void> open(open_cb _hidl_cb) override {
+      unique_fd fd = openDevAshmem();
+      if (fd == -1) {
+          _hidl_cb(nullptr);
+      } else {
+          native_handle_t *native_handle =
+              native_handle_create(1 /* num_fds */, 0 /* num_ints */);
+          native_handle->data[0] = fd.get();
+          _hidl_cb(native_handle);
+          // unique_fd, fd, will close when it falls out of scope, no need to
+          // call native_handle_close.
+          native_handle_delete(native_handle);
+      }
+      return Void();
+  }
+};
 
 }  // namespace ashmemd
 }  // namespace android
 
+using android::ashmemd::AshmemAidlService;
+using android::ashmemd::AshmemHidlService;
+
 int main() {
-    android::ashmemd::CreateAndRegisterService();
-    android::ashmemd::JoinThreadPool();
-    std::abort();  // unreachable
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    sp<AshmemAidlService> ashmemAidlService = new AshmemAidlService();
+    android::defaultServiceManager()->addService(
+        String16("ashmem_device_service"), ashmemAidlService,
+        true /* allowIsolated */);
+
+    sp<AshmemHidlService> ashmemHidlService = new AshmemHidlService();
+    auto status = ashmemHidlService->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Unable to register ashmem hidl service: " << status;
+    }
+
+    // Create non-HW binder threadpool for Aidl Service
+    sp<android::ProcessState> ps{android::ProcessState::self()};
+    ps->startThreadPool();
+
+    joinRpcThreadpool();
+    std::abort(); // unreachable
 }
diff --git a/tests/ashmemd_test.cpp b/tests/ashmemd_test.cpp
index ed3cfe3..0d57b0f 100644
--- a/tests/ashmemd_test.cpp
+++ b/tests/ashmemd_test.cpp
@@ -14,71 +14,114 @@
  * limitations under the License.
  */
 
-#include <dlfcn.h>
-
+#include <android-base/unique_fd.h>
+#include <android/ashmemd/IAshmemDeviceService.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <android/system/ashmem/1.0/IAshmem.h>
 #include <binder/IServiceManager.h>
+#include <dlfcn.h>
 #include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
 #include <linux/ashmem.h>
 #include <sys/mman.h>
 
-#include <android/ashmemd/IAshmemDeviceService.h>
-
 using android::IBinder;
 using android::IServiceManager;
 using android::String16;
 using android::ashmemd::IAshmemDeviceService;
+using android::base::unique_fd;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
 using android::os::ParcelFileDescriptor;
+using android::system::ashmem::V1_0::IAshmem;
 
 namespace android {
 namespace ashmemd {
 
-class AshmemdTest : public ::testing::Test {
+enum class Interface { AIDL, HIDL };
+
+class AshmemdTest : public ::testing::TestWithParam<Interface> {
   public:
-    virtual void SetUp() override {
+    void SetUp() override {
         sp<IServiceManager> sm = android::defaultServiceManager();
         sp<IBinder> binder = sm->getService(String16("ashmem_device_service"));
         ASSERT_NE(binder, nullptr);
 
-        ashmemService = android::interface_cast<IAshmemDeviceService>(binder);
-        ASSERT_NE(ashmemService, nullptr);
+        ashmemAidlService = android::interface_cast<IAshmemDeviceService>(binder);
+        ASSERT_NE(ashmemAidlService, nullptr);
+
+        ashmemHidlService = IAshmem::getService();
+        ASSERT_NE(ashmemHidlService, nullptr) << "failed to get ashmem hidl service";
     }
 
-    void openFd(ParcelFileDescriptor* fd) {
-        auto status = ashmemService->open(fd);
-        ASSERT_TRUE(status.isOk());
-        ASSERT_GE(fd->get(), 0);
+    unique_fd openFd(Interface interface) {
+        switch (interface) {
+            case Interface::AIDL: {
+                ParcelFileDescriptor fd;
+                ashmemAidlService->open(&fd);
+                return unique_fd(dup(fd.get()));
+            }
+            case Interface::HIDL: {
+                unique_fd fd;
+                ashmemHidlService->open([&fd](hidl_handle handle) {
+                    ASSERT_NE(handle, nullptr)
+                        << "failed to open /dev/ashmem from IAshmem.";
+                    fd = unique_fd(dup(handle->data[0]));
+                });
+                return fd;
+            }
+            default:
+                return unique_fd(-1);
+        }
     }
 
-    sp<IAshmemDeviceService> ashmemService;
+    sp<IAshmemDeviceService> ashmemAidlService;
+    sp<IAshmem> ashmemHidlService;
 };
 
-TEST_F(AshmemdTest, OpenFd) {
-    ParcelFileDescriptor fd;
-    openFd(&fd);
+TEST_P(AshmemdTest, OpenFd) {
+    unique_fd fd = openFd(GetParam());
+    ASSERT_GE(fd.get(), 0);
 }
 
-TEST_F(AshmemdTest, OpenMultipleFds) {
-    ParcelFileDescriptor fd1;
-    ParcelFileDescriptor fd2;
-    openFd(&fd1);
-    openFd(&fd2);
+TEST_P(AshmemdTest, OpenMultipleFds) {
+    unique_fd fd1 = openFd(GetParam());
+    unique_fd fd2 = openFd(GetParam());
     ASSERT_NE(fd1.get(), fd2.get());
 }
 
-TEST_F(AshmemdTest, MmapFd) {
-    ParcelFileDescriptor pfd;
-    openFd(&pfd);
-    int fd = pfd.get();
+TEST_P(AshmemdTest, MmapFd) {
+    unique_fd fd = openFd(GetParam());
     size_t testSize = 2097152;
 
-    ASSERT_EQ(ioctl(fd, ASHMEM_SET_NAME, "AshmemdTest"), 0);
-    ASSERT_EQ(ioctl(fd, ASHMEM_SET_SIZE, testSize), 0);
+    ASSERT_EQ(ioctl(fd.get(), ASHMEM_SET_NAME, "AshmemdTest"), 0);
+    ASSERT_EQ(ioctl(fd.get(), ASHMEM_SET_SIZE, testSize), 0);
 
-    void* data = mmap(NULL, testSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    void* data = mmap(NULL, testSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0);
     ASSERT_NE(data, MAP_FAILED) << "Failed to mmap() ashmem fd";
     ASSERT_EQ(munmap(data, testSize), 0) << "Failed to munmap() ashmem fd";
 }
 
+INSTANTIATE_TEST_SUITE_P(AshmemdTestSuite, AshmemdTest,
+                         ::testing::Values(Interface::AIDL, Interface::HIDL));
+
+TEST(IAshmemTest, OnlyOneInstance) {
+    using ::android::hidl::manager::V1_2::IServiceManager;
+    sp<IServiceManager> manager = android::hardware::defaultServiceManager1_2();
+    ASSERT_NE(manager, nullptr) << "Unable to open defaultServiceManager";
+
+    manager->listManifestByInterface(
+        IAshmem::descriptor, [](const hidl_vec<hidl_string>& names) {
+            int instances = 0;
+            for (const auto& name : names) {
+                ASSERT_EQ(name, std::string("default"));
+                instances += 1;
+            }
+            ASSERT_EQ(instances, 1);
+        });
+}
+
 TEST(LibAshmemdClientTest, OpenFd) {
     void* handle = dlopen("libashmemd_client.so", RTLD_NOW);
     ASSERT_NE(handle, nullptr) << "Failed to dlopen() libashmemd_client.so: " << dlerror();