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