android 8.1上新增hidl接口,从hal层往framework层传共享内存

        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 [email protected];
 
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、[email protected]、service.cpp、my_memory.h、my_memory.cpp这几个文件。其中Android.bp文件内容如下:

cc_library_shared {
name: "[email protected]",
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",
"[email protected]",
"libbinder",
"[email protected]",
"[email protected]",
"libhwbinder",
 "libhidlmemory",
], 
}
 
cc_binary {
name: "[email protected]",
init_rc: ["[email protected]"],
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",
"[email protected]",
"libbinder",
"[email protected]",
"[email protected]",
"libhwbinder",
 "libhidlmemory",
], 
}

service.cpp内容如下:

扫描二维码关注公众号,回复: 11465295 查看本文章
 
 #define LOG_TAG "[email protected]"
 
#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里以回调参数的方式传回给调用方。

[email protected]的内容如下:

service my_memory_server /vendor/bin/hw/[email protected]
    class hal
    user system
    group system 

        写好上面的代码,编译完成后会在system/lib下生成[email protected],在vendor/lib/hw下生成[email protected], 在vendor/bin/hw下生成[email protected]

       当然,如果仅仅这样,开机后,我们的[email protected]这个服务,不会自动启动,因为我们还没有给它配置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)

        上面权限加上后,开机时,就会自动启动我们在[email protected]里定义的服务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层。

猜你喜欢

转载自blog.csdn.net/xuhui_7810/article/details/103680318