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