1/*
2 * Copyright (c) 2021-2024 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 "hiview_service_ability.h"
16
17#include <cstdio>
18#include <dirent.h>
19#include <fcntl.h>
20#include <functional>
21#include <mutex>
22#include <sys/stat.h>
23#include <unistd.h>
24
25#include "bundle_mgr_client.h"
26#include "file_util.h"
27#include "hiview_log_config_manager.h"
28#include "ipc_skeleton.h"
29#include "iservice_registry.h"
30#include "string_util.h"
31#include "system_ability_definition.h"
32#include "utility/trace_collector.h"
33
34namespace OHOS {
35namespace HiviewDFX {
36namespace {
37DEFINE_LOG_TAG("HiViewSA-HiViewServiceAbility");
38constexpr int MAXRETRYTIMEOUT = 10;
39constexpr int USER_ID_MOD = 200000;
40
41static std::string GetApplicationNameById(int32_t uid)
42{
43    std::string bundleName;
44    AppExecFwk::BundleMgrClient client;
45    if (client.GetNameForUid(uid, bundleName) != ERR_OK) {
46        HIVIEW_LOGW("Failed to query bundle name, uid:%{public}d.", uid);
47    }
48    return bundleName;
49}
50
51static std::string GetSandBoxPathByUid(int32_t uid)
52{
53    std::string bundleName = GetApplicationNameById(uid);
54    if (bundleName.empty()) {
55        return "";
56    }
57    std::string path;
58    path.append("/data/app/el2/")
59        .append(std::to_string(uid / USER_ID_MOD))
60        .append("/base/")
61        .append(bundleName)
62        .append("/cache/hiview");
63    return path;
64}
65
66static std::string ComposeFilePath(const std::string& rootDir, const std::string& destDir, const std::string& fileName)
67{
68    std::string filePath(rootDir);
69    if (destDir.empty()) {
70        filePath.append("/").append(fileName);
71    } else {
72        filePath.append("/").append(destDir).append("/").append(fileName);
73    }
74    return filePath;
75}
76}
77
78int HiviewServiceAbility::Dump(int32_t fd, const std::vector<std::u16string> &args)
79{
80    auto service = GetOrSetHiviewService(nullptr);
81    if (service != nullptr) {
82        std::vector<std::string> cmds;
83        for (const auto &arg : args) {
84            cmds.push_back(StringUtil::ConvertToUTF8(arg));
85        }
86        service->DumpRequestDispatcher(fd, cmds);
87    }
88    return 0;
89}
90
91HiviewServiceAbility::HiviewServiceAbility() : SystemAbility(DFX_SYS_HIVIEW_ABILITY_ID, true)
92{
93    HIVIEW_LOGI("begin, cmd : %d", DFX_SYS_HIVIEW_ABILITY_ID);
94}
95
96HiviewServiceAbility::~HiviewServiceAbility()
97{
98    HIVIEW_LOGI("begin, cmd : %d", DFX_SYS_HIVIEW_ABILITY_ID);
99}
100
101void HiviewServiceAbility::StartServiceAbility(int sleepS)
102{
103    sptr<ISystemAbilityManager> serviceManager;
104
105    int retryTimeout = MAXRETRYTIMEOUT;
106    while (retryTimeout > 0) {
107        --retryTimeout;
108        if (sleepS > 0) {
109            sleep(sleepS);
110        }
111
112        SystemAbilityManagerClient::GetInstance().DestroySystemAbilityManagerObject();
113        serviceManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
114        if (serviceManager == nullptr) {
115            continue;
116        }
117
118        int result = serviceManager->AddSystemAbility(DFX_SYS_HIVIEW_ABILITY_ID, new HiviewServiceAbility());
119        if (result != 0) {
120            HIVIEW_LOGE("AddSystemAbility error %d", result);
121            continue;
122        }
123        break;
124    }
125
126    if (serviceManager == nullptr) {
127        HIVIEW_LOGE("serviceManager == nullptr");
128        return;
129    }
130
131    auto abilityObjext = serviceManager->AsObject();
132    if (abilityObjext == nullptr) {
133        HIVIEW_LOGE("AsObject() == nullptr");
134        return;
135    }
136
137    bool ret = abilityObjext->AddDeathRecipient(new HiviewServiceAbilityDeathRecipient());
138    if (ret == false) {
139        HIVIEW_LOGE("AddDeathRecipient == false");
140    }
141}
142
143void HiviewServiceAbility::StartService(HiviewService *service)
144{
145    GetOrSetHiviewService(service);
146    StartServiceAbility(0);
147    IPCSkeleton::JoinWorkThread();
148}
149
150HiviewService *HiviewServiceAbility::GetOrSetHiviewService(HiviewService *service)
151{
152    static HiviewService *ref = nullptr;
153    if (service != nullptr) {
154        ref = service;
155    }
156    return ref;
157}
158
159int32_t HiviewServiceAbility::List(const std::string& logType, std::vector<HiviewFileInfo>& fileInfos)
160{
161    auto configInfoPtr = HiviewLogConfigManager::GetInstance().GetConfigInfoByType(logType);
162    if (configInfoPtr == nullptr) {
163        HIVIEW_LOGI("invalid logtype: %{public}s", logType.c_str());
164        return HiviewNapiErrCode::ERR_INNER_INVALID_LOGTYPE;
165    }
166    GetFileInfoUnderDir(configInfoPtr->path, fileInfos);
167    return 0;
168}
169
170void HiviewServiceAbility::GetFileInfoUnderDir(const std::string& dirPath, std::vector<HiviewFileInfo>& fileInfos)
171{
172    DIR* dir = opendir(dirPath.c_str());
173    if (dir == nullptr) {
174        HIVIEW_LOGW("open dir failed.");
175        return;
176    }
177    struct stat statBuf {};
178    for (auto* ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
179        if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0 || ent->d_type == DT_DIR) {
180            continue;
181        }
182        std::string filePath(dirPath + ent->d_name);
183        if (stat(filePath.c_str(), &statBuf) != 0) {
184            HIVIEW_LOGW("stat file failed.");
185            continue;
186        }
187        fileInfos.emplace_back(ent->d_name, statBuf.st_mtime, statBuf.st_size);
188    }
189    closedir(dir);
190}
191
192int32_t HiviewServiceAbility::Copy(const std::string& logType, const std::string& logName, const std::string& dest)
193{
194    return CopyOrMoveFile(logType, logName, dest, false);
195}
196
197int32_t HiviewServiceAbility::Move(const std::string& logType, const std::string& logName, const std::string& dest)
198{
199    return CopyOrMoveFile(logType, logName, dest, true);
200}
201
202int32_t HiviewServiceAbility::CopyOrMoveFile(
203    const std::string& logType, const std::string& logName, const std::string& dest, bool isMove)
204{
205    auto service = GetOrSetHiviewService();
206    if (service == nullptr) {
207        return HiviewNapiErrCode::ERR_DEFAULT;
208    }
209    auto configInfoPtr = HiviewLogConfigManager::GetInstance().GetConfigInfoByType(logType);
210    if (configInfoPtr == nullptr) {
211        HIVIEW_LOGI("invalid logtype: %{public}s", logType.c_str());
212        return HiviewNapiErrCode::ERR_INNER_INVALID_LOGTYPE;
213    }
214    if (isMove && configInfoPtr->isReadOnly) {
215        HIVIEW_LOGW("log: %{public}s is read only.", logType.c_str());
216        return HiviewNapiErrCode::ERR_INNER_READ_ONLY;
217    }
218    int32_t uid = IPCSkeleton::GetCallingUid();
219    HIVIEW_LOGI("uid %{public}d, isMove: %{public}d, type:%{public}s, name:%{public}s",
220        uid, isMove, logType.c_str(), StringUtil::HideSnInfo(logName).c_str());
221    std::string sandboxPath = GetSandBoxPathByUid(uid);
222    if (sandboxPath.empty()) {
223        return HiviewNapiErrCode::ERR_DEFAULT;
224    }
225    std::string sourceFile = configInfoPtr->path + logName;
226    if (!FileUtil::FileExists(sourceFile)) {
227        HIVIEW_LOGW("file: %{public}s not exist.", StringUtil::HideSnInfo(logName).c_str());
228        return HiviewNapiErrCode::ERR_SOURCE_FILE_NOT_EXIST;
229    }
230    std::string fullPath = ComposeFilePath(sandboxPath, dest, logName);
231    return isMove ? service->Move(sourceFile, fullPath) : service->Copy(sourceFile, fullPath);
232}
233
234int32_t HiviewServiceAbility::Remove(const std::string& logType, const std::string& logName)
235{
236    auto service = GetOrSetHiviewService();
237    if (service == nullptr) {
238        return HiviewNapiErrCode::ERR_DEFAULT;
239    }
240    HIVIEW_LOGI("type:%{public}s, name:%{public}s", logType.c_str(), StringUtil::HideSnInfo(logName).c_str());
241    auto configInfoPtr = HiviewLogConfigManager::GetInstance().GetConfigInfoByType(logType);
242    if (configInfoPtr == nullptr) {
243        HIVIEW_LOGI("invalid logtype: %{public}s", logType.c_str());
244        return HiviewNapiErrCode::ERR_INNER_INVALID_LOGTYPE;
245    }
246    if (configInfoPtr->isReadOnly) {
247        HIVIEW_LOGW("log: %{public}s is read only.", logType.c_str());
248        return HiviewNapiErrCode::ERR_INNER_READ_ONLY;
249    }
250    std::string sourceFile = configInfoPtr->path + logName;
251    if (!FileUtil::FileExists(sourceFile)) {
252        HIVIEW_LOGW("file: %{public}s not exist.", StringUtil::HideSnInfo(logName).c_str());
253        return HiviewNapiErrCode::ERR_SOURCE_FILE_NOT_EXIST;
254    }
255    return service->Remove(sourceFile);
256}
257
258void HiviewServiceAbility::OnDump()
259{
260    HIVIEW_LOGI("called");
261}
262
263void HiviewServiceAbility::OnStart()
264{
265    HIVIEW_LOGI("called");
266}
267
268void HiviewServiceAbility::OnStop()
269{
270    HIVIEW_LOGI("called");
271}
272
273CollectResultParcelable<int32_t> HiviewServiceAbility::OpenSnapshotTrace(const std::vector<std::string>& tagGroups)
274{
275    auto traceRetHandler = [&tagGroups] (HiviewService* service) {
276        return service->OpenSnapshotTrace(tagGroups);
277    };
278    return TraceCalling<int32_t>(traceRetHandler);
279}
280
281CollectResultParcelable<std::vector<std::string>> HiviewServiceAbility::DumpSnapshotTrace(int32_t caller)
282{
283    auto traceRetHandler = [caller] (HiviewService* service) {
284        return service->DumpSnapshotTrace(static_cast<UCollect::TraceCaller>(caller));
285    };
286    return TraceCalling<std::vector<std::string>>(traceRetHandler);
287}
288
289CollectResultParcelable<int32_t> HiviewServiceAbility::OpenRecordingTrace(const std::string& tags)
290{
291    auto traceRetHandler = [&tags] (HiviewService* service) {
292        return service->OpenRecordingTrace(tags);
293    };
294    return TraceCalling<int32_t>(traceRetHandler);
295}
296
297CollectResultParcelable<int32_t> HiviewServiceAbility::RecordingTraceOn()
298{
299    auto traceRetHandler = [] (HiviewService* service) {
300        return service->RecordingTraceOn();
301    };
302    return TraceCalling<int32_t>(traceRetHandler);
303}
304
305CollectResultParcelable<std::vector<std::string>> HiviewServiceAbility::RecordingTraceOff()
306{
307    auto traceRetHandler = [] (HiviewService* service) {
308        return service->RecordingTraceOff();
309    };
310    return TraceCalling<std::vector<std::string>>(traceRetHandler);
311}
312
313CollectResultParcelable<int32_t> HiviewServiceAbility::CloseTrace()
314{
315    auto traceRetHandler = [] (HiviewService* service) {
316        return service->CloseTrace();
317    };
318    return TraceCalling<int32_t>(traceRetHandler);
319}
320
321CollectResultParcelable<int32_t> HiviewServiceAbility::RecoverTrace()
322{
323    auto traceRetHandler = [] (HiviewService* service) {
324        return service->RecoverTrace();
325    };
326    return TraceCalling<int32_t>(traceRetHandler);
327}
328
329CollectResultParcelable<int32_t> HiviewServiceAbility::CaptureDurationTrace(UCollectClient::AppCaller &appCaller)
330{
331    appCaller.uid = IPCSkeleton::GetCallingUid();
332    appCaller.pid = IPCSkeleton::GetCallingPid();
333
334    auto traceRetHandler = [=, &appCaller] (HiviewService* service) {
335        return service->CaptureDurationTrace(appCaller);
336    };
337    return TraceCalling<int32_t>(traceRetHandler);
338}
339
340CollectResultParcelable<double> HiviewServiceAbility::GetSysCpuUsage()
341{
342    return TraceCalling<double>([] (HiviewService* service) {
343        return service->GetSysCpuUsage();
344    });
345}
346
347CollectResultParcelable<int32_t> HiviewServiceAbility::SetAppResourceLimit(UCollectClient::MemoryCaller& memoryCaller)
348{
349    auto handler = [&memoryCaller] (HiviewService* service) {
350        return service->SetAppResourceLimit(memoryCaller);
351    };
352    return TraceCalling<int32_t>(handler);
353}
354
355CollectResultParcelable<int32_t> HiviewServiceAbility::GetGraphicUsage(int32_t pid)
356{
357    auto handler = [pid] (HiviewService* service) {
358        return service->GetGraphicUsage(pid);
359    };
360    return TraceCalling<int32_t>(handler);
361}
362
363HiviewServiceAbilityDeathRecipient::HiviewServiceAbilityDeathRecipient()
364{
365    HIVIEW_LOGI("called");
366}
367
368HiviewServiceAbilityDeathRecipient::~HiviewServiceAbilityDeathRecipient()
369{
370    HIVIEW_LOGI("called");
371}
372
373void HiviewServiceAbilityDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
374{
375    HIVIEW_LOGI("called");
376    if (object == nullptr) {
377        return;
378    }
379    HiviewServiceAbility::StartServiceAbility(1);
380}
381} // namespace HiviewDFX
382} // namespace OHOS
383