bundleMgrHelp

Signed-off-by: ZhangLiang <zhangliang335@h-partners.com>
Change-Id: I939342427adde843812bac847ad42a860787bd1c
This commit is contained in:
ZhangLiang 2024-10-15 03:49:30 +00:00
parent b913d90e8e
commit 8980628f60
10 changed files with 509 additions and 3 deletions

View File

@ -15,6 +15,12 @@
import("//build/ohos.gni")
group("vulkan_loader_test") {
testonly = true
public_deps = [ "openharmony/test:test" ]
}
# Vulkan loader build options
## Build libvulkan.so {{{
@ -30,6 +36,7 @@ config("vulkan_internal_config") {
"-Wno-unused-variable",
"-fPIC",
]
cflags_cc = [ "-std=c++17" ]
ldflags = [ "-Wl,-Bsymbolic" ]
defines += [
@ -86,13 +93,21 @@ ohos_shared_library("vulkan_loader") {
"loader/vk_loader_platform.h",
"loader/wsi.c",
"loader/wsi.h",
"openharmony/bundle_mgr_helper/vk_bundle_mgr_helper.cpp",
"openharmony/bundle_mgr_helper/vk_bundle_mgr_helper.h",
"openharmony/loader_hilog.h",
]
configs = [ ":vulkan_internal_config" ]
public_configs = [ ":vulkan_loader_config" ]
external_deps = [
"bundle_framework:appexecfwk_base",
"bundle_framework:appexecfwk_core",
"c_utils:utils",
"hilog:libhilog",
"init:libbegetutil",
"ipc:ipc_core",
"samgr:samgr_proxy",
]
public_external_deps = [ "vulkan-headers:vulkan_headers" ]

View File

@ -61,6 +61,71 @@ Vulkan Layer属于增强Vulkan开发环境的扩展功能可以由开发人
在OpenHarmony上Vulkan-Loader通过读取指定路径下的Layer的**json清单文件**加载Vulkan Layer。
### user mode下加载自定义layer使用指南
1. layer对应json文件和so文件放置
1. json文件放置位置 entry\src\main\resources\rawfile\layerName.json
2. so文件放置位置 entry\libs\arm64-v8a\libLayerName.so
2. json文件指定so文件位置
引入包管理后json文件中的library_path支持使用相对路径即将library_path修改为 libLayerName.so
同时兼容现有的library_path写绝对路径的方式即library_path为 /data/storage/el1/bundle/lib/arm64/libLayerName.so
3. 拷贝json文件至沙箱路径
由于当前loader无法直接从hap包中获取rawfile路径下文件因此需要hap工程手动复制json文件到沙箱中
在entry\src\main\ets\pages\Index.ets文件中引入@ohos.file.fs 并在aboutToAppear() 中写入复制方法,如下:
``` Java
// 在Index.ets文件中
import fs from '@ohos.file.fs';
// ......
aboutToAppear(): void { // Copy layerName.json to hap sandbox
let path = getContext(this).filesDir;
if (!fs.accessSync(path)) {
fs.mkdirSync(path);
}
buffer = getContext(this).resourceManager.getRawFileContentSync('layerName.json');
file = fs.openSync(path + '/layerName.json', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.writeSync(file.fd, buffer.buffer);
}
```
4. 设置环境变量
开启时设置环境变量
hdc shell param set debug.graphic.debug_layer layerName (应与json的名字保持一致:xxxxx.json)
hdc shell param set debug.graphic.debug_hap hapName (应于hap包名保持一致)
关闭时清空两个环境变量
hdc shell param set debug.graphic.debug_layer '' (设置成空字符)
hdc shell param set debug.graphic.debug_hap '' (设置成空字符)
5. 异常排查方法
1. 检查json文件位置是否正常
hap工程路径 \entry\src\main\resources\rawfile\layerName.json
hdc shell路径 /data/app/el2/100/base/{your_pakage_name}/file/layerName.json
应用视角下json文件的路径 /data/storage/el2/base/haps/entry/files/layerName.json
2. 检查so文件位置是否正常
hap工程路径: \entry\libs\arm64-v8a\libLayerName.so
hdc shell路径 /data/app/el1/bundle/public/{your_pakage_name}/libs/arm64/libLayerName.so
应用视角下json文件的路径 /data/storage/el1/bundle/libs/arm64/libLayerName.so
3. 抓取异常日志
```
hdc shell
hilog -b X
hilog -b D -D D001405
hilog |grep -i VulkanLoader
```
6. 进入应用视角
在调试过程中,如果权限不对或文件不存在,开发者需要从调试进程视角切换为应用视角,以便直观分析权限及文件目录问题。视角切换命令如下:
```
hdc shell // 进入shell
ps -ef|grep [hapName] // 通过ps命令找到对应应用的pid
nsenter -t [hapPid] -m /bin/sh // 通过上一步找到的应用pid进入对应应用的沙箱环境中
hdc shell // 进入shell
ps -ef|grep [hapName] // 通过ps命令找到对应应用的pid
nsenter -t [hapPid] -m /bin/sh // 通过上一步找到的应用pid进入对应应用的沙箱环境中
```
执行完成后,即切换到了应用视角,该视角下的目录路径为应用沙箱路径,可以去排查沙箱路径相关问题。
### 指定的扫描路径
```

View File

@ -17,6 +17,10 @@
"ram": "10000KB",
"deps": {
"components": [
"bundle_framework",
"c_utils",
"samgr",
"ipc",
"hilog",
"init"
],

View File

@ -3023,7 +3023,7 @@ VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enu
char *debug_layer_json_path = NULL;
bool currentProcessEnableDebugLayer = false;
if(NULL != debug_hap_name && '\0' != debug_hap_name[0] && NULL != debug_layer_name && '\0' != debug_layer_name[0]){
if (NULL != debug_layer_name && '\0' != debug_layer_name[0] && InitBundleInfo(debug_hap_name)) {
currentProcessEnableDebugLayer = true;
debug_layer_json_path = loader_secure_getenv("debug.graphic.vklayer_json_path",inst);
if (NULL == debug_layer_json_path || '\0' == debug_layer_json_path[0]){
@ -3039,6 +3039,7 @@ VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enu
strncat(debug_layer_json_path,debug_layer_name,debug_layer_json_path_len);
strncat(debug_layer_json_path,json_suffix,debug_layer_json_path_len);
}
loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "OHOS:: debug_layer_json_path: %s", debug_layer_json_path);
}
#endif
@ -4151,13 +4152,67 @@ struct loader_instance *loader_get_instance(const VkInstance instance) {
}
loader_platform_dl_handle loader_open_layer_file(const struct loader_instance *inst, struct loader_layer_properties *prop) {
if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) == NULL) {
char* libPath = prop->lib_name;
#if defined(__OHOS__)
char *debug_layer_name = loader_secure_getenv("debug.graphic.debug_layer", inst);
char *debug_hap_name = loader_secure_getenv("debug.graphic.debug_hap", inst);
bool isDebugLayer = false;
char* debugLayerLibPath = NULL;
if (NULL != debug_layer_name && '\0' != debug_layer_name[0] && InitBundleInfo(debug_hap_name)) {
const char lib_prefix[] = "lib";
const char so_suffix[] = ".so";
size_t totalLen = strlen(debug_layer_name) + strlen(lib_prefix) + strlen(so_suffix) + 1;
char* layerSoName = loader_instance_heap_calloc(inst, totalLen, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
if (layerSoName == NULL) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, "malloc layerSoName fail");
goto mallocErr;
}
strncpy(layerSoName, lib_prefix, totalLen);
strncat(layerSoName, debug_layer_name, totalLen);
strncat(layerSoName, so_suffix, totalLen);
if (strcmp(layerSoName, libPath) == 0) {
isDebugLayer = true;
debugLayerLibPath = GetDebugLayerLibPath(inst, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
if(debugLayerLibPath == NULL) {
loader_instance_heap_free(inst, layerSoName);
isDebugLayer = false;
goto mallocErr;
}
size_t totalLength = strlen(libPath) + strlen(debugLayerLibPath) + 1;
libPath = loader_instance_heap_calloc(inst, totalLength, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
if (libPath == NULL) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, "malloc libPath fail");
loader_instance_heap_free(inst, layerSoName);
loader_instance_heap_free(inst, debugLayerLibPath);
libPath = prop->lib_name;
isDebugLayer = false;
goto mallocErr;
}
strncpy(libPath, debugLayerLibPath, totalLength);
strncat(libPath, prop->lib_name, totalLength);
} else {
loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, "layerSoName != libPath : %s != %s",
layerSoName, libPath);
}
loader_instance_heap_free(inst, layerSoName);
}
mallocErr:
loader_free_getenv(debug_layer_name, inst);
loader_free_getenv(debug_hap_name, inst);
#endif
loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT, 0, "try to open libPath: %s", libPath);
if ((prop->lib_handle = loader_platform_open_library(libPath)) == NULL) {
loader_handle_load_library_error(inst, prop->lib_name, &prop->lib_status);
} else {
prop->lib_status = LOADER_LAYER_LIB_SUCCESS_LOADED;
loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Loading layer library %s", prop->lib_name);
}
#if defined(__OHOS__)
if (isDebugLayer) {
loader_instance_heap_free(inst, debugLayerLibPath);
loader_instance_heap_free(inst, libPath);
}
#endif
return prop->lib_handle;
}

View File

@ -31,6 +31,7 @@
#include "loader_common.h"
#include "cJSON.h"
#include "bundle_mgr_helper/vk_bundle_mgr_helper.h"
// Declare the once_init variable
LOADER_PLATFORM_THREAD_ONCE_EXTERN_DEFINITION(once_init)

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.. All rights reserved.
* 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 "vk_bundle_mgr_helper.h"
#include "iservice_registry.h"
#include "system_ability_definition.h"
#include "../loader_hilog.h"
#include <securec.h>
#define EOK 0
extern "C" {
void *loader_instance_heap_calloc(const struct loader_instance *instance, size_t size, VkSystemAllocationScope allocation_scope);
}
constexpr const char *DEBUG_SANDBOX_DIR = "/data/storage/el1/bundle/";
bool InitBundleInfo(char* debugHapName)
{
if (NULL == debugHapName || '\0' == debugHapName[0]) {
VKHILOGE("debug_hap_name is NULL!");
return false;
}
std::string debugHap(debugHapName);
auto vkBundleMgrHelper = OHOS::DelayedSingleton<OHOS::AppExecFwk::VKBundleMgrHelper>::GetInstance();
if (vkBundleMgrHelper == nullptr) {
VKHILOGE("vkBundleMgrHelper is null!");
return false;
}
if (vkBundleMgrHelper->GetBundleInfoForSelf(
OHOS::AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_APPLICATION, vkBundleMgrHelper->g_bundleInfo) ==
OHOS::ERR_OK) {
if (vkBundleMgrHelper->g_bundleInfo.name == debugHap) {
return true;
} else {
VKHILOGE("this hap is %{public}s, the debug hap is %{public}s",
vkBundleMgrHelper->g_bundleInfo.name.c_str(), debugHap.c_str());
}
} else {
VKHILOGE("Call GetBundleInfoForSelf func failed!");
}
return false;
}
char* GetDebugLayerLibPath(const struct loader_instance *inst, VkSystemAllocationScope allocation_sacope)
{
auto vkBundleMgrHelper = OHOS::DelayedSingleton<OHOS::AppExecFwk::VKBundleMgrHelper>::GetInstance();
std::string pathStr(DEBUG_SANDBOX_DIR);
std::string appLibPath = pathStr + vkBundleMgrHelper->g_bundleInfo.applicationInfo.nativeLibraryPath + "/";
const char* fullPath = appLibPath.c_str();
size_t len = strlen(fullPath) + 1;
char* libPath = static_cast<char*>(loader_instance_heap_calloc(inst, len, allocation_sacope));
if (libPath == NULL) {
VKHILOGE("malloc libPath fail");
return NULL;
}
if (memcpy_s(libPath, len, fullPath, len) != EOK) {
VKHILOGE("memcpy_s libPath fail, fullPath: %{public}s", fullPath);
return NULL;
}
VKHILOGD("GetDebugLayerLibPath(): the libPath is %{public}s", libPath);
return libPath;
}
namespace OHOS {
namespace AppExecFwk {
VKBundleMgrHelper::VKBundleMgrHelper() {}
VKBundleMgrHelper::~VKBundleMgrHelper()
{
if (bundleMgr_ != nullptr && bundleMgr_->AsObject() != nullptr && deathRecipient_ != nullptr) {
bundleMgr_->AsObject()->RemoveDeathRecipient(deathRecipient_);
}
}
sptr<AppExecFwk::IBundleMgr> VKBundleMgrHelper::Connect()
{
VKHILOGD("Call VKBundleMgrHelper::Connect");
std::lock_guard<std::mutex> lock(mutex_);
if (bundleMgr_ == nullptr) {
sptr<ISystemAbilityManager> systemAbilityManager =
SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (systemAbilityManager == nullptr) {
VKHILOGE("Failed to get system ability manager.");
return nullptr;
}
sptr<IRemoteObject> remoteObject_ = systemAbilityManager->GetSystemAbility(
BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
if (remoteObject_ == nullptr || (bundleMgr_ = iface_cast<IBundleMgr>(remoteObject_)) == nullptr) {
VKHILOGE("Failed to get bundle mgr service remote object");
return nullptr;
}
std::weak_ptr<VKBundleMgrHelper> weakPtr = shared_from_this();
auto deathCallback = [weakPtr](const wptr<IRemoteObject> &object) {
auto sharedPtr = weakPtr.lock();
if (sharedPtr == nullptr) {
VKHILOGE("Bundle helper instance is nullptr");
return;
}
sharedPtr->OnDeath();
};
deathRecipient_ = new(std::nothrow) VKBundleMgrServiceDeathRecipient(deathCallback);
if (deathRecipient_ == nullptr) {
VKHILOGE("Failed to create death recipient ptr deathRecipient_!");
return nullptr;
}
if (bundleMgr_->AsObject() != nullptr) {
bundleMgr_->AsObject()->AddDeathRecipient(deathRecipient_);
}
}
return bundleMgr_;
}
void VKBundleMgrHelper::OnDeath()
{
VKHILOGD("Call VKBundleMgrHelper::OnDeath");
std::lock_guard<std::mutex> lock(mutex_);
if (bundleMgr_ == nullptr || bundleMgr_->AsObject() == nullptr) {
VKHILOGE("bundleMgr_ is nullptr!");
return;
}
bundleMgr_->AsObject()->RemoveDeathRecipient(deathRecipient_);
bundleMgr_ = nullptr;
}
ErrCode VKBundleMgrHelper::GetBundleInfoForSelf(AppExecFwk::GetBundleInfoFlag flags, BundleInfo &bundleInfo)
{
VKHILOGD("Call VKBundleMgrHealper::GetBundleInfoForSelf.");
auto bundleMgr_ = Connect();
if (bundleMgr_ == nullptr) {
VKHILOGE("Failed to connect.");
return -1;
}
return bundleMgr_->GetBundleInfoForSelf(static_cast<int32_t>(flags), bundleInfo);
}
VKBundleMgrServiceDeathRecipient::VKBundleMgrServiceDeathRecipient(
const std::function<void(const wptr<IRemoteObject>& object)>& deathCallback)
: deathCallback_(deathCallback) {}
void VKBundleMgrServiceDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& object)
{
if (deathCallback_ != nullptr) {
deathCallback_(object);
}
}
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.. All rights reserved.
* 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 "vulkan/vulkan_core.h"
#ifdef __cplusplus
#include <singleton.h>
#include "bundle_mgr_interface.h"
extern "C" {
#endif // __cplusplus
bool InitBundleInfo(char* debugHapName);
char* GetDebugLayerLibPath(const struct loader_instance *inst, VkSystemAllocationScope allocation_sacope);
#ifdef __cplusplus
}
namespace OHOS {
namespace AppExecFwk {
class VKBundleMgrHelper : public std::enable_shared_from_this<VKBundleMgrHelper> {
public:
DISALLOW_COPY_AND_MOVE(VKBundleMgrHelper);
BundleInfo g_bundleInfo;
ErrCode GetBundleInfoForSelf(AppExecFwk::GetBundleInfoFlag flags, BundleInfo& bundleInfo);
private:
sptr<AppExecFwk::IBundleMgr> Connect();
void OnDeath();
private:
DECLARE_DELAYED_SINGLETON(VKBundleMgrHelper);
std::mutex mutex_;
sptr<AppExecFwk::IBundleMgr> bundleMgr_;
sptr<IRemoteObject::DeathRecipient> deathRecipient_ = nullptr;
};
class VKBundleMgrServiceDeathRecipient : public IRemoteObject::DeathRecipient {
public:
explicit VKBundleMgrServiceDeathRecipient(
const std::function<void(const wptr<IRemoteObject>& object)>& deathCallback);
DISALLOW_COPY_AND_MOVE(VKBundleMgrServiceDeathRecipient);
virtual ~VKBundleMgrServiceDeathRecipient() = default;
void OnRemoteDied(const wptr<IRemoteObject>& object) override;
private:
std::function<void (const wptr<IRemoteObject>& object)> deathCallback_;
};
}
}
#endif // __cplusplus

18
openharmony/test/BUILD.gn Normal file
View File

@ -0,0 +1,18 @@
# Copyright (c) 2023 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.
group("test") {
testonly = true
deps = [ "unittest:unittest" ]
}

View File

@ -0,0 +1,66 @@
# Copyright (c) 2023 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("//build/test.gni")
module_out_path = "thirdparty/vulkan-loader"
group("unittest") {
testonly = true
deps = [ ":vk_bundle_mgr_helper_test" ]
}
ohos_unittest("vk_bundle_mgr_helper_test") {
module_out_path = module_out_path
sources = [ "vk_bundle_mgr_helper_tests.cpp" ]
deps = [ ":vk_bundle_mgr_helper_test_common" ]
external_deps = [
"bundle_framework:appexecfwk_base",
"bundle_framework:appexecfwk_core",
"c_utils:utils",
"ipc:ipc_core",
"samgr:samgr_proxy",
]
}
ohos_static_library("vk_bundle_mgr_helper_test_common") {
visibility = [ ":*" ]
testonly = true
public_configs = [ ":vk_bundle_mgr_helper_test_common_public_config" ]
public_deps = [
"//third_party/googletest:gtest_main",
"//third_party/vulkan-loader:vulkan_loader",
]
external_deps = [
"c_utils:utils",
"hilog:libhilog",
]
subsystem_name = "bundle_info"
part_name = "vulkan-loader-bundle"
}
config("vk_bundle_mgr_helper_test_common_public_config") {
include_dirs = [ "vk_bundle_mgr_helper_tests.cpp" ]
cflags = [
"-Wall",
"-Werror",
"-g3",
"-Dprivate=public",
"-Dprotected=public",
]
}

View File

@ -0,0 +1,60 @@
/*
* 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, Hardware
* 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 <gtest/gtest.h>
#include "bundle_mgr_helper/vk_bundle_mgr_helper.h"
using namespace testing;
using namespace testing::ext;
namespace OHOS::Rosen {
class VkBundleMgrHelperTest : public testing::Test {
public:
static void SetUpTestCase() {}
static void TearDownTestCase() {}
void SetUp() {}
void TearDown() {}
};
/**
* @tc.name: Init001
* @tc.desc:
* @tc.type: FUNC
*/
HWTEST_F(VkBundleMgrHelperTest, VkBundleMgrHelperTest, Level1)
{
AppExecFwk::BundleInfo bundleInfo;
auto vkBundleMgrHelper = DelayedSingleton<AppExecFwk::VKBundleMgrHelper>::GetInstance();
auto result = vkBundleMgrHelper->GetBundleInfoForSelf(
AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_APPLICATION, bundleInfo);
EXPECT_NE(result, ERR_OK);
bool ret = InitBundleInfo(NULL);
EXPECT_EQ(ret, false);
string name = "\0";
ret = InitBundleInfo(const_cast<char*>(name.c_str()));
EXPECT_EQ(ret, false);
string fatalName = "randomFatalName";
ret = InitBundleInfo(const_cast<char*>(fatalName.c_str()));
EXPECT_EQ(ret, false);
ret = InitBundleInfo((const_cast<char*>(bundleInfo.name.c_str())));
EXPECT_EQ(ret, false);
char* path = GetDebugLayerLibPath();
EXPECT_NE(path, nullptr);
free(path);
}
}