1/*
2 * Copyright (c) 2021-2023 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 "faultlogger_service_ohos.h"
16
17#include <functional>
18#include <string>
19#include <vector>
20
21#include "if_system_ability_manager.h"
22#include "ipc_skeleton.h"
23#include "iservice_registry.h"
24#include "system_ability_definition.h"
25
26#include "hiview_logger.h"
27
28#include "faultlog_info.h"
29#include "faultlog_info_ohos.h"
30#include "faultlog_query_result_inner.h"
31#include "faultlog_query_result_ohos.h"
32#include "faultlogger.h"
33
34DEFINE_LOG_LABEL(0xD002D11, "FaultloggerServiceOhos");
35namespace OHOS {
36namespace HiviewDFX {
37namespace {
38constexpr int32_t UID_SHELL = 2000;
39constexpr int32_t UID_ROOT = 0;
40constexpr int32_t UID_HIDUMPER = 1212;
41constexpr int32_t UID_HIVIEW = 1201;
42}
43void FaultloggerServiceOhos::ClearQueryStub(int32_t uid)
44{
45    std::lock_guard<std::mutex> lock(mutex_);
46    queries_.erase(uid);
47}
48
49int32_t FaultloggerServiceOhos::Dump(int32_t fd, const std::vector<std::u16string> &args)
50{
51    int32_t uid = IPCSkeleton::GetCallingUid();
52    if ((uid != UID_SHELL) && (uid != UID_ROOT) && (uid != UID_HIDUMPER)) {
53        dprintf(fd, "No permission for uid:%d.\n", uid);
54        return -1;
55    }
56
57    std::vector<std::string> cmdList;
58    for (auto arg : args) {
59        for (auto c : arg) {
60            if (!isalnum(c) && c != '-' && c != ' ' && c != '_' && c != '.') {
61                dprintf(fd, "string arg contain invalid char:%c.\n", c);
62                return -1;
63            }
64        }
65    }
66    std::transform(args.begin(), args.end(), std::back_inserter(cmdList), [](const std::u16string &arg) {
67        std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
68        return converter.to_bytes(arg);
69    });
70
71    auto service = GetOrSetFaultlogger();
72    if (service == nullptr) {
73        dprintf(fd, "Service is not ready.\n");
74        return -1;
75    }
76
77    service->Dump(fd, cmdList);
78    return 0;
79}
80
81void FaultloggerServiceOhos::StartService(OHOS::HiviewDFX::Faultlogger *service)
82{
83    GetOrSetFaultlogger(service);
84    sptr<ISystemAbilityManager> serviceManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
85    if (serviceManager == nullptr) {
86        HIVIEW_LOGE("Failed to find samgr, exit.");
87        return;
88    }
89
90    static sptr<FaultloggerServiceOhos> instance = new FaultloggerServiceOhos();
91    serviceManager->AddSystemAbility(DFX_FAULT_LOGGER_ABILITY_ID, instance);
92    HIVIEW_LOGI("FaultLogger Service started.");
93}
94
95OHOS::HiviewDFX::Faultlogger *FaultloggerServiceOhos::GetOrSetFaultlogger(
96    OHOS::HiviewDFX::Faultlogger *service)
97{
98    static OHOS::HiviewDFX::Faultlogger *ref = nullptr;
99    if (service != nullptr) {
100        ref = service;
101    }
102    return ref;
103}
104
105void FaultloggerServiceOhos::AddFaultLog(const FaultLogInfoOhos& info)
106{
107    auto service = GetOrSetFaultlogger();
108    if (service == nullptr) {
109        return;
110    }
111
112    int32_t uid = IPCSkeleton::GetCallingUid();
113    HIVIEW_LOGD("info.uid:%{public}d uid:%{public}d info.pid:%{public}d", info.uid, uid, info.pid);
114    if (((uid != static_cast<int32_t>(getuid()))) && (uid != info.uid)) {
115        HIVIEW_LOGW("Fail to add fault log, mismatch uid:%{public}d(%{public}d)", uid, info.uid);
116        return;
117    }
118
119    FaultLogInfo outInfo;
120    outInfo.time = info.time;
121    outInfo.id = info.uid;
122    outInfo.pid = info.pid;
123    auto fdDeleter = [] (int32_t *ptr) {
124        if (*ptr > 0) {
125            close(*ptr);
126        }
127        delete ptr;
128    };
129    outInfo.pipeFd.reset(new int32_t(info.pipeFd), fdDeleter);
130    outInfo.faultLogType = info.faultLogType;
131    outInfo.fd = (info.fd > 0) ? dup(info.fd) : -1;
132    outInfo.module = info.module;
133    outInfo.reason = info.reason;
134    outInfo.summary = info.summary;
135    if (uid == UID_HIVIEW) {
136        outInfo.logPath = info.logPath;
137    }
138    outInfo.registers = info.registers;
139    outInfo.sectionMap = info.sectionMaps;
140    service->AddFaultLog(outInfo);
141}
142
143sptr<IRemoteObject> FaultloggerServiceOhos::QuerySelfFaultLog(int32_t faultType, int32_t maxNum)
144{
145    auto service = GetOrSetFaultlogger();
146    if (service == nullptr) {
147        return nullptr;
148    }
149
150    int32_t uid = IPCSkeleton::GetCallingUid();
151    int32_t pid = IPCSkeleton::GetCallingPid();
152    std::lock_guard<std::mutex> lock(mutex_);
153    if ((queries_.find(uid) != queries_.end()) &&
154        (queries_[uid]->pid == pid)) {
155        HIVIEW_LOGW("Ongoing query is still alive for uid:%d", uid);
156        return nullptr;
157    }
158
159    auto queryResult = service->QuerySelfFaultLog(uid, pid, faultType, maxNum);
160    if (queryResult == nullptr) {
161        HIVIEW_LOGW("Fail to query fault log for uid:%d", uid);
162        return nullptr;
163    }
164
165    sptr<FaultLogQueryResultOhos> resultRef =
166        new FaultLogQueryResultOhos(std::move(queryResult));
167    auto queryStub = std::make_unique<FaultLogQuery>();
168    queryStub->pid = pid;
169    queryStub->ptr = resultRef;
170    queries_[uid] = std::move(queryStub);
171    return resultRef->AsObject();
172}
173
174void FaultloggerServiceOhos::Destroy()
175{
176    auto service = GetOrSetFaultlogger();
177    if (service == nullptr) {
178        return;
179    }
180
181    int32_t uid = IPCSkeleton::GetCallingUid();
182    HIVIEW_LOGI("Destroy Query from uid:%d", uid);
183    ClearQueryStub(uid);
184}
185}  // namespace HiviewDFX
186}  // namespace OHOS