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