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