• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 "avcodec_server_manager.h"
17 #include <codecvt>
18 #include <dlfcn.h>
19 #include <locale>
20 #include <thread>
21 #include <unistd.h>
22 #include "avcodec_dump_utils.h"
23 #include "avcodec_errors.h"
24 #include "avcodec_log.h"
25 #include "avcodec_trace.h"
26 #include "avcodec_xcollie.h"
27 #include "system_ability_definition.h"
28 #ifdef SUPPORT_CODEC
29 #include "codec_service_stub.h"
30 #endif
31 #ifdef SUPPORT_CODECLIST
32 #include "codeclist_service_stub.h"
33 #endif
34 
35 namespace {
36 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "AVCodecServerManager"};
37 } // namespace
38 
39 namespace OHOS {
40 namespace MediaAVCodec {
GetInstance()41 AVCodecServerManager& AVCodecServerManager::GetInstance()
42 {
43     static AVCodecServerManager instance;
44     return instance;
45 }
46 
Dump(int32_t fd,const std::vector<std::u16string> & args)47 int32_t AVCodecServerManager::Dump(int32_t fd, const std::vector<std::u16string>& args)
48 {
49     if (fd < 0) {
50         return OHOS::NO_ERROR;
51     }
52     AVCodecXCollie::GetInstance().Dump(fd);
53 
54     std::unordered_multimap<pid_t, std::pair<sptr<IRemoteObject>, InstanceInfo>> codecStubMapTemp;
55     {
56         std::lock_guard<std::shared_mutex> lock(mutex_);
57         codecStubMapTemp = codecStubMap_;
58     }
59 
60     constexpr std::string_view dumpStr = "[Codec_Server]\n";
61     write(fd, dumpStr.data(), dumpStr.size());
62 
63     int32_t instanceIndex = 0;
64     for (auto iter : codecStubMapTemp) {
65         std::string instanceStr = std::string("    Instance_") + std::to_string(instanceIndex++) + "_Info\n";
66         write(fd, instanceStr.data(), instanceStr.size());
67         (void)iter.second.first->Dump(fd, args);
68     }
69 
70     return OHOS::NO_ERROR;
71 }
72 
AVCodecServerManager()73 AVCodecServerManager::AVCodecServerManager()
74 {
75     pid_ = getpid();
76     Init();
77     AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
78 }
79 
~AVCodecServerManager()80 AVCodecServerManager::~AVCodecServerManager()
81 {
82     AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
83 }
84 
Init()85 void AVCodecServerManager::Init()
86 {
87     void *handle = dlopen(LIB_PATH, RTLD_NOW);
88     CHECK_AND_RETURN_LOG(handle != nullptr, "Load so failed:%{public}s", LIB_PATH);
89     libMemMgrClientHandle_ = std::shared_ptr<void>(handle, dlclose);
90     notifyProcessStatusFunc_ = reinterpret_cast<NotifyProcessStatusFunc>(dlsym(handle, NOTIFY_STATUS_FUNC_NAME));
91     CHECK_AND_RETURN_LOG(notifyProcessStatusFunc_ != nullptr, "Load notifyProcessStatusFunc failed:%{public}s",
92                          NOTIFY_STATUS_FUNC_NAME);
93     setCriticalFunc_ = reinterpret_cast<SetCriticalFunc>(dlsym(handle, SET_CRITICAL_FUNC_NAME));
94     CHECK_AND_RETURN_LOG(setCriticalFunc_ != nullptr, "Load setCriticalFunc failed:%{public}s",
95                          SET_CRITICAL_FUNC_NAME);
96     return;
97 }
98 
CreateStubObject(StubType type,sptr<IRemoteObject> & object)99 int32_t AVCodecServerManager::CreateStubObject(StubType type, sptr<IRemoteObject> &object)
100 {
101     std::lock_guard<std::shared_mutex> lock(mutex_);
102     switch (type) {
103 #ifdef SUPPORT_CODECLIST
104         case CODECLIST: {
105             return CreateCodecListStubObject(object);
106         }
107 #endif
108 #ifdef SUPPORT_CODEC
109         case CODEC: {
110             return CreateCodecStubObject(object);
111         }
112 #endif
113         default: {
114             AVCODEC_LOGE("default case, av_codec server manager failed");
115             return AVCS_ERR_UNSUPPORT;
116         }
117     }
118 }
119 
120 #ifdef SUPPORT_CODECLIST
CreateCodecListStubObject(sptr<IRemoteObject> & object)121 int32_t AVCodecServerManager::CreateCodecListStubObject(sptr<IRemoteObject> &object)
122 {
123     sptr<CodecListServiceStub> stub = CodecListServiceStub::Create();
124     CHECK_AND_RETURN_RET_LOG(stub != nullptr, AVCS_ERR_CREATE_CODECLIST_STUB_FAILED,
125         "Failed to create AVCodecListServiceStub");
126     object = stub->AsObject();
127     CHECK_AND_RETURN_RET_LOG(object != nullptr, AVCS_ERR_CREATE_CODECLIST_STUB_FAILED,
128         "Failed to create AVCodecListServiceStub");
129 
130     pid_t pid = IPCSkeleton::GetCallingPid();
131     codecListStubMap_[object] = pid;
132     AVCODEC_LOGD("The number of codeclist services(%{public}zu)", codecListStubMap_.size());
133     return AVCS_ERR_OK;
134 }
135 #endif
136 #ifdef SUPPORT_CODEC
CreateCodecStubObject(sptr<IRemoteObject> & object)137 int32_t AVCodecServerManager::CreateCodecStubObject(sptr<IRemoteObject> &object)
138 {
139     static std::atomic<int32_t> instanceId = 0;
140     sptr<CodecServiceStub> stub = CodecServiceStub::Create(instanceId);
141     CHECK_AND_RETURN_RET_LOG(stub != nullptr, AVCS_ERR_CREATE_AVCODEC_STUB_FAILED, "Failed to create CodecServiceStub");
142 
143     object = stub->AsObject();
144     CHECK_AND_RETURN_RET_LOG(object != nullptr, AVCS_ERR_CREATE_AVCODEC_STUB_FAILED,
145         "Failed to create CodecServiceStub");
146 
147     pid_t pid = IPCSkeleton::GetCallingPid();
148     InstanceInfo instanceInfo = {
149         .instanceId = instanceId,
150         .caller = { .pid = pid },
151     };
152     instanceId++;
153     if (instanceId == INT32_MAX) {
154         instanceId = 0;
155     }
156     codecStubMap_.emplace(pid, std::make_pair(object, instanceInfo));
157 
158     SetCritical(true);
159     AVCODEC_LOGD("The number of codec services(%{public}zu)", codecStubMap_.size());
160     return AVCS_ERR_OK;
161 }
162 #endif
163 
DestroyStubObject(StubType type,sptr<IRemoteObject> object)164 void AVCodecServerManager::DestroyStubObject(StubType type, sptr<IRemoteObject> object)
165 {
166     std::lock_guard<std::shared_mutex> lock(mutex_);
167     pid_t pid = IPCSkeleton::GetCallingPid();
168     switch (type) {
169         case CODEC: {
170             auto it = find_if(codecStubMap_.begin(), codecStubMap_.end(),
171                 [object] (std::pair<pid_t, std::pair<sptr<IRemoteObject>, InstanceInfo>> objectPair) ->
172                     bool { return objectPair.second.first == object; });
173             CHECK_AND_BREAK_LOG(it != codecStubMap_.end(), "find codec object failed, pid(%{public}d)", pid);
174 
175             auto preSize = codecStubMap_.size();
176             AVCODEC_LOGI("codec stub services(%{public}zu->%{public}zu) pid(%{public}d)", preSize, preSize - 1, pid);
177             codecStubMap_.erase(it);
178             break;
179         }
180         case CODECLIST: {
181             auto it = find_if(codecListStubMap_.begin(), codecListStubMap_.end(),
182                 [object] (std::pair<sptr<IRemoteObject>, pid_t> objectPair) ->
183                     bool { return objectPair.first == object; });
184             CHECK_AND_BREAK_LOG(it != codecListStubMap_.end(), "find codeclist object failed, pid(%{public}d)", pid);
185 
186             auto preSize = codecListStubMap_.size();
187             AVCODEC_LOGI("codeclist stub services(%{public}zu->%{public}zu) pid(%{public}d)", preSize, preSize - 1,
188                          pid);
189             codecListStubMap_.erase(it);
190             break;
191         }
192         default: {
193             AVCODEC_LOGE("default case, av_codec server manager failed, pid(%{public}d)", pid);
194             break;
195         }
196     }
197     if (codecStubMap_.size() == 0) {
198         SetCritical(false);
199     }
200 }
201 
EraseObject(std::map<sptr<IRemoteObject>,pid_t> & stubMap,pid_t pid)202 void AVCodecServerManager::EraseObject(std::map<sptr<IRemoteObject>, pid_t>& stubMap, pid_t pid)
203 {
204     for (auto it = stubMap.begin(); it != stubMap.end();) {
205         if (it->second == pid) {
206             executor_.Commit(it->first);
207             it = stubMap.erase(it);
208         } else {
209             it++;
210         }
211     }
212     return;
213 }
214 
EraseCodecObjectByPid(pid_t pid)215 void AVCodecServerManager::EraseCodecObjectByPid(pid_t pid)
216 {
217     for (auto it = codecStubMap_.begin(); it != codecStubMap_.end();) {
218         if (it->first == pid) {
219             executor_.Commit(it->second.first);
220             it = codecStubMap_.erase(it);
221         } else {
222             it++;
223         }
224     }
225     return;
226 }
227 
DestroyStubObjectForPid(pid_t pid)228 void AVCodecServerManager::DestroyStubObjectForPid(pid_t pid)
229 {
230     std::lock_guard<std::shared_mutex> lock(mutex_);
231     auto preSize = codecStubMap_.size();
232     EraseCodecObjectByPid(pid);
233     AVCODEC_LOGI("codec stub services(%{public}zu->%{public}zu),pid(%{public}d)", preSize, codecStubMap_.size(), pid);
234 
235     preSize = codecListStubMap_.size();
236     EraseObject(codecListStubMap_, pid);
237     AVCODEC_LOGI("codeclist stub services(%{public}zu->%{public}zu),pid(%{public}d)", preSize, codecListStubMap_.size(),
238                  pid);
239     executor_.Clear();
240     if (codecStubMap_.size() == 0) {
241         SetCritical(false);
242     } else {
243         PrintCodecCallersInfo();
244     }
245 }
246 
PrintCodecCallersInfo()247 void AVCodecServerManager::PrintCodecCallersInfo()
248 {
249     typedef struct CodecCallerInfo {
250         InstanceInfo info;
251         int32_t count = 0;
252     } CodecCallerInfo;
253     auto processCodecType = [](auto &infoMap, const char *typeStr) {
254         for (auto &[pid, data] : infoMap) {
255             const InstanceInfo &info = data.info;
256             const bool isForwardCaller = (info.forwardCaller.pid != INVALID_PID);
257             const CallerInfo &caller = isForwardCaller ? info.forwardCaller : info.caller;
258             if (isForwardCaller) {
259                 AVCODEC_LOGI("[%{public}s->%{public}s][pid %{public}d] holding %{public}d %{public}s",
260                              caller.processName.c_str(), info.caller.processName.c_str(), caller.pid, data.count,
261                              typeStr);
262             } else {
263                 AVCODEC_LOGI("[%{public}s][pid %{public}d] holding %{public}d %{public}s", caller.processName.c_str(),
264                              caller.pid, data.count, typeStr);
265             }
266         }
267     };
268     std::map<pid_t, CodecCallerInfo> vencCallerInfo;
269     std::map<pid_t, CodecCallerInfo> vdecCallerInfo;
270     for (auto &[_, instance] : codecStubMap_) {
271         const InstanceInfo &info = instance.second;
272         const pid_t actualPid = (info.forwardCaller.pid != INVALID_PID) ? info.forwardCaller.pid : info.caller.pid;
273         auto *targetMap = (info.codecType == AVCODEC_TYPE_VIDEO_ENCODER)   ? &vencCallerInfo
274                           : (info.codecType == AVCODEC_TYPE_VIDEO_DECODER) ? &vdecCallerInfo
275                                                                            : nullptr;
276         if (targetMap == nullptr) {
277             continue;
278         }
279         CodecCallerInfo &data = (*targetMap)[actualPid];
280         if (data.count == 0) {
281             data.info = info;
282         }
283         data.count++;
284     }
285     processCodecType(vencCallerInfo, "video encoder");
286     processCodecType(vdecCallerInfo, "video decoder");
287 }
288 
NotifyProcessStatus(const int32_t status)289 void AVCodecServerManager::NotifyProcessStatus(const int32_t status)
290 {
291     CHECK_AND_RETURN_LOG(notifyProcessStatusFunc_ != nullptr, "notify memory manager is nullptr, %{public}d", status);
292     int32_t ret = notifyProcessStatusFunc_(pid_, 1, status, AV_CODEC_SERVICE_ID);
293     if (ret == 0) {
294         AVCODEC_LOGI("notify memory manager to %{public}d success", status);
295     } else {
296         AVCODEC_LOGW("notify memory manager to %{public}d fail", status);
297     }
298 }
299 
SetMemMgrStatus(const bool isStarted)300 void AVCodecServerManager::SetMemMgrStatus(const bool isStarted)
301 {
302     std::lock_guard<std::shared_mutex> lock(mutex_);
303     memMgrStarted_ = isStarted;
304 }
305 
SetCritical(const bool isKeyService)306 void AVCodecServerManager::SetCritical(const bool isKeyService)
307 {
308     CHECK_AND_RETURN_LOG(memMgrStarted_, "Memory manager service is not started");
309     CHECK_AND_RETURN_LOG(setCriticalFunc_ != nullptr, "set critical is nullptr, %{public}d", isKeyService);
310     int32_t ret = setCriticalFunc_(pid_, isKeyService, AV_CODEC_SERVICE_ID);
311     if (ret == 0) {
312         AVCODEC_LOGI("set critical to %{public}d success", isKeyService);
313     } else {
314         AVCODEC_LOGW("set critical to %{public}d fail", isKeyService);
315     }
316 }
317 
GetInstanceCount()318 uint32_t AVCodecServerManager::GetInstanceCount()
319 {
320     std::shared_lock<std::shared_mutex> lock(mutex_);
321     return codecStubMap_.size() + codecListStubMap_.size();
322 }
323 
GetInstanceInfoListByPid(pid_t pid)324 std::vector<CodecInstance> AVCodecServerManager::GetInstanceInfoListByPid(pid_t pid)
325 {
326     std::shared_lock<std::shared_mutex> lock(mutex_);
327     std::vector<CodecInstance> instanceInfoList;
328     auto range = codecStubMap_.equal_range(pid);
329     for (auto iter = range.first; iter != range.second; iter++) {
330         instanceInfoList.emplace_back(iter->second);
331     }
332     return instanceInfoList;
333 }
334 
GetInstanceInfoListByActualPid(pid_t pid)335 std::vector<CodecInstance> AVCodecServerManager::GetInstanceInfoListByActualPid(pid_t pid)
336 {
337     std::shared_lock<std::shared_mutex> lock(mutex_);
338     std::vector<CodecInstance> instanceInfoList;
339     for (auto iter = codecStubMap_.begin(); iter != codecStubMap_.end(); iter++) {
340         auto forwardCallerPid = iter->second.second.forwardCaller.pid;
341         auto callerPid = iter->second.second.caller.pid;
342         auto actualPid = forwardCallerPid == INVALID_PID ? callerPid : forwardCallerPid;
343         if (pid == actualPid) {
344             instanceInfoList.emplace_back(iter->second);
345         }
346     }
347     return instanceInfoList;
348 }
349 
GetInstanceInfoByInstanceId(int32_t instanceId)350 std::optional<InstanceInfo> AVCodecServerManager::GetInstanceInfoByInstanceId(int32_t instanceId)
351 {
352     std::shared_lock<std::shared_mutex> lock(mutex_);
353     for (auto iter = codecStubMap_.begin(); iter != codecStubMap_.end(); iter++) {
354         if (iter->second.second.instanceId == instanceId) {
355             return iter->second.second;
356         }
357     }
358     return std::nullopt;
359 }
360 
GetCodecInstanceByInstanceId(int32_t instanceId)361 std::optional<CodecInstance> AVCodecServerManager::GetCodecInstanceByInstanceId(int32_t instanceId)
362 {
363     std::shared_lock<std::shared_mutex> lock(mutex_);
364     for (auto iter = codecStubMap_.begin(); iter != codecStubMap_.end(); iter++) {
365         if (iter->second.second.instanceId == instanceId) {
366             return iter->second;
367         }
368     }
369     return std::nullopt;
370 }
371 
SetInstanceInfoByInstanceId(int32_t instanceId,const InstanceInfo & info)372 void AVCodecServerManager::SetInstanceInfoByInstanceId(int32_t instanceId, const InstanceInfo &info)
373 {
374     std::lock_guard<std::shared_mutex> lock(mutex_);
375     for (auto iter = codecStubMap_.begin(); iter != codecStubMap_.end(); iter++) {
376         if (iter->second.second.instanceId == instanceId) {
377             iter->second.second = info;
378         }
379     }
380 }
381 
Commit(sptr<IRemoteObject> obj)382 void AVCodecServerManager::AsyncExecutor::Commit(sptr<IRemoteObject> obj)
383 {
384     std::lock_guard<std::mutex> lock(listMutex_);
385     freeList_.push_back(obj);
386 }
387 
Clear()388 void AVCodecServerManager::AsyncExecutor::Clear()
389 {
390     std::thread(&AVCodecServerManager::AsyncExecutor::HandleAsyncExecution, this).detach();
391 }
392 
HandleAsyncExecution()393 void AVCodecServerManager::AsyncExecutor::HandleAsyncExecution()
394 {
395     std::list<sptr<IRemoteObject>> tempList;
396     {
397         std::lock_guard<std::mutex> lock(listMutex_);
398         freeList_.swap(tempList);
399     }
400     tempList.clear();
401 }
402 } // namespace MediaAVCodec
403 } // namespace OHOS
404