• 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 <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