• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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