1 /*
2 * Copyright (c) 2023-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 "camera_app_manager_client.h"
17 #include "camera_log.h"
18 #include "camera_window_manager_agent.h"
19 #include "camera_window_manager_client.h"
20 #include "ipc_skeleton.h"
21 #include "hcamera_service_proxy.h"
22 #include "system_ability_definition.h"
23 #include "iservice_registry.h"
24 #include "hcamera_device_manager.h"
25 #include <mutex>
26
27 namespace OHOS {
28 namespace CameraStandard {
29 static const int32_t FOREGROUND_STATE_OF_PROCESS = 0;
30 static const int32_t PIP_STATE_OF_PROCESS = 1;
31 static const int32_t BCAKGROUND_STATE_OF_PROCESS = 2;
32 static const int32_t UNKNOW_STATE_OF_PROCESS = 3;
33 static const std::unordered_map<int32_t, int32_t> APP_MGR_STATE_TO_CAMERA_STATE = {
34 {2, FOREGROUND_STATE_OF_PROCESS},
35 {4, BCAKGROUND_STATE_OF_PROCESS}
36 };
37 static const int32_t FOCUSED_STATE_OF_PROCESS = 1;
38 static const int32_t UNFOCUSED_STATE_OF_PROCESS = 0;
39 sptr<HCameraDeviceManager> HCameraDeviceManager::cameraDeviceManager_;
40 std::mutex HCameraDeviceManager::instanceMutex_;
41
HCameraDeviceManager()42 HCameraDeviceManager::HCameraDeviceManager() {}
43
~HCameraDeviceManager()44 HCameraDeviceManager::~HCameraDeviceManager()
45 {
46 HCameraDeviceManager::cameraDeviceManager_ = nullptr;
47 }
48
GetInstance()49 sptr<HCameraDeviceManager> &HCameraDeviceManager::GetInstance()
50 {
51 if (HCameraDeviceManager::cameraDeviceManager_ == nullptr) {
52 std::unique_lock<std::mutex> lock(instanceMutex_);
53 if (HCameraDeviceManager::cameraDeviceManager_ == nullptr) {
54 MEDIA_INFO_LOG("Initializing camera device manager instance");
55 HCameraDeviceManager::cameraDeviceManager_ = new HCameraDeviceManager();
56 CameraWindowManagerClient::GetInstance();
57 }
58 }
59 return HCameraDeviceManager::cameraDeviceManager_;
60 }
61
AddDevice(pid_t pid, sptr<HCameraDevice> device)62 void HCameraDeviceManager::AddDevice(pid_t pid, sptr<HCameraDevice> device)
63 {
64 MEDIA_INFO_LOG("HCameraDeviceManager::AddDevice start");
65 std::lock_guard<std::mutex> lock(mapMutex_);
66 int32_t cost = 0;
67 std::set<std::string> conflicting;
68 device->GetCameraResourceCost(cost, conflicting);
69 int32_t uidOfRequestProcess = IPCSkeleton::GetCallingUid();
70 int32_t pidOfRequestProcess = IPCSkeleton::GetCallingPid();
71 uint32_t accessTokenIdOfRequestProc = IPCSkeleton::GetCallingTokenID();
72 sptr<HCameraDeviceHolder> cameraHolder = new HCameraDeviceHolder(
73 pidOfRequestProcess, uidOfRequestProcess, FOREGROUND_STATE_OF_PROCESS,
74 FOCUSED_STATE_OF_PROCESS, device, accessTokenIdOfRequestProc, cost, conflicting);
75 pidToCameras_.EnsureInsert(pid, cameraHolder);
76 activeCameras_.push_back(cameraHolder);
77 MEDIA_INFO_LOG("HCameraDeviceManager::AddDevice end");
78 }
79
RemoveDevice(const std::string &cameraId)80 void HCameraDeviceManager::RemoveDevice(const std::string &cameraId)
81 {
82 MEDIA_INFO_LOG("HCameraDeviceManager::RemoveDevice cameraId=%{public}s start", cameraId.c_str());
83 std::lock_guard<std::mutex> lock(mapMutex_);
84 if (activeCameras_.empty()) {
85 return;
86 }
87 auto it = std::find_if(activeCameras_.begin(), activeCameras_.end(), [&](const sptr<HCameraDeviceHolder> &x) {
88 const std::string &curCameraId = x->GetDevice()->GetCameraId();
89 return cameraId == curCameraId;
90 });
91 if (it == activeCameras_.end()) {
92 MEDIA_ERR_LOG("HCameraDeviceManager::RemoveDevice error");
93 return;
94 }
95 pidToCameras_.Erase((*it)->GetPid());
96 activeCameras_.erase(it);
97 MEDIA_INFO_LOG("HCameraDeviceManager::RemoveDevice end");
98 }
99
GetCameraHolderByPid(pid_t pidRequest)100 sptr<HCameraDeviceHolder> HCameraDeviceManager::GetCameraHolderByPid(pid_t pidRequest)
101 {
102 MEDIA_INFO_LOG("HCameraDeviceManager::GetCameraHolderByPid start");
103 std::lock_guard<std::mutex> lock(mapMutex_);
104 sptr<HCameraDeviceHolder> cameraHolder = nullptr;
105 pidToCameras_.Find(pidRequest, cameraHolder);
106 MEDIA_INFO_LOG("HCameraDeviceManager::GetCameraHolderByPid end");
107 return cameraHolder;
108 }
109
GetCameraByPid(pid_t pidRequest)110 sptr<HCameraDevice> HCameraDeviceManager::GetCameraByPid(pid_t pidRequest)
111 {
112 MEDIA_INFO_LOG("HCameraDeviceManager::GetCameraByPid start");
113 std::lock_guard<std::mutex> lock(mapMutex_);
114 sptr<HCameraDeviceHolder> cameraHolder = nullptr;
115 pidToCameras_.Find(pidRequest, cameraHolder);
116 sptr<HCameraDevice> camera = nullptr;
117 if (cameraHolder != nullptr) {
118 camera = cameraHolder->GetDevice();
119 }
120 MEDIA_INFO_LOG("HCameraDeviceManager::GetCameraByPid end");
121 return camera;
122 }
123
GetActiveClient()124 pid_t HCameraDeviceManager::GetActiveClient()
125 {
126 MEDIA_INFO_LOG("HCameraDeviceManager::GetActiveClient start");
127 std::lock_guard<std::mutex> lock(mapMutex_);
128 pid_t activeClientPid = -1;
129 if (!pidToCameras_.IsEmpty()) {
130 pidToCameras_.Iterate([&](pid_t pid, sptr<HCameraDeviceHolder> camerasHolder) {
131 activeClientPid = pid;
132 });
133 }
134 MEDIA_INFO_LOG("HCameraDeviceManager::GetActiveClient end");
135 return activeClientPid;
136 }
137
GetActiveCameraHolders()138 std::vector<sptr<HCameraDeviceHolder>> HCameraDeviceManager::GetActiveCameraHolders()
139 {
140 return activeCameras_;
141 }
142
SetStateOfACamera(std::string cameraId, int32_t state)143 void HCameraDeviceManager::SetStateOfACamera(std::string cameraId, int32_t state)
144 {
145 MEDIA_INFO_LOG("HCameraDeviceManager::SetStateOfACamera start %{public}s, state: %{public}d",
146 cameraId.c_str(), state);\
147 if (state == 0) {
148 stateOfACamera_.EnsureInsert(cameraId, state);
149 } else {
150 stateOfACamera_.Clear();
151 }
152 MEDIA_INFO_LOG("HCameraDeviceManager::SetStateOfACamera end");
153 }
154
GetCameraStateOfASide()155 SafeMap<std::string, int32_t> &HCameraDeviceManager::GetCameraStateOfASide()
156 {
157 return stateOfACamera_;
158 }
159
SetPeerCallback(sptr<ICameraBroker>& callback)160 void HCameraDeviceManager::SetPeerCallback(sptr<ICameraBroker>& callback)
161 {
162 CHECK_ERROR_RETURN_LOG(callback == nullptr, "HCameraDeviceManager::SetPeerCallback failed to set peer callback");
163 std::lock_guard<std::mutex> lock(peerCbMutex_);
164 peerCallback_ = callback;
165 }
166
UnsetPeerCallback()167 void HCameraDeviceManager::UnsetPeerCallback()
168 {
169 std::lock_guard<std::mutex> lock(peerCbMutex_);
170 peerCallback_ = nullptr;
171 }
172
GetConflictDevices(sptr<HCameraDevice> &cameraNeedEvict, sptr<HCameraDevice> cameraRequestOpen)173 bool HCameraDeviceManager::GetConflictDevices(sptr<HCameraDevice> &cameraNeedEvict,
174 sptr<HCameraDevice> cameraRequestOpen)
175 {
176 pid_t pidOfActiveClient = GetActiveClient();
177 pid_t pidOfOpenRequest = IPCSkeleton::GetCallingPid();
178 pid_t uidOfOpenRequest = IPCSkeleton::GetCallingUid();
179 uint32_t accessTokenIdOfRequestProc = IPCSkeleton::GetCallingTokenID();
180 MEDIA_INFO_LOG("GetConflictDevices get active: %{public}d, openRequestPid:%{public}d, openRequestUid:%{public}d",
181 pidOfActiveClient, pidOfOpenRequest, uidOfOpenRequest);
182 if (stateOfACamera_.Size() != 0) {
183 CHECK_ERROR_RETURN_RET_LOG(pidOfActiveClient != -1, false,
184 "HCameraDeviceManager::GetConflictDevices rgm and OH camera is turning on in the same time");
185 return IsAllowOpen(pidOfOpenRequest);
186 } else {
187 MEDIA_INFO_LOG("HCameraDeviceManager::GetConflictDevices no rgm camera active");
188 }
189 if (pidOfActiveClient == -1) {
190 return true;
191 }
192 sptr<HCameraDeviceHolder> activeCameraHolder = GetCameraHolderByPid(pidOfActiveClient);
193 if (activeCameraHolder == nullptr) {
194 return true;
195 }
196 if (pidOfActiveClient == pidOfOpenRequest) {
197 MEDIA_INFO_LOG("HCameraDeviceManager::GetConflictDevices is same pid");
198 if (!activeCameraHolder->GetDevice()->GetCameraId().compare(cameraRequestOpen->GetCameraId())) {
199 cameraNeedEvict = activeCameraHolder->GetDevice();
200 return true;
201 } else {
202 return false;
203 }
204 }
205 int32_t activeState = CameraAppManagerClient::GetInstance()->GetProcessState(pidOfActiveClient);
206 int32_t requestState = CameraAppManagerClient::GetInstance()->GetProcessState(pidOfOpenRequest);
207 MEDIA_INFO_LOG("HCameraDeviceManager::GetConflictDevices active pid:%{public}d state: %{public}d,"
208 "request pid:%{public}d state: %{public}d", pidOfActiveClient, activeState, pidOfOpenRequest, requestState);
209 UpdateProcessState(activeState, requestState,
210 activeCameraHolder->GetAccessTokenId(), accessTokenIdOfRequestProc);
211 pid_t focusWindowPid = -1;
212 CameraWindowManagerClient::GetInstance()->GetFocusWindowInfo(focusWindowPid);
213 if (focusWindowPid == -1) {
214 MEDIA_INFO_LOG("GetFocusWindowInfo faild");
215 }
216
217 int32_t focusStateOfRequestProcess = focusWindowPid ==
218 pidOfOpenRequest ? FOCUSED_STATE_OF_PROCESS : UNFOCUSED_STATE_OF_PROCESS;
219 int32_t focusStateOfActiveProcess = focusWindowPid ==
220 pidOfActiveClient ? FOCUSED_STATE_OF_PROCESS : UNFOCUSED_STATE_OF_PROCESS;
221 activeCameraHolder->SetState(activeState);
222 activeCameraHolder->SetFocusState(focusStateOfActiveProcess);
223
224 int32_t cost = 0;
225 std::set<std::string> conflicting;
226
227 sptr<HCameraDeviceHolder> requestCameraHolder = new HCameraDeviceHolder(
228 pidOfOpenRequest, uidOfOpenRequest, requestState,
229 focusStateOfRequestProcess, cameraRequestOpen, accessTokenIdOfRequestProc, cost, conflicting);
230
231 PrintClientInfo(activeCameraHolder, requestCameraHolder);
232 if (*(activeCameraHolder->GetPriority()) <= *(requestCameraHolder->GetPriority())) {
233 cameraNeedEvict = activeCameraHolder->GetDevice();
234 return true;
235 } else {
236 return false;
237 }
238 }
239
HandleCameraEvictions(std::vector<sptr<HCameraDeviceHolder>> &evictedClients, sptr<HCameraDeviceHolder> &cameraRequestOpen)240 bool HCameraDeviceManager::HandleCameraEvictions(std::vector<sptr<HCameraDeviceHolder>> &evictedClients,
241 sptr<HCameraDeviceHolder> &cameraRequestOpen)
242 {
243 pid_t pidOfActiveClient = GetActiveClient();
244 int32_t activeState = CameraAppManagerClient::GetInstance()->GetProcessState(pidOfActiveClient);
245 pid_t pidOfOpenRequest = IPCSkeleton::GetCallingPid();
246 int32_t requestState = CameraAppManagerClient::GetInstance()->GetProcessState(pidOfOpenRequest);
247 const std::string &cameraId = cameraRequestOpen->GetDevice()->GetCameraId();
248 MEDIA_INFO_LOG("Request Open camera ID %{public}s active pid: %{public}d, state: %{public}d,"
249 "request pid: %{public}d, state: %{public}d", cameraId.c_str(), pidOfActiveClient,
250 activeState, pidOfOpenRequest, requestState);
251
252 pid_t focusWindowPid = -1;
253 CameraWindowManagerClient::GetInstance()->GetFocusWindowInfo(focusWindowPid);
254
255 int32_t focusStateOfRequestProcess = focusWindowPid ==
256 pidOfOpenRequest ? FOCUSED_STATE_OF_PROCESS : UNFOCUSED_STATE_OF_PROCESS;
257 cameraRequestOpen->SetState(activeState);
258 cameraRequestOpen->SetFocusState(focusStateOfRequestProcess);
259 MEDIA_INFO_LOG("focusStateOfRequestProcess = %{public}d", focusStateOfRequestProcess);
260
261 // Find Camera Device that would be evicted
262 std::vector<sptr<HCameraDeviceHolder>> evicted = WouldEvict(cameraRequestOpen);
263
264 // If the incoming client was 'evicted,' higher priority clients have the camera in the
265 // background, so we cannot do evictions
266 if (std::find(evicted.begin(), evicted.end(), cameraRequestOpen) != evicted.end()) {
267 MEDIA_INFO_LOG("PID %{public}d) rejected with higher priority", pidOfOpenRequest);
268 return false;
269 }
270 for (auto &x : evicted) {
271 if (x == nullptr) {
272 MEDIA_ERR_LOG("Invalid state: Null client in active client list.");
273 continue;
274 }
275 MEDIA_INFO_LOG("evicting conflicting client for camera ID %s",
276 x->GetDevice()->GetCameraId().c_str());
277 evictedClients.push_back(x);
278 }
279 MEDIA_INFO_LOG("Camera: %{public}s could be opened", cameraId.c_str());
280 return true;
281 }
282
WouldEvict(sptr<HCameraDeviceHolder> &cameraRequestOpen)283 std::vector<sptr<HCameraDeviceHolder>> HCameraDeviceManager::WouldEvict(sptr<HCameraDeviceHolder> &cameraRequestOpen)
284 {
285 std::vector<sptr<HCameraDeviceHolder>> evictList;
286 // Disallow null clients, return input
287 if (cameraRequestOpen == nullptr) {
288 evictList.push_back(cameraRequestOpen);
289 return evictList;
290 }
291 const std::string &cameraId = cameraRequestOpen->GetDevice()->GetCameraId();
292 sptr<CameraProcessPriority> requestPriority = cameraRequestOpen->GetPriority();
293 int32_t owner = cameraRequestOpen->GetPid();
294 int32_t totalCost = GetCurrentCost() + cameraRequestOpen->GetCost();
295
296 // Determine the MRU of the owners tied for having the highest priority
297 int32_t highestPriorityOwner = owner;
298 sptr<CameraProcessPriority> highestPriority = requestPriority;
299 for (const auto &x : activeCameras_) {
300 sptr<CameraProcessPriority> curPriority = x->GetPriority();
301 if (*curPriority >= *highestPriority) {
302 highestPriority = curPriority;
303 highestPriorityOwner = x->GetPid();
304 }
305 }
306 // Switch back owner if the incoming client has the highest priority, as it is MRU
307 highestPriorityOwner = (*highestPriority == *requestPriority) ? owner : highestPriorityOwner;
308
309 // Build eviction list of clients to remove
310 for (const auto &x : activeCameras_) {
311 const std::string &curCameraId = x->GetDevice()->GetCameraId();
312 int32_t curCost = x->GetCost();
313 sptr<CameraProcessPriority> curPriority = x->GetPriority();
314 int32_t curOwner = x->GetPid();
315
316 MEDIA_INFO_LOG("curCameraId: %{public}s, ReqCameraId: %{public}s.", curCameraId.c_str(), cameraId.c_str());
317 MEDIA_INFO_LOG("curCameraId Conflicting: %{public}d", x->IsConflicting(cameraId));
318 MEDIA_INFO_LOG("ReqCameraId Conflicting: %{public}d", cameraRequestOpen->IsConflicting(curCameraId));
319 bool conflicting = (curCameraId == cameraId || x->IsConflicting(cameraId) ||
320 cameraRequestOpen->IsConflicting(curCameraId));
321 // Find evicted clients
322 if (conflicting && *curPriority >= *requestPriority) {
323 // Pre-existing conflicting client with higher priority exists
324 evictList.clear();
325 evictList.push_back(cameraRequestOpen);
326 MEDIA_INFO_LOG("conflicting: Current PID has high priority, Evict ReqCamera.");
327 return evictList;
328 } else if (conflicting || ((totalCost > DEFAULT_MAX_COST && curCost > 0) &&
329 (*curPriority < *requestPriority) && !(highestPriorityOwner == owner && owner == curOwner))) {
330 // Add a pre-existing client to the eviction list if:
331 // - We are adding a client with higher priority that conflicts with this one.
332 // - The total cost including the incoming client's is more than the allowable
333 // maximum, and the client has a non-zero cost, lower priority, and a different
334 // owner than the incoming client when the incoming client has the
335 // highest priority.
336 MEDIA_INFO_LOG("Evict CurCamera.");
337 evictList.push_back(x);
338 totalCost -= curCost;
339 }
340 }
341 MEDIA_INFO_LOG("non-conflicting: totalCost:%{public}d", totalCost);
342 // If the total cost is too high, return the input unless the input has the highest priority
343 if (totalCost > DEFAULT_MAX_COST) {
344 MEDIA_INFO_LOG("totalCost > DEFAULT_MAX_COST, Evict ReqCamera");
345 evictList.clear();
346 evictList.push_back(cameraRequestOpen);
347 }
348 return evictList;
349 }
350
GetCurrentCost() const351 int32_t HCameraDeviceManager::GetCurrentCost() const
352 {
353 int32_t totalCost = 0;
354 for (const auto &x : activeCameras_) {
355 totalCost += x->GetCost();
356 }
357 MEDIA_INFO_LOG("HCameraDeviceManager::GetCurrentCost:%{public}d", totalCost);
358 return totalCost;
359 }
360
GetACameraId()361 std::string HCameraDeviceManager::GetACameraId()
362 {
363 MEDIA_INFO_LOG("HCameraDeviceManager::GetActiveClient start");
364 std::string cameraId;
365 if (!stateOfACamera_.IsEmpty()) {
366 stateOfACamera_.Iterate([&](const std::string pid, int32_t state) {
367 cameraId = pid;
368 });
369 }
370 MEDIA_INFO_LOG("HCameraDeviceManager::GetActiveClient end");
371 return cameraId;
372 }
373
IsAllowOpen(pid_t pidOfOpenRequest)374 bool HCameraDeviceManager::IsAllowOpen(pid_t pidOfOpenRequest)
375 {
376 MEDIA_INFO_LOG("HCameraDeviceManager::isAllowOpen has a client open in A proxy");
377 CHECK_ERROR_RETURN_RET_LOG(pidOfOpenRequest == -1, false,
378 "HCameraDeviceManager::GetConflictDevices wrong pid of the process whitch is goning to turn on");
379 std::string cameraId = GetACameraId();
380 CHECK_ERROR_RETURN_RET_LOG(peerCallback_ == nullptr, false,
381 "HCameraDeviceManager::isAllowOpen falied to close peer device");
382 peerCallback_->NotifyCloseCamera(cameraId);
383 MEDIA_ERR_LOG("HCameraDeviceManager::isAllowOpen success to close peer device");
384 return true;
385 }
386
UpdateProcessState(int32_t& activeState, int32_t& requestState, uint32_t activeAccessTokenId, uint32_t requestAccessTokenId)387 void HCameraDeviceManager::UpdateProcessState(int32_t& activeState, int32_t& requestState,
388 uint32_t activeAccessTokenId, uint32_t requestAccessTokenId)
389 {
390 sptr<IWindowManagerAgent> winMgrAgent = CameraWindowManagerClient::GetInstance()->GetWindowManagerAgent();
391 uint32_t accessTokenIdInPip = 0;
392 if (winMgrAgent != nullptr) {
393 accessTokenIdInPip =
394 static_cast<CameraWindowManagerAgent*>(winMgrAgent.GetRefPtr())->GetAccessTokenId();
395 MEDIA_DEBUG_LOG("update current pip window accessTokenId");
396 }
397
398 auto updateState = [accessTokenIdInPip](int32_t& state, uint32_t accessTokenId) {
399 auto it = APP_MGR_STATE_TO_CAMERA_STATE.find(state);
400 state = (it != APP_MGR_STATE_TO_CAMERA_STATE.end()) ? it->second : UNKNOW_STATE_OF_PROCESS;
401 if (accessTokenId == accessTokenIdInPip) {
402 state = PIP_STATE_OF_PROCESS;
403 }
404 };
405
406 updateState(activeState, activeAccessTokenId);
407 updateState(requestState, requestAccessTokenId);
408 }
409
PrintClientInfo(sptr<HCameraDeviceHolder> activeCameraHolder, sptr<HCameraDeviceHolder> requestCameraHolder)410 void HCameraDeviceManager::PrintClientInfo(sptr<HCameraDeviceHolder> activeCameraHolder,
411 sptr<HCameraDeviceHolder> requestCameraHolder)
412 {
413 MEDIA_INFO_LOG("activeInfo: uid: %{public}d, pid:%{public}d, processState:%{public}d,"
414 "focusState:%{public}d, cameraId:%{public}s",
415 activeCameraHolder->GetPriority()->GetUid(), activeCameraHolder->GetPid(),
416 activeCameraHolder->GetPriority()->GetState(),
417 activeCameraHolder->GetPriority()->GetFocusState(),
418 activeCameraHolder->GetDevice()->GetCameraId().c_str());
419
420 MEDIA_INFO_LOG("requestInfo: uid: %{public}d, pid:%{public}d, processState:%{public}d,"
421 "focusState:%{public}d, cameraId:%{public}s",
422 requestCameraHolder->GetPriority()->GetUid(), requestCameraHolder->GetPid(),
423 requestCameraHolder->GetPriority()->GetState(),
424 requestCameraHolder->GetPriority()->GetFocusState(),
425 requestCameraHolder->GetDevice()->GetCameraId().c_str());
426 }
427
IsMultiCameraActive(int32_t pid)428 bool HCameraDeviceManager::IsMultiCameraActive(int32_t pid)
429 {
430 std::lock_guard<std::mutex> lock(mapMutex_);
431 uint8_t count = 0;
432 for (const auto &x : activeCameras_) {
433 if (pid == x->GetPid()) {
434 count++;
435 }
436 }
437
438 MEDIA_INFO_LOG("pid(%{public}d) has activated %{public}d camera.", pid, count);
439 return count > 0;
440 }
441 } // namespace CameraStandard
442 } // namespace OHOS