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