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