• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 
16 #include "hidebug_native_interface.h"
17 
18 #include <chrono>
19 #include <fstream>
20 #include <memory>
21 #include <vector>
22 #include <unistd.h>
23 
24 #include "dump_usage.h"
25 #include "hidebug_app_thread_cpu.h"
26 #include "hidebug_util.h"
27 #include "hitrace_meter.h"
28 #include "hilog/log.h"
29 #include "client/cpu_collector_client.h"
30 #include "client/memory_collector_client.h"
31 #include "utility/memory_collector.h"
32 
33 namespace OHOS {
34 namespace HiviewDFX {
35 
36 #undef LOG_DOMAIN
37 #define LOG_DOMAIN 0xD002D0A
38 #undef LOG_TAG
39 #define LOG_TAG "HiDebug_Native_Interface"
40 
41 namespace {
42 constexpr int64_t SECOND_TO_NANOSECOND = 1000 * 1000 * 1000;
43 
GetNativeMemInfo(NativeMemInfo & nativeMemInfo)44 int GetNativeMemInfo(NativeMemInfo& nativeMemInfo)
45 {
46     std::shared_ptr<UCollectUtil::MemoryCollector> collector = UCollectUtil::MemoryCollector::Create();
47     if (!collector) {
48         HILOG_ERROR(LOG_CORE, "GetAppNativeMemInfo Failed");
49         return NATIVE_FAIL;
50     }
51     int pid = getprocpid();
52     auto collectResult = collector->CollectProcessMemory(pid);
53     if (collectResult.retCode != UCollect::UcError::SUCCESS) {
54         HILOG_ERROR(LOG_CORE, "CollectProcessMemory Failed,retCode = %{public}d",
55                     static_cast<int>(collectResult.retCode));
56         return NATIVE_FAIL;
57     }
58     auto collectVss = collector->CollectProcessVss(pid);
59     if (collectVss.retCode != UCollect::UcError::SUCCESS) {
60         HILOG_ERROR(LOG_CORE, "CollectProcessVss Failed,retCode = %{public}d", static_cast<int>(collectVss.retCode));
61         return NATIVE_FAIL;
62     }
63     nativeMemInfo.pss = static_cast<uint32_t>(collectResult.data.pss) +
64         static_cast<uint32_t>(collectResult.data.swapPss);
65     nativeMemInfo.rss = static_cast<uint32_t>(collectResult.data.rss);
66     nativeMemInfo.sharedDirty = static_cast<uint32_t>(collectResult.data.sharedDirty);
67     nativeMemInfo.privateDirty = static_cast<uint32_t>(collectResult.data.privateDirty);
68     nativeMemInfo.sharedClean = static_cast<uint32_t>(collectResult.data.sharedClean);
69     nativeMemInfo.privateClean = static_cast<uint32_t>(collectResult.data.privateClean);
70     nativeMemInfo.vss = static_cast<uint32_t>(collectVss.data);
71     return NATIVE_SUCCESS;
72 }
73 
GetGraphicMemoryInfo(int32_t & graphicMemoryInfo)74 int GetGraphicMemoryInfo(int32_t& graphicMemoryInfo)
75 {
76     auto collector = UCollectClient::MemoryCollector::Create();
77     if (!collector) {
78         HILOG_ERROR(LOG_CORE, "GetGraphicUsage Failed");
79         return NATIVE_FAIL;
80     }
81     auto collectResult = collector->GetGraphicUsage();
82     if (collectResult.retCode != UCollect::UcError::SUCCESS || collectResult.data < 0) {
83         HILOG_ERROR(LOG_CORE, "GetGraphicUsage Failed,retCode = %{public}d",
84                     static_cast<int>(collectResult.retCode));
85         return NATIVE_FAIL;
86     }
87     graphicMemoryInfo = collectResult.data;
88     return NATIVE_SUCCESS;
89 }
90 
GetSystemCpuUsageInfo(double & cpuUsage)91 int GetSystemCpuUsageInfo(double& cpuUsage)
92 {
93     std::shared_ptr<UCollectClient::CpuCollector> collector = UCollectClient::CpuCollector::Create();
94     if (!collector) {
95         HILOG_ERROR(LOG_CORE, "GetSystemCpuUsage Failed");
96         return NATIVE_FAIL;
97     }
98     auto collectResult = collector->GetSysCpuUsage();
99     if (collectResult.retCode != UCollect::UcError::SUCCESS) {
100         HILOG_ERROR(LOG_CORE, "GetSystemCpuUsage Failed, retCode: %{public}d",
101                     static_cast<int>(collectResult.retCode));
102         return NATIVE_FAIL;
103     }
104     cpuUsage = collectResult.data;
105     return NATIVE_SUCCESS;
106 }
107 }
108 
109 class HidebugNativeInterfaceImpl : public HidebugNativeInterface {
110 public:
111     HidebugNativeInterfaceImpl() = default;
112     HidebugNativeInterfaceImpl(const HidebugNativeInterfaceImpl&) = delete;
113     HidebugNativeInterfaceImpl& operator =(const HidebugNativeInterfaceImpl&) = delete;
114     double GetCpuUsage() override;
115     std::map<uint32_t, double> GetAppThreadCpuUsage() override;
116     TraceErrorCode StartAppTraceCapture(uint64_t tags, uint32_t flag,
117         uint32_t limitsize, std::string &file) override;
118     TraceErrorCode StopAppTraceCapture() override;
119     int GetMemoryLeakResource(const std::string& type, int32_t value, bool enabledDebugLog) override;
120     std::optional<double> GetSystemCpuUsage() override;
121     std::optional<MemoryLimitInfo> GetAppMemoryLimit() override;
122     std::optional<uint64_t> GetVss() override;
123     std::optional<NativeMemInfo> GetAppNativeMemInfo(bool withCache) override;
124     std::optional<SystemMemoryInfo> GetSystemMemInfo() override;
125     bool IsDebuggerConnected() override;
126     std::optional<int32_t> GetGraphicsMemory() override;
127 private:
128     static inline HidebugAppThreadCpu threadCpu_; // It should be initialized at startup.
129 };
130 
GetInstance()131 HidebugNativeInterface& HidebugNativeInterface::GetInstance()
132 {
133     static HidebugNativeInterfaceImpl instance;
134     return instance;
135 }
136 
GetCpuUsage()137 double HidebugNativeInterfaceImpl::GetCpuUsage()
138 {
139     std::unique_ptr<DumpUsage> dumpUsage = std::make_unique<DumpUsage>();
140     pid_t pid = getprocpid();
141     return dumpUsage->GetCpuUsage(pid);
142 }
143 
GetAppThreadCpuUsage()144 std::map<uint32_t, double> HidebugNativeInterfaceImpl::GetAppThreadCpuUsage()
145 {
146     auto collectResult = threadCpu_.CollectThreadStatInfos();
147     if (collectResult.retCode != UCollect::UcError::SUCCESS) {
148         HILOG_ERROR(LOG_CORE, "GetAppThreadCpuUsage fail, ret: %{public}d", static_cast<int>(collectResult.retCode));
149         return {};
150     }
151     std::map<uint32_t, double> threadMap;
152     for (const auto &threadCpuStatInfo : collectResult.data) {
153         threadMap[threadCpuStatInfo.tid] = threadCpuStatInfo.cpuUsage;
154     }
155     return threadMap;
156 }
157 
StartAppTraceCapture(uint64_t tags,uint32_t flag,uint32_t limitsize,std::string & file)158 TraceErrorCode HidebugNativeInterfaceImpl::StartAppTraceCapture(uint64_t tags, uint32_t flag,
159     uint32_t limitsize, std::string &file)
160 {
161     if (flag != TraceFlag::FLAG_MAIN_THREAD && flag != TraceFlag::FLAG_ALL_THREAD) {
162         return TRACE_INVALID_ARGUMENT;
163     }
164     auto ret = StartCaptureAppTrace(static_cast<TraceFlag>(flag), tags, limitsize, file);
165     if (ret == RET_SUCC) {
166         return TRACE_SUCCESS;
167     }
168     if (ret == RET_FAIL_INVALID_ARGS) {
169         return TRACE_INVALID_ARGUMENT;
170     }
171     if (ret == RET_STARTED) {
172         return TRACE_CAPTURED_ALREADY;
173     }
174     if (ret == RET_FAIL_MKDIR || ret == RET_FAIL_SETACL || ret == RET_FAIL_EACCES || ret == RET_FAIL_ENOENT) {
175         return TRACE_NO_PERMISSION;
176     }
177     return TRACE_ABNORMAL;
178 }
179 
StopAppTraceCapture()180 TraceErrorCode HidebugNativeInterfaceImpl::StopAppTraceCapture()
181 {
182     auto ret = StopCaptureAppTrace();
183     if (ret == RET_SUCC) {
184         return TRACE_SUCCESS;
185     }
186     if (ret == RET_STOPPED) {
187         return NO_TRACE_RUNNING;
188     }
189     return TRACE_ABNORMAL;
190 }
191 
GetSystemCpuUsage()192 std::optional<double> HidebugNativeInterfaceImpl::GetSystemCpuUsage()
193 {
194     static CachedValue<double> cachedCpuUsage;
195     HILOG_INFO(LOG_CORE, "GetSystemCpuUsage");
196     constexpr int64_t effectiveTime = 2 * SECOND_TO_NANOSECOND;
197     auto ret = cachedCpuUsage.GetOrUpdateCachedValue(effectiveTime, GetSystemCpuUsageInfo);
198     if (ret.first == NATIVE_SUCCESS) {
199         return ret.second;
200     }
201     return {};
202 }
203 
GetAppMemoryLimit()204 std::optional<MemoryLimitInfo> HidebugNativeInterfaceImpl::GetAppMemoryLimit()
205 {
206     auto collector = UCollectUtil::MemoryCollector::Create();
207     if (!collector) {
208         HILOG_ERROR(LOG_CORE, "GetAppMemoryLimit Failed");
209         return {};
210     }
211     auto collectResult = collector->CollectMemoryLimit();
212     if (collectResult.retCode != UCollect::UcError::SUCCESS) {
213         HILOG_ERROR(LOG_CORE, "GetAppMemoryLimit Failed, retCode: %{public}d", static_cast<int>(collectResult.retCode));
214         return {};
215     }
216 
217     MemoryLimitInfo memoryLimit;
218     memoryLimit.vssLimit = collectResult.data.vssLimit;
219     memoryLimit.rssLimit = collectResult.data.rssLimit;
220     return memoryLimit;
221 }
222 
GetAppNativeMemInfo(bool withCache)223 std::optional<NativeMemInfo> HidebugNativeInterfaceImpl::GetAppNativeMemInfo(bool withCache)
224 {
225     static CachedValue<NativeMemInfo> cachedNativeMemInfo;
226     constexpr int64_t effectiveTime = 5 * 60 * SECOND_TO_NANOSECOND;
227     auto ret = cachedNativeMemInfo.GetOrUpdateCachedValue(withCache ? effectiveTime : 0, GetNativeMemInfo);
228     if (ret.first == NATIVE_SUCCESS) {
229         return ret.second;
230     }
231     return {};
232 }
233 
GetVss()234 std::optional<uint64_t> HidebugNativeInterfaceImpl::GetVss()
235 {
236     std::shared_ptr<UCollectUtil::MemoryCollector> collector = UCollectUtil::MemoryCollector::Create();
237     if (!collector) {
238         HILOG_ERROR(LOG_CORE, "GetVssInfo Failed");
239         return {};
240     }
241     int pid = getprocpid();
242     auto collectVss = collector->CollectProcessVss(pid);
243     if (collectVss.retCode != UCollect::UcError::SUCCESS) {
244         HILOG_ERROR(LOG_CORE, "CollectProcessVss Failed,retCode = %{public}d", static_cast<int>(collectVss.retCode));
245         return {};
246     }
247     return collectVss.data;
248 }
249 
GetSystemMemInfo()250 std::optional<SystemMemoryInfo> HidebugNativeInterfaceImpl::GetSystemMemInfo()
251 {
252     std::shared_ptr<UCollectUtil::MemoryCollector> collector = UCollectUtil::MemoryCollector::Create();
253     if (!collector) {
254         HILOG_ERROR(LOG_CORE, "GetSystemMemInfo Failed");
255         return {};
256     }
257     auto collectResult = collector->CollectSysMemory();
258     if (collectResult.retCode != UCollect::UcError::SUCCESS) {
259         HILOG_ERROR(LOG_CORE, "GetSystemMemInfo Failed,retCode = %{public}d",
260                     static_cast<int>(collectResult.retCode));
261         return {};
262     }
263     SystemMemoryInfo systemMemoryInfo{};
264     systemMemoryInfo.totalMem = static_cast<uint32_t>(collectResult.data.memTotal);
265     systemMemoryInfo.freeMem = static_cast<uint32_t>(collectResult.data.memFree);
266     systemMemoryInfo.availableMem = static_cast<uint32_t>(collectResult.data.memAvailable);
267     return systemMemoryInfo;
268 }
269 
GetMemoryLeakResource(const std::string & type,int32_t value,bool enabledDebugLog)270 int HidebugNativeInterfaceImpl::GetMemoryLeakResource(const std::string& type,
271     int32_t value, bool enabledDebugLog)
272 {
273     HILOG_DEBUG(LOG_CORE, "GetMemoryLeakResource");
274     auto memoryCollect = UCollectClient::MemoryCollector::Create();
275     if (!memoryCollect) {
276         HILOG_ERROR(LOG_CORE, "GetMemoryLeakResource Failed, return result");
277         return NATIVE_FAIL;
278     }
279     UCollectClient::MemoryCaller memoryCaller;
280     memoryCaller.pid = getprocpid();
281     memoryCaller.resourceType = type;
282     memoryCaller.limitValue = value;
283     memoryCaller.enabledDebugLog = enabledDebugLog;
284     auto result = memoryCollect->SetAppResourceLimit(memoryCaller);
285     if (result.retCode != UCollect::UcError::SUCCESS) {
286         HILOG_ERROR(LOG_CORE, "GetMemoryLeakResource Failed, retCode: %{public}d, return the last result",
287             static_cast<int>(result.retCode));
288         return NATIVE_FAIL;
289     }
290     HILOG_DEBUG(LOG_CORE, "GetMemoryLeakResource Success, retCode: %{public}d", static_cast<int>(result.retCode));
291     return NATIVE_SUCCESS;
292 }
293 
IsDebuggerConnected()294 bool HidebugNativeInterfaceImpl::IsDebuggerConnected()
295 {
296     HILOG_DEBUG(LOG_CORE, "IsDebuggerConnected");
297     std::ifstream file("/proc/self/status");
298     if (!file.is_open()) {
299         HILOG_ERROR(LOG_CORE, "IsDebuggerConnected:: open status file failed!");
300         return false;
301     }
302     std::string line;
303     while (std::getline(file, line)) {
304         if (line.find("TracerPid:") != std::string::npos) {
305             std::string pidStr = line.substr(line.find(":") + 1);
306             return std::atoi(pidStr.c_str()) != 0;
307         }
308     }
309     HILOG_ERROR(LOG_CORE, "IsDebuggerConnected:: no find the TracerPid:");
310     return false;
311 }
312 
GetGraphicsMemory()313 std::optional<int32_t> HidebugNativeInterfaceImpl::GetGraphicsMemory()
314 {
315     static CachedValue<int32_t> cachedGraphicUsage;
316     constexpr int64_t effectiveTime = 2 * SECOND_TO_NANOSECOND; // 2s
317     auto ret = cachedGraphicUsage.GetOrUpdateCachedValue(effectiveTime, GetGraphicMemoryInfo);
318     if (ret.first == NATIVE_SUCCESS) {
319         return ret.second;
320     }
321     return {};
322 }
323 }
324 }
325