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