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
41namespace OHOS::HiviewDFX {
42
43#undef LOG_DOMAIN
44#define LOG_DOMAIN 0xD002D0A
45#undef LOG_TAG
46#define LOG_TAG "CJ_HiDebug"
47
48const std::string KEY_HIVIEW_USER_TYPE = "const.logsystem.versiontype";
49const std::string KEY_HIVIEW_DEVELOP_TYPE = "persist.hiview.leak_detector";
50
51enum 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
63static 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
69static 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
84extern "C" {
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
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
111    uint64_t FfiHidebugGetNativeHeapSize()
112    {
113        struct mallinfo mi = mallinfo();
114        return static_cast<uint64_t>(mi.uordblks + mi.fordblks);
115    }
116
117    uint64_t FfiHidebugGetNativeHeapAllocatedSize()
118    {
119        struct mallinfo mi = mallinfo();
120        return static_cast<uint64_t>(mi.uordblks);
121    }
122
123    uint64_t FfiHidebugGetNativeHeapFreeSize()
124    {
125        struct mallinfo mi = mallinfo();
126        return static_cast<uint64_t>(mi.fordblks);
127    }
128
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
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
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
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
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
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
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
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
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
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
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
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
344    bool FfiHidebugIsDebugState()
345    {
346        return HidebugNativeInterface::CreateInstance()->IsDebuggerConnected();
347    }
348}
349}
350