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