1 /*
2  * Copyright (c) 2024 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 "session/host/include/multi_instance_manager.h"
17 #include <bundlemgr/launcher_service.h>
18 #include "interfaces/include/ws_common.h"
19 #include "window_manager_hilog.h"
20 #include "window_helper.h"
21 
22 namespace OHOS::Rosen {
23 namespace {
24     const std::string APP_INSTANCE_KEY_PREFIX = "app_instance_";
25     constexpr uint32_t DEFAULT_INSTANCE_ID = 0u;
26 }
27 
GetInstance()28 MultiInstanceManager& MultiInstanceManager::GetInstance()
29 {
30     static MultiInstanceManager instance;
31     return instance;
32 }
33 
IsSupportMultiInstance(const SystemSessionConfig& systemConfig)34 bool MultiInstanceManager::IsSupportMultiInstance(const SystemSessionConfig& systemConfig)
35 {
36     return systemConfig.IsPcWindow();
37 }
38 
Init(const sptr<AppExecFwk::IBundleMgr>& bundleMgr, const std::shared_ptr<TaskScheduler>& taskScheduler)39 void MultiInstanceManager::Init(const sptr<AppExecFwk::IBundleMgr>& bundleMgr,
40     const std::shared_ptr<TaskScheduler>& taskScheduler)
41 {
42     if (bundleMgr == nullptr || taskScheduler == nullptr) {
43         TLOGE(WmsLogTag::WMS_LIFE, "bundleMgr or taskScheduler is nullptr");
44         return;
45     }
46     bundleMgr_ = bundleMgr;
47     taskScheduler_ = taskScheduler;
48 }
49 
SetCurrentUserId(int32_t userId)50 void MultiInstanceManager::SetCurrentUserId(int32_t userId)
51 {
52     userId_ = userId;
53     if (taskScheduler_ == nullptr) {
54         TLOGE(WmsLogTag::WMS_LIFE, "taskScheduler is nullptr");
55         return;
56     }
57     const char* const where = __func__;
58     auto task = [this, where] {
59         std::vector<AppExecFwk::ApplicationInfo> appInfos;
60         if (!bundleMgr_ || !bundleMgr_->GetApplicationInfos(
61             AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId_, appInfos)) {
62             TLOGNE(WmsLogTag::WMS_LIFE, "%{public}s:get application infos fail", where);
63             return;
64         }
65         std::unique_lock<std::shared_mutex> lock(appInfoMutex_);
66         appInfoMap_.clear();
67         for (auto& appInfo : appInfos) {
68             appInfoMap_[appInfo.bundleName] = appInfo;
69         }
70         TLOGNI(WmsLogTag::WMS_LIFE, "%{public}s:application infos init", where);
71     };
72     taskScheduler_->PostAsyncTask(task, where);
73 }
74 
IsMultiInstance(const std::string& bundleName)75 bool MultiInstanceManager::IsMultiInstance(const std::string& bundleName)
76 {
77     std::shared_lock<std::shared_mutex> lock(appInfoMutex_);
78     auto iter = appInfoMap_.find(bundleName);
79     if (iter == appInfoMap_.end()) {
80         AppExecFwk::ApplicationInfo appInfo;
81         if (bundleMgr_ && bundleMgr_->GetApplicationInfo(
82             bundleName, AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId_, appInfo)) {
83             appInfoMap_[bundleName] = appInfo;
84             return appInfo.multiAppMode.multiAppModeType == AppExecFwk::MultiAppModeType::MULTI_INSTANCE;
85         }
86         TLOGE(WmsLogTag::WMS_LIFE, "App info not found, bundleName:%{public}s", bundleName.c_str());
87         return false;
88     }
89     return iter->second.multiAppMode.multiAppModeType == AppExecFwk::MultiAppModeType::MULTI_INSTANCE;
90 }
91 
GetMaxInstanceCount(const std::string& bundleName)92 uint32_t MultiInstanceManager::GetMaxInstanceCount(const std::string& bundleName)
93 {
94     std::shared_lock<std::shared_mutex> lock(appInfoMutex_);
95     auto iter = appInfoMap_.find(bundleName);
96     if (iter == appInfoMap_.end()) {
97         AppExecFwk::ApplicationInfo appInfo;
98         if (bundleMgr_ && bundleMgr_->GetApplicationInfo(
99             bundleName, AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId_, appInfo)) {
100             appInfoMap_[bundleName] = appInfo;
101             return appInfo.multiAppMode.maxCount;
102         }
103         TLOGE(WmsLogTag::WMS_LIFE, "App info not found, bundleName:%{public}s", bundleName.c_str());
104         return 0u;
105     }
106     if (iter->second.multiAppMode.multiAppModeType == AppExecFwk::MultiAppModeType::MULTI_INSTANCE) {
107         return iter->second.multiAppMode.maxCount;
108     }
109     return 0u;
110 }
111 
GetInstanceCount(const std::string& bundleName)112 uint32_t MultiInstanceManager::GetInstanceCount(const std::string& bundleName)
113 {
114     std::shared_lock<std::shared_mutex> lock(mutex_);
115     auto iter = bundleInstanceIdListMap_.find(bundleName);
116     if (iter == bundleInstanceIdListMap_.end()) {
117         return 0u;
118     } else {
119         return static_cast<uint32_t>(iter->second.size());
120     }
121 }
122 
GetLastInstanceKey(const std::string& bundleName)123 std::string MultiInstanceManager::GetLastInstanceKey(const std::string& bundleName)
124 {
125     std::shared_lock<std::shared_mutex> lock(mutex_);
126     auto iter = bundleInstanceIdListMap_.find(bundleName);
127     if (iter == bundleInstanceIdListMap_.end() || iter->second.size() == 0) {
128         TLOGE(WmsLogTag::WMS_LIFE, "not found last instance key, bundleName:%{public}s", bundleName.c_str());
129         return "";
130     } else {
131         TLOGI(WmsLogTag::WMS_LIFE, "bundleName:%{public}s instanceKey:app_instance_%{public}u",
132             bundleName.c_str(), iter->second.back());
133         return APP_INSTANCE_KEY_PREFIX + std::to_string(iter->second.back());
134     }
135 }
136 
CreateNewInstanceKey(const std::string& bundleName, const std::string& instanceKey)137 std::string MultiInstanceManager::CreateNewInstanceKey(const std::string& bundleName, const std::string& instanceKey)
138 {
139     auto maxInstanceCount = GetMaxInstanceCount(bundleName);
140     uint32_t instanceId = DEFAULT_INSTANCE_ID;
141     if (!instanceKey.empty()) {
142         if (!ConvertInstanceKeyToInstanceId(instanceKey, instanceId) || instanceId >= maxInstanceCount) {
143             TLOGE(WmsLogTag::WMS_LIFE, "invalid instanceKey, bundleName:%{public}s instanceKey:%{public}s",
144                 bundleName.c_str(), instanceKey.c_str());
145             return instanceKey;
146         }
147         AddInstanceId(bundleName, instanceId);
148         return instanceKey;
149     }
150     instanceId = FindMinimumAvailableInstanceId(bundleName, maxInstanceCount);
151     AddInstanceId(bundleName, instanceId);
152     return APP_INSTANCE_KEY_PREFIX + std::to_string(instanceId);
153 }
154 
IsValidInstanceKey(const std::string& bundleName, const std::string& instanceKey)155 bool MultiInstanceManager::IsValidInstanceKey(const std::string& bundleName, const std::string& instanceKey)
156 {
157     if (instanceKey.find(APP_INSTANCE_KEY_PREFIX) == -1ul) {
158         TLOGE(WmsLogTag::WMS_LIFE, "bundleName:%{public}s with invalid instanceKey:%{public}s",
159             bundleName.c_str(), instanceKey.c_str());
160         return false;
161     }
162     auto maxInstanceCount = GetMaxInstanceCount(bundleName);
163     auto instanceId = DEFAULT_INSTANCE_ID;
164     if (!ConvertInstanceKeyToInstanceId(instanceKey, instanceId) || instanceId >= maxInstanceCount) {
165         TLOGE(WmsLogTag::WMS_LIFE, "invalid instanceKey, bundleName:%{public}s instanceKey:%{public}s",
166             bundleName.c_str(), instanceKey.c_str());
167         return false;
168     }
169     return true;
170 }
171 
IsInstanceKeyExist(const std::string& bundleName, const std::string& instanceKey)172 bool MultiInstanceManager::IsInstanceKeyExist(const std::string& bundleName, const std::string& instanceKey)
173 {
174     std::shared_lock<std::shared_mutex> lock(mutex_);
175     auto iter = bundleInstanceIdListMap_.find(bundleName);
176     if (iter == bundleInstanceIdListMap_.end()) {
177         TLOGE(WmsLogTag::WMS_LIFE, "instanceIdList not found, bundleName:%{public}s instanceKey:%{public}s",
178             bundleName.c_str(), instanceKey.c_str());
179         return false;
180     }
181     auto instanceId = DEFAULT_INSTANCE_ID;
182     if (!ConvertInstanceKeyToInstanceId(instanceKey, instanceId)) {
183         TLOGE(WmsLogTag::WMS_LIFE, "invalid instanceKey, bundleName:%{public}s instanceKey:%{public}s",
184             bundleName.c_str(), instanceKey.c_str());
185         return false;
186     }
187     return std::find(iter->second.begin(), iter->second.end(), instanceId) != iter->second.end();
188 }
189 
RemoveInstanceKey(const std::string& bundleName, const std::string& instanceKey)190 void MultiInstanceManager::RemoveInstanceKey(const std::string& bundleName, const std::string& instanceKey)
191 {
192     auto instanceId = DEFAULT_INSTANCE_ID;
193     if (!ConvertInstanceKeyToInstanceId(instanceKey, instanceId)) {
194         TLOGE(WmsLogTag::WMS_LIFE, "invalid instanceKey, bundleName:%{public}s instanceKey:%{public}s",
195             bundleName.c_str(), instanceKey.c_str());
196         return;
197     }
198     RemoveInstanceId(bundleName, instanceId);
199 }
200 
FindMinimumAvailableInstanceId(const std::string& bundleName, uint32_t maxInstanceCount)201 uint32_t MultiInstanceManager::FindMinimumAvailableInstanceId(const std::string& bundleName,
202     uint32_t maxInstanceCount)
203 {
204     std::shared_lock<std::shared_mutex> lock(mutex_);
205     auto iter = bundleInstanceUsageMap_.find(bundleName);
206     if (iter == bundleInstanceUsageMap_.end()) {
207         TLOGE(WmsLogTag::WMS_LIFE, "not found available instanceId");
208         return DEFAULT_INSTANCE_ID;
209     }
210     for (auto i = 0u; i < maxInstanceCount; i++) {
211         if (iter->second[i] == 0) {
212             return i;
213         }
214     }
215     TLOGE(WmsLogTag::WMS_LIFE, "not found available instanceId");
216     return DEFAULT_INSTANCE_ID;
217 }
218 
RefreshAppInfo(const std::string& bundleName)219 void MultiInstanceManager::RefreshAppInfo(const std::string& bundleName)
220 {
221     std::unique_lock<std::shared_mutex> lock(appInfoMutex_);
222     AppExecFwk::ApplicationInfo appInfo;
223     if (bundleMgr_ && bundleMgr_->GetApplicationInfo(
224         bundleName, AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId_, appInfo)) {
225         appInfoMap_[bundleName] = appInfo;
226     } else {
227         appInfoMap_.erase(bundleName);
228     }
229 }
230 
IncreaseInstanceKeyRefCount(const sptr<SceneSession>& sceneSession)231 void MultiInstanceManager::IncreaseInstanceKeyRefCount(const sptr<SceneSession>& sceneSession)
232 {
233     if (!sceneSession) {
234         TLOGE(WmsLogTag::WMS_LIFE, "sceneSession is nullptr");
235         return;
236     }
237     if (!WindowHelper::IsMainWindow(sceneSession->GetWindowType())) {
238         TLOGE(WmsLogTag::WMS_LIFE, "sceneSession is not main window");
239         return;
240     }
241     const auto& instanceKey = sceneSession->GetSessionInfo().appInstanceKey_;
242     if (instanceKey.empty()) {
243         TLOGD(WmsLogTag::WMS_LIFE, "instanceKey is empty");
244         return;
245     }
246     const auto& bundleName = sceneSession->GetSessionInfo().bundleName_;
247     const auto bundleInstanceKey = bundleName + instanceKey;
248     auto iter = instanceKeyRefCountMap_.find(bundleInstanceKey);
249     if (iter == instanceKeyRefCountMap_.end()) {
250         TLOGD(WmsLogTag::WMS_LIFE, "bundleInstanceKey not exist.");
251         instanceKeyRefCountMap_.emplace(bundleInstanceKey, 1);
252     } else {
253         ++(iter->second);
254     }
255 }
256 
DecreaseInstanceKeyRefCount(const sptr<SceneSession>& sceneSession)257 void MultiInstanceManager::DecreaseInstanceKeyRefCount(const sptr<SceneSession>& sceneSession)
258 {
259     if (!sceneSession) {
260         TLOGE(WmsLogTag::WMS_LIFE, "sceneSession is nullptr");
261         return;
262     }
263     if (!WindowHelper::IsMainWindow(sceneSession->GetWindowType())) {
264         TLOGE(WmsLogTag::WMS_LIFE, "sceneSession is not main window");
265         return;
266     }
267     const auto& instanceKey = sceneSession->GetSessionInfo().appInstanceKey_;
268     if (instanceKey.empty()) {
269         TLOGD(WmsLogTag::WMS_LIFE, "instanceKey is empty");
270         return;
271     }
272     const auto& bundleName = sceneSession->GetSessionInfo().bundleName_;
273     const auto bundleInstanceKey = bundleName + instanceKey;
274     auto iter = instanceKeyRefCountMap_.find(bundleInstanceKey);
275     if (iter == instanceKeyRefCountMap_.end()) {
276         TLOGD(WmsLogTag::WMS_LIFE, "bundleInstanceKey not exist.");
277         return;
278     }
279     if (--(iter->second) <= 0) {
280         instanceKeyRefCountMap_.erase(bundleInstanceKey);
281         RemoveInstanceKey(bundleName, instanceKey);
282     }
283 }
284 
FillInstanceKeyIfNeed(const sptr<SceneSession>& sceneSession)285 void MultiInstanceManager::FillInstanceKeyIfNeed(const sptr<SceneSession>& sceneSession)
286 {
287     if (!sceneSession) {
288         TLOGE(WmsLogTag::WMS_LIFE, "sceneSession is nullptr");
289         return;
290     }
291     if (!WindowHelper::IsMainWindow(sceneSession->GetWindowType())) {
292         TLOGD(WmsLogTag::WMS_LIFE, "sceneSession is not main window");
293         return;
294     }
295     const auto& bundleName = sceneSession->GetSessionInfo().bundleName_;
296     uint32_t maxInstanceCount = GetMaxInstanceCount(bundleName);
297     if (maxInstanceCount <= 0) {
298         TLOGD(WmsLogTag::WMS_LIFE, "maxInstanceCount is not valid");
299         return;
300     }
301     const auto& sessionInfo = sceneSession->GetSessionInfo();
302     if (sessionInfo.appInstanceKey_.empty()) {
303         uint32_t instanceCount = GetInstanceCount(bundleName);
304         if (sessionInfo.isNewAppInstance_ && instanceCount < maxInstanceCount) {
305             sceneSession->SetAppInstanceKey(CreateNewInstanceKey(bundleName));
306         } else {
307             sceneSession->SetAppInstanceKey(GetLastInstanceKey(bundleName));
308         }
309     } else if (!IsInstanceKeyExist(sessionInfo.bundleName_, sessionInfo.appInstanceKey_)) {
310         TLOGI(WmsLogTag::WMS_LIFE, "create not exist instanceKey, bundleName:%{public}s instanceKey:%{public}s",
311             bundleName.c_str(), sessionInfo.appInstanceKey_.c_str());
312         CreateNewInstanceKey(sessionInfo.bundleName_, sessionInfo.appInstanceKey_);
313     }
314 }
315 
MultiInstancePendingSessionActivation(SessionInfo& info)316 bool MultiInstanceManager::MultiInstancePendingSessionActivation(SessionInfo& info)
317 {
318     auto maxInstanceCount = GetMaxInstanceCount(info.bundleName_);
319     TLOGI(WmsLogTag::WMS_LIFE, "id:%{public}d maxInstanceCount:%{public}d", info.persistentId_, maxInstanceCount);
320     if (maxInstanceCount <= 0) {
321         return true;
322     }
323     if (info.appInstanceKey_.empty()) {
324         if (info.persistentId_ != 0) {
325             TLOGE(WmsLogTag::WMS_LIFE, "empty instance key, persistentId:%{public}d", info.persistentId_);
326             return false;
327         }
328         info.isNewAppInstance_ = true;
329         return true;
330     } else if (!IsValidInstanceKey(info.bundleName_, info.appInstanceKey_)) {
331         TLOGE(WmsLogTag::WMS_LIFE, "invalid instancekey:%{public}s", info.appInstanceKey_.c_str());
332         return false;
333     } else if (!IsInstanceKeyExist(info.bundleName_, info.appInstanceKey_)) {
334         TLOGI(WmsLogTag::WMS_LIFE, "id:%{public}d, create not exist instanceKey:%{public}s",
335             info.persistentId_, info.appInstanceKey_.c_str());
336         CreateNewInstanceKey(info.bundleName_, info.appInstanceKey_);
337     }
338     info.isNewAppInstance_ = false;
339     return true;
340 }
341 
AddInstanceId(const std::string& bundleName, uint32_t instanceId)342 void MultiInstanceManager::AddInstanceId(const std::string& bundleName, uint32_t instanceId)
343 {
344     std::unique_lock<std::shared_mutex> lock(mutex_);
345     auto iter = bundleInstanceIdListMap_.find(bundleName);
346     if (iter == bundleInstanceIdListMap_.end()) {
347         bundleInstanceIdListMap_.emplace(bundleName, std::vector{ instanceId });
348     } else {
349         iter->second.push_back(instanceId);
350     }
351     auto usageMapIter = bundleInstanceUsageMap_.find(bundleName);
352     if (usageMapIter == bundleInstanceUsageMap_.end()) {
353         std::bitset<MAX_INSTANCE_COUNT> bitset;
354         bitset.reset();
355         bitset[instanceId] = 1;
356         bundleInstanceUsageMap_.emplace(bundleName, bitset);
357     } else {
358         usageMapIter->second[instanceId] = 1;
359     }
360     std::ostringstream oss;
361     for (auto id : bundleInstanceIdListMap_.find(bundleName)->second) {
362         oss << id << ",";
363     }
364     TLOGI(WmsLogTag::WMS_LIFE, "bundleName:%{public}s instanceId:%{public}d idList:%{public}s",
365         bundleName.c_str(), instanceId, oss.str().c_str());
366 }
367 
RemoveInstanceId(const std::string& bundleName, uint32_t instanceId)368 void MultiInstanceManager::RemoveInstanceId(const std::string& bundleName, uint32_t instanceId)
369 {
370     std::unique_lock<std::shared_mutex> lock(mutex_);
371     auto iter = bundleInstanceIdListMap_.find(bundleName);
372     if (iter == bundleInstanceIdListMap_.end()) {
373         TLOGE(WmsLogTag::WMS_LIFE, "instanceIdList not found, bundleName:%{public}s instanceId:%{public}d",
374             bundleName.c_str(), instanceId);
375         return;
376     }
377     auto& instanceIdList = iter->second;
378     for (auto it = instanceIdList.begin(); it != instanceIdList.end(); ++it) {
379         if (*it == instanceId) {
380             instanceIdList.erase(it);
381             break;
382         }
383     }
384     auto usageMapIter = bundleInstanceUsageMap_.find(bundleName);
385     if (usageMapIter == bundleInstanceUsageMap_.end()) {
386         TLOGE(WmsLogTag::WMS_LIFE, "instanceUsage not found, bundleName:%{public}s instanceId:%{public}d",
387             bundleName.c_str(), instanceId);
388         return;
389     }
390     usageMapIter->second[instanceId] = 0;
391     std::ostringstream oss;
392     for (auto id : bundleInstanceIdListMap_.find(bundleName)->second) {
393         oss << id << ",";
394     }
395     TLOGI(WmsLogTag::WMS_LIFE, "bundleName:%{public}s instanceId:%{public}d idList:%{public}s",
396         bundleName.c_str(), instanceId, oss.str().c_str());
397 }
398 
ConvertInstanceKeyToInstanceId(const std::string& instanceKey, uint32_t& instanceId) const399 bool MultiInstanceManager::ConvertInstanceKeyToInstanceId(const std::string& instanceKey, uint32_t& instanceId) const
400 {
401     if (instanceKey.empty() || instanceKey.find(APP_INSTANCE_KEY_PREFIX) == -1ul) {
402         return false;
403     }
404     auto prefixSize = APP_INSTANCE_KEY_PREFIX.size();
405     const auto& instanceIdStr = instanceKey.substr(prefixSize, instanceKey.size() - prefixSize);
406     if (!WindowHelper::IsNumber(instanceIdStr)) {
407         return false;
408     }
409     auto instanceIdNum = std::stoi(instanceIdStr);
410     if (instanceIdNum < 0) {
411         return false;
412     }
413     instanceId = static_cast<uint32_t>(instanceIdNum);
414     return true;
415 }
416 } // namespace OHOS::Rosen
417