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_ffi.h"
17 
18 #include <numeric>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <memory>
23 #include <unistd.h>
24 #include <malloc.h>
25 #include <codecvt>
26 #include <string>
27 #include <vector>
28 #include <parameters.h>
29 
30 #include "cpu_collector.h"
31 #include "dump_usage.h"
32 #include "file_ex.h"
33 #include "directory_ex.h"
34 #include "storage_acl.h"
35 #include "hidebug_native_interface.h"
36 #include "memory_collector.h"
37 #include "hilog/log.h"
38 #include "system_ability_definition.h"
39 #include "iservice_registry.h"
40 
41 namespace OHOS::HiviewDFX {
42 
43 #undef LOG_DOMAIN
44 #define LOG_DOMAIN 0xD002D0A
45 #undef LOG_TAG
46 #define LOG_TAG "CJ_HiDebug"
47 
48 const std::string KEY_HIVIEW_USER_TYPE = "const.logsystem.versiontype";
49 const std::string KEY_HIVIEW_DEVELOP_TYPE = "persist.hiview.leak_detector";
50 
51 enum ErrorCode {
52     MEM_ERROR = 1,
53     PERMISSION_ERROR = 201,
54     PARAMETER_ERROR = 401,
55     VERSION_ERROR = 801,
56     SYSTEM_ABILITY_NOT_FOUND = 11400101,
57     HAVA_ALREADY_TRACE = 11400102,
58     WITHOUT_WRITE_PERMISSON = 11400103,
59     SYSTEM_STATUS_ABNORMAL = 11400104,
60     NO_CAPTURE_TRACE_RUNNING = 11400105,
61 };
62 
CheckVersionType(const std::string& type, const std::string& key)63 static bool CheckVersionType(const std::string& type, const std::string& key)
64 {
65     auto versionType = OHOS::system::GetParameter(key, "unknown");
66     return (versionType.find(type) != std::string::npos);
67 }
68 
CreateSanBoxDir()69 static bool CreateSanBoxDir()
70 {
71     constexpr mode_t defaultLogDirMode = 0x0770;
72     const std::string reourceLimitDir = "/data/storage/el2/log/resourcelimit/";
73     if (!OHOS::FileExists(reourceLimitDir)) {
74         OHOS::ForceCreateDirectory(reourceLimitDir);
75         OHOS::ChangeModeDirectory(reourceLimitDir, defaultLogDirMode);
76     }
77     if (OHOS::StorageDaemon::AclSetAccess(reourceLimitDir, "g:1201:rwx") != 0) {
78         HILOG_ERROR(LOG_CORE, "CreateSanBoxDir Failed to AclSetAccess");
79         return false;
80     }
81     return true;
82 }
83 
84 extern "C" {
FfiHidebugGetPss()85     uint64_t FfiHidebugGetPss()
86     {
87         std::shared_ptr<UCollectUtil::MemoryCollector> collector = UCollectUtil::MemoryCollector::Create();
88         if (collector != nullptr) {
89             int pid = getprocpid();
90             auto collectResult = collector->CollectProcessMemory(pid);
91             int32_t pssInfo = collectResult.data.pss + collectResult.data.swapPss;
92             return static_cast<uint64_t>(pssInfo);
93         } else {
94             return 0;
95         }
96     }
97 
FfiHidebugGetVss()98     uint64_t FfiHidebugGetVss()
99     {
100         std::shared_ptr<UCollectUtil::MemoryCollector> collector = UCollectUtil::MemoryCollector::Create();
101         if (collector != nullptr) {
102             pid_t pid = getprocpid();
103             auto collectResult = collector->CollectProcessVss(pid);
104             uint64_t vssInfo = collectResult.data;
105             return vssInfo;
106         } else {
107             return 0;
108         }
109     }
110 
FfiHidebugGetNativeHeapSize()111     uint64_t FfiHidebugGetNativeHeapSize()
112     {
113         struct mallinfo mi = mallinfo();
114         return static_cast<uint64_t>(mi.uordblks + mi.fordblks);
115     }
116 
FfiHidebugGetNativeHeapAllocatedSize()117     uint64_t FfiHidebugGetNativeHeapAllocatedSize()
118     {
119         struct mallinfo mi = mallinfo();
120         return static_cast<uint64_t>(mi.uordblks);
121     }
122 
FfiHidebugGetNativeHeapFreeSize()123     uint64_t FfiHidebugGetNativeHeapFreeSize()
124     {
125         struct mallinfo mi = mallinfo();
126         return static_cast<uint64_t>(mi.fordblks);
127     }
128 
FfiHidebugGetSharedDirty()129     uint64_t FfiHidebugGetSharedDirty()
130     {
131         std::shared_ptr<UCollectUtil::MemoryCollector> collector = UCollectUtil::MemoryCollector::Create();
132         if (collector != nullptr) {
133             int pid = getprocpid();
134             auto collectResult = collector->CollectProcessMemory(pid);
135             int32_t sharedDirtyInfo = collectResult.data.sharedDirty;
136             return static_cast<uint64_t>(sharedDirtyInfo);
137         } else {
138             return 0;
139         }
140     }
141 
FfiHidebugGetPrivateDirty()142     uint64_t FfiHidebugGetPrivateDirty()
143     {
144         std::shared_ptr<UCollectUtil::MemoryCollector> collector = UCollectUtil::MemoryCollector::Create();
145         if (collector != nullptr) {
146             pid_t pid = getprocpid();
147             auto collectResult = collector->CollectProcessMemory(pid);
148             int32_t privateDirty = collectResult.data.privateDirty;
149             return static_cast<uint64_t>(privateDirty);
150         } else {
151             return 0;
152         }
153     }
154 
FfiHidebugGetCpuUsage()155     double FfiHidebugGetCpuUsage()
156     {
157         std::unique_ptr<DumpUsage> dumpUsage = std::make_unique<DumpUsage>();
158         pid_t pid = getprocpid();
159         return dumpUsage->GetCpuUsage(pid);
160     }
161 
FfiHidebugGetSystemCpuUsage(int32_t &code)162     double FfiHidebugGetSystemCpuUsage(int32_t &code)
163     {
164         auto cpuUsageOptional = HidebugNativeInterface::CreateInstance()->GetSystemCpuUsage();
165         if (cpuUsageOptional.has_value()) {
166             return cpuUsageOptional.value();
167         }
168         code = ErrorCode::SYSTEM_STATUS_ABNORMAL;
169         return 0;
170     }
171 
FfiHidebugGetAppThreadCpuUsage(int32_t &code)172     ThreadCpuUsageArr FfiHidebugGetAppThreadCpuUsage(int32_t &code)
173     {
174         ThreadCpuUsageArr arr{ .head = nullptr, .size = 0};
175         auto nativeInterface = HidebugNativeInterface::CreateInstance();
176         if (!nativeInterface) {
177             code = ErrorCode::MEM_ERROR;
178             return arr;
179         }
180         std::map<uint32_t, double> threadMap = nativeInterface->GetAppThreadCpuUsage();
181         auto size = threadMap.size();
182         if (size <= 0) {
183             return arr;
184         }
185         arr.head = static_cast<CThreadCpuUsage *>(malloc(sizeof(CThreadCpuUsage) * size));
186         if (arr.head == nullptr) {
187             code = ErrorCode::MEM_ERROR;
188             return arr;
189         }
190         size_t idx = 0;
191         for (const auto[id, usage] : threadMap) {
192             arr.head[idx] = CThreadCpuUsage{ .threadId = id, .cpuUsage = usage };
193             idx++;
194         }
195         return arr;
196     }
197 
FfiHidebugGetSystemMemInfo(int32_t &code)198     CSystemMemInfo FfiHidebugGetSystemMemInfo(int32_t &code)
199     {
200         CSystemMemInfo info{.totalMem = 0, .freeMem = 0, .availableMem = 0};
201         auto nativeInterface = HidebugNativeInterface::CreateInstance();
202         if (!nativeInterface) {
203             code = ErrorCode::MEM_ERROR;
204             return info;
205         }
206 
207         auto systemMemInfo = nativeInterface->GetSystemMemInfo();
208         if (!systemMemInfo) {
209             code = ErrorCode::MEM_ERROR;
210             return info;
211         }
212 
213         info.totalMem = systemMemInfo->memTotal;
214         info.freeMem = systemMemInfo->memFree;
215         info.availableMem = systemMemInfo->memAvailable;
216         return info;
217     }
218 
FfiHidebugGetAppNativeMemInfo(int32_t &code)219     CNativeMemInfo FfiHidebugGetAppNativeMemInfo(int32_t &code)
220     {
221         CNativeMemInfo info{};
222         auto nativeInterface = HidebugNativeInterface::CreateInstance();
223         if (!nativeInterface) {
224             code = ErrorCode::MEM_ERROR;
225             return info;
226         }
227 
228         auto nativeMemInfo = nativeInterface->GetAppNativeMemInfo();
229         if (!nativeMemInfo) {
230             code = ErrorCode::MEM_ERROR;
231             return info;
232         }
233         info.pss = nativeMemInfo->pss;
234         info.vss = nativeMemInfo->vss;
235         info.rss = nativeMemInfo->rss;
236         info.sharedDirty = nativeMemInfo->sharedDirty;
237         info.privateDirty = nativeMemInfo->privateDirty;
238         info.sharedClean = nativeMemInfo->sharedClean;
239         info.privateClean = nativeMemInfo->privateClean;
240         return info;
241     }
242 
FfiHidebugGetAppMemoryLimit(int32_t &code)243     CMemoryLimit FfiHidebugGetAppMemoryLimit(int32_t &code)
244     {
245         CMemoryLimit limit{.rssLimit = 0, .vssLimit = 0};
246         auto nativeInterface = HidebugNativeInterface::CreateInstance();
247         if (!nativeInterface) {
248             code = ErrorCode::MEM_ERROR;
249             return limit;
250         }
251 
252         auto memoryLimit = nativeInterface->GetAppMemoryLimit();
253         if (!memoryLimit) {
254             code = ErrorCode::MEM_ERROR;
255             return limit;
256         }
257         limit.rssLimit = memoryLimit->rssLimit;
258         limit.vssLimit = memoryLimit->vssLimit;
259 
260         return limit;
261     }
262 
FfiHidebugGetServiceDump(int32_t serviceId, int32_t fd, CArrString args)263     int32_t FfiHidebugGetServiceDump(int32_t serviceId, int32_t fd, CArrString args)
264     {
265         sptr<ISystemAbilityManager> sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
266         if (!sam) {
267             return ErrorCode::MEM_ERROR;
268         }
269         sptr<IRemoteObject> sa = sam->CheckSystemAbility(serviceId);
270         if (sa == nullptr) {
271             return ErrorCode::SYSTEM_ABILITY_NOT_FOUND;
272         }
273         std::vector<std::u16string> cargs;
274         std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> strCnv;
275         for (int64_t i = 0; i < args.size; i++) {
276             cargs.push_back(strCnv.from_bytes(args.head[i]));
277         }
278         int dumpResult = sa->Dump(fd, cargs);
279         HILOG_INFO(LOG_CORE, "Dump result: %{public}d", dumpResult);
280         return 0;
281     }
282 
FfiHidebugStartAppTraceCapture(CArrUnit tags, int32_t flag, uint32_t limitSize, int32_t &code)283     char *FfiHidebugStartAppTraceCapture(CArrUnit tags, int32_t flag, uint32_t limitSize, int32_t &code)
284     {
285         std::vector<uint64_t> taglist;
286         uint64_t *tagPtr = static_cast<uint64_t *>(tags.head);
287         for (int64_t i = 0; i < tags.size; i++) {
288             taglist.push_back(tagPtr[i]);
289         }
290         uint64_t tag = std::accumulate(taglist.begin(), taglist.end(), 0ull,
291             [](uint64_t a, uint64_t b) { return a | b; });
292         std::string file;
293         auto nativeInterface = HidebugNativeInterface::CreateInstance();
294         if (!nativeInterface) {
295             code = ErrorCode::SYSTEM_STATUS_ABNORMAL;
296             return nullptr;
297         }
298         code = nativeInterface->StartAppTraceCapture(tag, flag, limitSize, file);
299         if (code != HIDEBUG_SUCCESS || file.empty()) {
300             return nullptr;
301         }
302         auto len = file.length() + 1;
303         char *res = static_cast<char *>(malloc(sizeof(char) * len));
304         if (res == nullptr) {
305             return nullptr;
306         }
307         return std::char_traits<char>::copy(res, file.c_str(), len);
308     }
309 
FfiHidebugStopAppTraceCapture()310     int32_t FfiHidebugStopAppTraceCapture()
311     {
312         auto nativeInterface = HidebugNativeInterface::CreateInstance();
313         if (!nativeInterface) {
314             return ErrorCode::MEM_ERROR;
315         }
316         return nativeInterface->StopAppTraceCapture();
317     }
318 
FfiHidebugSetAppResourceLimit(const char *type, int32_t value, bool enableDebugLog)319     int32_t FfiHidebugSetAppResourceLimit(const char *type, int32_t value, bool enableDebugLog)
320     {
321         if (!CheckVersionType("beta", KEY_HIVIEW_USER_TYPE) &&
322             !CheckVersionType("enable", KEY_HIVIEW_DEVELOP_TYPE)) {
323             HILOG_ERROR(LOG_CORE, "SetAppResourceLimit failed. Not developer options or beta versions");
324             return ErrorCode::VERSION_ERROR;
325         }
326         auto abilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
327         if (!abilityManager) {
328             return ErrorCode::MEM_ERROR;
329         }
330         sptr<IRemoteObject> remoteObject = abilityManager->CheckSystemAbility(DFX_SYS_HIVIEW_ABILITY_ID);
331         if (remoteObject == nullptr) {
332             HILOG_ERROR(LOG_CORE, "SetAppResourceLimit failed. No this system ability.");
333             return ErrorCode::SYSTEM_STATUS_ABNORMAL;
334         }
335         auto result =
336             HidebugNativeInterface::CreateInstance()->GetMemoryLeakResource(std::string(type), value, enableDebugLog);
337         if (result == MemoryState::MEMORY_FAILED) {
338             return 0;
339         }
340         CreateSanBoxDir();
341         return 0;
342     }
343 
FfiHidebugIsDebugState()344     bool FfiHidebugIsDebugState()
345     {
346         return HidebugNativeInterface::CreateInstance()->IsDebuggerConnected();
347     }
348 }
349 }
350