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