1 /*
2 * Copyright (c) 2022 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 "ohos_resource_adapter_impl.h"
17
18 #include <ctime>
19 #include <securec.h>
20 #include <sstream>
21 #include <cerrno>
22 #include <cstring>
23 #include <unistd.h>
24 #include <vector>
25 #include <fstream>
26 #include <json/json.h>
27
28 #include "application_context.h"
29 #include "bundle_mgr_proxy.h"
30 #include "extractor.h"
31 #include "if_system_ability_manager.h"
32 #include "iservice_registry.h"
33 #include "locale_config.h"
34 #include "nweb_log.h"
35 #include "ohos_adapter_helper.h"
36 #include "parameter.h"
37 #include "parameters.h"
38 #include "system_ability_definition.h"
39
40 using namespace OHOS::AbilityBase;
41
42 namespace {
43 const std::string NWEB_HAP_PATH = "/system/app/com.ohos.nweb/NWeb.hap";
44 const std::string NWEB_HAP_PATH_1 = "/system/app/NWeb/NWeb.hap";
45 const std::string ARKWEBCORE_HAP_SANDBOX_PATH = "/data/storage/el1/bundle/nweb/entry.hap";
46 const std::string PERSIST_ARKWEBCORE_INSTALL_PATH = "persist.arkwebcore.install_path";
47 const std::string NWEB_HAP_PATH_MODULE_UPDATE = "/module_update/ArkWebCore/app/com.ohos.nweb/NWeb.hap";
48 const std::string HAP_REAL_PATH_PREFIX = "/data/app/el1/bundle/public/";
49 const std::string HAP_SANDBOX_PATH_PREFIX = "/data/storage/el1/bundle/nweb/";
50
51 const std::string NWEB_BUNDLE_NAME = "com.ohos.nweb";
52 const std::string NWEB_PACKAGE = "entry";
53 const std::string RAWFILE_PREFIX = "resources/rawfile/";
54 const std::string BUNDLE_NAME_PREFIX = "bundleName:";
55 const std::string MODULE_NAME_PREFIX = "moduleName:";
56 constexpr uint32_t TM_YEAR_BITS = 9;
57 constexpr uint32_t TM_MON_BITS = 5;
58 constexpr uint32_t TM_MIN_BITS = 5;
59 constexpr uint32_t TM_HOUR_BITS = 11;
60 constexpr uint32_t START_YEAR = 1900;
61 } // namespace
62
63 namespace OHOS::NWeb {
64 namespace {
GetResourceMgr(const std::string & bundleName,const std::string & moduleName)65 std::shared_ptr<Global::Resource::ResourceManager> GetResourceMgr(
66 const std::string& bundleName, const std::string& moduleName)
67 {
68 std::shared_ptr<AbilityRuntime::ApplicationContext> context =
69 AbilityRuntime::ApplicationContext::GetApplicationContext();
70 if (!context) {
71 WVLOG_E("Failed to get application context.");
72 return nullptr;
73 }
74
75 if (bundleName.empty() || moduleName.empty()) {
76 return context->GetResourceManager();
77 }
78 auto moduleContext = context->CreateModuleContext(bundleName, moduleName);
79 if (!moduleContext) {
80 WVLOG_E("Failed to crate module context, bundleName: %{public}s, moduleName: %{public}s.",
81 bundleName.c_str(), moduleName.c_str());
82 return nullptr;
83 }
84 return moduleContext->GetResourceManager();
85 }
86
ParseRawFile(const std::string & rawFile,std::string & bundleName,std::string & moduleName,std::string & fileName)87 bool ParseRawFile(const std::string& rawFile,
88 std::string& bundleName, std::string& moduleName, std::string& fileName)
89 {
90 if (rawFile.substr(0, RAWFILE_PREFIX.size()) != RAWFILE_PREFIX) {
91 WVLOG_D("ParseRawFile failed, rawfile: %{public}s", rawFile.c_str());
92 return false;
93 }
94
95 std::string subStr = rawFile.substr(RAWFILE_PREFIX.size());
96 if (subStr.substr(0, BUNDLE_NAME_PREFIX.size()) != BUNDLE_NAME_PREFIX) {
97 return false;
98 }
99 subStr = subStr.substr(BUNDLE_NAME_PREFIX.size());
100 size_t pos = subStr.find('/');
101 if (pos == std::string::npos) {
102 WVLOG_D("ParseRawFile bundleName failed, rawfile: %{public}s", rawFile.c_str());
103 return false;
104 }
105 bundleName = subStr.substr(0, pos);
106
107 subStr = subStr.substr(pos + 1);
108 if (subStr.substr(0, MODULE_NAME_PREFIX.size()) != MODULE_NAME_PREFIX) {
109 return false;
110 }
111 subStr = subStr.substr(MODULE_NAME_PREFIX.size());
112 pos = subStr.find('/');
113 if (pos == std::string::npos) {
114 WVLOG_D("ParseRawFile moduleName failed, rawfile: %{public}s", rawFile.c_str());
115 return false;
116 }
117 moduleName = subStr.substr(0, pos);
118
119 fileName = subStr.substr(pos + 1);
120 if (fileName.empty()) {
121 WVLOG_D("ParseRawFile fileName failed, rawfile: %{public}s", rawFile.c_str());
122 return false;
123 }
124 return true;
125 }
126
GetArkWebHapPath(const std::string & arkWebCoreHapPathOverride,std::vector<std::pair<std::string,int>> & errorMessage)127 std::string GetArkWebHapPath(const std::string& arkWebCoreHapPathOverride,
128 std::vector<std::pair<std::string, int>>& errorMessage)
129 {
130 std::string prefixPath = WEBVIEW_SANDBOX_PATH;
131 if (access(arkWebCoreHapPathOverride.c_str(), F_OK) == 0) {
132 std::string sandboxPath = OhosResourceAdapterImpl::ConvertToSandboxPath(arkWebCoreHapPathOverride, prefixPath);
133 if (access(sandboxPath.c_str(), F_OK) == 0) {
134 WVLOG_D("eixt HAP_arkWebCoreHapPathOverride");
135 return sandboxPath;
136 }
137 }
138 errorMessage.emplace_back("access arkWebCoreHapPathOverride path failed", errno);
139
140 std::string installPath = OhosResourceAdapterImpl::ConvertToSandboxPath(
141 OHOS::system::GetParameter(PERSIST_ARKWEBCORE_INSTALL_PATH, ""), prefixPath);
142 if (access(installPath.c_str(), F_OK) == 0) {
143 WVLOG_D("exit install_path,%{public}s", installPath.c_str());
144 return installPath;
145 }
146 errorMessage.emplace_back("access nweb install path failed", errno);
147
148 if (access(WEBVIEW_SANDBOX_HAP_PATH, F_OK) == 0) {
149 WVLOG_D("exit WEBVIEW_SANDBOX_HAP_PATH");
150 return WEBVIEW_SANDBOX_HAP_PATH;
151 }
152 errorMessage.emplace_back("access arkwebcore hap sandbox path failed", errno);
153 if (access(WEBVIEW_APP_HAP_PATH2, F_OK) == 0) {
154 WVLOG_D("exit WEBVIEW_APP_HAP_PATH2");
155 return WEBVIEW_APP_HAP_PATH2;
156 }
157 errorMessage.emplace_back("access ohos nweb hap path failed", errno);
158 if (access(WEBVIEW_APP_HAP_PATH, F_OK) == 0) {
159 WVLOG_D("exit WEBVIEW_APP_HAP_PATH");
160 return WEBVIEW_APP_HAP_PATH;
161 }
162 errorMessage.emplace_back("access nweb hap path failed", errno);
163 if (access(WEBVIEW_HAP_PATH, F_OK) == 0) {
164 WVLOG_D("exit WEBVIEW_HAP_PATH");
165 return WEBVIEW_HAP_PATH;
166 }
167 errorMessage.emplace_back("access nweb hap module update path failed", errno);
168 return "";
169 }
170
171 } // namespace
172
OhosFileMapperImpl(std::unique_ptr<OHOS::AbilityBase::FileMapper> fileMap,const std::shared_ptr<Extractor> & extractor)173 OhosFileMapperImpl::OhosFileMapperImpl(std::unique_ptr<OHOS::AbilityBase::FileMapper> fileMap,
174 const std::shared_ptr<Extractor>& extractor): extractor_(extractor), fileMap_(std::move(fileMap))
175 {
176 }
177
GetFd()178 int32_t OhosFileMapperImpl::GetFd()
179 {
180 return -1;
181 }
182
GetOffset()183 int32_t OhosFileMapperImpl::GetOffset()
184 {
185 return fileMap_ ? fileMap_->GetOffset(): -1;
186 }
187
GetFileName()188 std::string OhosFileMapperImpl::GetFileName()
189 {
190 return fileMap_ ? fileMap_->GetFileName(): "";
191 }
192
IsCompressed()193 bool OhosFileMapperImpl::IsCompressed()
194 {
195 return fileMap_ ? fileMap_->IsCompressed(): false;
196 }
197
GetDataPtr()198 void* OhosFileMapperImpl::GetDataPtr()
199 {
200 return fileMap_ ? fileMap_->GetDataPtr(): nullptr;
201 }
202
GetDataLen()203 size_t OhosFileMapperImpl::GetDataLen()
204 {
205 return fileMap_ ? fileMap_->GetDataLen(): 0;
206 }
207
UnzipData(uint8_t ** dest,size_t & len)208 bool OhosFileMapperImpl::UnzipData(uint8_t** dest, size_t& len)
209 {
210 if (extractor_ && IsCompressed()) {
211 std::unique_ptr<uint8_t[]> data;
212 bool result = extractor_->UnzipData(std::move(fileMap_), data, len);
213 if (result) {
214 *dest = data.release();
215 }
216 return result;
217 }
218 return false;
219 }
220
221 std::string OhosResourceAdapterImpl::arkWebCoreHapPathOverride_ = "";
ConvertToSandboxPath(const std::string & installPath,const std::string & prefixPath)222 std::string OhosResourceAdapterImpl::ConvertToSandboxPath(const std::string& installPath, const std::string& prefixPath)
223 {
224 if (installPath.empty()) {
225 return "";
226 }
227 size_t result = installPath.find(HAP_REAL_PATH_PREFIX);
228 if (result != std::string::npos) {
229 size_t pos = installPath.find_last_of('/');
230 if (pos != std::string::npos && pos != installPath.size() - 1) {
231 return prefixPath + installPath.substr(pos + 1);
232 }
233 }
234 return installPath;
235 }
236
OhosResourceAdapterImpl(const std::string & hapPath)237 OhosResourceAdapterImpl::OhosResourceAdapterImpl(const std::string& hapPath)
238 {
239 Init(hapPath);
240 }
241
Init(const std::string & hapPath)242 void OhosResourceAdapterImpl::Init(const std::string& hapPath)
243 {
244 bool newCreate = false;
245 std::vector<std::pair<std::string, int>> errorMessage;
246 std::string arkWebHapPath = GetArkWebHapPath(arkWebCoreHapPathOverride_, errorMessage);
247 if (!arkWebHapPath.empty()) {
248 sysExtractor_ = ExtractorUtil::GetExtractor(arkWebHapPath, newCreate);
249 if (!sysExtractor_) {
250 WVLOG_E("RuntimeExtractor create failed for %{public}s", arkWebHapPath.c_str());
251 }
252 }
253 for (const auto& err : errorMessage) {
254 WVLOG_E("%{public}s, errno(%{public}d): %{public}s", err.first.c_str(), err.second, strerror(err.second));
255 }
256 if (hapPath.empty()) {
257 return;
258 }
259 std::string loadPath = ExtractorUtil::GetLoadFilePath(hapPath);
260 extractor_ = ExtractorUtil::GetExtractor(loadPath, newCreate);
261 if (!extractor_) {
262 WVLOG_E("RuntimeExtractor create failed for %{public}s", hapPath.c_str());
263 }
264 }
265
GetRawFileData(const std::string & rawFile,size_t & len,uint8_t ** dest,bool isSys)266 bool OhosResourceAdapterImpl::GetRawFileData(const std::string& rawFile, size_t& len,
267 uint8_t** dest, bool isSys)
268 {
269 std::unique_ptr<uint8_t[]> data;
270 bool result;
271 if (isSys) {
272 result = GetRawFileData(sysExtractor_, rawFile, len, data);
273 if (result) {
274 *dest = data.release();
275 }
276 return result;
277 }
278 std::string bundleName;
279 std::string moduleName;
280 std::string fileName;
281 if (ParseRawFile(rawFile, bundleName, moduleName, fileName)) {
282 auto resourceManager = GetResourceMgr(bundleName, moduleName);
283 if (!resourceManager) {
284 result = GetRawFileData(extractor_, rawFile, len, data);
285 if (result) {
286 *dest = data.release();
287 }
288 return result;
289 }
290 auto state = resourceManager->GetRawFileFromHap(fileName, len, data);
291 if (state != Global::Resource::SUCCESS) {
292 WVLOG_E("GetRawFileFromHap failed, state: %{public}d, fileName: %{public}s", state, fileName.c_str());
293 result = GetRawFileData(extractor_, rawFile, len, data);
294 if (result) {
295 *dest = data.release();
296 }
297 return result;
298 }
299 *dest = data.release();
300 return true;
301 }
302
303 result = GetRawFileData(extractor_, rawFile, len, data);
304 if (result) {
305 *dest = data.release();
306 }
307 return result;
308 }
309
GetResourceString(const std::string & bundleName,const std::string & moduleName,const int32_t resId,std::string & result)310 bool OhosResourceAdapterImpl::GetResourceString(const std::string& bundleName,
311 const std::string& moduleName, const int32_t resId, std::string& result)
312 {
313 auto resourceManager = GetResourceMgr(bundleName, moduleName);
314 if (!resourceManager) {
315 return false;
316 }
317 if (resourceManager->GetStringById(resId, result) == Global::Resource::SUCCESS) {
318 return true;
319 }
320 return false;
321 }
322
GetRawFileMapper(const std::string & rawFile,bool isSys)323 std::shared_ptr<OhosFileMapper> OhosResourceAdapterImpl::GetRawFileMapper(const std::string& rawFile,
324 bool isSys)
325 {
326 return GetRawFileMapper(isSys? sysExtractor_: extractor_, rawFile);
327 }
328
IsRawFileExist(const std::string & rawFile,bool isSys)329 bool OhosResourceAdapterImpl::IsRawFileExist(const std::string& rawFile, bool isSys)
330 {
331 return HasEntry(isSys? sysExtractor_: extractor_, rawFile);
332 }
333
GetRawFileLastModTime(const std::string & rawFile,uint16_t & date,uint16_t & time,bool isSys)334 bool OhosResourceAdapterImpl::GetRawFileLastModTime(const std::string& rawFile,
335 uint16_t& date, uint16_t& time, bool isSys)
336 {
337 FileInfo info;
338 if (GetFileInfo(isSys? sysExtractor_: extractor_, rawFile, info)) {
339 date = info.lastModDate;
340 time = info.lastModTime;
341 return true;
342 }
343 return false;
344 }
345
GetRawFileLastModTime(const std::string & rawFile,time_t & time,bool isSys)346 bool OhosResourceAdapterImpl::GetRawFileLastModTime(const std::string& rawFile, time_t& time, bool isSys)
347 {
348 FileInfo info;
349 if (GetFileInfo(isSys? sysExtractor_: extractor_, rawFile, info)) {
350 uint16_t modifiedDate = info.lastModDate;
351 uint16_t modifiedTime = info.lastModTime;
352 struct tm newTime;
353 newTime.tm_year = ((modifiedDate >> TM_YEAR_BITS) & 0x7f) + START_YEAR;
354 newTime.tm_mon = (modifiedDate >> TM_MON_BITS) & 0xf;
355 newTime.tm_mday = modifiedDate & 0x1f;
356 newTime.tm_hour = (modifiedTime >> TM_HOUR_BITS) & 0x1f;
357 newTime.tm_min = (modifiedTime >> TM_MIN_BITS) & 0x2f;
358 newTime.tm_sec = (modifiedTime << 1) & 0x1f;
359 newTime.tm_isdst = 0;
360 time = mktime(&newTime);
361 return true;
362 }
363 return false;
364 }
365
366 // static
HasEntry(const std::shared_ptr<OHOS::AbilityBase::Extractor> & manager,const std::string & rawFile)367 bool OhosResourceAdapterImpl::HasEntry(const std::shared_ptr<OHOS::AbilityBase::Extractor>& manager,
368 const std::string& rawFile)
369 {
370 if (!manager) {
371 return false;
372 }
373 return manager->HasEntry(rawFile);
374 }
375
GetFileInfo(const std::shared_ptr<OHOS::AbilityBase::Extractor> & manager,const std::string & rawFile,OHOS::AbilityBase::FileInfo & info)376 bool OhosResourceAdapterImpl::GetFileInfo(const std::shared_ptr<OHOS::AbilityBase::Extractor>& manager,
377 const std::string& rawFile, OHOS::AbilityBase::FileInfo& info)
378 {
379 if (!manager) {
380 return false;
381 }
382 return manager->GetFileInfo(rawFile, info);
383 }
384
GetModuleName(const char * configStr,size_t len)385 std::string OhosResourceAdapterImpl::GetModuleName(const char *configStr, size_t len)
386 {
387 if (configStr == nullptr) {
388 return std::string();
389 }
390 std::string config(configStr, len);
391 static const char *key = "\"moduleName\"";
392 auto idx = config.find(key);
393 if (idx == std::string::npos) {
394 return std::string();
395 }
396 auto start = config.find("\"", idx + strlen(key));
397 if (start == std::string::npos) {
398 return std::string();
399 }
400 auto end = config.find("\"", start + 1);
401 if (end == std::string::npos || end < start + 1) {
402 return std::string();
403 }
404
405 std::string retStr = std::string(configStr + start + 1, end - start - 1);
406 return retStr;
407 }
408
ParseModuleName(const std::shared_ptr<Extractor> & manager)409 std::string OhosResourceAdapterImpl::ParseModuleName(const std::shared_ptr<Extractor> &manager)
410 {
411 if (manager == nullptr) {
412 return std::string();
413 }
414 std::unique_ptr<uint8_t[]> configBuf;
415 size_t len;
416 bool ret = manager->ExtractToBufByName("config.json", configBuf, len);
417 if (!ret) {
418 WVLOG_E("failed to get config data from ability");
419 return std::string();
420 }
421 // parse config.json
422 std::string mName = GetModuleName(reinterpret_cast<char *>(configBuf.get()), len);
423 if (mName.size() == 0) {
424 WVLOG_E("parse moduleName from config.json error");
425 return std::string();
426 }
427 return mName;
428 }
429
GetRawFileData(const std::shared_ptr<Extractor> & manager,const std::string & rawFile,size_t & len,std::unique_ptr<uint8_t[]> & dest)430 bool OhosResourceAdapterImpl::GetRawFileData(const std::shared_ptr<Extractor>& manager,
431 const std::string& rawFile, size_t& len, std::unique_ptr<uint8_t[]>& dest)
432 {
433 if (!manager) {
434 return false;
435 }
436 if (manager->IsStageModel()) {
437 return manager->ExtractToBufByName(rawFile, dest, len);
438 }
439 std::string moduleName = OhosResourceAdapterImpl::ParseModuleName(manager);
440 std::string rawFilePath("assets/");
441 rawFilePath.append(moduleName);
442 rawFilePath.append("/");
443 rawFilePath.append(rawFile);
444 WVLOG_E("fa filepath:%{public}s", rawFilePath.c_str());
445 return manager->ExtractToBufByName(rawFilePath, dest, len);
446 }
447
GetRawFileMapper(const std::shared_ptr<OHOS::AbilityBase::Extractor> & manager,const std::string & rawFile)448 std::shared_ptr<OhosFileMapper> OhosResourceAdapterImpl::GetRawFileMapper(
449 const std::shared_ptr<OHOS::AbilityBase::Extractor>& manager,
450 const std::string& rawFile)
451 {
452 if (!manager) {
453 return nullptr;
454 }
455 std::unique_ptr<OHOS::AbilityBase::FileMapper> fileMap;
456 auto& systemPropertiesAdapter = OhosAdapterHelper::GetInstance().GetSystemPropertiesInstance();
457 if (systemPropertiesAdapter.GetWebOptimizationValue()) {
458 fileMap = manager->GetMmapData(rawFile);
459 } else {
460 fileMap = manager->GetData(rawFile);
461 }
462 if (fileMap == nullptr) {
463 return nullptr;
464 }
465 bool isCompressed = fileMap->IsCompressed();
466 return std::make_shared<OhosFileMapperImpl>(std::move(fileMap), isCompressed ? manager: nullptr);
467 }
468
GetArkWebVersion()469 std::string OhosResourceAdapterImpl::GetArkWebVersion()
470 {
471 const std::string hapPaths[] = {
472 "/module_update/ArkWebCore/app/com.huawei.hmos.arkwebcore/ArkWebCore.hap",
473 "/system/app/com.ohos.arkwebcore/ArkWebCore.hap"
474 };
475 const std::string packInfoPath = "pack.info";
476
477 for (const auto& hapPath : hapPaths) {
478 OHOS::AbilityBase::Extractor extractor(hapPath);
479 if (!extractor.Init()) {
480 WVLOG_E("Failed to initialize extractor for HAP file: %{public}s", hapPath.c_str());
481 continue;
482 }
483
484 std::ostringstream contentStream;
485 bool ret = extractor.ExtractByName(packInfoPath, contentStream);
486 if (!ret) {
487 WVLOG_E("Failed to extract pack.info from HAP: %{public}s", hapPath.c_str());
488 continue;
489 }
490
491 std::string configContent = contentStream.str();
492
493 Json::Value root;
494 Json::Reader reader;
495 if (!reader.parse(configContent, root)) {
496 WVLOG_E("Failed to parse pack.info from HAP: %{public}s", hapPath.c_str());
497 continue;
498 }
499
500 if (root.isMember("summary") &&
501 root["summary"].isMember("app") &&
502 root["summary"]["app"].isMember("version") &&
503 root["summary"]["app"]["version"].isMember("name")) {
504 return root["summary"]["app"]["version"]["name"].asString();
505 }
506
507 WVLOG_E("Version information not found in pack.info from HAP: %{public}s", hapPath.c_str());
508 }
509
510 WVLOG_E("Failed to get ArkWeb version from any of the specified paths");
511 return "";
512 }
513
SetArkWebCoreHapPathOverride(const std::string & hapPath)514 void OhosResourceAdapterImpl::SetArkWebCoreHapPathOverride(const std::string& hapPath)
515 {
516 arkWebCoreHapPathOverride_ = hapPath;
517 }
518
GetSystemLanguage()519 std::string OhosResourceAdapterImpl::GetSystemLanguage()
520 {
521 return OHOS::Global::I18n::LocaleConfig::GetSystemLanguage();
522 }
523
524 } // namespace OHOS::NWeb
525