android8.1和之前的版本有一个很大的不同,那就是8.1以后的版本将hal层和framework层分隔开来,不在同一个进程,不能直接通信。如果framework层需要和hal层通信,需要用到hidl接口。
之前我这边有个模块,在android6.0上时,需要在hal层通过ashmem_create_region来创建一块共享内存。然后将创建的共享内存句柄,通过binder,传送给framework层和app层。在android6.0上,一切都很顺利,framework层通过binder获取到hal层创建的共享内存后,mmap一下,就可以得到这块共享内存,并进行读写。
后来需要将这个模块移植到8.1上,将代码移过去后,发现之前能正常运行的binder,无法将hal层创建的共享内存fd传给framewrok层。结研究发现,这就是8.1上将hal和framework层分隔开来引起的。需要解决这个问题,只能引进hidl接口了。
hidl接口中,共享内存是通过IAllocator来创建的,然后再通过hidl_memory接收分配的对象,然后通过mapMemory到本进程中的IMemory对象中。hidl_memory类型会映射到 libhidlbase
中的 hidl_memory
类,该类表示未映射的共享内存。这是要在 HIDL 中共享内存而必须在进程之间传递的对象。使用IAllocator分配内存代码如下:
native_handle_t* mHidlHandle = nullptr;
hidl_memory mHidlHeap;
void* mHidlHeapMemData;
sp<IMemory> mHidlHeapMemory; // munmap happens in ~IMemory()
sp<IAllocator> mAshmemAllocator = IAllocator::getService("ashmem");
mAshmemAllocator->allocate(len,
[&](bool success, const hidl_memory& mem) {
if (!success) {
ALOGI("allocating ashmem of %zu bytes failed!", len);
return;
}
mHidlHandle = native_handle_clone(mem.handle());
mHidlHeap = hidl_memory("ashmem", mHidlHandle, len);
mHidlHeapMemory = mapMemory(mHidlHeap);
if (mHidlHeapMemory == nullptr) {
ALOGE("memory map failed!");
native_handle_close(mHidlHandle); // close FD for the shared memory
native_handle_delete(mHidlHandle);
mHidlHeap = hidl_memory();
mHidlHandle = nullptr;
return;
}
mHidlHeapMemData = mHidlHeapMemory->getPointer();
fd(mHidlHandle);
})
上面演示了怎么去分配一块共享内存,下面再完整的讲一下怎么使用hidl接口来传递共享内存。
1.)在hardware\interfaces目录下新建一个文件夹my_memory,里面新建一个Android.bp,内容如下
subdirs = [
"1.0",
"1.0/default",
]
再创建一个名为“1.0”的文件夹。里面包含Android.bp、IMy_memory.hal文件,以及default文件夹。其中Android.bp在运行./hardware/interfaces/update-makefiles.sh时会自动生成,运行这条命令时,会同时检查你的hal文件以及对应的实现文件是否符合hidl的接口规范,如果不符合,则会提示你。
IMy_memory.hal内容如下:
package android.hardware.my_memory@1.0;
interface IMy_memory
{
createMemory()generates(handle memory_ptr);
getMemory()generates(handle memory_ptr);
getMemoryFd()generates(uint8_t ret);
getMemorySize()generates(uint32_t ret);
};
对应的default下有Android.bp、android.hardware.my_memory@1.0-service.rc、service.cpp、my_memory.h、my_memory.cpp这几个文件。其中Android.bp文件内容如下:
cc_library_shared {
name: "android.hardware.my_memory@1.0-impl",
defaults: ["hidl_defaults"],
proprietary: true,
relative_install_path: "hw",
srcs: ["my_memory.cpp"],
cflags: ["-Werror", "-Wno-unused-parameter"],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libhardware",
"liblog",
"libutils",
"libcutils",
"android.hardware.my_memory@1.0",
"libbinder",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libhwbinder",
"libhidlmemory",
],
}
cc_binary {
name: "android.hardware.my_memory@1.0-service",
init_rc: ["android.hardware.mymemory@1.0-service.rc"],
defaults: ["hidl_defaults"],
proprietary: true,
relative_install_path: "hw",
srcs: ["service.cpp",
"my_memory.cpp"],
cflags: ["-Werror", "-Wno-unused-parameter"],
shared_libs: [
"liblog",
"libhardware",
"libhidlbase",
"libhidltransport",
"libutils",
"libcutils",
"android.hardware.my_memory@1.0",
"libbinder",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libhwbinder",
"libhidlmemory",
],
}
service.cpp内容如下:
#define LOG_TAG "android.hardware.my_memory@1.0-service"
#include <android/hardware/my_memory/1.0/IMy_memory.h>
#include <hidl/LegacySupport.h>
#include <binder/ProcessState.h>
#include "my_memory.h"
using android::hardware::my_memory::V1_0::IMy_memory;
using android::hardware::my_memory::V1_0::implementation::my_memory;
using android::hardware::defaultPassthroughServiceImplementation;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::sp;
int main() {
android::ProcessState::initWithDriver("/dev/vndbinder");
return defaultPassthroughServiceImplementation<IMy_memory>("my_memory", /*maxThreads*/ 6);
}
my_memory.h内容如下:
#ifndef ANDROID_HARDWARE_MY_MEMORY_V1_0_H
#define ANDROID_HARDWARE_MY_MEMORY_V1_0_H
#include <android/hardware/my_memory/1.0/IMy_memory.h>
#include <unordered_map>
#include <hidl/Status.h>
#include <hidl/MQDescriptor.h>
#include <hidlmemory/mapping.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidl/MQDescriptor.h>
namespace android {
namespace hardware {
namespace my_memory {
namespace V1_0 {
namespace implementation {
using ::android::hardware::my_memory::V1_0::IMy_memory;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
using ::android::hardware::hidl_memory;
using ::android::hidl::allocator::V1_0::IAllocator;
using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::memory::V1_0::IMemory;
struct my_memory : public IMy_memory {
public:
my_memory();
~my_memory();
Return<void>createMemory(createMemory_cb fd) override;
Return<uint32_t>getMemorySize()override;
private:
native_handle_t* mHidlHandle = nullptr;
sp<IAllocator> mAshmemAllocator = nullptr;
hidl_memory mHidlHeap;
void* mHidlHeapMemData;
sp<IMemory> mHidlHeapMemory; // munmap happens in ~IMemory()
int32_t mSize = 0;
};
extern "C" IMy_memory* HIDL_FETCH_IMy_memory(const char* name);
} // namespace implementation
} // namespace V1_0
} // namespace led
} // namespace hardware
} // namespace android
#endif //ANDROID_HARDWARE_MY_MEMORY_V1_0_H
#define LOG_TAG "my_memory.cpp"
#include <log/log.h>
#include "my_memory.h"
namespace android {
namespace hardware {
namespace my_memory {
namespace V1_0 {
namespace implementation {
my_memory::my_memory() {
ALOGI("my_memory Init");
}
my_memory::~my_memory() {
ALOGI("my_memory ~my_memory()");
if (mHidlHeapMemory != nullptr) {
mHidlHeapMemData = nullptr;
mHidlHeapMemory.clear(); // The destructor will trigger munmap
}
if (mHidlHandle) {
native_handle_close(mHidlHandle); // close FD for the shared memory
native_handle_delete(mHidlHandle);
}
}
Return<void> my_memory::createMemory(createMemory_cb fd, int32_t size)
{
ALOGI("yovtimestamps_memory::createMemory start");
int32_t pageSize = getpagesize();
if((mHidlHandle == nullptr) || size > mSize)
{
//mHidlHandle不为NULL,且size != mSize,表明已经创建过共享内存,但是现在的内存,比之前的
//要大,要重新分配。
if (mHidlHeapMemory != nullptr) {
mHidlHeapMemData = nullptr;
mHidlHeapMemory.clear(); // The destructor will trigger munmap
}
if(mHidlHandle != nullptr)
{
ALOGI("new size %d, > old size %d, need reallocate", size, mSize);
native_handle_close(mHidlHandle); // close FD for the shared memory
native_handle_delete(mHidlHandle);
}
else
{
ALOGI("createMemory, first allocation ");
}
if(mAshmemAllocator == nullptr)
{
mAshmemAllocator = IAllocator::getService("ashmem");
}
if (mAshmemAllocator == nullptr) {
ALOGI("%s: cannot get ashmemAllocator", __FUNCTION__);
return Void();
}
int32_t len = ((size + pageSize-1) & ~(pageSize-1));
mAshmemAllocator->allocate(len,
[&](bool success, const hidl_memory& mem) {
if (!success) {
ALOGI("allocating ashmem of %zu bytes failed!", len);
return;
}
mHidlHandle = native_handle_clone(mem.handle());
mHidlHeap = hidl_memory("ashmem", mHidlHandle, len);
mHidlHeapMemory = mapMemory(mHidlHeap);
if (mHidlHeapMemory == nullptr) {
ALOGE("memory map failed!");
native_handle_close(mHidlHandle); // close FD for the shared memory
native_handle_delete(mHidlHandle);
mHidlHeap = hidl_memory();
mHidlHandle = nullptr;
return;
}
mHidlHeapMemData = mHidlHeapMemory->getPointer();
fd(mHidlHandle);
});
}
else
{
//如果现在申请的内存,小于等于之前的内存,那么就不用重新分配,直接反回。
ALOGI("mHidlHandle has already exist");
fd(mHidlHandle);
}
mSize = size;
return Void();
}
Return<uint32_t> my_memory::getMemorySize()
{
return mSize;
}
IMy_memory* HIDL_FETCH_IMy_memory(const char * /*name*/) {
ALOGI("my_memory HIDL_FETCH_IMy_memory ");
return new my_memory();
}
} // namespace implementation
} // namespace V1_0
} // namespace led
} // namespace hardware
} // namespace android
其中参数“createMemory_cb fd”的类型createMemory_cb,是编译时自动生成的,我们的要传回给framework层的内容是一个native_handle_t型的指针mHidlHandle。native_handle_t这个类型定义在system\core\include\cutils\native_handle.h
typedef struct native_handle
{
int version; /* sizeof(native_handle_t) */
int numFds; /* number of file-descriptors at &data[0] */
int numInts; /* number of ints at &data[numFds] */
int data[0]; /* numFds + numInts ints */
} native_handle_t;
其中, data[0]存的就是我们刚刚allocate出来的共享内存的文件句柄,我们需要通过这个类型,在hidl里以回调参数的方式传回给调用方。
android.hardware.my_memory@1.0-service.rc的内容如下:
service my_memory_server /vendor/bin/hw/android.hardware.my_memory@1.0-service
class hal
user system
group system
写好上面的代码,编译完成后会在system/lib下生成android.hardware.my_memory@1.0.so,在vendor/lib/hw下生成android.hardware.my_memory@1.0-impl.so, 在vendor/bin/hw下生成android.hardware.yovtimestamps_memory@1.0-service。
当然,如果仅仅这样,开机后,我们的android.hardware.my_memory@1.0-service这个服务,不会自动启动,因为我们还没有给它配置selinux权限,注意,这个权限,哪怕是selinux关闭了,也要配置。配置过程如下:
1、)在prebuilts/api/26.0/public/attributes里新增如下代码:
attribute hal_my_memory;
attribute hal_my_memory_client;
attribute hal_my_memory_server;
2、)在prebuilts/api/26.0/public/hwservice.te 新增如下代码:
type hal_my_memory_hwservice, hwservice_manager_type;
3、)在prebuilts/api/26.0/public/下新增hal_my_memory.te文件,内容如下:
# HwBinder IPC from client to server, and callbacks
binder_call(hal_my_memory_client, hal_my_memory_server)
binder_call(hal_my_memory_server, hal_my_memory_client)
add_hwservice(hal_my_memory_server, hal_my_memory_hwservice)
allow hal_my_memory_client hal_my_memory_hwservice:hwservice_manager find;
4、)在private/compat/26.0/26.0.ignore.cil新增一行代码
hal_my_memory_hwservice))
5、)在private/hwservice_contexts里新加一行代码:
android.hardware.my_memory::IMy_memory u:object_r:hal_my_memory_hwservice:s0
6、)在public/attributes里新增几行代码:
attribute hal_my_memory;
attribute hal_my_memory_client;
attribute hal_my_memory_server;
7、)在public里新增一个文件hal_my_memory.te
# HwBinder IPC from client to server, and callbacks
binder_call(hal_my_memory_client, hal_my_memory_server)
binder_call(hal_my_memory_server, hal_my_memory_client)
add_hwservice(hal_my_memory_server, hal_my_memory_hwservice)
allow hal_my_memory_client hal_my_memory_hwservice:hwservice_manager find;
8、)在public/hwservice.te里新增一行代码
type hal_my_memory_hwservice, hwservice_manager_type;
9、)在vendor/file_contexts里新增一行代码:
(vendor|system/vendor)/bin/hw/android\.hardware\.my_memory@1\.0-service u:object_r:hal_my_memory_default_exec:s0
10、)在vendor下新增一文件hal_my_memory_default.te
type hal_my_memory_default, domain;
hal_server_domain(hal_my_memory_default, hal_my_memory)
type hal_my_memory_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_my_memory_default)
上面权限加上后,开机时,就会自动启动我们在android.hardware.my_memory@1.0-service.rc里定义的服务my_memory_server了,它会调用到我们的hidl接口HIDL_FETCH_IMy_memory.
下面再讲下在hal层,是怎么调用到我们接口去创建共享内存的。hal层的调用代码如下:
sp<IMy_memory> mMy_memoryService = NULL;
size_t mPageSize = 0;
hidl_memory mHidlHeap;
sp<::android::hidl::memory::V1_0::IMemory> mHidlHeapMemory;
void* mHidlHeapMemData = NULL;
if(mMy_memoryService == NULL)
{
mMy_memoryService = IMy_memory::getService("my_memory");
}
if(mMy_memoryService != NULL)
{
mTimestamps_memoryService->createMemory([&](hidl_handle handle, size){
mHidlHeap = hidl_memory("ashmem", handle, size);
mHidlHeapMemory = mapMemory(mHidlHeap);
if (mHidlHeapMemory == nullptr) {
ALOGE("memory map failed!");
native_handle_close(handle); // close FD for the shared memory
native_handle_delete(handle);
mHidlHeap = hidl_memory();
handle = nullptr;
return NO_ERROR;
}
mHidlHeapMemData = mHidlHeapMemory->getPointer();
return NO_ERROR;
});
ALOGI("DisplayClient::init 8");
}
在framework层获取共享内存的句柄的代码如下:
sp<IMy_memory> mClient = IMy_memory::getService("my_memory");
if(mClient != NULL)
{
mClient->getMemory([&](hidl_handle handle){
//在这里必须dup一下,因为handle->data[0]这个值,出了这个函数的作用域,就被释放掉了.
//mFD的值是一个无效的文件句柄. 必须先dup一下,将它复制出来.这样才可以在出了这个函
//数的作用域后,仍可以使用
mFD = dup(handle->data[0]);
return NO_ERROR;
});
}
else
{
ALOGI("AutotimestampService::get IYovtimestamps_memory == NULL\n");
}
好了,到这里就讲完了,如何从hal层传共享内存到framework层。