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