1 /*
2 * Copyright (c) 2023 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 "form_module_preloader.h"
17
18 #include <mutex>
19 #include <unordered_map>
20
21 #include "adapter/ohos/entrance/utils.h"
22 #include "base/log/log.h"
23 #include "base/json/json_util.h"
24 #include "frameworks/bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h"
25
26
27 namespace OHOS::Ace {
28 namespace {
29 // KEY: bundleName, VALUE: formModuleList
30 std::unordered_map<std::string, std::unordered_set<std::string>> gFormModuleMap_;
31
32 std::mutex gMapLock_;
33 }
34 #ifdef FORM_SUPPORTED
OHOS_ACE_PreloadAceModuleCard(void * runtime,const char * bundleName,const void * hapPathMap)35 extern "C" ACE_FORCE_EXPORT void OHOS_ACE_PreloadAceModuleCard(void* runtime, const char* bundleName,
36 const void* hapPathMap)
37 {
38 std::unordered_set<std::string> formModuleList;
39 auto hapPathMapPtr = reinterpret_cast<const std::map<std::string, std::string>*>(hapPathMap);
40 if (!FormModulePreloader::CreateFormModuleList(std::string(bundleName), formModuleList, hapPathMapPtr)) {
41 TAG_LOGW(AceLogTag::ACE_FORM, "CreateFormModuleList failed, will load all modules later.");
42 }
43 Framework::JsiDeclarativeEngineInstance::PreloadAceModuleCard(runtime, formModuleList);
44 }
45
OHOS_ACE_ReloadAceModuleCard(void * runtime,const char * bundleName,const void * hapPathMap)46 extern "C" ACE_FORCE_EXPORT void OHOS_ACE_ReloadAceModuleCard(void* runtime, const char* bundleName,
47 const void* hapPathMap)
48 {
49 std::unordered_set<std::string> formModuleList;
50 auto hapPathMapPtr = reinterpret_cast<const std::map<std::string, std::string>*>(hapPathMap);
51 bool ret = FormModulePreloader::GetNewFormModuleList(std::string(bundleName), formModuleList, hapPathMapPtr);
52 if (ret && formModuleList.empty()) {
53 TAG_LOGI(AceLogTag::ACE_FORM, "There are no new components to load.");
54 return;
55 } else if (!ret) {
56 TAG_LOGW(AceLogTag::ACE_FORM, "GetNewFormModuleList failed, will load all modules later.");
57 formModuleList.clear(); // JsiDeclarativeEngineInstance will load all module if input list is empty.
58 }
59 Framework::JsiDeclarativeEngineInstance::ReloadAceModuleCard(runtime, formModuleList);
60 }
61 #endif
62
CreateFormModuleList(const std::string & bundleName,std::unordered_set<std::string> & formModuleList,const std::map<std::string,std::string> * hapPathMap)63 bool FormModulePreloader::CreateFormModuleList(const std::string& bundleName,
64 std::unordered_set<std::string>& formModuleList, const std::map<std::string, std::string>* hapPathMap)
65 {
66 if (ReadFormModuleList(bundleName, formModuleList, hapPathMap, false)) {
67 std::lock_guard<std::mutex> lock(gMapLock_);
68 gFormModuleMap_.emplace(bundleName, formModuleList);
69 TAG_LOGI(AceLogTag::ACE_FORM, "push formModuleList to map, bundleName: %{public}s.", bundleName.c_str());
70 return true;
71 }
72 return false;
73 }
74
GetNewFormModuleList(const std::string & bundleName,std::unordered_set<std::string> & formModuleList,const std::map<std::string,std::string> * hapPathMap)75 bool FormModulePreloader::GetNewFormModuleList(const std::string& bundleName,
76 std::unordered_set<std::string>& formModuleList, const std::map<std::string, std::string>* hapPathMap)
77 {
78 {
79 std::lock_guard<std::mutex> lock(gMapLock_);
80 if (gFormModuleMap_.find(bundleName) == gFormModuleMap_.end()) {
81 // This means that reading the list of components fails on preload
82 TAG_LOGW(AceLogTag::ACE_FORM, "All modules of bundle %{public}s have been loaded.", bundleName.c_str());
83 return true;
84 }
85 }
86 return ReadFormModuleList(bundleName, formModuleList, hapPathMap, true);
87 }
88
ReadFormModuleList(const std::string & bundleName,std::unordered_set<std::string> & formModuleList,const std::map<std::string,std::string> * hapPathMap,bool isReloadCondition)89 bool FormModulePreloader::ReadFormModuleList(const std::string& bundleName, std::unordered_set<std::string>&
90 formModuleList, const std::map<std::string, std::string>* hapPathMap, bool isReloadCondition)
91 {
92 if (hapPathMap == nullptr) {
93 TAG_LOGE(AceLogTag::ACE_FORM, "hapPathMap of bundle %{public}s is null.", bundleName.c_str());
94 return false;
95 }
96 TAG_LOGI(AceLogTag::ACE_FORM, "hapPaths size of bundle %{public}s is %{public}zu",
97 bundleName.c_str(), hapPathMap->size());
98 bool readSuccess = false;
99 for (auto hapPathPair: *hapPathMap) {
100 const std::string& hapPath = hapPathPair.second;
101 // Create HapAssetProvider
102 RefPtr<AssetManager> assetManager = CreateAssetManager(hapPath);
103 if (assetManager == nullptr) {
104 TAG_LOGW(AceLogTag::ACE_FORM, "CreateAssetManager failed, hapPath: %{private}s.", hapPath.c_str());
105 continue;
106 }
107 // Read component_collection.json
108 std::string content;
109 if (!ReadFileFromAssetManager(assetManager, "component_collection.json", content)) {
110 TAG_LOGW(
111 AceLogTag::ACE_FORM, "Read component_collection.json failed, hapPath: %{private}s.", hapPath.c_str());
112 continue;
113 }
114 // Parse component_collection.json
115 if (!ParseComponentCollectionJson(bundleName, content, formModuleList, isReloadCondition)) {
116 TAG_LOGW(
117 AceLogTag::ACE_FORM, "Parse component_collection.json failed, hapPath: %{private}s.", hapPath.c_str());
118 continue;
119 }
120 readSuccess = true;
121 }
122 return readSuccess;
123 }
124
ParseComponentCollectionJson(const std::string & bundleName,const std::string & content,std::unordered_set<std::string> & formModuleList,bool isReloadCondition)125 bool FormModulePreloader::ParseComponentCollectionJson(
126 const std::string& bundleName, const std::string& content,
127 std::unordered_set<std::string>& formModuleList, bool isReloadCondition)
128 {
129 auto collectionJson = JsonUtil::ParseJsonString(content);
130 if (collectionJson == nullptr || collectionJson->IsNull()) {
131 TAG_LOGW(AceLogTag::ACE_FORM, "Parse component_collection.json failed");
132 return false;
133 }
134 for (auto child = collectionJson->GetChild(); child && !child->IsNull(); child = child->GetNext()) {
135 std::string etsPath = child->GetKey();
136 auto item = collectionJson->GetValue(etsPath);
137 if (item == nullptr || !item->IsValid() || !item->IsArray()) {
138 TAG_LOGW(
139 AceLogTag::ACE_FORM, "Parse component_collection.json failed, etsPath: %{private}s.", etsPath.c_str());
140 return false;
141 }
142 int32_t len = item->GetArraySize();
143 for (int32_t index = 0; index < len; ++index) {
144 auto component = item->GetArrayItem(index);
145 if (component == nullptr || !component->IsString()) {
146 TAG_LOGW(AceLogTag::ACE_FORM, "Read view failed, etsPath: %{private}s.", etsPath.c_str());
147 return false;
148 }
149 std::string componentName = component->GetString();
150 if (!isReloadCondition) {
151 formModuleList.emplace(componentName);
152 continue;
153 }
154 std::lock_guard<std::mutex> lock(gMapLock_);
155 auto& iter = gFormModuleMap_[bundleName];
156 if (iter.find(componentName) == iter.end()) {
157 formModuleList.emplace(componentName);
158 iter.emplace(bundleName);
159 }
160 }
161 }
162 return true;
163 }
164
ReadFileFromAssetManager(const RefPtr<AssetManager> & assetManager,const std::string & fileName,std::string & content)165 bool FormModulePreloader::ReadFileFromAssetManager(
166 const RefPtr<AssetManager>& assetManager, const std::string& fileName, std::string& content)
167 {
168 if (assetManager == nullptr) {
169 TAG_LOGW(AceLogTag::ACE_FORM, "assetManager is null.");
170 return false;
171 }
172 auto jsAsset = assetManager->GetAsset(fileName);
173 if (jsAsset == nullptr) {
174 TAG_LOGW(AceLogTag::ACE_FORM, "uri: %{private}s Asset is null", fileName.c_str());
175 return false;
176 }
177 auto bufLen = jsAsset->GetSize();
178 auto buffer = jsAsset->GetData();
179 if ((buffer == nullptr) || (bufLen <= 0)) {
180 TAG_LOGW(AceLogTag::ACE_FORM, "uri: %{private}s buffer is null", fileName.c_str());
181 return false;
182 }
183 content.assign(buffer, buffer + bufLen);
184 return true;
185 }
186
CreateAssetManager(const std::string & hapPath)187 RefPtr<AssetManager> FormModulePreloader::CreateAssetManager(const std::string& hapPath)
188 {
189 std::vector<std::string> basePaths;
190 basePaths.emplace_back("");
191 basePaths.emplace_back("ets/");
192 basePaths.emplace_back("ets/widget/");
193 basePaths.emplace_back("resources/base/profile/");
194 RefPtr<AssetManager> assetManager = Referenced::MakeRefPtr<AssetManagerImpl>();
195 if (assetManager == nullptr) {
196 TAG_LOGW(AceLogTag::ACE_FORM, "Create AssetManagerImpl failed.");
197 return nullptr;
198 }
199 auto assetProvider = CreateAssetProviderImpl(hapPath, basePaths, false);
200 if (assetProvider == nullptr) {
201 TAG_LOGW(AceLogTag::ACE_FORM, "CreateAssetProvider failed.");
202 return nullptr;
203 }
204 assetManager->PushBack(std::move(assetProvider));
205 return assetManager;
206 }
207 } // namespace OHOS::Ace
208