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 return UNLOAD_IMMEDIATELY;
123 } else {
124 GetIdleRequest();
125 return DYNAMIC_EXIT_DELAY_TIME;
126 }
127 } else {
128 return UNLOAD_IMMEDIATELY;
129 }
130 }
131
SetCpuSchedAffinity()132 void DumpManagerService::SetCpuSchedAffinity()
133 {
134 pid_t hidumperServicePid = getprocpid();
135 cpu_set_t mask;
136 CPU_ZERO(&mask);
137 for (int i = 0; i < SMALL_CPU_SIZE; i++) {
138 CPU_SET(i, &mask);
139 }
140 if (sched_setaffinity(hidumperServicePid, sizeof(mask), &mask) < 0) {
141 DUMPER_HILOGE(MODULE_SERVICE, "error|sched_setaffinity failed");
142 }
143 }
144
Dump(int32_t fd,const std::vector<std::u16string> & args)145 int32_t DumpManagerService::Dump(int32_t fd, const std::vector<std::u16string> &args)
146 {
147 std::string result = DUMPMGR_SERVICE_NAME;
148 if (!SaveStringToFd(fd, result)) {
149 DUMPER_HILOGE(MODULE_SERVICE, "DumpManagerService::Dump failed, save to fd failed.");
150 DUMPER_HILOGE(MODULE_SERVICE, "Dump Info:\n");
151 DUMPER_HILOGE(MODULE_SERVICE, "%{public}s", result.c_str());
152 return ERR_OK;
153 }
154 return ERR_OK;
155 }
156
Request(std::vector<std::u16string> & args,int outfd)157 int32_t DumpManagerService::Request(std::vector<std::u16string> &args, int outfd)
158 {
159 if (blockRequest_) {
160 return DumpStatus::DUMP_FAIL;
161 }
162 if (!started_) {
163 return DumpStatus::DUMP_FAIL;
164 }
165 int32_t uid = IPCSkeleton::GetCallingUid();
166 if (!HasDumpPermission() && uid != HIPORFILER_UID) {
167 DUMPER_HILOGE(MODULE_SERVICE, "No dump permission, please check!, uid:%{public}d.", uid);
168 return DumpStatus::DUMP_FAIL;
169 }
170 int sum = GetRequestSum();
171 DUMPER_HILOGD(MODULE_SERVICE, "debug|sum=%{public}d", sum);
172 if (sum >= REQUEST_MAX) {
173 DUMPER_HILOGE(MODULE_SERVICE, "sum is greater than the request max, sum:%{public}d.", sum);
174 return DumpStatus::DUMP_REQUEST_MAX;
175 } else if (sum == 0) {
176 DumpLogManager::Init();
177 }
178 DelayUnloadTask();
179 DUMPER_HILOGD(MODULE_SERVICE, "enter|");
180 const std::shared_ptr<RawParam> rawParam = AddRequestRawParam(args, outfd);
181 int32_t ret = StartRequest(rawParam);
182 DUMPER_HILOGD(MODULE_SERVICE, "leave|ret=%{public}d", ret);
183 return ret;
184 }
185
186 // Authenticate dump permissions
HasDumpPermission() const187 bool DumpManagerService::HasDumpPermission() const
188 {
189 uint32_t callingTokenID = IPCSkeleton::GetCallingTokenID();
190 int res = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callingTokenID, "ohos.permission.DUMP");
191 if (res != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
192 DUMPER_HILOGI(MODULE_SERVICE, "No dump permission, please check!");
193 return false;
194 }
195 return true;
196 }
197
GetFileDescriptorNums(int32_t pid,std::string requestType) const198 uint32_t DumpManagerService::GetFileDescriptorNums(int32_t pid, std::string requestType) const
199 {
200 if (requestType.find("..") != std::string::npos) {
201 DUMPER_HILOGE(MODULE_SERVICE, "requestType is invalid, please check!");
202 return 0;
203 }
204 std::string taskPath = "/proc/" + std::to_string(pid) + "/" + requestType;
205 std::vector<std::string> fdList = DumpCommonUtils::GetSubNodes(taskPath, true);
206 return fdList.size();
207 }
208
ScanPidOverLimit(std::string requestType,int32_t limitSize,std::vector<int32_t> & pidList)209 int32_t DumpManagerService::ScanPidOverLimit(std::string requestType, int32_t limitSize, std::vector<int32_t> &pidList)
210 {
211 if (!HasDumpPermission()) {
212 return DumpStatus::DUMP_FAIL;
213 }
214 if (limitSize < 0) {
215 return DumpStatus::DUMP_FAIL;
216 }
217 int32_t ret = DumpStatus::DUMP_OK;
218 std::vector<int32_t> pids = DumpCommonUtils::GetAllPids();
219 for (const auto &pid : pids) {
220 uint32_t num = GetFileDescriptorNums(pid, requestType);
221 if (num < static_cast<uint32_t>(limitSize)) {
222 continue;
223 }
224 auto it = std::find(pidList.begin(), pidList.end(), pid);
225 if (it != pidList.end()) {
226 continue;
227 }
228 pidList.push_back(pid);
229 }
230 return ret;
231 }
232
GetFdLinkNum(const std::string & linkPath) const233 std::string DumpManagerService::GetFdLinkNum(const std::string &linkPath) const
234 {
235 char linkDest[PATH_MAX] = {0};
236 ssize_t linkDestSize = readlink(linkPath.c_str(), linkDest, sizeof(linkDest) - 1);
237 if (linkDestSize < 0) {
238 return "unknown";
239 }
240 linkDest[linkDestSize] = '\0';
241 return linkDest;
242 }
243
RecordDetailFdInfo(std::string & detailFdInfo,std::string & topLeakedType)244 void DumpManagerService::RecordDetailFdInfo(std::string &detailFdInfo, std::string &topLeakedType)
245 {
246 lock_guard<mutex> lock(linkCntMutex_);
247 if (linkCnt_.empty()) {
248 DUMPER_HILOGE(MODULE_SERVICE, "linkCnt_ is empty!");
249 return;
250 }
251 topLeakedType = linkCnt_[0].first;
252 for (size_t i = 0; i < linkCnt_.size() && i < FD_LOG_NUM; i++) {
253 detailFdInfo += std::to_string(linkCnt_[i].second) + "\t" + linkCnt_[i].first + "\n";
254 }
255 }
256
RecordDirFdInfo(std::string & detailFdInfo)257 void DumpManagerService::RecordDirFdInfo(std::string &detailFdInfo)
258 {
259 std::unordered_map<std::string, int> fileTypeMap;
260 std::vector<pair<std::string, int>> fileTypeList;
261 {
262 lock_guard<mutex> lock(linkCntMutex_);
263 for (const auto &each : linkCnt_) {
264 if (g_fdLeakWp.find(each.first) == g_fdLeakWp.end()) {
265 std::string fileName(each.first, 0, DumpCommonUtils::FindDigitIndex(each.first));
266 if (fileTypeMap.find(fileName) == fileTypeMap.end()) {
267 fileTypeMap[fileName] = each.second;
268 } else {
269 fileTypeMap[fileName] += each.second;
270 }
271 }
272 }
273 }
274 for (std::pair<std::string, int> fileNamePair : fileTypeMap) {
275 fileTypeList.push_back(fileNamePair);
276 }
277 sort(fileTypeList.begin(), fileTypeList.end(),
278 [](const std::pair<std::string, int> &p1, const std::pair<std::string, int> &p2) {
279 return p1.second > p2.second;
280 });
281 detailFdInfo += "\nTop Dir Type 10:\n";
282 for (size_t i = 0; i < fileTypeList.size() && i < FD_LOG_NUM; i++) {
283 detailFdInfo += std::to_string(fileTypeList[i].second) + "\t" + fileTypeList[i].first + "\n";
284 }
285 }
286
CountFdNums(int32_t pid,uint32_t & fdNums,std::string & detailFdInfo,std::string & topLeakedType)287 int32_t DumpManagerService::CountFdNums(int32_t pid, uint32_t &fdNums,
288 std::string &detailFdInfo, std::string &topLeakedType)
289 {
290 if (!HasDumpPermission()) {
291 return DumpStatus::DUMP_FAIL;
292 }
293 // transfor to vector to sort by map value.
294 int32_t ret = DumpStatus::DUMP_OK;
295 std::map<std::string, int64_t> linkNameCnt;
296 {
297 lock_guard<mutex> lock(linkCntMutex_);
298 if (!linkCnt_.empty()) {
299 linkCnt_.clear();
300 }
301 }
302 std::string taskPath = "/proc/" + std::to_string(pid) + "/fd";
303 std::vector<std::string> fdList = DumpCommonUtils::GetSubNodes(taskPath, true);
304 fdNums = GetFileDescriptorNums(pid, "fd");
305 for (const auto &each : fdList) {
306 std::string linkPath = taskPath + "/" + each;
307 std::string linkName = GetFdLinkNum(linkPath);
308 // we count the fd number by name contained the keywords socket/dmabuf...
309 bool contained = false;
310 for (const auto &fdWp : g_fdLeakWp) {
311 if (linkName.find(fdWp.first) != std::string::npos) {
312 linkNameCnt[fdWp.first]++;
313 contained = true;
314 break;
315 }
316 }
317 if (!contained) {
318 linkNameCnt[linkName]++;
319 }
320 }
321 {
322 lock_guard<mutex> lock(linkCntMutex_);
323 for (const auto &each : linkNameCnt) {
324 linkCnt_.push_back(each);
325 }
326 if (linkCnt_.empty()) {
327 return DumpStatus::DUMP_FAIL;
328 }
329 std::sort(linkCnt_.begin(), linkCnt_.end(),
330 [](const std::pair<std::string, int> &a, const std::pair<std::string, int> &b) {
331 return a.second > b.second;
332 });
333 }
334 RecordDetailFdInfo(detailFdInfo, topLeakedType);
335 RecordDirFdInfo(detailFdInfo);
336 return ret;
337 }
338
339 #ifdef DUMP_TEST_MODE // for mock test
SetTestMainFunc(DumpManagerServiceTestMainFunc testMainFunc)340 void DumpManagerService::SetTestMainFunc(DumpManagerServiceTestMainFunc testMainFunc)
341 {
342 testMainFunc_ = testMainFunc;
343 }
344 #endif // for mock test
345
Init()346 bool DumpManagerService::Init()
347 {
348 if (!eventRunner_) {
349 eventRunner_ = AppExecFwk::EventRunner::Create(DUMPMGR_SERVICE_NAME);
350 if (eventRunner_ == nullptr) {
351 DUMPER_HILOGE(MODULE_SERVICE, "error|create EventRunner");
352 return false;
353 }
354 }
355 if (!handler_) {
356 handler_ = std::make_shared<AppExecFwk::EventHandler>(eventRunner_);
357 if (handler_ == nullptr) {
358 DUMPER_HILOGE(MODULE_SERVICE, "error|create EventHandler");
359 return false;
360 }
361 }
362 return true;
363 }
364
GetRequestSum()365 int DumpManagerService::GetRequestSum()
366 {
367 unique_lock<mutex> lock(mutex_);
368 return requestRawParamMap_.size();
369 }
370
AddRequestRawParam(std::vector<std::u16string> & args,int outfd)371 std::shared_ptr<RawParam> DumpManagerService::AddRequestRawParam(std::vector<std::u16string> &args, int outfd)
372 {
373 unique_lock<mutex> lock(mutex_);
374 uint32_t requestId = 0;
375 do { // find a requestId
376 requestId = GetRequestId();
377 } while (requestRawParamMap_.count(requestId) > 0);
378 int32_t calllingUid = IPCSkeleton::GetCallingUid();
379 int32_t calllingPid = IPCSkeleton::GetCallingPid();
380 auto calllingTokenID = IPCSkeleton::GetCallingTokenID();
381 SetFirstCallerTokenID(calllingTokenID);
382 DUMPER_HILOGD(MODULE_SERVICE, "debug|requestId=%{public}u, calllingUid=%{public}d, calllingPid=%{public}d",
383 requestId, calllingUid, calllingPid);
384 std::shared_ptr<RawParam> requestHandle =
385 std::make_shared<RawParam>(calllingUid, calllingPid, requestId, args, outfd);
386 requestRawParamMap_.insert(std::make_pair(requestId, requestHandle));
387 return requestHandle;
388 }
389
EraseRequestRawParam(const std::shared_ptr<RawParam> rawParam)390 void DumpManagerService::EraseRequestRawParam(const std::shared_ptr<RawParam> rawParam)
391 {
392 if (rawParam == nullptr) {
393 return;
394 }
395 DUMPER_HILOGD(MODULE_SERVICE, "enter|");
396 unique_lock<mutex> lock(mutex_);
397 uint32_t requestId = rawParam->GetRequestId();
398 DUMPER_HILOGD(MODULE_SERVICE, "debug|requestId=%{public}u", requestId);
399 if (requestRawParamMap_.count(requestId) > 0) {
400 requestRawParamMap_.erase(requestId);
401 DUMPER_HILOGD(MODULE_SERVICE, "debug|erase");
402 }
403 DUMPER_HILOGD(MODULE_SERVICE, "leave|");
404 }
405
CancelAllRequest()406 void DumpManagerService::CancelAllRequest()
407 {
408 DUMPER_HILOGD(MODULE_SERVICE, "enter|");
409 unique_lock<mutex> lock(mutex_);
410 for (auto &requestIt : requestRawParamMap_) {
411 if (requestIt.second == nullptr) {
412 continue;
413 }
414 requestIt.second->Cancel();
415 }
416 DUMPER_HILOGD(MODULE_SERVICE, "leave|");
417 }
418
GetRequestId()419 uint32_t DumpManagerService::GetRequestId()
420 {
421 requestIndex_ = (requestIndex_ + 1) % REQUESTID_MAX;
422 return requestIndex_;
423 }
424
GetIdleRequest()425 void DumpManagerService::GetIdleRequest()
426 {
427 unique_lock<mutex> lock(mutex_);
428 for (auto &requestIt : requestRawParamMap_) {
429 if (requestIt.second == nullptr) {
430 continue;
431 }
432 int argC = requestIt.second->GetArgc();
433 char **argV = requestIt.second->GetArgv();
434 if (argV == nullptr) {
435 continue;
436 }
437 std::stringstream dumpCmdSs;
438 for (int i = 0; i < argC; i++) {
439 dumpCmdSs << std::string(argV[i]) << " ";
440 }
441 DUMPER_HILOGI(MODULE_SERVICE, "idle cmd:%{public}s, calllingUid=%{public}d, calllingPid=%{public}d.",
442 dumpCmdSs.str().c_str(), requestIt.second->GetUid(), requestIt.second->GetPid());
443 }
444 }
445
StartRequest(const std::shared_ptr<RawParam> rawParam)446 int32_t DumpManagerService::StartRequest(const std::shared_ptr<RawParam> rawParam)
447 {
448 RequestMain(rawParam);
449 return DumpStatus::DUMP_OK;
450 }
451
RequestMain(const std::shared_ptr<RawParam> rawParam)452 void DumpManagerService::RequestMain(const std::shared_ptr<RawParam> rawParam)
453 {
454 DUMPER_HILOGD(MODULE_SERVICE, "enter|");
455 int argC = rawParam->GetArgc();
456 char **argV = rawParam->GetArgv();
457 std::string folder = DumpLogManager::CreateTmpFolder(rawParam->GetRequestId());
458 rawParam->SetFolder(folder);
459 if ((argC > 0) && (argV != nullptr)) {
460 DUMPER_HILOGD(MODULE_SERVICE, "debug|enter task, argC=%{public}d", argC);
461 for (int i = 0; i < argC; i++) {
462 DUMPER_HILOGD(MODULE_SERVICE, "debug|argV[%{public}d]=%{public}s", i, argV[i]);
463 }
464 DumpImplement::GetInstance().Main(argC, argV, rawParam);
465 DUMPER_HILOGD(MODULE_SERVICE, "debug|leave task");
466 }
467 DumpLogManager::EraseTmpFolder(rawParam->GetRequestId());
468 DumpLogManager::EraseLogs();
469 rawParam->CloseOutputFd();
470 EraseRequestRawParam(rawParam);
471 DUMPER_HILOGD(MODULE_SERVICE, "leave|");
472 }
473
DelayUnloadTask()474 void DumpManagerService::DelayUnloadTask()
475 {
476 int32_t calllingPid = IPCSkeleton::GetCallingPid();
477 DUMPER_HILOGI(MODULE_SERVICE, "recieve new request, delay unload task begin, calllingPid=%{public}d", calllingPid);
478 auto task = [this]() {
479 DUMPER_HILOGI(MODULE_SERVICE, "do unload task");
480 auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
481 if (samgrProxy == nullptr) {
482 DUMPER_HILOGE(MODULE_SERVICE, "get samgr failed");
483 return;
484 }
485 int32_t ret = samgrProxy->UnloadSystemAbility(DFX_SYS_HIDUMPER_ABILITY_ID);
486 if (ret != ERR_OK) {
487 DUMPER_HILOGE(MODULE_SERVICE, "remove system ability failed");
488 return;
489 }
490 };
491 handler_->RemoveTask(TASK_ID);
492 handler_->PostTask(task, TASK_ID, DYNAMIC_EXIT_DELAY_TIME);
493 }
494 } // namespace HiviewDFX
495 } // namespace OHOS
496