• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "accesstoken_kit.h"
26 #include "bundle_mgr_client.h"
27 #include "client/trace_collector_client.h"
28 #include "client/memory_collector_client.h"
29 #include "file_util.h"
30 #include "hiview_log_config_manager.h"
31 #include "ipc_skeleton.h"
32 #include "iservice_registry.h"
33 #include "parameter_ex.h"
34 #include "string_util.h"
35 #include "system_ability_definition.h"
36 #include "utility/trace_collector.h"
37 
38 namespace OHOS {
39 namespace HiviewDFX {
40 namespace {
41 DEFINE_LOG_TAG("HiViewSA-HiviewServiceAbility");
42 constexpr int MAXRETRYTIMEOUT = 10;
43 constexpr int USER_ID_MOD = 200000;
44 constexpr int32_t MAX_SPLIT_MEMORY_SIZE = 256;
45 constexpr int32_t MEDIA_UID = 1013;
46 const std::string READ_HIVIEW_SYSTEM_PERMISSION = "ohos.permission.READ_HIVIEW_SYSTEM";
47 const std::string WRITE_HIVIEW_SYSTEM_PERMISSION = "ohos.permission.WRITE_HIVIEW_SYSTEM";
48 const std::string DUMP_PERMISSION = "ohos.permission.DUMP";
49 
GetApplicationNameById(int32_t uid)50 static std::string GetApplicationNameById(int32_t uid)
51 {
52     std::string bundleName;
53     AppExecFwk::BundleMgrClient client;
54     if (client.GetNameForUid(uid, bundleName) != ERR_OK) {
55         HIVIEW_LOGW("Failed to query bundle name, uid:%{public}d.", uid);
56     }
57     return bundleName;
58 }
59 
GetSandBoxPathByUid(int32_t uid)60 static std::string GetSandBoxPathByUid(int32_t uid)
61 {
62     std::string bundleName = GetApplicationNameById(uid);
63     if (bundleName.empty()) {
64         return "";
65     }
66     std::string path;
67     path.append("/data/app/el2/")
68         .append(std::to_string(uid / USER_ID_MOD))
69         .append("/base/")
70         .append(bundleName)
71         .append("/cache/hiview");
72     return path;
73 }
74 
ComposeFilePath(const std::string & rootDir,const std::string & destDir,const std::string & fileName)75 static std::string ComposeFilePath(const std::string& rootDir, const std::string& destDir, const std::string& fileName)
76 {
77     std::string filePath(rootDir);
78     if (destDir.empty()) {
79         filePath.append("/").append(fileName);
80     } else {
81         filePath.append("/").append(destDir).append("/").append(fileName);
82     }
83     return filePath;
84 }
85 
HasAccessPermission(const std::string & permission)86 static bool HasAccessPermission(const std::string& permission)
87 {
88     using namespace Security::AccessToken;
89     AccessTokenID callerToken = IPCSkeleton::GetCallingTokenID();
90     int verifyResult = AccessTokenKit::VerifyAccessToken(callerToken, permission);
91     if (verifyResult == PERMISSION_GRANTED) {
92         return true;
93     }
94     HIVIEW_LOGW("%{public}s not granted.", permission.c_str());
95     return false;
96 }
97 }
98 
Dump(int32_t fd,const std::vector<std::u16string> & args)99 int HiviewServiceAbility::Dump(int32_t fd, const std::vector<std::u16string> &args)
100 {
101     auto service = GetOrSetHiviewService(nullptr);
102     if (service != nullptr) {
103         std::vector<std::string> cmds;
104         for (const auto &arg : args) {
105             cmds.push_back(StringUtil::ConvertToUTF8(arg));
106         }
107         service->DumpRequestDispatcher(fd, cmds);
108     }
109     return 0;
110 }
111 
HiviewServiceAbility()112 HiviewServiceAbility::HiviewServiceAbility() : SystemAbility(DFX_SYS_HIVIEW_ABILITY_ID, true)
113 {
114     HIVIEW_LOGI("begin, cmd : %d", DFX_SYS_HIVIEW_ABILITY_ID);
115 }
116 
~HiviewServiceAbility()117 HiviewServiceAbility::~HiviewServiceAbility()
118 {
119     HIVIEW_LOGI("begin, cmd : %d", DFX_SYS_HIVIEW_ABILITY_ID);
120 }
121 
StartServiceAbility(int sleepS)122 void HiviewServiceAbility::StartServiceAbility(int sleepS)
123 {
124     sptr<ISystemAbilityManager> serviceManager;
125 
126     int retryTimeout = MAXRETRYTIMEOUT;
127     while (retryTimeout > 0) {
128         --retryTimeout;
129         if (sleepS > 0) {
130             sleep(sleepS);
131         }
132 
133         SystemAbilityManagerClient::GetInstance().DestroySystemAbilityManagerObject();
134         serviceManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
135         if (serviceManager == nullptr) {
136             continue;
137         }
138 
139         int result = serviceManager->AddSystemAbility(DFX_SYS_HIVIEW_ABILITY_ID, new HiviewServiceAbility());
140         if (result != 0) {
141             HIVIEW_LOGE("AddSystemAbility error %d", result);
142             continue;
143         }
144         break;
145     }
146 
147     if (serviceManager == nullptr) {
148         HIVIEW_LOGE("serviceManager == nullptr");
149         return;
150     }
151 
152     auto abilityObjext = serviceManager->AsObject();
153     if (abilityObjext == nullptr) {
154         HIVIEW_LOGE("AsObject() == nullptr");
155         return;
156     }
157 
158     bool ret = abilityObjext->AddDeathRecipient(new HiviewServiceAbilityDeathRecipient());
159     if (ret == false) {
160         HIVIEW_LOGE("AddDeathRecipient == false");
161     }
162 }
163 
StartService(HiviewService * service)164 void HiviewServiceAbility::StartService(HiviewService *service)
165 {
166     GetOrSetHiviewService(service);
167     StartServiceAbility(0);
168     IPCSkeleton::JoinWorkThread();
169 }
170 
GetOrSetHiviewService(HiviewService * service)171 HiviewService *HiviewServiceAbility::GetOrSetHiviewService(HiviewService *service)
172 {
173     static HiviewService *ref = nullptr;
174     if (service != nullptr) {
175         ref = service;
176     }
177     return ref;
178 }
179 
ListFiles(const std::string & logType,std::vector<HiviewFileInfo> & fileInfos)180 ErrCode HiviewServiceAbility::ListFiles(const std::string& logType, std::vector<HiviewFileInfo>& fileInfos)
181 {
182     if (!HasAccessPermission(READ_HIVIEW_SYSTEM_PERMISSION)) {
183         return HiviewNapiErrCode::ERR_PERMISSION_CHECK;
184     }
185     auto configInfoPtr = HiviewLogConfigManager::GetInstance().GetConfigInfoByType(logType);
186     if (configInfoPtr == nullptr) {
187         HIVIEW_LOGI("invalid logtype: %{public}s", logType.c_str());
188         return HiviewNapiErrCode::ERR_INNER_INVALID_LOGTYPE;
189     }
190     GetFileInfoUnderDir(configInfoPtr->path, fileInfos);
191     return 0;
192 }
193 
GetFileInfoUnderDir(const std::string & dirPath,std::vector<HiviewFileInfo> & fileInfos)194 void HiviewServiceAbility::GetFileInfoUnderDir(const std::string& dirPath, std::vector<HiviewFileInfo>& fileInfos)
195 {
196     DIR* dir = opendir(dirPath.c_str());
197     if (dir == nullptr) {
198         HIVIEW_LOGW("open dir failed.");
199         return;
200     }
201     struct stat statBuf {};
202     for (auto* ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
203         if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0 || ent->d_type == DT_DIR) {
204             continue;
205         }
206         std::string filePath(dirPath + ent->d_name);
207         if (stat(filePath.c_str(), &statBuf) != 0) {
208             HIVIEW_LOGW("stat file failed.");
209             continue;
210         }
211         fileInfos.emplace_back(ent->d_name, statBuf.st_mtime, statBuf.st_size);
212     }
213     closedir(dir);
214 }
215 
Copy(const std::string & logType,const std::string & logName,const std::string & dest)216 ErrCode HiviewServiceAbility::Copy(const std::string& logType, const std::string& logName, const std::string& dest)
217 {
218     if (!HasAccessPermission(READ_HIVIEW_SYSTEM_PERMISSION)) {
219         return HiviewNapiErrCode::ERR_PERMISSION_CHECK;
220     }
221     return CopyOrMoveFile(logType, logName, dest, false);
222 }
223 
Move(const std::string & logType,const std::string & logName,const std::string & dest)224 ErrCode HiviewServiceAbility::Move(const std::string& logType, const std::string& logName, const std::string& dest)
225 {
226     if (!HasAccessPermission(WRITE_HIVIEW_SYSTEM_PERMISSION)) {
227         return HiviewNapiErrCode::ERR_PERMISSION_CHECK;
228     }
229     return CopyOrMoveFile(logType, logName, dest, true);
230 }
231 
CopyOrMoveFile(const std::string & logType,const std::string & logName,const std::string & dest,bool isMove)232 ErrCode HiviewServiceAbility::CopyOrMoveFile(
233     const std::string& logType, const std::string& logName, const std::string& dest, bool isMove)
234 {
235     if (dest.find("..") != std::string::npos) {
236         HIVIEW_LOGW("invalid dest dir.");
237         return HiviewNapiErrCode::ERR_DEFAULT;
238     }
239     auto service = GetOrSetHiviewService();
240     if (service == nullptr) {
241         return HiviewNapiErrCode::ERR_DEFAULT;
242     }
243     auto configInfoPtr = HiviewLogConfigManager::GetInstance().GetConfigInfoByType(logType);
244     if (configInfoPtr == nullptr) {
245         HIVIEW_LOGI("invalid logtype: %{public}s", logType.c_str());
246         return HiviewNapiErrCode::ERR_INNER_INVALID_LOGTYPE;
247     }
248     if (isMove && configInfoPtr->isReadOnly) {
249         HIVIEW_LOGW("log: %{public}s is read only.", logType.c_str());
250         return HiviewNapiErrCode::ERR_INNER_READ_ONLY;
251     }
252     int32_t uid = IPCSkeleton::GetCallingUid();
253     HIVIEW_LOGI("uid %{public}d, isMove: %{public}d, type:%{public}s, name:%{public}s",
254         uid, isMove, logType.c_str(), StringUtil::HideSnInfo(logName).c_str());
255     std::string sandboxPath = GetSandBoxPathByUid(uid);
256     if (sandboxPath.empty()) {
257         return HiviewNapiErrCode::ERR_DEFAULT;
258     }
259     std::string sourceFile = configInfoPtr->path + logName;
260     if (!FileUtil::FileExists(sourceFile)) {
261         HIVIEW_LOGW("file: %{public}s not exist.", StringUtil::HideSnInfo(logName).c_str());
262         return HiviewNapiErrCode::ERR_SOURCE_FILE_NOT_EXIST;
263     }
264     std::string fullPath = ComposeFilePath(sandboxPath, dest, logName);
265     return isMove ? service->Move(sourceFile, fullPath) : service->Copy(sourceFile, fullPath);
266 }
267 
Remove(const std::string & logType,const std::string & logName)268 ErrCode HiviewServiceAbility::Remove(const std::string& logType, const std::string& logName)
269 {
270     if (!HasAccessPermission(WRITE_HIVIEW_SYSTEM_PERMISSION)) {
271         return HiviewNapiErrCode::ERR_PERMISSION_CHECK;
272     }
273     auto service = GetOrSetHiviewService();
274     if (service == nullptr) {
275         return HiviewNapiErrCode::ERR_DEFAULT;
276     }
277     HIVIEW_LOGI("type:%{public}s, name:%{public}s", logType.c_str(), StringUtil::HideSnInfo(logName).c_str());
278     auto configInfoPtr = HiviewLogConfigManager::GetInstance().GetConfigInfoByType(logType);
279     if (configInfoPtr == nullptr) {
280         HIVIEW_LOGI("invalid logtype: %{public}s", logType.c_str());
281         return HiviewNapiErrCode::ERR_INNER_INVALID_LOGTYPE;
282     }
283     if (configInfoPtr->isReadOnly) {
284         HIVIEW_LOGW("log: %{public}s is read only.", logType.c_str());
285         return HiviewNapiErrCode::ERR_INNER_READ_ONLY;
286     }
287     std::string sourceFile = configInfoPtr->path + logName;
288     if (!FileUtil::FileExists(sourceFile)) {
289         HIVIEW_LOGW("file: %{public}s not exist.", StringUtil::HideSnInfo(logName).c_str());
290         return HiviewNapiErrCode::ERR_SOURCE_FILE_NOT_EXIST;
291     }
292     return service->Remove(sourceFile);
293 }
294 
OnDump()295 void HiviewServiceAbility::OnDump()
296 {
297     HIVIEW_LOGI("called");
298 }
299 
OnStart()300 void HiviewServiceAbility::OnStart()
301 {
302     HIVIEW_LOGI("called");
303 }
304 
OnStop()305 void HiviewServiceAbility::OnStop()
306 {
307     HIVIEW_LOGI("called");
308 }
309 
OpenSnapshotTrace(const std::vector<std::string> & tagGroups,int32_t & errNo,int32_t & ret)310 ErrCode HiviewServiceAbility::OpenSnapshotTrace(const std::vector<std::string>& tagGroups, int32_t& errNo, int32_t& ret)
311 {
312     if (!HasAccessPermission(DUMP_PERMISSION) && !HasAccessPermission(WRITE_HIVIEW_SYSTEM_PERMISSION)) {
313         return HiviewNapiErrCode::ERR_PERMISSION_CHECK;
314     }
315     auto traceRetHandler = [&tagGroups] (HiviewService* service) {
316         return service->OpenSnapshotTrace(tagGroups);
317     };
318     TraceCalling<int32_t>(traceRetHandler, errNo, ret);
319     return 0;
320 }
321 
DumpSnapshotTrace(int32_t client,int32_t & errNo,std::vector<std::string> & files)322 ErrCode HiviewServiceAbility::DumpSnapshotTrace(int32_t client, int32_t& errNo, std::vector<std::string>& files)
323 {
324     if (!HasAccessPermission(DUMP_PERMISSION) && !HasAccessPermission(READ_HIVIEW_SYSTEM_PERMISSION)) {
325         return HiviewNapiErrCode::ERR_PERMISSION_CHECK;
326     }
327     auto traceRetHandler = [client] (HiviewService* service) {
328         return service->DumpSnapshotTrace(static_cast<UCollect::TraceClient>(client));
329     };
330     TraceCalling<std::vector<std::string>>(traceRetHandler, errNo, files);
331     return 0;
332 }
333 
OpenRecordingTrace(const std::string & tags,int32_t & errNo,int32_t & ret)334 ErrCode HiviewServiceAbility::OpenRecordingTrace(const std::string& tags, int32_t& errNo, int32_t& ret)
335 {
336     if (!HasAccessPermission(DUMP_PERMISSION) && !HasAccessPermission(WRITE_HIVIEW_SYSTEM_PERMISSION)) {
337         return HiviewNapiErrCode::ERR_PERMISSION_CHECK;
338     }
339     auto traceRetHandler = [&tags] (HiviewService* service) {
340         return service->OpenRecordingTrace(tags);
341     };
342     TraceCalling<int32_t>(traceRetHandler, errNo, ret);
343     return 0;
344 }
345 
RecordingTraceOn(int32_t & errNo,int32_t & ret)346 ErrCode HiviewServiceAbility::RecordingTraceOn(int32_t& errNo, int32_t& ret)
347 {
348     if (!HasAccessPermission(DUMP_PERMISSION) && !HasAccessPermission(READ_HIVIEW_SYSTEM_PERMISSION)) {
349         return HiviewNapiErrCode::ERR_PERMISSION_CHECK;
350     }
351     auto traceRetHandler = [] (HiviewService* service) {
352         return service->RecordingTraceOn();
353     };
354     TraceCalling<int32_t>(traceRetHandler, errNo, ret);
355     return 0;
356 }
357 
RecordingTraceOff(int32_t & errNo,std::vector<std::string> & files)358 ErrCode HiviewServiceAbility::RecordingTraceOff(int32_t& errNo, std::vector<std::string>& files)
359 {
360     if (!HasAccessPermission(DUMP_PERMISSION) && !HasAccessPermission(READ_HIVIEW_SYSTEM_PERMISSION)) {
361         return HiviewNapiErrCode::ERR_PERMISSION_CHECK;
362     }
363     auto traceRetHandler = [] (HiviewService* service) {
364         return service->RecordingTraceOff();
365     };
366     TraceCalling<std::vector<std::string>>(traceRetHandler, errNo, files);
367     return 0;
368 }
369 
CloseTrace(int32_t & errNo,int32_t & ret)370 ErrCode HiviewServiceAbility::CloseTrace(int32_t& errNo, int32_t& ret)
371 {
372     if (!HasAccessPermission(DUMP_PERMISSION) && !HasAccessPermission(WRITE_HIVIEW_SYSTEM_PERMISSION)) {
373         return HiviewNapiErrCode::ERR_PERMISSION_CHECK;
374     }
375     auto traceRetHandler = [] (HiviewService* service) {
376         return service->CloseTrace();
377     };
378     TraceCalling<int32_t>(traceRetHandler, errNo, ret);
379     return 0;
380 }
381 
CaptureDurationTrace(const AppCallerParcelable & appCallerParcelable,int32_t & errNo,int32_t & ret)382 ErrCode HiviewServiceAbility::CaptureDurationTrace(
383     const AppCallerParcelable& appCallerParcelable, int32_t& errNo, int32_t& ret)
384 {
385     auto caller = appCallerParcelable.GetAppCaller();
386     caller.uid = IPCSkeleton::GetCallingUid();
387     caller.pid = IPCSkeleton::GetCallingPid();
388     auto traceRetHandler = [=, &caller] (HiviewService* service) {
389         return service->CaptureDurationTrace(caller);
390     };
391     TraceCalling<int32_t>(traceRetHandler, errNo, ret);
392     return 0;
393 }
394 
GetSysCpuUsage(int32_t & errNo,double & ret)395 ErrCode HiviewServiceAbility::GetSysCpuUsage(int32_t& errNo, double& ret)
396 {
397     TraceCalling<double>([] (HiviewService* service) {
398         return service->GetSysCpuUsage();
399         }, errNo, ret);
400     return 0;
401 }
402 
SetAppResourceLimit(const MemoryCallerParcelable & memoryCallerParcelable,int32_t & errNo,int32_t & ret)403 ErrCode HiviewServiceAbility::SetAppResourceLimit(
404     const MemoryCallerParcelable& memoryCallerParcelable, int32_t& errNo, int32_t& ret)
405 {
406     if (!Parameter::IsBetaVersion() && !Parameter::IsLeakStateMode()) {
407         HIVIEW_LOGE("Called SetAppResourceLimitRequest service failed.");
408         return TraceErrCode::ERR_READ_MSG_PARCEL;
409     }
410     auto caller = memoryCallerParcelable.GetMemoryCaller();
411     caller.pid = IPCObjectStub::GetCallingPid();
412     if (caller.pid < 0) {
413         return TraceErrCode::ERR_SEND_REQUEST;
414     }
415     auto handler = [&caller] (HiviewService* service) {
416         return service->SetAppResourceLimit(caller);
417     };
418     TraceCalling<int32_t>(handler, errNo, ret);
419     return 0;
420 }
421 
SetSplitMemoryValue(const std::vector<MemoryCallerParcelable> & memCallerParcelableList,int32_t & errNo,int32_t & ret)422 ErrCode HiviewServiceAbility::SetSplitMemoryValue(
423     const std::vector<MemoryCallerParcelable>& memCallerParcelableList, int32_t& errNo, int32_t& ret)
424 {
425     int uid = IPCObjectStub::GetCallingUid();
426     if (uid != MEDIA_UID) {
427         HIVIEW_LOGE("calling uid is not media, uid: %{public}d", uid);
428         return TraceErrCode::ERR_SEND_REQUEST;
429     }
430     if (memCallerParcelableList.empty() || memCallerParcelableList.size() > MAX_SPLIT_MEMORY_SIZE) {
431         HIVIEW_LOGW("mem list size is invalid.");
432         return TraceErrCode::ERR_READ_MSG_PARCEL;
433     }
434     std::vector<UCollectClient::MemoryCaller> memList(memCallerParcelableList.size());
435     for (const auto& item : memCallerParcelableList) {
436         memList.emplace_back(item.GetMemoryCaller());
437     }
438     auto handler = [&memList] (HiviewService* service) {
439         return service->SetSplitMemoryValue(memList);
440     };
441     TraceCalling<int32_t>(handler, errNo, ret);
442     return 0;
443 }
444 
GetGraphicUsage(int32_t & errNo,int32_t & ret)445 ErrCode HiviewServiceAbility::GetGraphicUsage(int32_t& errNo, int32_t& ret)
446 {
447     int32_t pid = IPCObjectStub::GetCallingPid();
448     if (pid < 0) {
449         return TraceErrCode::ERR_SEND_REQUEST;
450     }
451     auto handler = [pid] (HiviewService* service) {
452         return service->GetGraphicUsage(pid);
453     };
454     TraceCalling<int32_t>(handler, errNo, ret);
455     return 0;
456 }
457 
HiviewServiceAbilityDeathRecipient()458 HiviewServiceAbilityDeathRecipient::HiviewServiceAbilityDeathRecipient()
459 {
460     HIVIEW_LOGI("called");
461 }
462 
~HiviewServiceAbilityDeathRecipient()463 HiviewServiceAbilityDeathRecipient::~HiviewServiceAbilityDeathRecipient()
464 {
465     HIVIEW_LOGI("called");
466 }
467 
OnRemoteDied(const wptr<IRemoteObject> & object)468 void HiviewServiceAbilityDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
469 {
470     HIVIEW_LOGI("called");
471     if (object == nullptr) {
472         return;
473     }
474     HiviewServiceAbility::StartServiceAbility(1);
475 }
476 } // namespace HiviewDFX
477 } // namespace OHOS
478