• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "dump_manager_service.h"
16 #include <file_ex.h>
17 #include <if_system_ability_manager.h>
18 #include <ipc_skeleton.h>
19 #include <iservice_registry.h>
20 #include <sched.h>
21 #include <string_ex.h>
22 #include <sstream>
23 #include <sys/syscall.h>
24 #include <system_ability_definition.h>
25 #include <thread>
26 #include <queue>
27 #include <unistd.h>
28 
29 #include "common.h"
30 #include "common/dumper_constant.h"
31 #include "dump_log_manager.h"
32 #include "inner/dump_service_id.h"
33 #include "hilog_wrapper.h"
34 #include "manager/dump_implement.h"
35 #include "raw_param.h"
36 #include "token_setproc.h"
37 #include "accesstoken_kit.h"
38 #include "system_ability_ondemand_reason.h"
39 
40 using namespace std;
41 namespace OHOS {
42 namespace HiviewDFX {
43 namespace {
44 const std::string DUMPMGR_SERVICE_NAME = "HiDumperManagerService";
45 auto dumpManagerService = DumpDelayedSpSingleton<DumpManagerService>::GetInstance();
46 const bool G_REGISTER_RESULT = SystemAbility::MakeAndRegisterAbility(dumpManagerService.GetRefPtr());
47 static const int32_t HIPORFILER_UID = 3063;
48 static const int32_t STOP_WAIT = 3;
49 static const int32_t REQUEST_MAX = 5;
50 static const uint32_t REQUESTID_MAX = 100000;
51 static const int SMALL_CPU_SIZE = 4;
52 const std::string TASK_ID = "unload";
53 constexpr int32_t DYNAMIC_EXIT_DELAY_TIME = 120000;
54 constexpr int32_t UNLOAD_IMMEDIATELY = 0;
55 constexpr size_t FD_TOP_CNT = 10;
56 constexpr int32_t NEED_DUMP_FDLINK_NUMS = 1200;
57 }
58 
DumpManagerService()59 DumpManagerService::DumpManagerService() : SystemAbility(DFX_SYS_HIDUMPER_ABILITY_ID, true)
60 {
61 }
62 
~DumpManagerService()63 DumpManagerService::~DumpManagerService()
64 {
65 }
66 
OnStart()67 void DumpManagerService::OnStart()
68 {
69     if (started_) {
70         DUMPER_HILOGE(MODULE_SERVICE, "error|it's ready, nothing to do.");
71         return;
72     }
73 
74     if (!Init()) {
75         DUMPER_HILOGE(MODULE_SERVICE, "error|init fail, nothing to do.");
76         return;
77     }
78     if (!Publish(DumpDelayedSpSingleton<DumpManagerService>::GetInstance())) {
79         DUMPER_HILOGE(MODULE_SERVICE, "error|register to system ability manager failed.");
80         return;
81     }
82     started_ = true;
83 }
84 
OnStop()85 void DumpManagerService::OnStop()
86 {
87     if (!started_) {
88         return;
89     }
90     DUMPER_HILOGD(MODULE_SERVICE, "enter|");
91     blockRequest_ = true;
92     CancelAllRequest();
93     for (int i = 0; i < STOP_WAIT; i++) {
94         {
95             unique_lock<mutex> lock(mutex_);
96             if (requestRawParamMap_.empty()) {
97                 break;
98             }
99         }
100         sleep(1);
101     }
102     started_ = false;
103     blockRequest_ = false;
104     DUMPER_HILOGD(MODULE_SERVICE, "leave|");
105 }
106 
OnIdle(const SystemAbilityOnDemandReason & idleReason)107 int32_t DumpManagerService::OnIdle(const SystemAbilityOnDemandReason& idleReason)
108 {
109     DUMPER_HILOGI(MODULE_SERVICE, "on idle enter, idle reason %{public}d, %{public}s, request sum=%{public}d",
110         idleReason.GetId(), idleReason.GetName().c_str(), GetRequestSum());
111 
112     if (idleReason.GetId() == OnDemandReasonId::INTERFACE_CALL) {
113         if (GetRequestSum() == 0) {
114             started_ = false;
115             return UNLOAD_IMMEDIATELY;
116         } else {
117             GetIdleRequest();
118             return DYNAMIC_EXIT_DELAY_TIME;
119         }
120     } else {
121         return UNLOAD_IMMEDIATELY;
122     }
123 }
124 
SetCpuSchedAffinity()125 void DumpManagerService::SetCpuSchedAffinity()
126 {
127     int curTid = syscall(SYS_gettid);
128     cpu_set_t mask;
129     CPU_ZERO(&mask);
130     for (int i = 0; i < SMALL_CPU_SIZE; i++) {
131         CPU_SET(i, &mask);
132     }
133     if (sched_setaffinity(curTid, sizeof(mask), &mask) < 0) {
134         DUMPER_HILOGE(MODULE_SERVICE, "error|sched_setaffinity failed");
135     }
136 }
137 
Dump(int32_t fd,const std::vector<std::u16string> & args)138 int32_t DumpManagerService::Dump(int32_t fd, const std::vector<std::u16string> &args)
139 {
140     std::string result = DUMPMGR_SERVICE_NAME;
141     if (!SaveStringToFd(fd, result)) {
142         DUMPER_HILOGE(MODULE_SERVICE, "DumpManagerService::Dump failed, save to fd failed.");
143         DUMPER_HILOGE(MODULE_SERVICE, "Dump Info:\n");
144         DUMPER_HILOGE(MODULE_SERVICE, "%{public}s", result.c_str());
145         return ERR_OK;
146     }
147     return ERR_OK;
148 }
149 
HandleRequestError(std::vector<std::u16string> & args,int outfd,const int32_t & errorCode,const std::string & errorMsg)150 void DumpManagerService::HandleRequestError(std::vector<std::u16string> &args, int outfd,
151     const int32_t& errorCode, const std::string& errorMsg)
152 {
153     close(outfd);
154     int callerPpid = -1;
155     if (args.size() >= ARG_MIN_COUNT) {
156         StrToInt(Str16ToStr8(args[args.size() - 1]), callerPpid);
157         args.pop_back();
158     }
159     std::stringstream dumpCmdSs;
160     for (size_t i = 0; i < args.size(); i++) {
161         dumpCmdSs << Str16ToStr8(args[i]).c_str() << " ";
162     }
163     std::unique_ptr<DumperSysEventParams> param = std::make_unique<DumperSysEventParams>();
164     param->errorCode = errorCode;
165     param->callerPpid = callerPpid;
166     param->arguments = dumpCmdSs.str();
167     param->errorMsg = errorMsg;
168     param->opt = "";
169     param->subOpt = "";
170     param->target = "";
171     DumpCommonUtils::ReportCmdUsage(param);
172 }
173 
Request(std::vector<std::u16string> & args,int outfd)174 int32_t DumpManagerService::Request(std::vector<std::u16string> &args, int outfd)
175 {
176     if (blockRequest_) {
177         HandleRequestError(args, outfd, static_cast<int32_t>(DumpStatus::DUMP_FAIL), "request has blocked");
178         return DumpStatus::DUMP_FAIL;
179     }
180     if (!started_) {
181         DUMPER_HILOGE(MODULE_SERVICE, "hidumper_service has stopped.");
182         HandleRequestError(args, outfd, static_cast<int32_t>(DumpStatus::DUMP_FAIL), "request has stopped");
183         return DumpStatus::DUMP_FAIL;
184     }
185     int32_t uid = IPCSkeleton::GetCallingUid();
186     if (!HasDumpPermission() && uid != HIPORFILER_UID) {
187         DUMPER_HILOGE(MODULE_SERVICE, "No dump permission, please check!, uid:%{public}d.", uid);
188         HandleRequestError(args, outfd, static_cast<int32_t>(DumpStatus::DUMP_FAIL), "no dump permission");
189         return DumpStatus::DUMP_FAIL;
190     }
191     int sum = GetRequestSum();
192     DUMPER_HILOGD(MODULE_SERVICE, "debug|sum=%{public}d", sum);
193     if (sum >= REQUEST_MAX) {
194         DUMPER_HILOGE(MODULE_SERVICE, "sum is greater than the request max, sum:%{public}d.", sum);
195         HandleRequestError(args, outfd, static_cast<int32_t>(DumpStatus::DUMP_FAIL), "request sum reached max");
196         return DumpStatus::DUMP_REQUEST_MAX;
197     } else if (sum == 0) {
198         DumpLogManager::Init();
199     }
200     DelayUnloadTask();
201     DUMPER_HILOGD(MODULE_SERVICE, "enter|");
202     const std::shared_ptr<RawParam> rawParam = AddRequestRawParam(args, outfd);
203     int32_t ret = StartRequest(rawParam);
204     DUMPER_HILOGD(MODULE_SERVICE, "leave|ret=%{public}d", ret);
205     return ret;
206 }
207 
208 // Authenticate dump permissions
HasDumpPermission() const209 bool DumpManagerService::HasDumpPermission() const
210 {
211     uint32_t callingTokenID = IPCSkeleton::GetCallingTokenID();
212     int res = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callingTokenID, "ohos.permission.DUMP");
213     if (res != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
214         DUMPER_HILOGI(MODULE_SERVICE, "No dump permission, please check!");
215         return false;
216     }
217     return true;
218 }
219 
GetFileDescriptorNums(int32_t pid,std::string requestType) const220 uint32_t DumpManagerService::GetFileDescriptorNums(int32_t pid, std::string requestType) const
221 {
222     if (requestType.find("..") != std::string::npos) {
223         DUMPER_HILOGE(MODULE_SERVICE, "requestType is invalid, please check!");
224         return 0;
225     }
226     std::string taskPath = "/proc/" + std::to_string(pid) + "/" + requestType;
227     std::vector<std::string> fdList = DumpCommonUtils::GetSubNodes(taskPath, true);
228     return fdList.size();
229 }
230 
ScanPidOverLimit(std::string requestType,int32_t limitSize,std::vector<int32_t> & pidList)231 int32_t DumpManagerService::ScanPidOverLimit(std::string requestType, int32_t limitSize, std::vector<int32_t> &pidList)
232 {
233     if (!HasDumpPermission()) {
234         return DumpStatus::DUMP_FAIL;
235     }
236     if (limitSize < 0) {
237         return DumpStatus::DUMP_FAIL;
238     }
239     int32_t ret = DumpStatus::DUMP_OK;
240     std::vector<int32_t> pids = DumpCommonUtils::GetAllPids();
241     for (const auto &pid : pids) {
242         uint32_t num = GetFileDescriptorNums(pid, requestType);
243         if (num < static_cast<uint32_t>(limitSize)) {
244             continue;
245         }
246         auto it = std::find(pidList.begin(), pidList.end(), pid);
247         if (it != pidList.end()) {
248             continue;
249         }
250         pidList.push_back(pid);
251     }
252     return ret;
253 }
254 
GetFdLink(const std::string & linkPath) const255 std::string DumpManagerService::GetFdLink(const std::string &linkPath) const
256 {
257     char linkDest[PATH_MAX] = {0};
258     ssize_t linkDestSize = readlink(linkPath.c_str(), linkDest, sizeof(linkDest) - 1);
259     if (linkDestSize < 0) {
260         return "unknown";
261     }
262     linkDest[linkDestSize] = '\0';
263     return linkDest;
264 }
265 
GetFdLinks(int pid)266 vector<string> DumpManagerService::GetFdLinks(int pid)
267 {
268     std::string fdPath = "/proc/" + std::to_string(pid) + "/fd/";
269     vector<string> nodes = DumpCommonUtils::GetSubNodes(fdPath, true);
270     vector<string> links;
271     for (const auto &node : nodes) {
272         std::string linkPath = fdPath + node;
273         links.push_back(GetFdLink(linkPath));
274     }
275 
276     return links;
277 }
278 
MaybeKnownType(const string & link)279 string DumpManagerService::MaybeKnownType(const string &link)
280 {
281     const set<string> knownTypes{"eventfd", "eventpoll", "sync_file", "dmabuf", "socket", "pipe", "ashmem"};
282     for (const auto &type : knownTypes) {
283         if (link.find(type) != std::string::npos) {
284             return type;
285         }
286     }
287 
288     return "unknown";
289 }
290 
CountPaths(const vector<string> & links)291 unordered_map<string, int> DumpManagerService::CountPaths(const vector<string>& links)
292 {
293     unordered_map<string, int> counter;
294     for (const auto& link : links) {
295         string type = MaybeKnownType(link);
296         if (type != "unknown") {
297             ++counter[type];
298         } else {
299             ++counter[link];
300         }
301     }
302 
303     return counter;
304 }
305 
TopN(const unordered_map<string,int> & counter,size_t n)306 vector<pair<string, int>> DumpManagerService::TopN(const unordered_map<string, int>& counter, size_t n)
307 {
308     using Entry = pair<string, int>;
309 
310     auto cmp = [](const Entry& a, const Entry& b) {
311         return a.second > b.second;
312     };
313     priority_queue<Entry, vector<Entry>, decltype(cmp)> minHeap(cmp);
314 
315     for (const auto& kv : counter) {
316         if (minHeap.size() < n) {
317             minHeap.push(kv);
318         } else if (kv.second > minHeap.top().second) {
319             minHeap.pop();
320             minHeap.push(kv);
321         }
322     }
323 
324     vector<Entry> result;
325     while (!minHeap.empty()) {
326         result.push_back(minHeap.top());
327         minHeap.pop();
328     }
329     std::sort(result.begin(), result.end(),
330               [](const Entry& a, const Entry& b) {
331                   return (a.second == b.second && a.first < b.first) || (a.second > b.second);
332               });
333 
334     return result;
335 }
336 
GetSummary(const vector<pair<string,int>> & topLinks,const vector<pair<string,int>> & topTypes)337 string DumpManagerService::GetSummary(const vector<pair<string, int>> &topLinks,
338                                       const vector<pair<string, int>> &topTypes)
339 {
340     if (topLinks.size() == 0 && topTypes.size() == 0) {
341         return "";
342     }
343     if (topLinks.size() == 0) {
344         return "Leaked dir:" + topTypes[0].first;
345     }
346     if (topTypes.size() == 0) {
347         return "Leaked fd:" + topLinks[0].first;
348     }
349     if (topTypes[0].second > topLinks[0].second) {
350         return "Leaked dir:" + topTypes[0].first;
351     }
352     return "Leaked fd:" + topLinks[0].first;
353 }
354 
GetTopFdInfo(const vector<pair<string,int>> & topLinks)355 string DumpManagerService::GetTopFdInfo(const vector<pair<string, int>> &topLinks)
356 {
357     stringstream rtn;
358     for (const auto &[name, count] : topLinks) {
359         rtn << to_string(count) << "\t" << name << "\n";
360     }
361 
362     return rtn.str();
363 }
364 
GetTopDirInfo(const vector<pair<string,int>> & topTypes,const map<string,unordered_map<string,int>> & typePaths)365 std::string DumpManagerService::GetTopDirInfo(const vector<pair<string, int>> &topTypes,
366                                               const map<string, unordered_map<string, int>> &typePaths)
367 {
368     stringstream rtn;
369     for (size_t i = 0; i < topTypes.size(); ++i) {
370         const auto &[type, total] = topTypes[i];
371         rtn << to_string(total) << "\t" << type << "\n";
372         auto it = typePaths.find(type);
373         if (it == typePaths.end()) {
374             continue;
375         }
376         auto paths = TopN(it->second, FD_TOP_CNT);
377         for (const auto &[path, count] : paths) {
378             rtn << "0" << to_string(count) << "\t" << path << "\n";
379         }
380     }
381 
382     return rtn.str();
383 }
384 
CountFdNums(int32_t pid,uint32_t & fdNums,std::string & detailFdInfo,std::vector<std::string> & topLeakedTypeList)385 int32_t DumpManagerService::CountFdNums(int32_t pid, uint32_t &fdNums, std::string &detailFdInfo,
386     std::vector<std::string> &topLeakedTypeList)
387 {
388     if (!HasDumpPermission()) {
389         return DumpStatus::DUMP_FAIL;
390     }
391 
392     auto links = GetFdLinks(pid);
393     if (links.empty()) {
394         return DumpStatus::DUMP_FAIL;
395     }
396     auto linkCounts = CountPaths(links);
397     auto topLinks = TopN(linkCounts, FD_TOP_CNT);
398 
399     map<string, unordered_map<string, int>> typePaths;
400     for (const auto& [path, count] : linkCounts) {
401         string type(path, 0, DumpCommonUtils::FindFdClusterStartIndex(path));
402         if (type != path) {
403             typePaths[type][path] = count;
404         }
405     }
406     unordered_map<string, int> typeTotal;
407     for (const auto& [type, paths] : typePaths) {
408         int total = 0;
409         for (const auto& [path, count] : paths) {
410             total += count;
411         }
412         typeTotal[type] = total;
413     }
414     auto topTypes = TopN(typeTotal, FD_TOP_CNT);
415 
416     fdNums = links.size();
417     topLeakedTypeList.push_back(topLinks[0].first);
418     for (size_t i = 0; i < topLinks.size() && i <FD_TOP_CNT; i++) {
419         if (i > 0 && topLinks[i].second > NEED_DUMP_FDLINK_NUMS) {
420             topLeakedTypeList.push_back(topLinks[i].first);
421         }
422     }
423 
424     stringstream output;
425     output << "Summary:\n";
426     output << GetSummary(topLinks, topTypes);
427     output << "\n\nLeaked fd Top 10:\n";
428     output << GetTopFdInfo(topLinks);
429     output << "Top Dir " << to_string(FD_TOP_CNT) << ":\n";
430     output << GetTopDirInfo(topTypes, typePaths);
431     detailFdInfo = output.str();
432 
433     return DumpStatus::DUMP_OK;
434 }
435 
436 #ifdef DUMP_TEST_MODE // for mock test
SetTestMainFunc(DumpManagerServiceTestMainFunc testMainFunc)437 void DumpManagerService::SetTestMainFunc(DumpManagerServiceTestMainFunc testMainFunc)
438 {
439     testMainFunc_ = testMainFunc;
440 }
441 #endif // for mock test
442 
Init()443 bool DumpManagerService::Init()
444 {
445     if (!eventRunner_) {
446         eventRunner_ = AppExecFwk::EventRunner::Create(DUMPMGR_SERVICE_NAME);
447         if (eventRunner_ == nullptr) {
448             DUMPER_HILOGE(MODULE_SERVICE, "error|create EventRunner");
449             return false;
450         }
451     }
452     if (!handler_) {
453         handler_ = std::make_shared<AppExecFwk::EventHandler>(eventRunner_);
454         if (handler_ == nullptr) {
455             DUMPER_HILOGE(MODULE_SERVICE, "error|create EventHandler");
456             return false;
457         }
458     }
459     return true;
460 }
461 
GetRequestSum()462 int DumpManagerService::GetRequestSum()
463 {
464     unique_lock<mutex> lock(mutex_);
465     return requestRawParamMap_.size();
466 }
467 
AddRequestRawParam(std::vector<std::u16string> & args,int outfd)468 std::shared_ptr<RawParam> DumpManagerService::AddRequestRawParam(std::vector<std::u16string> &args, int outfd)
469 {
470     unique_lock<mutex> lock(mutex_);
471     uint32_t requestId = 0;
472     do { // find a requestId
473         requestId = GetRequestId();
474     } while (requestRawParamMap_.count(requestId) > 0);
475     int32_t calllingUid = IPCSkeleton::GetCallingUid();
476     int32_t calllingPid = IPCSkeleton::GetCallingPid();
477     auto calllingTokenID = IPCSkeleton::GetCallingTokenID();
478     SetFirstCallerTokenID(calllingTokenID);
479     DUMPER_HILOGD(MODULE_SERVICE, "debug|requestId=%{public}u, calllingUid=%{public}d, calllingPid=%{public}d",
480                   requestId, calllingUid, calllingPid);
481     std::shared_ptr<RawParam> requestHandle =
482         std::make_shared<RawParam>(calllingUid, calllingPid, requestId, args, outfd);
483     requestRawParamMap_.insert(std::make_pair(requestId, requestHandle));
484     return requestHandle;
485 }
486 
EraseRequestRawParam(const std::shared_ptr<RawParam> rawParam)487 void DumpManagerService::EraseRequestRawParam(const std::shared_ptr<RawParam> rawParam)
488 {
489     if (rawParam == nullptr) {
490         return;
491     }
492     DUMPER_HILOGD(MODULE_SERVICE, "enter|");
493     unique_lock<mutex> lock(mutex_);
494     uint32_t requestId = rawParam->GetRequestId();
495     DUMPER_HILOGD(MODULE_SERVICE, "debug|requestId=%{public}u", requestId);
496     if (requestRawParamMap_.count(requestId) > 0) {
497         requestRawParamMap_.erase(requestId);
498         DUMPER_HILOGD(MODULE_SERVICE, "debug|erase");
499     }
500     DUMPER_HILOGD(MODULE_SERVICE, "leave|");
501 }
502 
CancelAllRequest()503 void DumpManagerService::CancelAllRequest()
504 {
505     DUMPER_HILOGD(MODULE_SERVICE, "enter|");
506     unique_lock<mutex> lock(mutex_);
507     for (auto &requestIt : requestRawParamMap_) {
508         if (requestIt.second == nullptr) {
509             continue;
510         }
511         requestIt.second->Cancel();
512     }
513     DUMPER_HILOGD(MODULE_SERVICE, "leave|");
514 }
515 
GetRequestId()516 uint32_t DumpManagerService::GetRequestId()
517 {
518     requestIndex_ = (requestIndex_ + 1) % REQUESTID_MAX;
519     return requestIndex_;
520 }
521 
GetIdleRequest()522 void DumpManagerService::GetIdleRequest()
523 {
524     unique_lock<mutex> lock(mutex_);
525     for (auto &requestIt : requestRawParamMap_) {
526         if (requestIt.second == nullptr) {
527             continue;
528         }
529         int argC = requestIt.second->GetArgc();
530         char **argV = requestIt.second->GetArgv();
531         if (argV == nullptr) {
532             continue;
533         }
534         std::stringstream dumpCmdSs;
535         for (int i = 0; i < argC; i++) {
536             dumpCmdSs << std::string(argV[i]) << " ";
537         }
538         DUMPER_HILOGI(MODULE_SERVICE, "idle cmd:%{public}s, calllingUid=%{public}d, calllingPid=%{public}d.",
539             dumpCmdSs.str().c_str(), requestIt.second->GetUid(), requestIt.second->GetPid());
540     }
541 }
542 
StartRequest(const std::shared_ptr<RawParam> rawParam)543 int32_t DumpManagerService::StartRequest(const std::shared_ptr<RawParam> rawParam)
544 {
545     RequestMain(rawParam);
546     return DumpStatus::DUMP_OK;
547 }
548 
RequestMain(const std::shared_ptr<RawParam> rawParam)549 void DumpManagerService::RequestMain(const std::shared_ptr<RawParam> rawParam)
550 {
551     DUMPER_HILOGD(MODULE_SERVICE, "enter|");
552     int argC = rawParam->GetArgc();
553     char **argV = rawParam->GetArgv();
554     std::string folder = DumpLogManager::CreateTmpFolder(rawParam->GetRequestId());
555     rawParam->SetFolder(folder);
556     if ((argC > 0) && (argV != nullptr)) {
557         DUMPER_HILOGD(MODULE_SERVICE, "debug|enter task, argC=%{public}d", argC);
558         for (int i = 0; i < argC; i++) {
559             DUMPER_HILOGD(MODULE_SERVICE, "debug|argV[%{public}d]=%{public}s", i, argV[i]);
560         }
561         DumpImplement::GetInstance().Main(argC, argV, rawParam);
562         DUMPER_HILOGD(MODULE_SERVICE, "debug|leave task");
563     }
564     DumpLogManager::EraseTmpFolder(rawParam->GetRequestId());
565     DumpLogManager::EraseLogs();
566     rawParam->CloseOutputFd();
567     EraseRequestRawParam(rawParam);
568     DUMPER_HILOGD(MODULE_SERVICE, "leave|");
569 }
570 
DelayUnloadTask()571 void DumpManagerService::DelayUnloadTask()
572 {
573     int32_t calllingPid = IPCSkeleton::GetCallingPid();
574     DUMPER_HILOGI(MODULE_SERVICE, "recieve new request, delay unload task begin, calllingPid=%{public}d", calllingPid);
575     auto task = [this]() {
576         DUMPER_HILOGI(MODULE_SERVICE, "do unload task, request sum=%{public}d", GetRequestSum());
577         if (GetRequestSum() != 0) {
578             GetIdleRequest();
579             return;
580         }
581         auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
582         if (samgrProxy == nullptr) {
583             DUMPER_HILOGE(MODULE_SERVICE, "get samgr failed");
584             return;
585         }
586         int32_t ret = samgrProxy->UnloadSystemAbility(DFX_SYS_HIDUMPER_ABILITY_ID);
587         if (ret != ERR_OK) {
588             DUMPER_HILOGE(MODULE_SERVICE, "remove system ability failed");
589             return;
590         }
591     };
592     handler_->RemoveTask(TASK_ID);
593     handler_->PostTask(task, TASK_ID, DYNAMIC_EXIT_DELAY_TIME);
594 }
595 } // namespace HiviewDFX
596 } // namespace OHOS
597