• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         auto flag = static_cast<int32_t>(AppExecFwk::GetApplicationFlag::GET_APPLICATION_INFO_DEFAULT);
61         if (!bundleMgr_ || bundleMgr_->GetApplicationInfosV9(flag, 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::unique_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     if (!IsMultiInstance(bundleName)) {
95         return 0u;
96     }
97     std::shared_lock<std::shared_mutex> lock(appInfoMutex_);
98     auto iter = appInfoMap_.find(bundleName);
99     if (iter != appInfoMap_.end()) {
100         return iter->second.multiAppMode.maxCount;
101     }
102     return 0u;
103 }
104 
GetInstanceCount(const std::string & bundleName)105 uint32_t MultiInstanceManager::GetInstanceCount(const std::string& bundleName)
106 {
107     std::shared_lock<std::shared_mutex> lock(mutex_);
108     auto iter = bundleInstanceIdListMap_.find(bundleName);
109     if (iter == bundleInstanceIdListMap_.end()) {
110         return 0u;
111     } else {
112         return static_cast<uint32_t>(iter->second.size());
113     }
114 }
115 
GetLastInstanceKey(const std::string & bundleName)116 std::string MultiInstanceManager::GetLastInstanceKey(const std::string& bundleName)
117 {
118     std::shared_lock<std::shared_mutex> lock(mutex_);
119     auto iter = bundleInstanceIdListMap_.find(bundleName);
120     if (iter == bundleInstanceIdListMap_.end() || iter->second.size() == 0) {
121         TLOGE(WmsLogTag::WMS_LIFE, "not found last instance key, bundleName:%{public}s", bundleName.c_str());
122         return "";
123     } else {
124         TLOGI(WmsLogTag::WMS_LIFE, "bundleName:%{public}s instanceKey:app_instance_%{public}u",
125             bundleName.c_str(), iter->second.back());
126         return APP_INSTANCE_KEY_PREFIX + std::to_string(iter->second.back());
127     }
128 }
129 
CreateNewInstanceKey(const std::string & bundleName,const std::string & instanceKey)130 std::string MultiInstanceManager::CreateNewInstanceKey(const std::string& bundleName, const std::string& instanceKey)
131 {
132     auto maxInstanceCount = GetMaxInstanceCount(bundleName);
133     uint32_t instanceId = DEFAULT_INSTANCE_ID;
134     if (!instanceKey.empty()) {
135         if (!ConvertInstanceKeyToInstanceId(instanceKey, instanceId) || instanceId >= maxInstanceCount) {
136             TLOGE(WmsLogTag::WMS_LIFE, "invalid instanceKey, bundleName:%{public}s instanceKey:%{public}s",
137                 bundleName.c_str(), instanceKey.c_str());
138             return instanceKey;
139         }
140         AddInstanceId(bundleName, instanceId);
141         return instanceKey;
142     }
143     instanceId = FindMinimumAvailableInstanceId(bundleName, maxInstanceCount);
144     AddInstanceId(bundleName, instanceId);
145     return APP_INSTANCE_KEY_PREFIX + std::to_string(instanceId);
146 }
147 
IsValidInstanceKey(const std::string & bundleName,const std::string & instanceKey)148 bool MultiInstanceManager::IsValidInstanceKey(const std::string& bundleName, const std::string& instanceKey)
149 {
150     if (instanceKey.find(APP_INSTANCE_KEY_PREFIX) == -1ul) {
151         TLOGE(WmsLogTag::WMS_LIFE, "bundleName:%{public}s with invalid instanceKey:%{public}s",
152             bundleName.c_str(), instanceKey.c_str());
153         return false;
154     }
155     auto maxInstanceCount = GetMaxInstanceCount(bundleName);
156     auto instanceId = DEFAULT_INSTANCE_ID;
157     if (!ConvertInstanceKeyToInstanceId(instanceKey, instanceId) || instanceId >= maxInstanceCount) {
158         TLOGE(WmsLogTag::WMS_LIFE, "invalid instanceKey, bundleName:%{public}s instanceKey:%{public}s",
159             bundleName.c_str(), instanceKey.c_str());
160         return false;
161     }
162     return true;
163 }
164 
IsInstanceKeyExist(const std::string & bundleName,const std::string & instanceKey)165 bool MultiInstanceManager::IsInstanceKeyExist(const std::string& bundleName, const std::string& instanceKey)
166 {
167     std::shared_lock<std::shared_mutex> lock(mutex_);
168     auto iter = bundleInstanceIdListMap_.find(bundleName);
169     if (iter == bundleInstanceIdListMap_.end()) {
170         TLOGE(WmsLogTag::WMS_LIFE, "instanceIdList not found, bundleName:%{public}s instanceKey:%{public}s",
171             bundleName.c_str(), instanceKey.c_str());
172         return false;
173     }
174     auto instanceId = DEFAULT_INSTANCE_ID;
175     if (!ConvertInstanceKeyToInstanceId(instanceKey, instanceId)) {
176         TLOGE(WmsLogTag::WMS_LIFE, "invalid instanceKey, bundleName:%{public}s instanceKey:%{public}s",
177             bundleName.c_str(), instanceKey.c_str());
178         return false;
179     }
180     return std::find(iter->second.begin(), iter->second.end(), instanceId) != iter->second.end();
181 }
182 
RemoveInstanceKey(const std::string & bundleName,const std::string & instanceKey)183 void MultiInstanceManager::RemoveInstanceKey(const std::string& bundleName, const std::string& instanceKey)
184 {
185     auto instanceId = DEFAULT_INSTANCE_ID;
186     if (!ConvertInstanceKeyToInstanceId(instanceKey, instanceId)) {
187         TLOGE(WmsLogTag::WMS_LIFE, "invalid instanceKey, bundleName:%{public}s instanceKey:%{public}s",
188             bundleName.c_str(), instanceKey.c_str());
189         return;
190     }
191     RemoveInstanceId(bundleName, instanceId);
192 }
193 
FindMinimumAvailableInstanceId(const std::string & bundleName,uint32_t maxInstanceCount)194 uint32_t MultiInstanceManager::FindMinimumAvailableInstanceId(const std::string& bundleName,
195     uint32_t maxInstanceCount)
196 {
197     std::shared_lock<std::shared_mutex> lock(mutex_);
198     auto iter = bundleInstanceUsageMap_.find(bundleName);
199     if (iter == bundleInstanceUsageMap_.end()) {
200         TLOGE(WmsLogTag::WMS_LIFE, "not found available instanceId");
201         return DEFAULT_INSTANCE_ID;
202     }
203     for (auto i = 0u; i < maxInstanceCount; i++) {
204         if (iter->second[i] == 0) {
205             return i;
206         }
207     }
208     TLOGE(WmsLogTag::WMS_LIFE, "not found available instanceId");
209     return DEFAULT_INSTANCE_ID;
210 }
211 
RefreshAppInfo(const std::string & bundleName)212 void MultiInstanceManager::RefreshAppInfo(const std::string& bundleName)
213 {
214     std::unique_lock<std::shared_mutex> lock(appInfoMutex_);
215     AppExecFwk::ApplicationInfo appInfo;
216     if (bundleMgr_ && bundleMgr_->GetApplicationInfo(
217         bundleName, AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId_, appInfo)) {
218         appInfoMap_[bundleName] = appInfo;
219     } else {
220         appInfoMap_.erase(bundleName);
221     }
222 }
223 
IncreaseInstanceKeyRefCount(const sptr<SceneSession> & sceneSession)224 void MultiInstanceManager::IncreaseInstanceKeyRefCount(const sptr<SceneSession>& sceneSession)
225 {
226     if (!sceneSession) {
227         TLOGE(WmsLogTag::WMS_LIFE, "sceneSession is nullptr");
228         return;
229     }
230     if (!WindowHelper::IsMainWindow(sceneSession->GetWindowType())) {
231         TLOGE(WmsLogTag::WMS_LIFE, "sceneSession is not main window");
232         return;
233     }
234     const auto& instanceKey = sceneSession->GetSessionInfo().appInstanceKey_;
235     if (instanceKey.empty()) {
236         TLOGD(WmsLogTag::WMS_LIFE, "instanceKey is empty");
237         return;
238     }
239     const auto& bundleName = sceneSession->GetSessionInfo().bundleName_;
240     const auto bundleInstanceKey = bundleName + instanceKey;
241     auto iter = instanceKeyRefCountMap_.find(bundleInstanceKey);
242     if (iter == instanceKeyRefCountMap_.end()) {
243         TLOGD(WmsLogTag::WMS_LIFE, "bundleInstanceKey not exist.");
244         instanceKeyRefCountMap_.emplace(bundleInstanceKey, 1);
245     } else {
246         ++(iter->second);
247     }
248 }
249 
DecreaseInstanceKeyRefCount(const sptr<SceneSession> & sceneSession)250 void MultiInstanceManager::DecreaseInstanceKeyRefCount(const sptr<SceneSession>& sceneSession)
251 {
252     if (!sceneSession) {
253         TLOGE(WmsLogTag::WMS_LIFE, "sceneSession is nullptr");
254         return;
255     }
256     if (!WindowHelper::IsMainWindow(sceneSession->GetWindowType())) {
257         TLOGE(WmsLogTag::WMS_LIFE, "sceneSession is not main window");
258         return;
259     }
260     const auto& instanceKey = sceneSession->GetSessionInfo().appInstanceKey_;
261     if (instanceKey.empty()) {
262         TLOGD(WmsLogTag::WMS_LIFE, "instanceKey is empty");
263         return;
264     }
265     const auto& bundleName = sceneSession->GetSessionInfo().bundleName_;
266     DecreaseInstanceKeyRefCountByBundleNameAndInstanceKey(bundleName, instanceKey);
267 }
268 
DecreaseInstanceKeyRefCountByBundleNameAndInstanceKey(const std::string & bundleName,const std::string & instanceKey)269 void MultiInstanceManager::DecreaseInstanceKeyRefCountByBundleNameAndInstanceKey(const std::string& bundleName,
270     const std::string& instanceKey)
271 {
272     const auto bundleInstanceKey = bundleName + instanceKey;
273     auto iter = instanceKeyRefCountMap_.find(bundleInstanceKey);
274     if (iter == instanceKeyRefCountMap_.end()) {
275         TLOGD(WmsLogTag::WMS_LIFE, "bundleInstanceKey not exist.");
276         return;
277     }
278     if (--(iter->second) <= 0) {
279         instanceKeyRefCountMap_.erase(bundleInstanceKey);
280         RemoveInstanceKey(bundleName, instanceKey);
281     }
282 }
283 
FillInstanceKeyIfNeed(const sptr<SceneSession> & sceneSession)284 void MultiInstanceManager::FillInstanceKeyIfNeed(const sptr<SceneSession>& sceneSession)
285 {
286     if (!sceneSession) {
287         TLOGE(WmsLogTag::WMS_LIFE, "sceneSession is nullptr");
288         return;
289     }
290     if (!WindowHelper::IsMainWindow(sceneSession->GetWindowType())) {
291         TLOGD(WmsLogTag::WMS_LIFE, "sceneSession is not main window");
292         return;
293     }
294     const auto& bundleName = sceneSession->GetSessionInfo().bundleName_;
295     uint32_t maxInstanceCount = GetMaxInstanceCount(bundleName);
296     if (maxInstanceCount <= 0) {
297         TLOGD(WmsLogTag::WMS_LIFE, "maxInstanceCount is not valid");
298         return;
299     }
300     const auto& sessionInfo = sceneSession->GetSessionInfo();
301     if (sessionInfo.appInstanceKey_.empty()) {
302         uint32_t instanceCount = GetInstanceCount(bundleName);
303         if (sessionInfo.isNewAppInstance_ && instanceCount < maxInstanceCount) {
304             sceneSession->SetAppInstanceKey(CreateNewInstanceKey(bundleName));
305         } else {
306             sceneSession->SetAppInstanceKey(GetLastInstanceKey(bundleName));
307         }
308     } else if (!IsInstanceKeyExist(sessionInfo.bundleName_, sessionInfo.appInstanceKey_)) {
309         TLOGI(WmsLogTag::WMS_LIFE, "create not exist instanceKey, bundleName:%{public}s instanceKey:%{public}s",
310             bundleName.c_str(), sessionInfo.appInstanceKey_.c_str());
311         CreateNewInstanceKey(sessionInfo.bundleName_, sessionInfo.appInstanceKey_);
312     }
313 }
314 
MultiInstancePendingSessionActivation(SessionInfo & info)315 bool MultiInstanceManager::MultiInstancePendingSessionActivation(SessionInfo& info)
316 {
317     auto maxInstanceCount = GetMaxInstanceCount(info.bundleName_);
318     TLOGI(WmsLogTag::WMS_LIFE, "id:%{public}d maxInstanceCount:%{public}d", info.persistentId_, maxInstanceCount);
319     if (maxInstanceCount <= 0) {
320         return true;
321     }
322     if (info.appInstanceKey_.empty()) {
323         if (info.persistentId_ != 0) {
324             TLOGE(WmsLogTag::WMS_LIFE, "empty instance key, persistentId:%{public}d", info.persistentId_);
325             return false;
326         }
327         info.isNewAppInstance_ = true;
328         return true;
329     } else if (!IsValidInstanceKey(info.bundleName_, info.appInstanceKey_)) {
330         TLOGE(WmsLogTag::WMS_LIFE, "invalid instancekey:%{public}s", info.appInstanceKey_.c_str());
331         return false;
332     } else if (!IsInstanceKeyExist(info.bundleName_, info.appInstanceKey_)) {
333         TLOGI(WmsLogTag::WMS_LIFE, "id:%{public}d, create not exist instanceKey:%{public}s",
334             info.persistentId_, info.appInstanceKey_.c_str());
335         CreateNewInstanceKey(info.bundleName_, info.appInstanceKey_);
336     }
337     info.isNewAppInstance_ = false;
338     return true;
339 }
340 
AddInstanceId(const std::string & bundleName,uint32_t instanceId)341 void MultiInstanceManager::AddInstanceId(const std::string& bundleName, uint32_t instanceId)
342 {
343     std::unique_lock<std::shared_mutex> lock(mutex_);
344     auto iter = bundleInstanceIdListMap_.find(bundleName);
345     if (iter == bundleInstanceIdListMap_.end()) {
346         bundleInstanceIdListMap_.emplace(bundleName, std::vector{ instanceId });
347     } else {
348         iter->second.push_back(instanceId);
349     }
350     auto usageMapIter = bundleInstanceUsageMap_.find(bundleName);
351     if (usageMapIter == bundleInstanceUsageMap_.end()) {
352         std::bitset<MAX_INSTANCE_COUNT> bitset;
353         bitset.reset();
354         bitset[instanceId] = 1;
355         bundleInstanceUsageMap_.emplace(bundleName, bitset);
356     } else {
357         usageMapIter->second[instanceId] = 1;
358     }
359     std::ostringstream oss;
360     for (auto id : bundleInstanceIdListMap_.find(bundleName)->second) {
361         oss << id << ",";
362     }
363     TLOGI(WmsLogTag::WMS_LIFE, "bundleName:%{public}s instanceId:%{public}d idList:%{public}s",
364         bundleName.c_str(), instanceId, oss.str().c_str());
365 }
366 
RemoveInstanceId(const std::string & bundleName,uint32_t instanceId)367 void MultiInstanceManager::RemoveInstanceId(const std::string& bundleName, uint32_t instanceId)
368 {
369     std::unique_lock<std::shared_mutex> lock(mutex_);
370     auto iter = bundleInstanceIdListMap_.find(bundleName);
371     if (iter == bundleInstanceIdListMap_.end()) {
372         TLOGE(WmsLogTag::WMS_LIFE, "instanceIdList not found, bundleName:%{public}s instanceId:%{public}d",
373             bundleName.c_str(), instanceId);
374         return;
375     }
376     auto& instanceIdList = iter->second;
377     for (auto it = instanceIdList.begin(); it != instanceIdList.end(); ++it) {
378         if (*it == instanceId) {
379             instanceIdList.erase(it);
380             break;
381         }
382     }
383     auto usageMapIter = bundleInstanceUsageMap_.find(bundleName);
384     if (usageMapIter == bundleInstanceUsageMap_.end()) {
385         TLOGE(WmsLogTag::WMS_LIFE, "instanceUsage not found, bundleName:%{public}s instanceId:%{public}d",
386             bundleName.c_str(), instanceId);
387         return;
388     }
389     usageMapIter->second[instanceId] = 0;
390     std::ostringstream oss;
391     for (auto id : bundleInstanceIdListMap_.find(bundleName)->second) {
392         oss << id << ",";
393     }
394     TLOGI(WmsLogTag::WMS_LIFE, "bundleName:%{public}s instanceId:%{public}d idList:%{public}s",
395         bundleName.c_str(), instanceId, oss.str().c_str());
396 }
397 
ConvertInstanceKeyToInstanceId(const std::string & instanceKey,uint32_t & instanceId) const398 bool MultiInstanceManager::ConvertInstanceKeyToInstanceId(const std::string& instanceKey, uint32_t& instanceId) const
399 {
400     if (instanceKey.empty() || instanceKey.find(APP_INSTANCE_KEY_PREFIX) == -1ul) {
401         return false;
402     }
403     auto prefixSize = APP_INSTANCE_KEY_PREFIX.size();
404     const auto& instanceIdStr = instanceKey.substr(prefixSize, instanceKey.size() - prefixSize);
405     if (!WindowHelper::IsNumber(instanceIdStr)) {
406         return false;
407     }
408     auto instanceIdNum = std::stoi(instanceIdStr);
409     if (instanceIdNum < 0) {
410         return false;
411     }
412     instanceId = static_cast<uint32_t>(instanceIdNum);
413     return true;
414 }
415 
GetApplicationInfo(const std::string & bundleName) const416 AppExecFwk::ApplicationInfo MultiInstanceManager::GetApplicationInfo(const std::string& bundleName) const
417 {
418     std::shared_lock<std::shared_mutex> lock(appInfoMutex_);
419     AppExecFwk::ApplicationInfo applicationInfo;
420     if (appInfoMap_.count(bundleName)) {
421         applicationInfo = appInfoMap_.at(bundleName);
422     }
423     return applicationInfo;
424 }
425 } // namespace OHOS::Rosen
426