dlopen加载so库并获取Rawfile资源
介绍
本示例中主要介绍在TaskPool子线程中使用dlopen加载so库,以及如何使用Native Rawfile接口操作Rawfile目录和文件。功能包括文件列表遍历、文件打开、搜索、读取和关闭Rawfile。
效果预览
使用说明
应用界面中展示了Rawfile相关的接口调用,包括获取resources/rawfile目录下的文件、对应的rawfile文件内容、对应rawfile文件的descriptor。其中使用到的功能包括文件列表遍历、文件打开、搜索、读取和关闭Rawfile。
工程目录
├──entry/libs/ // 需要加载的.so文件
│ ├──arm64-v8a
│ │ └──libentry.so
│ └──x86_64
│ └──libentry.so
├──entry/src/main/cpp/ // native侧代码
│ ├──include
│ │ └──global_handlers.h // 包含全局对象global_handlers的头文件
│ ├──types
│ │ ├──libentry
│ │ │ ├──index.d.ts // 接口导出
│ │ │ └──oh-package.json5
│ │ └──libpreloadso
│ │ ├──index.d.ts // 接口导出
│ │ └──oh-package.json5
│ ├──CMakeLists.txt // 编译脚本
│ ├──global_handlers.cpp // 定义全局对象global_handlers
│ ├──preloadso.cpp // preload接口
│ └──rawfile_demo.cpp // 调用native接口
├──entry/src/main/ets // ArkTS侧代码
│ ├──entryability
│ │ └──EntryAbility.ets
│ ├──pages
│ │ └──Index.ets // 首页
│ └──utils
│ ├──Constants.ets // 预加载的so文件数组
│ ├──Logger.ets // 日志工具
│ └──TaskPool.ets // TaskPool子线程加载so库
└──entry/src/main/resources // 应用静态资源目录└──rawfile // rawfile资源├──subrawfile│ └──rawfile2.txt├──rawfile.txt└──rawfile1.txt
具体实现
在TaskPool子线程中使用dlopen加载so库,将需要加载的.so文件放到工程文件libs中,在CMakeLists编译脚本中使用target_link_directories命令将包含这些库文件的目录添加到预加载库的链接目录,使用target_link_libraries命令将需要预加载的so库链接到项目中。 在Native层的Preload接口中,遍历传入的.so路径数组,使用dlopen函数加载库,并将句柄保存到global_handlers中。暴露Preload接口给ArkTS层使用,使其能够通过preload调用Native层的Preload接口。源码参考:[preloadso.cpp]
/** Copyright (c) 2024 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#include "napi/native_api.h"
#include <dlfcn.h>
#include "global_handlers.h"
#include <hilog/log.h>// Hilog parameters.
const int GLOBAL_RESMGR = 0xFF00;
const char *TAG = "[Preload]";static napi_value Preload(napi_env env, napi_callback_info info) {OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "Preload init");size_t argc = 1;napi_value args[1] = {nullptr};napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_value result;napi_create_array(env, &result); // Create an array to hold the results.// Args[0] is the SO library path array.napi_valuetype valuetype;napi_typeof(env, args[0], &valuetype);if (valuetype != napi_object) {return nullptr;}// Obtains the length of the input SO library path array.uint32_t arrayLength;napi_get_array_length(env, args[0], &arrayLength);napi_value pathString;// Path for storing the SO library.char path[256];size_t pathLength;OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "Preload start");for (uint32_t i = 0; i < arrayLength; i++) {napi_get_element(env, args[0], i, &pathString);napi_status status = napi_get_value_string_utf8(env, pathString, path, sizeof(path), &pathLength);if (status != napi_ok) {// Processing the Failure of Obtaining the Path.OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, " Preload failed");continue;}// Use dlopen to dynamically load the SO library and return the handle of the SO library.void *handler = dlopen(path, RTLD_LAZY);if (handler == nullptr) {// Dlerror throws failure to load library.OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, " Preload failed");dlerror();continue;}// Save the handles to the global object global_handlers.global_handlers[std::string(path)] = handler;// Add the path of the successfully loaded library to the result array.napi_set_element(env, result, i, pathString);}OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "Preload finish");// Return the result array that is loaded successfully.return result;
}EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {napi_property_descriptor desc[] = {{"preload", nullptr, Preload, nullptr, nullptr, nullptr, napi_default, nullptr}};napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);return exports;
}
EXTERN_C_ENDstatic napi_module demoModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = Init,.nm_modname = "preloadso",.nm_priv = ((void *)0),.reserved = {0},
};extern "C" __attribute__((constructor)) void RegisterPreloadsoModule(void) { napi_module_register(&demoModule); }
ArkTS层使用TaskPool创建子线程,通过preload接口调用Native侧的Preload接口,实现在TaskPool子线程中加载.so库,导出preloadSOByTaskPool函数。 在Ability的onCreate生命周期函数中,调用preloadSOByTaskPool开启子线程,完成so库的预加载。源码参考:[TaskPool.ets]
/** Copyright (c) 2024 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import { taskpool } from '@kit.ArkTS';
import { BusinessError } from '@kit.BasicServicesKit';
import napi from 'libpreloadso.so';
import Constants from './Constants';
import { Logger } from './Logger';/*** Enable the taskpool subthread to preload .so files.* @param* @returns string[] Loaded so library.*/
@Concurrent
function preloadSO(): string[] {return napi.preload(Constants.LIBRARY_PATH_ARRAY);
}/*** Starts the taskpool sub-thread.* @param* @returns Promise<string[]> Asynchronously return the loaded so library.*/
export function preloadSOByTaskPool(): void {// Use new taskpool.Task () to create a task item and input the task execution function and required parameters.const task: taskpool.Task = new taskpool.Task(preloadSO);try {// Use taskpool.execute to put the function to be executed into the internal task queue of TaskPool for execution.taskpool.execute(task, taskpool.Priority.HIGH).then((res: Object) => {// Processing after the so library is preloaded.Logger.info('PreloadSOByTaskPool:' + JSON.stringify(res));}).catch((error: BusinessError) => {Logger.error('PreloadSOByTaskPool: execute failed, ' + error.toString());});} catch (err) {Logger.error('PreloadSOByTaskPool: execute failed, ' + (err as BusinessError).toString());}
}
在Native层定义对外接口为getFileList、getRawFileContent、getRawFileDescriptor,映射C++接口分别为GetFileList、GetRawFileContent、GetRawFileDescriptor。 通过获取Js的资源对象,并转为Native的资源对象,即可调用资源的Native接口,获取rawfile列表、rawfile文件内容以及rawfile描述符{fd, offset, length}。 在Js侧导入"libentry.so",通过getContext().resourceManager获取资源管理对象。调用src/main/cpp/types/libentry/index.d.ts中声明的接口,传入js的资源对象和相关参数获取对于rawfile相关资源信息。 源码参考:[rawfile_demo.cpp] 。
/** Copyright (c) 2024 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#include <js_native_api.h>
#include <js_native_api_types.h>
#include <vector>
#include "napi/native_api.h"
#include "rawfile/raw_file_manager.h"
#include "rawfile/raw_file.h"
#include "rawfile/raw_dir.h"
#include "hilog/log.h"const int GLOBAL_RESMGR = 0xFF00;
const char *TAG = "[Sample_rawfile]";
static napi_value GetFileList(napi_env env, napi_callback_info info) {OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "GetFileList Begin");size_t argc = 2;napi_value argv[2] = {nullptr};napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);napi_valuetype valueType;napi_typeof(env, argv[0], &valueType);NativeResourceManager *mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, argv[0]);size_t strSize;char strBuf[256];napi_get_value_string_utf8(env, argv[1], strBuf, sizeof(strBuf), &strSize);std::string filename(strBuf, strSize);RawDir *rawDir = OH_ResourceManager_OpenRawDir(mNativeResMgr, filename.c_str());int count = OH_ResourceManager_GetRawFileCount(rawDir);std::vector<std::string> tempArray;for (int i = 0; i < count; i++) {std::string filename = OH_ResourceManager_GetRawFileName(rawDir, i);tempArray.emplace_back(filename);}napi_value fileList;napi_create_array(env, &fileList);for (size_t i = 0; i < tempArray.size(); i++) {napi_value jsString;napi_create_string_utf8(env, tempArray[i].c_str(), NAPI_AUTO_LENGTH, &jsString);napi_set_element(env, fileList, i, jsString);}OH_ResourceManager_CloseRawDir(rawDir);OH_ResourceManager_ReleaseNativeResourceManager(mNativeResMgr);return fileList;
}namespace {
napi_value CreateJsArrayValue(napi_env env, std::unique_ptr<uint8_t[]> &data, long length) {napi_value buffer;napi_status status = napi_create_external_arraybuffer(env, data.get(), length, [](napi_env env, void *data, void *hint) { delete[] static_cast<char *>(data); },nullptr, &buffer);if (status != napi_ok) {OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Failed to create external array buffer");return nullptr;}napi_value result = nullptr;status = napi_create_typedarray(env, napi_uint8_array, length, buffer, 0, &result);if (status != napi_ok) {OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Failed to create media typed array");return nullptr;}data.release();return result;
}
} // namespacestatic napi_value GetRawFileContent(napi_env env, napi_callback_info info) {OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "GetFileContent Begin");size_t argc = 2;napi_value argv[2] = {nullptr};napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);napi_valuetype valueType;napi_typeof(env, argv[0], &valueType);NativeResourceManager *mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, argv[0]);size_t strSize;char strBuf[256];napi_get_value_string_utf8(env, argv[1], strBuf, sizeof(strBuf), &strSize);std::string filename(strBuf, strSize);RawFile *rawFile = OH_ResourceManager_OpenRawFile(mNativeResMgr, filename.c_str());if (rawFile != nullptr) {OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "OH_ResourceManager_OpenRawFile success");}long len = OH_ResourceManager_GetRawFileSize(rawFile);std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t[]>(len);int res = OH_ResourceManager_ReadRawFile(rawFile, data.get(), len);OH_ResourceManager_CloseRawFile(rawFile);OH_ResourceManager_ReleaseNativeResourceManager(mNativeResMgr);return CreateJsArrayValue(env, data, len);
}namespace {
napi_value createJsFileDescriptor(napi_env env, RawFileDescriptor &descriptor) {napi_value result;napi_status status = napi_create_object(env, &result);if (status != napi_ok) {return result;}napi_value fd;status = napi_create_int32(env, descriptor.fd, &fd);if (status != napi_ok) {return result;}status = napi_set_named_property(env, result, "fd", fd);if (status != napi_ok) {return result;}napi_value offset;status = napi_create_int64(env, descriptor.start, &offset);if (status != napi_ok) {return result;}status = napi_set_named_property(env, result, "offset", offset);if (status != napi_ok) {return result;}napi_value length;status = napi_create_int64(env, descriptor.length, &length);if (status != napi_ok) {return result;}status = napi_set_named_property(env, result, "length", length);if (status != napi_ok) {return result;}return result;
}
} // namespacestatic napi_value GetRawFileDescriptor(napi_env env, napi_callback_info info) {OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "GetRawFileDescriptor Begin");size_t argc = 2;napi_value argv[2] = {nullptr};napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);napi_valuetype valueType;napi_typeof(env, argv[0], &valueType);NativeResourceManager *mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, argv[0]);size_t strSize;char strBuf[256];napi_get_value_string_utf8(env, argv[1], strBuf, sizeof(strBuf), &strSize);std::string filename(strBuf, strSize);RawFile *rawFile = OH_ResourceManager_OpenRawFile(mNativeResMgr, filename.c_str());if (rawFile != nullptr) {OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "OH_ResourceManager_OpenRawFile success");}RawFileDescriptor descriptor;OH_ResourceManager_GetRawFileDescriptor(rawFile, descriptor);OH_ResourceManager_CloseRawFile(rawFile);OH_ResourceManager_ReleaseNativeResourceManager(mNativeResMgr);return createJsFileDescriptor(env, descriptor);
}EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {napi_property_descriptor desc[] = {{"getFileList", nullptr, GetFileList, nullptr, nullptr, nullptr, napi_default, nullptr},{"getRawFileContent", nullptr, GetRawFileContent, nullptr, nullptr, nullptr, napi_default, nullptr},{"getRawFileDescriptor", nullptr, GetRawFileDescriptor, nullptr, nullptr, nullptr, napi_default, nullptr}};napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);return exports;
}
EXTERN_C_ENDstatic napi_module demoModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = Init,.nm_modname = "entry",.nm_priv = ((void *)0),.reserved = {0},
};extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
涉及到的相关接口:
接口名 | 描述 |
---|---|
初始化native resource manager。 | NativeResourceManager *OH_ResourceManager_InitNativeResourceManager(napi_env env, napi_value jsResMgr) |
打开指定rawfile目录。 | RawDir *OH_ResourceManager_OpenRawDir(const NativeResourceManager *mgr, const char *dirName) |
获取指定rawfile目录下的rawfile文件数量。 | int OH_ResourceManager_GetRawFileCount(RawDir *rawDir) |
获取rawfile名字。 | const char *OH_ResourceManager_GetRawFileName(RawDir *rawDir, int index) |
打开指定rawfile文件。 | RawFile *OH_ResourceManager_OpenRawFile(const NativeResourceManager *mgr, const char *fileName) |
获取rawfile文件大小。 | long OH_ResourceManager_GetRawFileSize(RawFile *rawFile) |
读取rawfile文件内容。 | int OH_ResourceManager_ReadRawFile(const RawFile *rawFile, void *buf, size_t length) |
释放rawfile文件相关资源。 | void OH_ResourceManager_CloseRawFile(RawFile *rawFile) |
释放rawfile目录相关资源。 | void OH_ResourceManager_CloseRawDir(RawDir *rawDir) |
获取rawfile的fd。 | bool OH_ResourceManager_GetRawFileDescriptor(const RawFile *rawFile, RawFileDescriptor &descriptor) |
释放native resource manager相关资源。 | void OH_ResourceManager_ReleaseNativeResourceManager(NativeResourceManager *resMgr) |
以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下:
内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!
鸿蒙【北向应用开发+南向系统层开发】文档
鸿蒙【基础+实战项目】视频
鸿蒙面经
为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!