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();