1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "hybrid_js_module_reader.h"
17
18 #include <regex>
19 #include "bundle_info.h"
20 #include "bundle_mgr_helper.h"
21 #include "bundle_mgr_proxy.h"
22 #include "hilog_tag_wrapper.h"
23 #include "hitrace_meter.h"
24 #include "iservice_registry.h"
25 #include "js_runtime_utils.h"
26 #include "singleton.h"
27
28 using namespace OHOS::AbilityBase;
29
30 namespace OHOS {
31 namespace AbilityRuntime {
32 bool HybridJsModuleReader::needFindPluginHsp_ = true;
33
HybridJsModuleReader(const std::string & bundleName,const std::string & hapPath,bool isFormRender)34 HybridJsModuleReader::HybridJsModuleReader(const std::string& bundleName, const std::string& hapPath, bool isFormRender)
35 : JsModuleSearcher(bundleName), isFormRender_(isFormRender)
36 {
37 if (!hapPath.empty() && hapPath.find(std::string(ABS_DATA_CODE_PATH)) != 0) {
38 isSystemPath_ = true;
39 } else {
40 isSystemPath_ = false;
41 }
42 }
43
GetExtractor(const std::string & inputPath,std::string & errorMsg) const44 std::shared_ptr<Extractor> HybridJsModuleReader::GetExtractor(
45 const std::string& inputPath, std::string& errorMsg) const
46 {
47 auto realHapPath = GetAppPath(inputPath, SHARED_FILE_SUFFIX);
48 if (realHapPath.empty()) {
49 TAG_LOGE(AAFwkTag::JSRUNTIME, "empty realHapPath");
50 return nullptr;
51 }
52 if (needFindPluginHsp_) {
53 realHapPath = GetPluginHspPath(inputPath);
54 if (realHapPath.empty()) {
55 TAG_LOGE(AAFwkTag::JSRUNTIME, "empty realHapPath");
56 return nullptr;
57 }
58 needFindPluginHsp_ = true;
59 }
60 bool newCreate = false;
61 std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(realHapPath, newCreate);
62 if (extractor != nullptr) {
63 return extractor;
64 }
65
66 realHapPath = GetAppPath(inputPath, ABILITY_FILE_SUFFIX);
67 if (realHapPath.empty()) {
68 TAG_LOGE(AAFwkTag::JSRUNTIME, "empty realHapPath");
69 return nullptr;
70 }
71 extractor = ExtractorUtil::GetExtractor(realHapPath, newCreate);
72 if (extractor == nullptr) {
73 errorMsg = "hap path error: " + inputPath;
74 TAG_LOGE(AAFwkTag::JSRUNTIME, "inputPath %{private}s GetExtractor failed", inputPath.c_str());
75 return nullptr;
76 }
77 return extractor;
78 }
79
operator ()(const std::string & inputPath,uint8_t ** buff,size_t * buffSize,std::string & errorMsg) const80 bool HybridJsModuleReader::operator()(const std::string& inputPath,
81 uint8_t **buff, size_t *buffSize, std::string& errorMsg) const
82 {
83 TAG_LOGD(AAFwkTag::JSRUNTIME, "called start: %{private}s", inputPath.c_str());
84 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
85 if (inputPath.empty() || buff == nullptr || buffSize == nullptr) {
86 TAG_LOGE(AAFwkTag::JSRUNTIME, "Invalid param");
87 return false;
88 }
89
90 std::shared_ptr<Extractor> extractor = GetExtractor(inputPath, errorMsg);
91 if (extractor == nullptr) {
92 TAG_LOGE(AAFwkTag::JSRUNTIME, "failed to get extractor %{private}s", inputPath.c_str());
93 return false;
94 }
95
96 auto data = extractor->GetSafeData(MERGE_ABC_PATH);
97 if (!data) {
98 TAG_LOGE(AAFwkTag::JSRUNTIME, "null data");
99 return false;
100 }
101
102 *buff = data->GetDataPtr();
103 *buffSize = data->GetDataLen();
104 return true;
105 }
106
GetPluginHspPath(const std::string & inputPath) const107 std::string HybridJsModuleReader::GetPluginHspPath(const std::string& inputPath) const
108 {
109 std::string presetAppHapPath = "";
110 auto bundleMgrHelper = DelayedSingleton<AppExecFwk::BundleMgrHelper>::GetInstance();
111 if (bundleMgrHelper == nullptr) {
112 TAG_LOGE(AAFwkTag::JSRUNTIME, "null bundleMgrHelper");
113 return presetAppHapPath;
114 }
115 std::string moduleName = inputPath.substr(inputPath.find_last_of("/") + 1);
116 std::string tmpPath = inputPath.substr(inputPath.find_first_of("/") + 1);
117 const std::string sharedBundleName = tmpPath.substr(0, tmpPath.find_first_of("/"));
118 TAG_LOGI(AAFwkTag::JSRUNTIME, "moduleName: %{public}s, sharedBundleName: %{public}s",
119 moduleName.c_str(), sharedBundleName.c_str());
120 if (moduleName.empty() || sharedBundleName.empty()) {
121 TAG_LOGE(AAFwkTag::JSRUNTIME, "empty moduleName");
122 return presetAppHapPath;
123 }
124
125 std::vector<AppExecFwk::PluginBundleInfo> pluginBundleInfos;
126 if (bundleMgrHelper->GetPluginInfosForSelf(pluginBundleInfos) != ERR_OK) {
127 TAG_LOGE(AAFwkTag::JSRUNTIME, "GetPluginInfosForSelf failed");
128 return presetAppHapPath;
129 }
130
131 for (auto &pluginBundleInfo : pluginBundleInfos) {
132 for (auto &pluginModuleInfo : pluginBundleInfo.pluginModuleInfos) {
133 if (moduleName == pluginModuleInfo.moduleName
134 && sharedBundleName == pluginBundleInfo.pluginBundleName) {
135 presetAppHapPath = pluginModuleInfo.hapPath;
136 TAG_LOGD(AAFwkTag::JSRUNTIME, "presetAppHapPath %{public}s", presetAppHapPath.c_str());
137 std::regex pattern(std::string(ABS_DATA_CODE_PATH) + bundleName_ + "/");
138 presetAppHapPath = std::regex_replace(
139 presetAppHapPath, pattern, std::string(ABS_CODE_PATH) + std::string(BUNDLE));
140 TAG_LOGD(AAFwkTag::JSRUNTIME, "presetAppHapPath %{public}s", presetAppHapPath.c_str());
141 return presetAppHapPath;
142 }
143 }
144 }
145 TAG_LOGE(AAFwkTag::JSRUNTIME, "GetPluginHspPath failed");
146 return presetAppHapPath;
147 }
148
GetAppPath(const std::string & inputPath,const std::string & suffix) const149 std::string HybridJsModuleReader::GetAppPath(const std::string& inputPath, const std::string& suffix) const
150 {
151 if (isFormRender_) {
152 return GetFormAppPath(inputPath, suffix);
153 }
154 return GetCommonAppPath(inputPath, suffix);
155 }
156
GetFormAppPath(const std::string & inputPath,const std::string & suffix) const157 std::string HybridJsModuleReader::GetFormAppPath(const std::string& inputPath, const std::string& suffix) const
158 {
159 std::string realHapPath;
160 realHapPath.append("/data/bundles/")
161 .append(bundleName_).append("/")
162 .append(GetModuleName(inputPath))
163 .append(SHARED_FILE_SUFFIX);
164
165 TAG_LOGI(AAFwkTag::JSRUNTIME, "realHapPath: %{private}s", realHapPath.c_str());
166 if (realHapPath.empty() ||
167 realHapPath.length() < suffix.length() ||
168 realHapPath.compare(realHapPath.length() - suffix.length(), suffix.length(), suffix) != 0) {
169 TAG_LOGE(AAFwkTag::JSRUNTIME, "obtain realHapPath failed");
170 return realHapPath;
171 }
172 return realHapPath;
173 }
174
GetModuleName(const std::string & inputPath) const175 std::string HybridJsModuleReader::GetModuleName(const std::string& inputPath) const
176 {
177 return inputPath.substr(inputPath.find_last_of("/") + 1);
178 }
179
GetCommonAppPath(const std::string & inputPath,const std::string & suffix) const180 std::string HybridJsModuleReader::GetCommonAppPath(const std::string& inputPath, const std::string& suffix) const
181 {
182 std::string realHapPath = GetPresetAppHapPath(inputPath, bundleName_);
183 if ((realHapPath.find(ABS_DATA_CODE_PATH) == 0) || (realHapPath == inputPath)) {
184 realHapPath = std::string(ABS_CODE_PATH) + inputPath + suffix;
185 }
186
187 TAG_LOGD(AAFwkTag::JSRUNTIME, "realHapPath: %{private}s", realHapPath.c_str());
188 if (realHapPath.empty() ||
189 realHapPath.length() < suffix.length() ||
190 realHapPath.compare(realHapPath.length() - suffix.length(), suffix.length(), suffix) != 0) {
191 TAG_LOGE(AAFwkTag::JSRUNTIME, "obtain realHapPath failed");
192 return realHapPath;
193 }
194 return realHapPath;
195 }
196
GetOtherHspPath(const std::string & bundleName,const std::string & moduleName,const std::string & inputPath)197 std::string HybridJsModuleReader::GetOtherHspPath(const std::string& bundleName, const std::string& moduleName,
198 const std::string& inputPath)
199 {
200 std::string presetAppHapPath = inputPath;
201
202 auto bundleMgrHelper = DelayedSingleton<AppExecFwk::BundleMgrHelper>::GetInstance();
203 if (bundleMgrHelper == nullptr) {
204 TAG_LOGE(AAFwkTag::JSRUNTIME, "null bundleMgrHelper");
205 return presetAppHapPath;
206 }
207
208 std::vector<AppExecFwk::BaseSharedBundleInfo> baseSharedBundleInfos;
209 if (bundleMgrHelper->GetBaseSharedBundleInfos(bundleName, baseSharedBundleInfos) != 0) {
210 TAG_LOGE(AAFwkTag::JSRUNTIME, "GetBaseSharedBundleInfos failed");
211 return presetAppHapPath;
212 }
213 std::string tmpPath = inputPath.substr(inputPath.find_first_of("/") + 1);
214 const std::string sharedBundleName = tmpPath.substr(0, tmpPath.find_first_of("/"));
215 for (const auto &info : baseSharedBundleInfos) {
216 if ((info.bundleName == sharedBundleName) && (info.moduleName == moduleName)) {
217 presetAppHapPath = info.hapPath;
218 needFindPluginHsp_ = false;
219 break;
220 }
221 }
222 AppExecFwk::BundleInfo bundleInfo;
223 int32_t ret = bundleMgrHelper->GetDependentBundleInfo(sharedBundleName, bundleInfo,
224 AppExecFwk::GetDependentBundleInfoFlag::GET_APP_SERVICE_HSP_BUNDLE_INFO);
225 if (ret != ERR_OK) {
226 TAG_LOGE(AAFwkTag::JSRUNTIME, "GetDependentBundleInfo failed");
227 return presetAppHapPath;
228 }
229 for (const auto &info : bundleInfo.hapModuleInfos) {
230 if (info.moduleName == moduleName) {
231 presetAppHapPath = info.hapPath;
232 needFindPluginHsp_ = false;
233 break;
234 }
235 }
236 return presetAppHapPath;
237 }
238
GetPresetAppHapPath(const std::string & inputPath,const std::string & bundleName)239 std::string HybridJsModuleReader::GetPresetAppHapPath(const std::string& inputPath, const std::string& bundleName)
240 {
241 std::string presetAppHapPath = inputPath;
242 std::string moduleName = inputPath.substr(inputPath.find_last_of("/") + 1);
243 if (moduleName.empty()) {
244 TAG_LOGE(AAFwkTag::JSRUNTIME, "empty moduleName");
245 return presetAppHapPath;
246 }
247 auto bundleMgrHelper = DelayedSingleton<AppExecFwk::BundleMgrHelper>::GetInstance();
248 if (bundleMgrHelper == nullptr) {
249 TAG_LOGE(AAFwkTag::JSRUNTIME, "null bundleMgrHelper");
250 return presetAppHapPath;
251 }
252 if (inputPath.find_first_of("/") == inputPath.find_last_of("/")) {
253 AppExecFwk::BundleInfo bundleInfo;
254 auto getInfoResult = bundleMgrHelper->GetBundleInfoForSelf(static_cast<int32_t>(AppExecFwk::GetBundleInfoFlag::
255 GET_BUNDLE_INFO_WITH_HAP_MODULE), bundleInfo);
256 if (getInfoResult != 0 || bundleInfo.hapModuleInfos.empty()) {
257 TAG_LOGE(AAFwkTag::JSRUNTIME, "GetBundleInfoForSelf failed");
258 return presetAppHapPath;
259 }
260 for (auto hapModuleInfo : bundleInfo.hapModuleInfos) {
261 if (hapModuleInfo.moduleName == moduleName) {
262 presetAppHapPath = hapModuleInfo.hapPath;
263 needFindPluginHsp_ = false;
264 break;
265 }
266 }
267 } else {
268 presetAppHapPath = GetOtherHspPath(bundleName, moduleName, presetAppHapPath);
269 }
270 return presetAppHapPath;
271 }
272 } // namespace AbilityRuntime
273 } // namespace OHOS