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