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