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 <thread>
18 #include <unistd.h>
19 #include <codecvt>
20 #include <locale>
21 #include "avcodec_trace.h"
22 #include "avcodec_errors.h"
23 #include "avcodec_log.h"
24 #include "avcodec_xcollie.h"
25 #include "avcodec_dump_utils.h"
26 #include "avcodec_bitstream_dump.h"
27 #ifdef SUPPORT_CODEC
28 #include "codec_service_stub.h"
29 #endif
30 #ifdef SUPPORT_CODECLIST
31 #include "codeclist_service_stub.h"
32 #endif
33
34 namespace {
35 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecServerManager"};
36 constexpr uint32_t DUMP_MENU_INDEX = 0x01000000;
37 constexpr uint32_t DUMP_INSTANCE_INDEX = 0x01010000;
38 constexpr uint32_t DUMP_PID_INDEX = 0x01010100;
39 constexpr uint32_t DUMP_UID_INDEX = 0x01010200;
40 constexpr uint32_t DUMP_OFFSET_16 = 16;
41
42 const std::vector<const std::string> SA_DUMP_MENU_DUMP_TABLE = {
43 "All", "Codec", " ", "Switch_bitstream_dump"
44 };
45
46 const std::map<OHOS::MediaAVCodec::AVCodecServerManager::StubType, const std::string> STUB_TYPE_STRING_MAP = {
47 { OHOS::MediaAVCodec::AVCodecServerManager::StubType::CODEC, "Codec"},
48 { OHOS::MediaAVCodec::AVCodecServerManager::StubType::MUXER, "Muxer"},
49 };
50 } // namespace
51
52 namespace OHOS {
53 namespace MediaAVCodec {
54 constexpr uint32_t SERVER_MAX_NUMBER = 16;
GetInstance()55 AVCodecServerManager& AVCodecServerManager::GetInstance()
56 {
57 static AVCodecServerManager instance;
58 return instance;
59 }
60
WriteFd(int32_t fd,std::string & str)61 void WriteFd(int32_t fd, std::string& str)
62 {
63 if (fd != -1) {
64 write(fd, str.c_str(), str.size());
65 }
66 str.clear();
67 }
68
WriteInfo(int32_t fd,std::string & dumpString,std::vector<Dumper> dumpers,bool needDetail)69 int32_t WriteInfo(int32_t fd, std::string& dumpString, std::vector<Dumper> dumpers, bool needDetail)
70 {
71 WriteFd(fd, dumpString);
72
73 if (needDetail) {
74 int32_t instanceIndex = 0;
75 for (auto iter : dumpers) {
76 AVCodecDumpControler dumpControler;
77 dumpControler.AddInfo(DUMP_INSTANCE_INDEX, std::string("Instance_") +
78 std::to_string(instanceIndex++) + "_Info");
79 dumpControler.AddInfo(DUMP_PID_INDEX, "PID", std::to_string(iter.pid_));
80 dumpControler.AddInfo(DUMP_UID_INDEX, "UID", std::to_string(iter.uid_));
81 dumpControler.GetDumpString(dumpString);
82 WriteFd(fd, dumpString);
83
84 int32_t ret = iter.entry_(fd);
85 std::string lineBreak = "\n";
86 WriteFd(fd, lineBreak);
87 CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, OHOS::INVALID_OPERATION, "Call dumper callback failed");
88 }
89 }
90
91 return OHOS::NO_ERROR;
92 }
93
DumpServer(int32_t fd,StubType stubType,std::unordered_set<std::u16string> & argSets)94 void AVCodecServerManager::DumpServer(int32_t fd, StubType stubType, std::unordered_set<std::u16string> &argSets)
95 {
96 auto itServeName = STUB_TYPE_STRING_MAP.find(stubType);
97 CHECK_AND_RETURN_LOG(itServeName != STUB_TYPE_STRING_MAP.end(), "Get a unknow stub type!");
98
99 std::string ServeName = itServeName->second;
100 std::string dumpString = "[" + ServeName + "_Server]\n";
101 bool dumpFlag = argSets.find(u"All") != argSets.end();
102 dumpFlag = dumpFlag || (argSets.find(std::wstring_convert<
103 std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(ServeName)) != argSets.end());
104 int32_t ret = WriteInfo(fd, dumpString, dumperTbl_[stubType], dumpFlag);
105 CHECK_AND_RETURN_LOG(ret == OHOS::NO_ERROR,
106 "Failed to write %{public}s server information", ServeName.c_str());
107 }
108
Dump(int32_t fd,const std::vector<std::u16string> & args)109 int32_t AVCodecServerManager::Dump(int32_t fd, const std::vector<std::u16string>& args)
110 {
111 std::string dumpString;
112 std::unordered_set<std::u16string> argSets;
113 for (decltype(args.size()) index = 0; index < args.size(); ++index) {
114 argSets.insert(args[index]);
115 }
116
117 #ifdef SUPPORT_CODEC
118 DumpServer(fd, StubType::CODEC, argSets);
119 #endif
120 int32_t ret = AVCodecXCollie::GetInstance().Dump(fd);
121 CHECK_AND_RETURN_RET_LOG(ret == OHOS::NO_ERROR, OHOS::INVALID_OPERATION,
122 "Failed to write xcollie dump information");
123
124 if (argSets.empty() || argSets.find(u"h") != argSets.end() || argSets.find(u"help") != argSets.end()) {
125 PrintDumpMenu(fd);
126 }
127
128 if (argSets.find(u"Switch_bitstream_dump") != argSets.end()) {
129 dumpString += "[Bitstream_Dump]\n";
130 bool isEnable = AVCodecBitStreamDumper::GetInstance().SwitchEnable();
131 dumpString += " status - ";
132 dumpString += isEnable ? "Enable" : "Disable";
133 dumpString += "\n";
134
135 WriteFd(fd, dumpString);
136 }
137
138 return OHOS::NO_ERROR;
139 }
140
AVCodecServerManager()141 AVCodecServerManager::AVCodecServerManager()
142 {
143 AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
144 }
145
~AVCodecServerManager()146 AVCodecServerManager::~AVCodecServerManager()
147 {
148 AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
149 }
150
CreateStubObject(StubType type)151 sptr<IRemoteObject> AVCodecServerManager::CreateStubObject(StubType type)
152 {
153 std::lock_guard<std::mutex> lock(mutex_);
154 switch (type) {
155 #ifdef SUPPORT_CODECLIST
156 case CODECLIST: {
157 return CreateCodecListStubObject();
158 }
159 #endif
160 #ifdef SUPPORT_CODEC
161 case CODEC: {
162 return CreateCodecStubObject();
163 }
164 #endif
165 default: {
166 AVCODEC_LOGE("default case, av_codec server manager failed");
167 return nullptr;
168 }
169 }
170 }
171
172 #ifdef SUPPORT_CODECLIST
CreateCodecListStubObject()173 sptr<IRemoteObject> AVCodecServerManager::CreateCodecListStubObject()
174 {
175 if (codecListStubMap_.size() >= SERVER_MAX_NUMBER) {
176 AVCODEC_LOGE(
177 "The number of codeclist services(%{public}zu) has reached the upper limit."
178 "Please release the applied resources.",
179 codecListStubMap_.size());
180 return nullptr;
181 }
182 sptr<CodecListServiceStub> stub = CodecListServiceStub::Create();
183 if (stub == nullptr) {
184 AVCODEC_LOGE("failed to create AVCodecListServiceStub");
185 return nullptr;
186 }
187 sptr<IRemoteObject> object = stub->AsObject();
188 if (object != nullptr) {
189 pid_t pid = IPCSkeleton::GetCallingPid();
190 codecListStubMap_[object] = pid;
191 AVCODEC_LOGD("The number of codeclist services(%{public}zu).", codecListStubMap_.size());
192 }
193 return object;
194 }
195 #endif
196 #ifdef SUPPORT_CODEC
CreateCodecStubObject()197 sptr<IRemoteObject> AVCodecServerManager::CreateCodecStubObject()
198 {
199 if (codecStubMap_.size() >= SERVER_MAX_NUMBER) {
200 AVCODEC_LOGE(
201 "The number of codec services(%{public}zu) has reached the upper limit."
202 "Please release the applied resources.",
203 codecStubMap_.size());
204 return nullptr;
205 }
206 sptr<CodecServiceStub> stub = CodecServiceStub::Create();
207 if (stub == nullptr) {
208 AVCODEC_LOGE("failed to create CodecServiceStub");
209 return nullptr;
210 }
211 sptr<IRemoteObject> object = stub->AsObject();
212 if (object != nullptr) {
213 pid_t pid = IPCSkeleton::GetCallingPid();
214 codecStubMap_[object] = pid;
215
216 Dumper dumper;
217 dumper.entry_ = [stub](int32_t fd) -> int32_t { return stub->DumpInfo(fd); };
218 dumper.pid_ = pid;
219 dumper.uid_ = IPCSkeleton::GetCallingUid();
220 dumper.remoteObject_ = object;
221 dumperTbl_[StubType::CODEC].emplace_back(dumper);
222 AVCODEC_LOGD("The number of codec services(%{public}zu).", codecStubMap_.size());
223 if (Dump(-1, std::vector<std::u16string>()) != OHOS::NO_ERROR) {
224 AVCODEC_LOGW("failed to call InstanceDump");
225 }
226 }
227 return object;
228 }
229 #endif
230
EraseObject(std::map<sptr<IRemoteObject>,pid_t>::iterator & iter,std::map<sptr<IRemoteObject>,pid_t> & stubMap,pid_t pid,const std::string & stubName)231 void AVCodecServerManager::EraseObject(std::map<sptr<IRemoteObject>, pid_t>::iterator& iter,
232 std::map<sptr<IRemoteObject>, pid_t>& stubMap,
233 pid_t pid,
234 const std::string& stubName)
235 {
236 if (iter != stubMap.end()) {
237 AVCODEC_LOGD("destroy %{public}s stub services(%{public}zu) pid(%{public}d).", stubName.c_str(),
238 stubMap.size(), pid);
239 (void)stubMap.erase(iter);
240 return;
241 }
242 AVCODEC_LOGE("find %{public}s object failed, pid(%{public}d).", stubName.c_str(), pid);
243 return;
244 }
245
DestroyStubObject(StubType type,sptr<IRemoteObject> object)246 void AVCodecServerManager::DestroyStubObject(StubType type, sptr<IRemoteObject> object)
247 {
248 std::lock_guard<std::mutex> lock(mutex_);
249 pid_t pid = IPCSkeleton::GetCallingPid();
250 DestroyDumper(type, object);
251 auto compare_func = [object](std::pair<sptr<IRemoteObject>, pid_t> objectPair) -> bool {
252 return objectPair.first == object;
253 };
254 switch (type) {
255 case CODEC: {
256 auto it = find_if(codecStubMap_.begin(), codecStubMap_.end(), compare_func);
257 EraseObject(it, codecStubMap_, pid, "codec");
258 return;
259 }
260 case CODECLIST: {
261 auto it = find_if(codecListStubMap_.begin(), codecListStubMap_.end(), compare_func);
262 EraseObject(it, codecListStubMap_, pid, "codeclist");
263 return;
264 }
265 default: {
266 AVCODEC_LOGE("default case, av_codec server manager failed, pid(%{public}d).", pid);
267 break;
268 }
269 }
270 }
271
EraseObject(std::map<sptr<IRemoteObject>,pid_t> & stubMap,pid_t pid)272 void AVCodecServerManager::EraseObject(std::map<sptr<IRemoteObject>, pid_t>& stubMap, pid_t pid)
273 {
274 for (auto it = stubMap.begin(); it != stubMap.end();) {
275 if (it->second == pid) {
276 executor_.Commit(it->first);
277 it = stubMap.erase(it);
278 } else {
279 it++;
280 }
281 }
282 return;
283 }
284
DestroyStubObjectForPid(pid_t pid)285 void AVCodecServerManager::DestroyStubObjectForPid(pid_t pid)
286 {
287 std::lock_guard<std::mutex> lock(mutex_);
288 DestroyDumperForPid(pid);
289 AVCODEC_LOGD("codec stub services(%{public}zu) pid(%{public}d).", codecStubMap_.size(), pid);
290 EraseObject(codecStubMap_, pid);
291 AVCODEC_LOGD("codec stub services(%{public}zu).", codecStubMap_.size());
292 AVCODEC_LOGD("codeclist stub services(%{public}zu) pid(%{public}d).", codecListStubMap_.size(), pid);
293 EraseObject(codecListStubMap_, pid);
294 AVCODEC_LOGD("codeclist stub services(%{public}zu).", codecListStubMap_.size());
295 executor_.Clear();
296 }
297
DestroyDumper(StubType type,sptr<IRemoteObject> object)298 void AVCodecServerManager::DestroyDumper(StubType type, sptr<IRemoteObject> object)
299 {
300 for (auto it = dumperTbl_[type].begin(); it != dumperTbl_[type].end(); it++) {
301 if (it->remoteObject_ == object) {
302 (void)dumperTbl_[type].erase(it);
303 AVCODEC_LOGD("AVCodecServerManager::DestroyDumper");
304 if (Dump(-1, std::vector<std::u16string>()) != OHOS::NO_ERROR) {
305 AVCODEC_LOGW("failed to call InstanceDump");
306 }
307 return;
308 }
309 }
310 }
311
DestroyDumperForPid(pid_t pid)312 void AVCodecServerManager::DestroyDumperForPid(pid_t pid)
313 {
314 for (auto& dumpers : dumperTbl_) {
315 for (auto it = dumpers.second.begin(); it != dumpers.second.end();) {
316 if (it->pid_ == pid) {
317 it = dumpers.second.erase(it);
318 AVCODEC_LOGD("AVCodecServerManager::DestroyDumperForPid");
319 } else {
320 it++;
321 }
322 }
323 }
324 if (Dump(-1, std::vector<std::u16string>()) != OHOS::NO_ERROR) {
325 AVCODEC_LOGW("failed to call InstanceDump");
326 }
327 }
328
Commit(sptr<IRemoteObject> obj)329 void AVCodecServerManager::AsyncExecutor::Commit(sptr<IRemoteObject> obj)
330 {
331 std::lock_guard<std::mutex> lock(listMutex_);
332 freeList_.push_back(obj);
333 }
334
Clear()335 void AVCodecServerManager::AsyncExecutor::Clear()
336 {
337 std::thread(&AVCodecServerManager::AsyncExecutor::HandleAsyncExecution, this).detach();
338 }
339
HandleAsyncExecution()340 void AVCodecServerManager::AsyncExecutor::HandleAsyncExecution()
341 {
342 std::list<sptr<IRemoteObject>> tempList;
343 {
344 std::lock_guard<std::mutex> lock(listMutex_);
345 freeList_.swap(tempList);
346 }
347 tempList.clear();
348 }
349
PrintDumpMenu(int32_t fd)350 void AVCodecServerManager::PrintDumpMenu(int32_t fd)
351 {
352 AVCodecDumpControler dumpControler;
353 dumpControler.AddInfo(DUMP_MENU_INDEX, "[AVCodec Dump Menu]");
354 uint32_t index = 1;
355 for (auto iter : SA_DUMP_MENU_DUMP_TABLE) {
356 dumpControler.AddInfo(DUMP_MENU_INDEX + (index << DUMP_OFFSET_16), iter);
357 index++;
358 }
359
360 std::string dumpString;
361 dumpControler.GetDumpString(dumpString);
362 dumpString += "\n";
363 dumpString += "Add args to get more infomation about avcodec components.\n";
364 dumpString += "Example: hidumper -s AVCodecService -a \"All\"\n";
365
366 if (fd != -1) {
367 write(fd, dumpString.c_str(), dumpString.size());
368 }
369 }
370 } // namespace MediaAVCodec
371 } // namespace OHOS
372