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