• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #ifndef LOG_TAG
16 #define LOG_TAG "AudioDumpPCM"
17 #endif
18 
19 #include "audio_dump_pcm.h"
20 #include "audio_dump_pcm_private.h"
21 
22 #include <utility>
23 
24 #include "media_monitor_manager.h"
25 #include "callback_handler.h"
26 #include "audio_service_log.h"
27 #include "audio_errors.h"
28 #include "audio_utils.h"
29 #include "audio_schedule.h"
30 
31 namespace OHOS {
32 namespace AudioStandard {
33 
34 constexpr uint64_t MAX_LIMIT_BUFFER_SIZE = 100 * 1024 * 1024;   // 100M
35 constexpr size_t EACH_CHUNK_SIZE = 1024 * 1024;                 // 1M
36 constexpr int64_t MEMBLOCK_RELEASE_TIME = 5 * 60 * 1000000;     // release pcm 5min ago
37 constexpr int64_t MEMBLOCK_CHECK_TIME_MS = 30 * 1000;           // check cached data's time every 30s
38 constexpr int64_t MEMORY_PRINT_TIME_MS = 60 * 1000;             // print memory info every 60s
39 constexpr int64_t MEMORY_PRINT_MININUM_SIZE = 5 * 1024 * 1024;  // print memory info only when used excceds 5M
40 constexpr uint16_t FILENAME_ID_MAX_INDEX = 65530;               // FileNameId 0 - 65530
41 constexpr size_t FILENAME_AND_ID_SIZE = 128;                    // estimate each entry size in map
42 constexpr size_t NAME_MAP_NUM = 2;                              // FileNameIdMap and idFileNameMap
43 constexpr int32_t MAX_RECYCLE_TIMES = 1000;
44 
MemChunk()45 MemChunk::MemChunk() : totalBufferSize_(EACH_CHUNK_SIZE), pointerOffset_(0), curFileNameId_(0)
46 {
47     Trace trace("MemChunk::MemChunk");
48     firstMemBlockTime_ = ClockTime::GetRealNano();
49     lastMemBlockTime_ = firstMemBlockTime_;
50     bufferPointer_ = new (std::nothrow) uint8_t[EACH_CHUNK_SIZE];
51     if (bufferPointer_ == nullptr) {
52         AUDIO_ERR_LOG("failed to get memory!");
53     }
54     memBlockDeque_ = std::make_shared<std::deque<MemBlock>>();
55 }
56 
~MemChunk()57 MemChunk::~MemChunk()
58 {
59     Trace trace("MemChunk::~MemChunk");
60     if (bufferPointer_ != nullptr) {
61         delete bufferPointer_;
62     }
63     bufferPointer_ = nullptr;
64 }
65 
GetMemBlock(size_t dataLength,std::string & dumpFileName,MemBlock & curMemBlock)66 int32_t MemChunk::GetMemBlock(size_t dataLength, std::string &dumpFileName, MemBlock &curMemBlock)
67 {
68     CHECK_AND_RETURN_RET(totalBufferSize_ - pointerOffset_ >= dataLength, ERROR);
69     Trace trace("MemChunk::GetMemBlock");
70 
71     if (fileNameIdMap_.find(dumpFileName) != fileNameIdMap_.end()) {
72         curMemBlock.dumpFileNameId_ = fileNameIdMap_[dumpFileName];
73     } else {
74         curMemBlock.dumpFileNameId_ = (curFileNameId_ + 1 >= FILENAME_ID_MAX_INDEX) ? 0 : ++curFileNameId_;
75         fileNameIdMap_[dumpFileName] = curFileNameId_;
76         idFileNameMap_[curFileNameId_] = dumpFileName;
77     }
78 
79     curMemBlock.dataPointer_ = bufferPointer_ + pointerOffset_;
80     curMemBlock.dataLength_ = dataLength;
81     pointerOffset_ += dataLength;
82     lastMemBlockTime_ = ClockTime::GetRealNano();
83     memBlockDeque_->push_back(curMemBlock);
84     return SUCCESS;
85 }
86 
GetMemBlockDeque()87 std::shared_ptr<std::deque<MemBlock>> MemChunk::GetMemBlockDeque()
88 {
89     return memBlockDeque_;
90 }
91 
GetMemChunkDuration(int64_t & startTime,int64_t & endTime)92 void MemChunk::GetMemChunkDuration(int64_t &startTime, int64_t &endTime)
93 {
94     startTime = firstMemBlockTime_;
95     endTime = lastMemBlockTime_;
96 }
97 
GetCurUsedMemory(size_t & dataLength,size_t & bufferLength,size_t & structLength)98 int32_t MemChunk::GetCurUsedMemory(size_t &dataLength, size_t &bufferLength, size_t &structLength)
99 {
100     dataLength = pointerOffset_;
101     bufferLength = totalBufferSize_;
102     structLength = 0;
103     CHECK_AND_RETURN_RET_LOG(memBlockDeque_ != nullptr, ERROR, "memBlockDeque_ is nullptr");
104     structLength = sizeof(MemBlock) * memBlockDeque_->size() + sizeof(MemChunk) +
105         FILENAME_AND_ID_SIZE * idFileNameMap_.size() * NAME_MAP_NUM; // roughly estimate the size of the map structure
106     return SUCCESS;
107 }
108 
Reset()109 void MemChunk::Reset()
110 {
111     Trace trace("MemChunk::Reset");
112     pointerOffset_ = 0;
113     curFileNameId_ = 0;
114     firstMemBlockTime_ = ClockTime::GetRealNano();
115     lastMemBlockTime_ = firstMemBlockTime_;
116     idFileNameMap_ = {};
117     fileNameIdMap_ = {};
118     memBlockDeque_->clear();
119 }
120 
GetInstance()121 AudioCacheMgr& AudioCacheMgr::GetInstance()
122 {
123     static AudioCacheMgrInner mgr;
124     return mgr;
125 }
126 
AudioCacheMgrInner()127 AudioCacheMgrInner::AudioCacheMgrInner()
128 {
129     Trace trace("AudioCacheMgrInner::AudioCacheMgrInner");
130     totalMemChunkNums_ = MAX_LIMIT_BUFFER_SIZE / EACH_CHUNK_SIZE;
131 }
132 
~AudioCacheMgrInner()133 AudioCacheMgrInner::~AudioCacheMgrInner()
134 {
135     std::lock_guard<std::mutex> runnerlock(runnerMutex_);
136     if (callbackHandler_ != nullptr) {
137         AUDIO_INFO_LOG("runner move");
138         callbackHandler_->ReleaseEventRunner();
139         callbackHandler_ = nullptr;
140     }
141 }
142 
Init()143 bool AudioCacheMgrInner::Init()
144 {
145     if (isInited_ == false) {
146         InitCallbackHandler();
147         isInited_ = true;
148         return true;
149     }
150     AUDIO_WARNING_LOG("AudioCacheMgr is Inited!");
151     return true;
152 }
153 
DeInit()154 bool AudioCacheMgrInner::DeInit()
155 {
156     Trace trace("AudioCacheMgrInner::DeInit");
157     {
158         std::lock_guard<std::mutex> processLock(g_Mutex);
159         isInited_ = false;
160         memChunkDeque_ = {};
161         AUDIO_INFO_LOG("clear all cached pcm success");
162     }
163     std::unique_lock<std::mutex> lock(runnerMutex_);
164     if (callbackHandler_ != nullptr) {
165         callbackHandler_->ReleaseEventRunner();
166         callbackHandler_ = nullptr;
167         handler_ = nullptr;
168         AUDIO_INFO_LOG("deinit handler success");
169     }
170     lock.unlock();
171     AUDIO_WARNING_LOG("AudioCacheMgr is DeInited!");
172     return true;
173 }
174 
CacheData(std::string & dumpFileName,void * srcDataPointer,size_t dataLength)175 void AudioCacheMgrInner::CacheData(std::string &dumpFileName, void* srcDataPointer, size_t dataLength)
176 {
177     if (!isInited_.load()) {
178         Trace trace("AudioCacheMgrInner::CacheData::NotInited");
179         return;
180     }
181 
182     Trace trace("AudioCacheMgrInner::CacheData");
183     if (isDumpingData_.load()) {
184         Trace trace("AudioCacheMgrInner::CacheData::ReturnWhenDumpingData");
185         return;
186     }
187 
188     if (!g_Mutex.try_lock()) {
189         /*
190         * condition 1: cacheData thread and dumpData thread in Concurrency
191         * if dumpData thread gets mutex, discard cacheData and return directly
192         * if cacheData threads gets mutex, dumpData thread waits for cacheData finish,
193         * cause cacheData excutes very fast.
194         */
195         if (isDumpingData_.load()) {
196             Trace trace("AudioCacheMgrInner::CacheData::TryLockFailedWhenDumpingData");
197             return;
198         }
199         /*
200         * condition 2: two cacheData threads in Concurrency, one gets mutex
201         * the other thread waits for mutex.
202         */
203         g_Mutex.lock();
204     }
205 
206     MemBlock curMemBlock {nullptr, 0, 0};
207     int ret = GetAvailableMemBlock(dataLength, dumpFileName, curMemBlock);
208     if (ret != SUCCESS) {
209         AUDIO_ERR_LOG("GetAvailableMemBlock failed. Unable to cacheData!");
210         g_Mutex.unlock();
211         return;
212     }
213     g_Mutex.unlock();
214 
215     ret = memcpy_s(curMemBlock.dataPointer_, dataLength, srcDataPointer, dataLength);
216     CHECK_AND_RETURN_LOG(ret == SUCCESS, "memcpy_s failed. Unable to cacheData!");
217 }
218 
GetAvailableMemBlock(size_t dataLength,std::string & dumpFileName,MemBlock & curMemBlock)219 int32_t AudioCacheMgrInner::GetAvailableMemBlock(size_t dataLength, std::string &dumpFileName, MemBlock &curMemBlock)
220 {
221     if (!memChunkDeque_.empty()) {
222         Trace trace1("AudioCacheMgrInner::GetAvailableMemBlock::hasNotFillMemChunk");
223         std::shared_ptr<MemChunk> lastMemChunk = memChunkDeque_.back();
224         if (lastMemChunk->GetMemBlock(dataLength, dumpFileName, curMemBlock) == SUCCESS) {
225             return SUCCESS;
226         }
227     }
228 
229     if (memChunkDeque_.size() < totalMemChunkNums_) {
230         Trace trace2("AudioCacheMgrInner::getAvailMemBlock::GetMemBlock");
231         std::shared_ptr<MemChunk> newMemChunk = std::make_shared<MemChunk>();
232         Trace::Count("UsedMemChunk", memChunkDeque_.size());
233         memChunkDeque_.push_back(newMemChunk);
234         if (newMemChunk->GetMemBlock(dataLength, dumpFileName, curMemBlock) == SUCCESS) {
235             return SUCCESS;
236         }
237     }
238 
239     if (!memChunkDeque_.empty()) {
240         Trace trace3("AudioCacheMgrInner::GetAvailableMemBlock::RecycleOneMemChunk");
241         std::shared_ptr<MemChunk> recycleMemChunk = memChunkDeque_.front();
242         memChunkDeque_.pop_front();
243         recycleMemChunk->Reset();
244         memChunkDeque_.push_back(recycleMemChunk);
245         if (recycleMemChunk->GetMemBlock(dataLength, dumpFileName, curMemBlock) == SUCCESS) {
246             return SUCCESS;
247         }
248     }
249 
250     AUDIO_ERR_LOG("failed to get available memBlock");
251     return ERROR;
252 }
253 
DumpAllMemBlock()254 int32_t AudioCacheMgrInner::DumpAllMemBlock()
255 {
256     if (!isInited_.load()) {
257         Trace trace("AudioCacheMgrInner::DumpAllMemBlock::NotInited");
258         AUDIO_WARNING_LOG("not inited!");
259         return ERR_ILLEGAL_STATE;
260     }
261 
262     Trace trace("AudioCacheMgrInner::DumpAllMemBlock");
263     bool targetStatus = false;
264     if (!isDumpingData_.compare_exchange_strong(targetStatus, true)) {
265         AUDIO_WARNING_LOG("Already in dumping data!");
266     }
267 
268     std::lock_guard<std::mutex> processsLock(g_Mutex);
269 
270     std::vector<std::pair<std::string, std::string>> paramStart;
271     paramStart.push_back({"BETA", "true"});
272     Media::MediaMonitor::MediaMonitorManager::GetInstance().SetMediaParameters(paramStart);
273 
274     while (!memChunkDeque_.empty()) {
275         std::shared_ptr<MemChunk> curMemChunk = memChunkDeque_.front();
276         memChunkDeque_.pop_front();
277 
278         std::shared_ptr<std::deque<MemBlock>> curMemBlockDeque = curMemChunk->GetMemBlockDeque();
279         for (auto it = curMemBlockDeque->begin(); it != curMemBlockDeque->end(); ++it) {
280             Media::MediaMonitor::MediaMonitorManager::GetInstance().WriteAudioBuffer("pcm_dump_" +
281                 curMemChunk->idFileNameMap_[it->dumpFileNameId_], it->dataPointer_, it->dataLength_);
282         }
283         Trace::Count("UsedMemChunk", memChunkDeque_.size());
284     }
285 
286     std::vector<std::pair<std::string, std::string>> paramEnd;
287     paramEnd.push_back({"BETA", "false"});
288     Media::MediaMonitor::MediaMonitorManager::GetInstance().SetMediaParameters(paramEnd);
289 
290     isDumpingData_.store(false);
291     return SUCCESS;
292 }
293 
GetCachedDuration(int64_t & startTime,int64_t & endTime)294 void AudioCacheMgrInner::GetCachedDuration(int64_t &startTime, int64_t &endTime)
295 {
296     Trace trace("AudioCacheMgrInner::GetCacheDuration");
297     if (!isInited_.load()) {
298         Trace trace("AudioCacheMgrInner::GetCachedDuration::NotInited");
299         AUDIO_WARNING_LOG("not inited!");
300         return;
301     }
302     std::lock_guard<std::mutex> processLock(g_Mutex);
303     // init but no data in memchunk
304     if (memChunkDeque_.size() == 0) {
305         startTime = ClockTime::GetRealNano();
306         endTime = startTime;
307         AUDIO_WARNING_LOG("GetCachedDuration while memChunkDeque_ is empty!");
308         return;
309     }
310 
311     int64_t temp;
312     if (memChunkDeque_.front() != nullptr) {
313         memChunkDeque_.front()->GetMemChunkDuration(startTime, temp);
314     }
315     if (memChunkDeque_.back() != nullptr) {
316         memChunkDeque_.back()->GetMemChunkDuration(temp, endTime);
317     }
318     AUDIO_INFO_LOG("startTime:%{public}s, endTime:%{public}s.",
319         ClockTime::NanoTimeToString(startTime).c_str(), ClockTime::NanoTimeToString(endTime).c_str());
320 }
321 
PrintCurMemoryCondition()322 void AudioCacheMgrInner::PrintCurMemoryCondition()
323 {
324     Trace trace("AudioCacheMgrInner::PrintCurMemoryCondition");
325     CHECK_AND_RETURN_LOG(isInited_.load(), "AudioCacheMgr is Not Inited!");
326     SafeSendCallBackEvent(PRINT_MEMORY_CONDITION, 0, MEMORY_PRINT_TIME_MS);
327 
328     size_t dataLength = 0;
329     size_t bufferLength = 0;
330     size_t structLength = 0;
331     GetCurMemoryCondition(dataLength, bufferLength, structLength);
332     if (bufferLength >= MEMORY_PRINT_MININUM_SIZE) {
333         AUDIO_INFO_LOG("dataLength: %{public}zu KB, bufferLength: %{public}zu KB, structLength: %{public}zu KB",
334             dataLength / BYTE_TO_KB_SIZE, bufferLength / BYTE_TO_KB_SIZE, structLength / BYTE_TO_KB_SIZE);
335     }
336 }
337 
GetCurMemoryCondition(size_t & dataLength,size_t & bufferLength,size_t & structLength)338 void AudioCacheMgrInner::GetCurMemoryCondition(size_t &dataLength, size_t &bufferLength, size_t &structLength)
339 {
340     Trace trace("AudioCacheMgrInner::GetCurMemoryCondition");
341     std::lock_guard<std::mutex> processLock(g_Mutex);
342 
343     size_t curDataLength = 0;
344     size_t curBufferLength = 0;
345     size_t curStructLength = 0;
346     if (memChunkDeque_.empty()) {
347         return;
348     }
349 
350     for (auto it = memChunkDeque_.begin(); it != memChunkDeque_.end(); ++it) {
351         (*it)->GetCurUsedMemory(curDataLength, curBufferLength, curStructLength);
352         dataLength += curDataLength;
353         bufferLength += curBufferLength;
354         structLength += curStructLength;
355     }
356 }
357 
ReleaseOverTimeMemBlock()358 void AudioCacheMgrInner::ReleaseOverTimeMemBlock()
359 {
360     Trace trace("AudioCacheMgrInner::ReleaseOverTimeMemBlock");
361     CHECK_AND_RETURN_LOG(isInited_.load(), "AudioCacheMgr is Not Inited!");
362     SafeSendCallBackEvent(RELEASE_OVERTIME_MEMBLOCK, 0, MEMBLOCK_CHECK_TIME_MS);
363 
364     int32_t recycleNums = 0;
365     int64_t curTime = ClockTime::GetRealNano();
366     int64_t startTime;
367     int64_t endTime;
368 
369     while (recycleNums < MAX_RECYCLE_TIMES) {
370         Trace trace1("AudioCacheMgrInner::ReleaseOneMemChunk");
371         std::unique_lock<std::mutex> processLock(g_Mutex);
372         if (isDumpingData_.load()) {
373             AUDIO_INFO_LOG("now dumping memblock, no need ReleaseOverTimeMemBlock");
374             return;
375         }
376         if (memChunkDeque_.empty()) {
377             break;
378         }
379         std::shared_ptr<MemChunk> releaseChunk = memChunkDeque_.front();
380         releaseChunk->GetMemChunkDuration(startTime, endTime);
381         if (curTime - endTime < MEMBLOCK_RELEASE_TIME * AUDIO_MS_PER_SECOND) {
382             break;
383         }
384         memChunkDeque_.pop_front();
385         Trace::Count("UsedMemChunk", memChunkDeque_.size());
386         // ~memchunk needs 500ns but is no need to keep lock; in this way we delay the destruct time until out the loop
387         processLock.unlock();
388         ++recycleNums;
389     }
390     if (recycleNums != 0) {
391         AUDIO_INFO_LOG("CheckMemBlock Recycle %{public}d memBlocks", recycleNums);
392     }
393 }
394 
GetDumpParameter(const std::vector<std::string> & subKeys,std::vector<std::pair<std::string,std::string>> & result)395 bool AudioCacheMgrInner::GetDumpParameter(const std::vector<std::string> &subKeys,
396     std::vector<std::pair<std::string, std::string>> &result)
397 {
398     // vector size check had done before call this function
399     // audioCacheState 0:close, 1:open, 2:init
400     if (subKeys[0] == GET_STATUS_KEY) {
401         int32_t audioCacheState = 0;
402         GetSysPara("persist.multimedia.audio.audioCacheState", audioCacheState);
403         CHECK_AND_RETURN_RET_LOG(audioCacheState >= 0 &&
404             audioCacheState < static_cast<int32_t>(AUDIO_CACHE_STATE.size()),
405             false, "get invalid audioCacheState %{public}d", audioCacheState);
406         result.push_back({"STATUS", AUDIO_CACHE_STATE[audioCacheState]});
407     } else if (subKeys[0] == GET_TIME_KEY) {
408         int64_t startTime = 0;
409         int64_t endTime = 0;
410         GetCachedDuration(startTime, endTime);
411         result.push_back({ClockTime::NanoTimeToString(startTime), ClockTime::NanoTimeToString(endTime)});
412     } else if (subKeys[0] == GET_MEMORY_KEY) {
413         size_t dataLength = 0;
414         size_t bufferLength = 0;
415         size_t structLength = 0;
416         GetCurMemoryCondition(dataLength, bufferLength, structLength);
417         result.push_back({std::to_string(dataLength), std::to_string(bufferLength + structLength)});
418     } else {
419         AUDIO_ERR_LOG("invalid param %{public}s", subKeys[0].c_str());
420         return false;
421     }
422     return true;
423 }
424 
SetDumpParameter(const std::vector<std::pair<std::string,std::string>> & params)425 bool AudioCacheMgrInner::SetDumpParameter(const std::vector<std::pair<std::string, std::string>> &params)
426 {
427     // vector size check had done before call this function
428     // audioCacheState 0:close, 1:open, 2:init
429     int32_t audioCacheState = 0;
430     GetSysPara("persist.multimedia.audio.audioCacheState", audioCacheState);
431     if (params[0].first == SET_OPEN_KEY) {
432         Init();
433         SetSysPara("persist.multimedia.audio.audioCacheState", 1);
434     } else if (params[0].first == SET_CLOSE_KEY) {
435         DeInit();
436         SetSysPara("persist.multimedia.audio.audioCacheState", 0);
437     } else if (params[0].first == SET_UPLOAD_KEY) {
438         // only when user argees to cachedata, audioCacheState will change to 1(open),.
439         CHECK_AND_RETURN_RET_LOG(audioCacheState == 1, false,
440             "cannot upload, curAudioCacheState is %{public}d, not code 1! ", audioCacheState);
441         CHECK_AND_RETURN_RET_LOG(DumpAllMemBlock() == SUCCESS, false,
442             "upload allMemBlock failed!");
443     } else {
444         AUDIO_ERR_LOG("invalid param %{public}s", params[0].first.c_str());
445         return false;
446     }
447     return true;
448 }
449 
InitCallbackHandler()450 void AudioCacheMgrInner::InitCallbackHandler()
451 {
452     Trace trace("AudioCacheMgrInner::InitCallbackHandler");
453     std::unique_lock<std::mutex> lock(runnerMutex_);
454     if (callbackHandler_ == nullptr) {
455         handler_ = std::make_shared<AudioCacheHandler>(this);
456         callbackHandler_ = CallbackHandler::GetInstance(handler_, "OS_AUDIODumpCB");
457         AUDIO_INFO_LOG("init handler success");
458     }
459     lock.unlock();
460     SafeSendCallBackEvent(RELEASE_OVERTIME_MEMBLOCK, 0, MEMBLOCK_CHECK_TIME_MS);
461     SafeSendCallBackEvent(PRINT_MEMORY_CONDITION, 0, MEMORY_PRINT_TIME_MS);
462     SafeSendCallBackEvent(RAISE_PRIORITY, 0, 0);
463 }
464 
SafeSendCallBackEvent(uint32_t eventCode,int64_t data,int64_t delayTime)465 void AudioCacheMgrInner::SafeSendCallBackEvent(uint32_t eventCode, int64_t data, int64_t delayTime)
466 {
467     Trace trace("AudioCacheMgrInner::SafeSendCallBackEvent");
468     std::lock_guard<std::mutex> lock(runnerMutex_);
469     CHECK_AND_RETURN_LOG(callbackHandler_ != nullptr, "Runner is Release");
470 
471     callbackHandler_->SendCallbackEvent(eventCode, data, delayTime);
472 }
473 
OnHandle(uint32_t code,int64_t data)474 void AudioCacheMgrInner::OnHandle(uint32_t code, int64_t data)
475 {
476     switch (code) {
477         case RELEASE_OVERTIME_MEMBLOCK:
478             ReleaseOverTimeMemBlock();
479             break;
480         case PRINT_MEMORY_CONDITION:
481             PrintCurMemoryCondition();
482             break;
483         case RAISE_PRIORITY:
484             ScheduleThreadInServer(getpid(), gettid());
485             break;
486         default:
487             break;
488     }
489 }
490 
AudioCacheHandler(IHandler * handler)491 AudioCacheHandler::AudioCacheHandler(IHandler* handler) : handler_(handler) {}
492 
OnHandle(uint32_t code,int64_t data)493 void AudioCacheHandler::OnHandle(uint32_t code, int64_t data)
494 {
495     CHECK_AND_RETURN_LOG(handler_ != nullptr, "handler is nullptr");
496     handler_->OnHandle(code, data);
497 }
498 
499 } // namespace AudioStandard
500 } // namespace OHOS
501