* Copyright (c) 2022-2025 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 <regex>
#include "js_module_reader.h"
#include "bundle_info.h"
#include "bundle_mgr_helper.h"
#include "bundle_mgr_proxy.h"
#include "file_path_utils.h"
#include "hilog_tag_wrapper.h"
#include "hitrace_meter.h"
#include "iservice_registry.h"
#include "js_runtime_utils.h"
#include "singleton.h"
#include "system_ability_definition.h"
using namespace OHOS::AbilityBase;
namespace OHOS {
namespace AbilityRuntime {
using IBundleMgr = AppExecFwk::IBundleMgr;
JsModuleReader::JsModuleReader(const std::string& bundleName, const std::string& hapPath, bool isFormRender)
: JsModuleSearcher(bundleName), isFormRender_(isFormRender)
{
if (!hapPath.empty() && hapPath.find(std::string(ABS_DATA_CODE_PATH)) != 0) {
isSystemPath_ = true;
} else {
isSystemPath_ = false;
}
}
bool JsModuleReader::operator()(const std::string& inputPath, uint8_t **buff,
size_t *buffSize, std::string& errorMsg) const
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called start: %{private}s", inputPath.c_str());
std::string connector = "##";
std::string traceName = __PRETTY_FUNCTION__ + connector + inputPath;
HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, traceName);
if (inputPath.empty() || buff == nullptr || buffSize == nullptr) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "Invalid param");
return false;
}
bool needFindPluginHsp = true;
auto realHapPath = GetAppHspPath(inputPath, needFindPluginHsp, errorMsg);
TAG_LOGD(AAFwkTag::JSRUNTIME, "GetAppHspPath: %{public}d, inputPath: %{private}s, appHspPath: %{private}s",
!needFindPluginHsp, inputPath.c_str(), realHapPath.c_str());
if (realHapPath.empty()) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "empty appHspPath");
return false;
}
if (needFindPluginHsp) {
realHapPath = GetPluginHspPath(inputPath);
if (realHapPath.empty()) {
if (errorMsg.empty()) {
errorMsg = "get plugin hspPath failed, please check the module is correct";
}
TAG_LOGE(AAFwkTag::JSRUNTIME, "empty pluginHspPath");
return false;
}
}
bool newCreate = false;
std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(realHapPath, newCreate);
if (extractor == nullptr) {
errorMsg = "GetExtractor failed, please check " + realHapPath;
TAG_LOGE(AAFwkTag::JSRUNTIME, "realHapPath %{private}s GetExtractor failed", realHapPath.c_str());
return false;
}
auto data = extractor->GetSafeData(MERGE_ABC_PATH);
if (!data) {
errorMsg = "getData failed, please check " + realHapPath;
TAG_LOGE(AAFwkTag::JSRUNTIME, "null data");
return false;
}
*buff = data->GetDataPtr();
*buffSize = data->GetDataLen();
return true;
}
std::string JsModuleReader::GetPluginHspPath(const std::string& inputPath) const
{
std::string presetAppHapPath = "";
auto bundleMgrHelper = DelayedSingleton<AppExecFwk::BundleMgrHelper>::GetInstance();
if (bundleMgrHelper == nullptr) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "null bundleMgrHelper");
return presetAppHapPath;
}
std::string moduleName = inputPath.substr(inputPath.find_last_of("/") + 1);
std::string tmpPath = inputPath.substr(inputPath.find_first_of("/") + 1);
const std::string sharedBundleName = tmpPath.substr(0, tmpPath.find_first_of("/"));
TAG_LOGI(AAFwkTag::JSRUNTIME, "moduleName: %{public}s, sharedBundleName: %{public}s",
moduleName.c_str(), sharedBundleName.c_str());
if (moduleName.empty() || sharedBundleName.empty()) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "empty moduleName");
return presetAppHapPath;
}
std::vector<AppExecFwk::PluginBundleInfo> pluginBundleInfos;
if (bundleMgrHelper->GetPluginInfosForSelf(pluginBundleInfos) != ERR_OK) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "GetPluginInfosForSelf failed");
return presetAppHapPath;
}
for (auto &pluginBundleInfo : pluginBundleInfos) {
for (auto &pluginModuleInfo : pluginBundleInfo.pluginModuleInfos) {
if (moduleName == pluginModuleInfo.moduleName
&& sharedBundleName == pluginBundleInfo.pluginBundleName) {
presetAppHapPath = pluginModuleInfo.hapPath;
TAG_LOGD(AAFwkTag::JSRUNTIME, "presetAppHapPath %{public}s", presetAppHapPath.c_str());
std::regex pattern(std::string(ABS_DATA_CODE_PATH) + bundleName_ + "/");
presetAppHapPath = std::regex_replace(
presetAppHapPath, pattern, std::string(ABS_CODE_PATH) + std::string(BUNDLE));
TAG_LOGD(AAFwkTag::JSRUNTIME, "presetAppHapPath %{public}s", presetAppHapPath.c_str());
return presetAppHapPath;
}
}
}
TAG_LOGE(AAFwkTag::JSRUNTIME, "GetPluginHspPath failed");
return presetAppHapPath;
}
std::string JsModuleReader::GetAppHspPath(const std::string& inputPath,
bool& needFindPluginHsp, std::string& errorMsg) const
{
if (isFormRender_) {
return GetFormAppHspPath(inputPath, needFindPluginHsp, errorMsg);
}
return GetCommonAppHspPath(inputPath, needFindPluginHsp, errorMsg);
}
std::string JsModuleReader::GetFormAppHspPath(const std::string& inputPath,
bool& needFindPluginHsp, std::string& errorMsg) const
{
std::string realHapPath;
std::string suffix = std::string(SHARED_FILE_SUFFIX);
realHapPath.append("/data/bundles/")
.append(bundleName_).append("/")
.append(GetModuleName(inputPath))
.append(SHARED_FILE_SUFFIX);
TAG_LOGI(AAFwkTag::JSRUNTIME, "realHapPath: %{private}s", realHapPath.c_str());
if (realHapPath.empty() ||
realHapPath.length() < suffix.length() ||
realHapPath.compare(realHapPath.length() - suffix.length(), suffix.length(), suffix) != 0) {
errorMsg = "Get form HspPath failed: invalid path or suffix";
TAG_LOGE(AAFwkTag::JSRUNTIME, "obtain realHapPath failed");
return realHapPath;
}
needFindPluginHsp = false;
return realHapPath;
}
std::string JsModuleReader::GetModuleName(const std::string& inputPath) const
{
return inputPath.substr(inputPath.find_last_of("/") + 1);
}
std::string JsModuleReader::GetCommonAppHspPath(const std::string& inputPath,
bool& needFindPluginHsp, std::string& errorMsg) const
{
std::string suffix = std::string(SHARED_FILE_SUFFIX);
std::string realHapPath = GetPresetAppHapPath(inputPath, bundleName_, needFindPluginHsp, errorMsg);
if (needFindPluginHsp && errorMsg.empty()) {
if (inputPath.find_first_of("/") == inputPath.find_last_of("/")) {
errorMsg = "Get in-app HspPath failed, please check the module is correct";
} else {
errorMsg = "Get shared HspPath failed, please check the module is correct";
}
}
if ((realHapPath.find(ABS_DATA_CODE_PATH) == 0) || (realHapPath == inputPath)) {
realHapPath = std::string(ABS_CODE_PATH) + inputPath + suffix;
}
TAG_LOGD(AAFwkTag::JSRUNTIME, "realHapPath: %{private}s", realHapPath.c_str());
if (realHapPath.empty() ||
realHapPath.length() < suffix.length() ||
realHapPath.compare(realHapPath.length() - suffix.length(), suffix.length(), suffix) != 0) {
errorMsg = "Get HspPath failed: invalid path or suffix";
TAG_LOGE(AAFwkTag::JSRUNTIME, "obtain realHapPath failed");
return realHapPath;
}
return realHapPath;
}
std::string JsModuleReader::GetOtherHspPath(const std::string& bundleName, const std::string& moduleName,
const std::string& inputPath, bool& needFindPluginHsp, std::string& errorMsg)
{
std::string presetAppHapPath = inputPath;
auto bundleMgrHelper = DelayedSingleton<AppExecFwk::BundleMgrHelper>::GetInstance();
if (bundleMgrHelper == nullptr) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "null bundleMgrHelper");
return presetAppHapPath;
}
std::vector<AppExecFwk::BaseSharedBundleInfo> baseSharedBundleInfos;
if (bundleMgrHelper->GetBaseSharedBundleInfos(bundleName, baseSharedBundleInfos) != 0) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "GetBaseSharedBundleInfos failed");
return presetAppHapPath;
}
std::string tmpPath = inputPath.substr(inputPath.find_first_of("/") + 1);
const std::string sharedBundleName = tmpPath.substr(0, tmpPath.find_first_of("/"));
for (const auto &info : baseSharedBundleInfos) {
if ((info.bundleName == sharedBundleName) && (info.moduleName == moduleName)) {
presetAppHapPath = info.hapPath;
needFindPluginHsp = false;
break;
}
}
AppExecFwk::BundleInfo bundleInfo;
int32_t ret = bundleMgrHelper->GetDependentBundleInfo(sharedBundleName, bundleInfo,
AppExecFwk::GetDependentBundleInfoFlag::GET_APP_SERVICE_HSP_BUNDLE_INFO);
if (ret != ERR_OK) {
TAG_LOGW(AAFwkTag::JSRUNTIME, "GetDependentBundleInfo failed");
return presetAppHapPath;
}
for (const auto &info : bundleInfo.hapModuleInfos) {
if (info.moduleName == moduleName) {
presetAppHapPath = info.hapPath;
needFindPluginHsp = false;
break;
}
}
return presetAppHapPath;
}
std::string JsModuleReader::GetPresetAppHapPath(const std::string& inputPath, const std::string& bundleName,
bool& needFindPluginHsp, std::string& errorMsg)
{
std::string presetAppHapPath = inputPath;
std::string moduleName = inputPath.substr(inputPath.find_last_of("/") + 1);
if (moduleName.empty()) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "empty moduleName");
return presetAppHapPath;
}
auto bundleMgrHelper = DelayedSingleton<AppExecFwk::BundleMgrHelper>::GetInstance();
if (bundleMgrHelper == nullptr) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "null bundleMgrHelper");
return presetAppHapPath;
}
if (inputPath.find_first_of("/") == inputPath.find_last_of("/")) {
AppExecFwk::AbilityInfo abilityInfo;
abilityInfo.bundleName = bundleName;
abilityInfo.package = moduleName;
AppExecFwk::HapModuleInfo hapModuleInfo;
if (!bundleMgrHelper->GetHapModuleInfo(abilityInfo, hapModuleInfo)) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "GetHapModuleInfo failed");
return presetAppHapPath;
}
presetAppHapPath = hapModuleInfo.hapPath;
needFindPluginHsp = false;
} else {
presetAppHapPath = GetOtherHspPath(bundleName, moduleName, presetAppHapPath, needFindPluginHsp, errorMsg);
}
return presetAppHapPath;
}
void JsModuleReader::GetHapPathList(const std::string &bundleName, std::vector<std::string> &hapList)
{
auto systemAbilityManagerClient = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (!systemAbilityManagerClient) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "null systemAbilityManagerClient");
return;
}
auto remoteObject = systemAbilityManagerClient->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
if (!remoteObject) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "null remoteObject");
return;
}
auto bundleMgrProxy = iface_cast<IBundleMgr>(remoteObject);
AppExecFwk::BundleInfo bundleInfo;
auto getInfoResult = bundleMgrProxy->GetBundleInfoForSelf(static_cast<int32_t>(AppExecFwk::GetBundleInfoFlag::
GET_BUNDLE_INFO_WITH_HAP_MODULE), bundleInfo);
if (getInfoResult != 0 || bundleInfo.hapModuleInfos.empty()) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "GetBundleInfoForSelf failed");
return;
}
for (auto hapModuleInfo : bundleInfo.hapModuleInfos) {
hapList.emplace_back(hapModuleInfo.hapPath);
}
}
}
}