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