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