From 717b271a8698e89f8d99d8570991453353a54b43 Mon Sep 17 00:00:00 2001 From: liujia178 Date: Sun, 27 Apr 2025 21:51:55 +0800 Subject: [PATCH] feature: add hidebug ani Signed-off-by: liujia178 Change-Id: I968592734c15d448a4af7ae1e0128259849a057c (cherry picked from commit 1e1324f46c1483b35df87d3e934ec4ed4c7c1b0b) --- bundle.json | 4 + hidebug/interfaces/ets/ani/BUILD.gn | 24 + hidebug/interfaces/ets/ani/hidebug/BUILD.gn | 76 ++ .../ets/ani/hidebug/ets/@ohos.hidebug.ets | 191 +++++ .../ets/ani/hidebug/include/ani_util.h | 38 + .../ets/ani/hidebug/include/error_code.h | 28 + .../ets/ani/hidebug/include/hiappevent_util.h | 38 + .../ets/ani/hidebug/src/ani_hidebug.cpp | 683 ++++++++++++++++++ .../ets/ani/hidebug/src/ani_util.cpp | 118 +++ .../ets/ani/hidebug/src/hiappevent_util.cpp | 111 +++ 10 files changed, 1311 insertions(+) create mode 100644 hidebug/interfaces/ets/ani/BUILD.gn create mode 100644 hidebug/interfaces/ets/ani/hidebug/BUILD.gn create mode 100644 hidebug/interfaces/ets/ani/hidebug/ets/@ohos.hidebug.ets create mode 100644 hidebug/interfaces/ets/ani/hidebug/include/ani_util.h create mode 100644 hidebug/interfaces/ets/ani/hidebug/include/error_code.h create mode 100644 hidebug/interfaces/ets/ani/hidebug/include/hiappevent_util.h create mode 100644 hidebug/interfaces/ets/ani/hidebug/src/ani_hidebug.cpp create mode 100644 hidebug/interfaces/ets/ani/hidebug/src/ani_util.cpp create mode 100644 hidebug/interfaces/ets/ani/hidebug/src/hiappevent_util.cpp diff --git a/bundle.json b/bundle.json index 096550376..183fe2da0 100644 --- a/bundle.json +++ b/bundle.json @@ -49,8 +49,10 @@ "libpng", "napi", "protobuf", + "runtime_core", "safwk", "samgr", + "storage_service", "drivers_interface_memorytracker", "graphic_2d", "os_account", @@ -74,6 +76,8 @@ "sub_component": [ "//developtools/profiler/device:hiprofiler_targets", "//developtools/profiler/hidebug/interfaces/js/kits:profiler_jsapi_module", + "//developtools/profiler/hidebug/interfaces/cj:cj_hidebug_ffi", + "//developtools/profiler/hidebug/interfaces/ets/ani:ani_profiler_hidebug_package", "//developtools/profiler/hidebug/frameworks/hidebug_ndk:ohhidebug", "//developtools/profiler/hidebug/frameworks/native:hidebug_native", "//developtools/profiler/host/smartperf/client/client_command/:SP_daemon", diff --git a/hidebug/interfaces/ets/ani/BUILD.gn b/hidebug/interfaces/ets/ani/BUILD.gn new file mode 100644 index 000000000..eeb0f5008 --- /dev/null +++ b/hidebug/interfaces/ets/ani/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +group("ani_profiler_hidebug_package") { + deps = [] + if (support_jsapi) { + deps += [ + "hidebug:hidebug_ani", + "hidebug:hidebug_etc" + ] + } +} diff --git a/hidebug/interfaces/ets/ani/hidebug/BUILD.gn b/hidebug/interfaces/ets/ani/hidebug/BUILD.gn new file mode 100644 index 000000000..4c0786f17 --- /dev/null +++ b/hidebug/interfaces/ets/ani/hidebug/BUILD.gn @@ -0,0 +1,76 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") +import("//developtools/profiler/hidebug/hidebug.gni") + +ohos_shared_library("hidebug_ani") { + include_dirs = [ + "./include/", + "$hidebug_path/frameworks/native/include", + "$hidebug_path/interfaces/native/kits/include", + ] + + sources = [ + "./src/ani_hidebug.cpp", + "./src/ani_util.cpp", + "./src/hiappevent_util.cpp", + ] + + deps = [ + "$hidebug_path/frameworks/native:hidebug_native" + ] + + external_deps = [ + "ability_base:configuration", + "ability_base:want", + "ability_runtime:app_context", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "ffrt:libffrt", + "hiappevent:hiappevent_innerapi", + "hidumper:lib_dump_usage", + "hilog:libhilog", + "hitrace:hitrace_meter", + "hiview:libucollection_utility", + "init:libbegetutil", + "ipc:ipc_core", + "napi:ace_napi", + "runtime_core:ani", + "runtime_core:libarkruntime", + "samgr:samgr_proxy", + "storage_service:storage_manager_acl", + ] + + subsystem_name = "developtools" + part_name = "hiprofiler" + output_extension = "so" +} + +generate_static_abc("hidebug") { + base_url = "./ets" + files = [ "./ets/@ohos.hidebug.ets" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/hidebug.abc" +} + +ohos_prebuilt_etc("hidebug_etc") { + source = "$target_out_dir/hidebug.abc" + module_install_dir = "framework" + subsystem_name = "developtools" + part_name = "hiprofiler" + deps = [ ":hidebug" ] +} diff --git a/hidebug/interfaces/ets/ani/hidebug/ets/@ohos.hidebug.ets b/hidebug/interfaces/ets/ani/hidebug/ets/@ohos.hidebug.ets new file mode 100644 index 000000000..9d0fea54d --- /dev/null +++ b/hidebug/interfaces/ets/ani/hidebug/ets/@ohos.hidebug.ets @@ -0,0 +1,191 @@ +/* +* Copyright (C) 2025 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import { BusinessError } from '@ohos.base'; + +function createVoidBusinessError(code: number, msg: string): BusinessError { + let error = new BusinessError(); + error.code = code; + error.message = msg; + return error; +} + +export namespace hidebug { + loadLibrary("hidebug_ani"); + export native function startJsCpuProfiling(filename: string): void; + + export native function stopJsCpuProfiling(): void; + + export native function getNativeHeapSize(): bigint; + + export native function getNativeHeapAllocatedSize(): bigint; + + export native function getNativeHeapFreeSize(): bigint; + + export native function getVss(): bigint; + + export native function getPss(): bigint; + + export native function getSharedDirty(): bigint; + + export native function getPrivateDirty(): bigint; + + export native function getCpuUsage(): number; + + export native function getServiceDump(serviceid: int, fd: int, args: Array): void; + + export native function getSystemCpuUsage(): number; + + export interface ThreadCpuUsage { + threadId: long; + cpuUsage: number; + } + + class ThreadCpuUsageImpl implements ThreadCpuUsage { + threadId: long; + cpuUsage: number; + } + + export native function getAppThreadCpuUsage(): ThreadCpuUsage[]; + + interface SystemMemInfo { + totalMem: bigint; + freeMem: bigint; + availableMem: bigint; + } + + class SystemMemInfoImpl implements SystemMemInfo { + totalMem: bigint; + freeMem: bigint; + availableMem: bigint; + } + + export native function getSystemMemInfo(): SystemMemInfo; + + export interface NativeMemInfo { + pss: bigint; + vss: bigint; + rss: bigint; + sharedDirty: bigint; + privateDirty: bigint; + sharedClean: bigint; + privateClean: bigint; + } + + class NativeMemInfoImpl implements NativeMemInfo { + pss: bigint; + vss: bigint; + rss: bigint; + sharedDirty: bigint; + privateDirty: bigint; + sharedClean: bigint; + privateClean: bigint; + } + + export native function getAppNativeMemInfo(): NativeMemInfo; + + export interface VMMemoryInfo { + totalHeap: bigint; + heapUsed: bigint; + allArraySize: bigint; + } + + class VMMemoryInfoImpl implements VMMemoryInfo { + totalHeap: bigint; + heapUsed: bigint; + allArraySize: bigint; + } + + export native function getAppVMMemoryInfo(): VMMemoryInfo; + + export interface MemoryLimit { + rssLimit: bigint; + vssLimit: bigint; + vmHeapLimit: bigint; + vmTotalHeapSize: bigint; + } + + class MemoryLimitImpl implements MemoryLimit { + rssLimit: bigint; + vssLimit: bigint; + vmHeapLimit: bigint; + vmTotalHeapSize: bigint; + } + + export native function getAppMemoryLimit(): MemoryLimit; + + export enum TraceFlag { + MAIN_THREAD = 1, + ALL_THREADS = 2 + } + + export namespace tags { + const ABILITY_MANAGER: long = 2147483648; // 1 << 31; + const ARKUI: long = 549755813888; // 1 << 39; + const ARK: long = 140737488355328; // 1 << 47; + const BLUETOOTH: long = 1152921504606846976; // 1 << 60; + const COMMON_LIBRARY: long = 65536; // 1 << 16; + const DISTRIBUTED_HARDWARE_DEVICE_MANAGER: long = 18014398509481984; // 1 << 54; + const DISTRIBUTED_AUDIO: long = 134217728; // 1 << 27; + const DISTRIBUTED_CAMERA: long = 2251799813685248; // 1 << 51; + const DISTRIBUTED_DATA: long = 68719476736; // 1 << 36; + const DISTRIBUTED_HARDWARE_FRAMEWORK: long = 4503599627370496; // 1 << 52; + const DISTRIBUTED_INPUT: long = 576460752303423488; // 1 << 59; + const DISTRIBUTED_SCREEN: long = 1125899906842624; // 1 << 50; + const DISTRIBUTED_SCHEDULER: long = 144115188075855872; // 1 << 57; + const FFRT: long = 8192; // 1 << 13; + const FILE_MANAGEMENT: long = 536870912; // 1 << 29; + const GLOBAL_RESOURCE_MANAGER: long = 9007199254740992; // 1 << 53; + const GRAPHICS: long = 274877906944; // 1 << 38; + const HDF: long = 262144; // 1 << 18; + const MISC: long = 2199023255552; // 1 << 41; + const MULTIMODAL_INPUT: long = 4398046511104; // 1 << 42; + const NET: long = 8388608; // 1 << 23; + const NOTIFICATION: long = 1099511627776; // 1 << 40; + const NWEB: long = 16777216; // 1 << 24; + const OHOS: long = 1073741824; // 1 << 30; + const POWER_MANAGER: long = 72057594037927936; // 1 << 56; + const RPC: long = 70368744177664; // 1 << 46; + const SAMGR: long = 36028797018963968; // 1 << 55; + const WINDOW_MANAGER: long = 281474976710656; // 1 << 48; + const AUDIO: long = 34359738368; // 1 << 35; + const CAMERA: long = 4294967296; // 1 << 30; + const IMAGE: long = 17179869184; // 1 << 34; + const MEDIA: long = 8589934592; // 1 << 33; + } + type GcStats = Record; + + export native function getVMRuntimeStats(): GcStats; + + export native function getVMRuntimeStat(item: string): long; + + export native function startAppTraceCapture(tags: long[], flag: TraceFlag, limitSize: int): string; + + export native function stopAppTraceCapture(): void; + + export native function isDebugState(): boolean; + + export function getGraphicsMemory(): Promise { + return new Promise((resolve: (v: int) => void, reject: (e: BusinessError) => void) => { + taskpool.execute(getGraphicsMemorySync).then((ret: NullishType): void => { + resolve(ret as int); + }).catch((err: Object | null | undefined) => { + reject(err as BusinessError); + }); + }); + } + + export native function getGraphicsMemorySync(): int; +} diff --git a/hidebug/interfaces/ets/ani/hidebug/include/ani_util.h b/hidebug/interfaces/ets/ani/hidebug/include/ani_util.h new file mode 100644 index 000000000..a94091fdb --- /dev/null +++ b/hidebug/interfaces/ets/ani/hidebug/include/ani_util.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DEVELOPTOOLS_PROFILER_HIDEBUG_ANI_UTIL_H +#define DEVELOPTOOLS_PROFILER_HIDEBUG_ANI_UTIL_H + +#include + +#include "ani.h" + +namespace OHOS { +namespace HiviewDFX { +constexpr int32_t HIDEBUG_DEFAULT_ERROR_CODE = 11400104; //SYSTEM_STATUS_ABNORMAL +class AniUtil { +public: + static void ThrowErrorMessage(ani_env *env, const std::string &msg, int32_t errCode = HIDEBUG_DEFAULT_ERROR_CODE); + static ani_object CreateUndefined(ani_env *env); + static ani_status ToAniBigInt(ani_env *env, uint64_t uint64Val, ani_object &aniBigInt); + static ani_status ParseAniString(ani_env *env, ani_string aniStr, std::string &str); + static ani_status ParseAniEnum(ani_env *env, ani_enum_item enumItem, uint32_t &value); + static ani_status SetNamedPropertyNumber(ani_env *env, ani_object object, const std::string& name, double value); + static ani_status SetNamedPropertyBigInt(ani_env *env, ani_object object, const std::string& name, uint64_t value); +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif //DEVELOPTOOLS_PROFILER_HIDEBUG_ANI_UTIL_H diff --git a/hidebug/interfaces/ets/ani/hidebug/include/error_code.h b/hidebug/interfaces/ets/ani/hidebug/include/error_code.h new file mode 100644 index 000000000..14e3a697e --- /dev/null +++ b/hidebug/interfaces/ets/ani/hidebug/include/error_code.h @@ -0,0 +1,28 @@ +/* +* Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ERROR_CODE_H +#define ERROR_CODE_H +enum ErrorCode { + PERMISSION_ERROR = 201, + PARAMETER_ERROR = 401, + VERSION_ERROR = 801, + SYSTEM_ABILITY_NOT_FOUND = 11400101, + HAVA_ALREADY_TRACE = 11400102, + WITHOUT_WRITE_PERMISSON = 11400103, + SYSTEM_STATUS_ABNORMAL = 11400104, + NO_CAPTURE_TRACE_RUNNING = 11400105, +}; +#endif //ERROR_CODE_H diff --git a/hidebug/interfaces/ets/ani/hidebug/include/hiappevent_util.h b/hidebug/interfaces/ets/ani/hidebug/include/hiappevent_util.h new file mode 100644 index 000000000..66a926fe0 --- /dev/null +++ b/hidebug/interfaces/ets/ani/hidebug/include/hiappevent_util.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DEVELOPTOOLS_PROFILER_HIDEBUG_HIAPPEVENT_UTIL_H +#define DEVELOPTOOLS_PROFILER_HIDEBUG_HIAPPEVENT_UTIL_H + +#include +#include + +namespace OHOS { +namespace HiviewDFX { +class ApiInvokeRecorder { +public: + explicit ApiInvokeRecorder(std::string apiName); + ~ApiInvokeRecorder(); + void SetErrorCode(int errorCode); + static void InitProcessor(); +private: + std::string apiName_; + int errorCode_{0}; + int64_t beginTime_; + static int64_t processId_; +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif // DEVELOPTOOLS_PROFILER_HIDEBUG_HIAPPEVENT_UTIL_H diff --git a/hidebug/interfaces/ets/ani/hidebug/src/ani_hidebug.cpp b/hidebug/interfaces/ets/ani/hidebug/src/ani_hidebug.cpp new file mode 100644 index 000000000..3fd5be236 --- /dev/null +++ b/hidebug/interfaces/ets/ani/hidebug/src/ani_hidebug.cpp @@ -0,0 +1,683 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ani_util.h" +#include "application_context.h" +#include "context.h" +#include "cpu_collector.h" +#include "directory_ex.h" +#include "dump_usage.h" +#include "error_code.h" +#include "file_ex.h" +#include "hiappevent_util.h" +#include "hidebug_native_interface.h" +#include "hidebug_util.h" +#include "hilog/log.h" +#include "iservice_registry.h" +#include "memory_collector.h" +#include "refbase.h" +#include "static_core/plugins/ets/dfx/heap_helpers.h" +#include "static_core/runtime/tooling/inspector/debugger_arkapi.h" +#include "storage_acl.h" +#include "system_ability_definition.h" + +using namespace OHOS; +using namespace OHOS::HiviewDFX; + +namespace { +#undef LOG_DOMAIN +#define LOG_DOMAIN 0xD002D0A +#undef LOG_TAG +#define LOG_TAG "HiDebug_ANI" +constexpr int BYTE_2_KB_SHIFT_BITS = 10; +constexpr int MAX_TAGS_ARRAY_LENGTH = 40; +constexpr auto SLASH_STR = "/"; +constexpr auto JSON_FILE = ".json"; + +static ani_vm* g_currentVm = nullptr; + +std::map GetVmGcMap() +{ + return { + {"ark.gc.gc-count", ark::dfx::GetGCCount}, + {"ark.gc.gc-time", ark::dfx::GetGCDuration}, + {"ark.gc.gc-bytes-allocated", ark::dfx::GetAccumulatedAllocateSize}, + {"ark.gc.gc-bytes-freed", ark::dfx::GetAccumulatedFreeSize}, + {"ark.gc.fullgc-longtime-count", ark::dfx::GetFullGCLongTimeCount} + }; +} +} + +static bool IsArrayForAniValue(ani_env *env, ani_object param, ani_int &arraySize) +{ + ani_boolean isArray = ANI_FALSE; + ani_class cls = nullptr; + ani_static_method isArrayMethod = nullptr; + if (env->FindClass("escompat.Array", &cls) != ANI_OK || + env->Class_FindStaticMethod(cls, "isArray", "C{std.core.Object}:z", &isArrayMethod) != ANI_OK || + env->Class_CallStaticMethod_Boolean(cls, isArrayMethod, &isArray, param) != ANI_OK || + isArray == ANI_FALSE) { + return false; + } + + ani_double length = 0; + if (env->Object_GetPropertyByName_Double(param, "length", &length) != ANI_OK) { + return false; + } + arraySize = static_cast(length); + return true; +} + +static bool GetDumpParam(ani_env *env, ani_object argsAni, std::vector &args) +{ + ani_int arraySize = 0; + if (!IsArrayForAniValue(env, argsAni, arraySize)) { + HILOG_ERROR(LOG_CORE, "Get input args failed."); + return false; + } + for (ani_int i = 0; i < arraySize; i++) { + ani_ref aniValue = nullptr; + if (env->Object_CallMethodByName_Ref(argsAni, "$_get", "i:C{std.core.Object}", &aniValue, i) != ANI_OK) { + HILOG_ERROR(LOG_CORE, "get_element -> Get input args failed."); + return false; + } + std::string strValue; + if (AniUtil::ParseAniString(env, static_cast(aniValue), strValue) != ANI_OK) { + HILOG_ERROR(LOG_CORE, "get_value -> Get input args failed."); + return false; + } + std::wstring_convert, char16_t> strCnv; + args.push_back(strCnv.from_bytes(strValue)); + } + return true; +} + +static bool GetTraceParam(ani_env *env, ani_array_long tagsAni, std::vector &tags) +{ + ani_size arraySize = 0; + if (env->Array_GetLength(static_cast(tagsAni), &arraySize) != ANI_OK) { + HILOG_ERROR(LOG_CORE, "Get input tags size failed."); + return false; + } + if (arraySize > static_cast(MAX_TAGS_ARRAY_LENGTH)) { + HILOG_ERROR(LOG_CORE, "The length of tags array exceeds the limit."); + return false; + } + ani_long *aniValues = new ani_long[arraySize]; + if (env->Array_GetRegion_Long(tagsAni, 0, arraySize, aniValues) != ANI_OK) { + HILOG_ERROR(LOG_CORE, "Get input tags value failed."); + delete []aniValues; + return false; + } + for (ani_size i = 0; i < arraySize; i++) { + tags.push_back(static_cast(aniValues[i])); + } + delete []aniValues; + return true; +} + +ani_object GetPss(ani_env *env) +{ + ani_object pss = nullptr; + std::shared_ptr collector = UCollectUtil::MemoryCollector::Create(); + if (collector != nullptr) { + int pid = getprocpid(); + auto collectResult = collector->CollectProcessMemory(pid); + uint64_t pssInfo = collectResult.data.pss + collectResult.data.swapPss; + AniUtil::ToAniBigInt(env, pssInfo, pss); + } else { + AniUtil::ToAniBigInt(env, 0, pss); + } + return pss; +} + +ani_object GetSharedDirty(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getSharedDirty"); + ani_object sharedDirty = nullptr; + std::shared_ptr collector = UCollectUtil::MemoryCollector::Create(); + if (collector != nullptr) { + int pid = getprocpid(); + auto collectResult = collector->CollectProcessMemory(pid); + uint64_t sharedDirtyInfo = collectResult.data.sharedDirty; + AniUtil::ToAniBigInt(env, sharedDirtyInfo, sharedDirty); + } else { + AniUtil::ToAniBigInt(env, 0, sharedDirty); + } + return sharedDirty; +} + +ani_object GetPrivateDirty(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getPrivateDirty"); + ani_object privateDirtyValue = nullptr; + std::shared_ptr collector = UCollectUtil::MemoryCollector::Create(); + if (collector != nullptr) { + pid_t pid = getprocpid(); + auto collectResult = collector->CollectProcessMemory(pid); + uint64_t privateDirty = collectResult.data.privateDirty; + AniUtil::ToAniBigInt(env, privateDirty, privateDirtyValue); + } else { + AniUtil::ToAniBigInt(env, 0, privateDirtyValue); + } + return privateDirtyValue; +} + +ani_double GetCpuUsage(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getCpuUsage"); + std::unique_ptr dumpUsage = std::make_unique(); + pid_t pid = getprocpid(); + double cpuUsage = dumpUsage->GetCpuUsage(pid); + ani_double cpuUsageValue = static_cast(cpuUsage); + return cpuUsageValue; +} + +ani_object GetNativeHeapSize(ani_env *env) +{ + struct mallinfo mi = mallinfo(); + ani_object nativeHeapSize = nullptr; + AniUtil::ToAniBigInt(env, uint64_t(mi.uordblks + mi.fordblks), nativeHeapSize); + return nativeHeapSize; +} + +ani_object GetNativeHeapAllocatedSize(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getNativeHeapAllocatedSize"); + struct mallinfo mi = mallinfo(); + ani_object nativeHeapAllocatedSize = nullptr; + AniUtil::ToAniBigInt(env, uint64_t(mi.uordblks), nativeHeapAllocatedSize); + return nativeHeapAllocatedSize; +} + +ani_object GetNativeHeapFreeSize(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getNativeHeapFreeSize"); + struct mallinfo mi = mallinfo(); + ani_object nativeHeapFreeSize = nullptr; + AniUtil::ToAniBigInt(env, uint64_t(mi.fordblks), nativeHeapFreeSize); + return nativeHeapFreeSize; +} + +static void GetServiceDump(ani_env *env, + ani_int serviceIdAni, ani_int fdAni, ani_object argsAni) +{ + ApiInvokeRecorder apiInvokeRecorder("getServiceDump"); + int serviceAbilityId = static_cast(serviceIdAni); + int fd = static_cast(fdAni); + std::vector args; + if (!GetDumpParam(env, argsAni, args)) { + std::string paramErrorMessage = "The parameter check failed."; + AniUtil::ThrowErrorMessage(env, paramErrorMessage, ErrorCode::PARAMETER_ERROR); + return; + } + sptr sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (!sam) { + return; + } + sptr sa = sam->CheckSystemAbility(serviceAbilityId); + if (sa == nullptr) { + HILOG_ERROR(LOG_CORE, "no this system ability."); + std::string idErrorMessage = "ServiceId invalid. The system ability does not exist."; + AniUtil::ThrowErrorMessage(env, idErrorMessage, ErrorCode::SYSTEM_ABILITY_NOT_FOUND); + return; + } + int dumpResult = sa->Dump(fd, args); + HILOG_INFO(LOG_CORE, "Dump result: %{public}d", dumpResult); +} + +ani_object GetVss(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getVss"); + ani_object vss = nullptr; + std::shared_ptr collector = UCollectUtil::MemoryCollector::Create(); + if (collector != nullptr) { + pid_t pid = getprocpid(); + auto collectResult = collector->CollectProcessVss(pid); + uint64_t vssInfo = collectResult.data; + AniUtil::ToAniBigInt(env, vssInfo, vss); + } else { + AniUtil::ToAniBigInt(env, 0, vss); + } + return vss; +} + +static ani_double GetSystemCpuUsage(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getSystemCpuUsage"); + auto cpuUsageOptional = HidebugNativeInterface::GetInstance().GetSystemCpuUsage(); + if (!cpuUsageOptional) { + std::string paramErrorMessage = "The status of the system CPU usage is abnormal."; + AniUtil::ThrowErrorMessage(env, paramErrorMessage, ErrorCode::SYSTEM_STATUS_ABNORMAL); + return 0; + } + ani_double retMsg = static_cast(cpuUsageOptional.value()); + return retMsg; +} + +static ani_object ConvertThreadCpuUsageToEts(ani_env *env, ani_class cls, uint32_t threadIdValue, double cpuUsageValue) +{ + ani_method ctorMethod = nullptr; + ani_object obj = nullptr; + if (env->Class_FindMethod(cls, "", ":", &ctorMethod) != ANI_OK || + env->Object_New(cls, ctorMethod, &obj) != ANI_OK) { + return AniUtil::CreateUndefined(env); + } + env->Object_SetPropertyByName_Long(obj, "threadId", static_cast(threadIdValue)); + AniUtil::SetNamedPropertyNumber(env, obj, "cpuUsage", cpuUsageValue); + return obj; +} + +static ani_array_ref ConvertThreadCpuUsageMapToEts(ani_env *env, const std::map &threadMap) +{ + ani_class cls = nullptr; + ani_size aniSize = static_cast(threadMap.size()); + ani_array_ref result = nullptr; + if (env->FindClass("@ohos.hidebug.hidebug.ThreadCpuUsageImpl", &cls) != ANI_OK || + env->Array_New_Ref(static_cast(cls), aniSize, nullptr, &result) != ANI_OK) { + return result; + } + ani_size idx = 0; + for (const auto[threadId, cpuUsage] : threadMap) { + ani_object obj = ConvertThreadCpuUsageToEts(env, cls, threadId, cpuUsage); + env->Array_Set_Ref(result, idx, static_cast(obj)); + idx++; + } + return result; +} + +ani_array GetAppThreadCpuUsage(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getAppThreadCpuUsage"); + ani_array result = nullptr; + std::map threadMap = HidebugNativeInterface::GetInstance().GetAppThreadCpuUsage(); + return ConvertThreadCpuUsageMapToEts(env, threadMap); +} + +ani_object GetAppNativeMemInfo(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getAppNativeMemInfo"); + HiDebug_NativeMemInfo nativeMemInfo{}; + auto nativeMemInfoOption = HidebugNativeInterface::GetInstance().GetAppNativeMemInfo(); + if (nativeMemInfoOption) { + nativeMemInfo = nativeMemInfoOption.value(); + } + + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_object memInfo = nullptr; + if (env->FindClass("@ohos.hidebug.hidebug.NativeMemInfoImpl", &cls) != ANI_OK || + env->Class_FindMethod(cls, "", ":", &ctorMethod) != ANI_OK || + env->Object_New(cls, ctorMethod, &memInfo) != ANI_OK) { + return AniUtil::CreateUndefined(env); + } + AniUtil::SetNamedPropertyBigInt(env, memInfo, "pss", nativeMemInfo.pss); + AniUtil::SetNamedPropertyBigInt(env, memInfo, "rss", nativeMemInfo.rss); + AniUtil::SetNamedPropertyBigInt(env, memInfo, "sharedDirty", nativeMemInfo.sharedDirty); + AniUtil::SetNamedPropertyBigInt(env, memInfo, "privateDirty", nativeMemInfo.privateDirty); + AniUtil::SetNamedPropertyBigInt(env, memInfo, "sharedClean", nativeMemInfo.sharedClean); + AniUtil::SetNamedPropertyBigInt(env, memInfo, "privateClean", nativeMemInfo.privateClean); + AniUtil::SetNamedPropertyBigInt(env, memInfo, "vss", nativeMemInfo.vss); + return memInfo; +} + +ani_object GetSystemMemInfo(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getSystemMemInfo"); + SysMemory systemMemInfo{}; + auto systemMemInfoOption = HidebugNativeInterface::GetInstance().GetSystemMemInfo(); + if (systemMemInfoOption) { + systemMemInfo = systemMemInfoOption.value(); + } + + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_object sysMemInfo = nullptr; + if (env->FindClass("@ohos.hidebug.hidebug.SystemMemInfoImpl", &cls) != ANI_OK || + env->Class_FindMethod(cls, "", ":", &ctorMethod) != ANI_OK || + env->Object_New(cls, ctorMethod, &sysMemInfo) != ANI_OK) { + return AniUtil::CreateUndefined(env); + } + + AniUtil::SetNamedPropertyBigInt(env, sysMemInfo, "totalMem", systemMemInfo.memTotal); + AniUtil::SetNamedPropertyBigInt(env, sysMemInfo, "freeMem", systemMemInfo.memFree); + AniUtil::SetNamedPropertyBigInt(env, sysMemInfo, "availableMem", systemMemInfo.memAvailable); + return sysMemInfo; +} + +ani_string StartAppTraceCapture(ani_env *env, + ani_array_long tagsAni, ani_enum_item flagAni, ani_int limitSizeAni) +{ + ApiInvokeRecorder apiInvokeRecorder("startAppTraceCapture"); + ani_string result = nullptr; + uint32_t traceFlag = 0; + uint32_t limitSize = static_cast(limitSizeAni); + std::vector tags; + if (AniUtil::ParseAniEnum(env, flagAni, traceFlag) != ANI_OK || !GetTraceParam(env, tagsAni, tags)) { + std::string paramErrorMessage = "Invalid argument"; + ani_object undefinedResult = AniUtil::CreateUndefined(env); + apiInvokeRecorder.SetErrorCode(ErrorCode::PARAMETER_ERROR); + AniUtil::ThrowErrorMessage(env, paramErrorMessage, ErrorCode::PARAMETER_ERROR); + return nullptr; + } + uint64_t tag = std::accumulate(tags.begin(), tags.end(), 0ull, [](uint64_t a, uint64_t b) { return a | b; }); + std::string file; + auto ret = HidebugNativeInterface::GetInstance().StartAppTraceCapture(tag, traceFlag, limitSize, file); + if (ret == HIDEBUG_SUCCESS) { + env->String_NewUTF8(file.c_str(), file.size(), &result); + return result; + } + if (ret == HIDEBUG_INVALID_ARGUMENT) { + std::string errorMessage = "Invalid argument"; + apiInvokeRecorder.SetErrorCode(ErrorCode::PARAMETER_ERROR); + AniUtil::ThrowErrorMessage(env, errorMessage, ErrorCode::PARAMETER_ERROR); + } + if (ret == HIDEBUG_TRACE_CAPTURED_ALREADY) { + std::string errorMessage = "Capture trace already enabled."; + apiInvokeRecorder.SetErrorCode(ErrorCode::HAVA_ALREADY_TRACE); + AniUtil::ThrowErrorMessage(env, errorMessage, ErrorCode::HAVA_ALREADY_TRACE); + } + if (ret == HIDEBUG_NO_PERMISSION) { + std::string errorMessage = "No write permission on the file."; + apiInvokeRecorder.SetErrorCode(ErrorCode::WITHOUT_WRITE_PERMISSON); + AniUtil::ThrowErrorMessage(env, errorMessage, ErrorCode::WITHOUT_WRITE_PERMISSON); + } + std::string errorMessage = "Abnormal trace status."; + apiInvokeRecorder.SetErrorCode(ErrorCode::SYSTEM_STATUS_ABNORMAL); + AniUtil::ThrowErrorMessage(env, errorMessage, ErrorCode::SYSTEM_STATUS_ABNORMAL); + return nullptr; +} + +static ani_boolean IsDebugState(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("isDebugState"); + bool debugState = ark::ArkDebugNativeAPI::IsDebugModeEnabled() || + HidebugNativeInterface::GetInstance().IsDebuggerConnected(); + ani_boolean result = static_cast(debugState); + return result; +} + +void StopAppTraceCapture(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("stopAppTraceCapture"); + auto ret = HidebugNativeInterface::GetInstance().StopAppTraceCapture(); + if (ret == HIDEBUG_TRACE_ABNORMAL) { + std::string errorMessage = "The status of the trace is abnormal"; + apiInvokeRecorder.SetErrorCode(ErrorCode::SYSTEM_STATUS_ABNORMAL); + AniUtil::ThrowErrorMessage(env, errorMessage, ErrorCode::SYSTEM_STATUS_ABNORMAL); + return; + } + if (ret == HIDEBUG_NO_TRACE_RUNNING) { + std::string errorMessage = "No capture trace running"; + apiInvokeRecorder.SetErrorCode(ErrorCode::NO_CAPTURE_TRACE_RUNNING); + AniUtil::ThrowErrorMessage(env, errorMessage, ErrorCode::NO_CAPTURE_TRACE_RUNNING); + return; + } +} + +ani_int GetGraphicsMemorySync(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getGraphicsMemorySync"); + std::optional result = HidebugNativeInterface::GetInstance().GetGraphicsMemory(); + if (result) { + return static_cast(result.value()); + } + constexpr const char* errMsg = "Failed to get the application memory due to a remote exception"; + AniUtil::ThrowErrorMessage(env, errMsg, ErrorCode::SYSTEM_STATUS_ABNORMAL); + apiInvokeRecorder.SetErrorCode(ErrorCode::SYSTEM_STATUS_ABNORMAL); + return 0; +} + +static bool GetTheOnlyStringParam(ani_env *env, ani_string filenameAni, std::string &fileName) +{ + if (AniUtil::ParseAniString(env, filenameAni, fileName) != ANI_OK) { + HILOG_ERROR(LOG_CORE, "Failed to parse ani_string filename"); + return false; + } + size_t bufLen = fileName.size(); + const int bufMax = 128; + if (bufLen > bufMax || bufLen == 0) { + HILOG_ERROR(LOG_CORE, "input filename param length is illegal."); + return false; + } + return true; +} + +static ani_object GetAppVMMemoryInfo(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getAppVMMemoryInfo"); + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_object vMMemoryInfo = nullptr; + if (env->FindClass("@ohos.hidebug.hidebug.VMMemoryInfoImpl", &cls) != ANI_OK || + env->Class_FindMethod(cls, "", ":", &ctorMethod) != ANI_OK || + env->Object_New(cls, ctorMethod, &vMMemoryInfo) != ANI_OK) { + return AniUtil::CreateUndefined(env); + } + + uint64_t totalHeapValue = ark::dfx::GetHeapTotalSize(g_currentVm); + totalHeapValue = totalHeapValue >> BYTE_2_KB_SHIFT_BITS; + AniUtil::SetNamedPropertyBigInt(env, vMMemoryInfo, "totalHeap", totalHeapValue); + + uint64_t heapUsedValue = ark::dfx::GetHeapUsedSize(g_currentVm); + heapUsedValue = heapUsedValue >> BYTE_2_KB_SHIFT_BITS; + AniUtil::SetNamedPropertyBigInt(env, vMMemoryInfo, "heapUsed", heapUsedValue); + + uint64_t allArraySizeValue = ark::dfx::GetArrayBufferSize(g_currentVm); + allArraySizeValue = allArraySizeValue >> BYTE_2_KB_SHIFT_BITS; + AniUtil::SetNamedPropertyBigInt(env, vMMemoryInfo, "allArraySize", allArraySizeValue); + + return vMMemoryInfo; +} + +static ani_object GetAppMemoryLimit(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getAppMemoryLimit"); + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_object appMemoryLimit = nullptr; + if (env->FindClass("@ohos.hidebug.hidebug.MemoryLimitImpl", &cls) != ANI_OK || + env->Class_FindMethod(cls, "", ":", &ctorMethod) != ANI_OK || + env->Object_New(cls, ctorMethod, &appMemoryLimit) != ANI_OK) { + return AniUtil::CreateUndefined(env); + } + MemoryLimit memoryLimit{}; + auto memoryLimitOption = HidebugNativeInterface::GetInstance().GetAppMemoryLimit(); + if (memoryLimitOption) { + memoryLimit = memoryLimitOption.value(); + } + AniUtil::SetNamedPropertyBigInt(env, appMemoryLimit, "rssLimit", memoryLimit.rssLimit); + AniUtil::SetNamedPropertyBigInt(env, appMemoryLimit, "vssLimit", memoryLimit.vssLimit); + uint64_t vmHeapLimitValue = ark::dfx::GetHeapLimitSize(g_currentVm); + vmHeapLimitValue = vmHeapLimitValue >> BYTE_2_KB_SHIFT_BITS; + AniUtil::SetNamedPropertyBigInt(env, appMemoryLimit, "vmHeapLimit", vmHeapLimitValue); + uint64_t vmTotalHeapSizeValue = ark::dfx::GetProcessHeapLimitSize(g_currentVm); + vmTotalHeapSizeValue = vmTotalHeapSizeValue >> BYTE_2_KB_SHIFT_BITS; + AniUtil::SetNamedPropertyBigInt(env, appMemoryLimit, "vmTotalHeapSize", vmTotalHeapSizeValue); + return appMemoryLimit; +} + +static ani_object GetVMRuntimeStats(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("getVMRuntimeStats"); + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_object vmRunTimeStats = nullptr; + if (env->FindClass("escompat.Record", &cls) != ANI_OK || + env->Class_FindMethod(cls, "", nullptr, &ctorMethod) != ANI_OK || + env->Object_New(cls, ctorMethod, &vmRunTimeStats, nullptr) != ANI_OK) { + HILOG_ERROR(LOG_CORE, "failed to init record."); + return AniUtil::CreateUndefined(env); + } + ani_method setMethod = nullptr; + if (env->Class_FindMethod(cls, "$_set", nullptr, &setMethod) != ANI_OK) { + return vmRunTimeStats; + } + ani_class longClass = nullptr; + env->FindClass("std.core.Long", &longClass); + ani_method longCtor = nullptr; + env->Class_FindMethod(longClass, "", "l:", &longCtor); + auto vmGcMap = GetVmGcMap(); + for (const auto &[k, targetFunction] : vmGcMap) { + ani_string aniKey = nullptr; + if (ANI_OK != env->String_NewUTF8(k.c_str(), k.size(), &aniKey)) { + HILOG_ERROR(LOG_CORE, "create new value string failed"); + } + ani_object longObject = nullptr; + env->Object_New(longClass, longCtor, &longObject, static_cast(targetFunction(g_currentVm))); + env->Object_CallMethod_Void(vmRunTimeStats, setMethod, aniKey, longObject); + } + return vmRunTimeStats; +} + +static ani_long GetVMRuntimeStat(ani_env *env, ani_string itemAni) +{ + ApiInvokeRecorder apiInvokeRecorder("getVMRuntimeStat"); + std::string param; + if (!GetTheOnlyStringParam(env, itemAni, param)) { + std::string paramErrorMessage = "Invalid parameter, a string parameter required."; + AniUtil::ThrowErrorMessage(env, paramErrorMessage, ErrorCode::PARAMETER_ERROR); + apiInvokeRecorder.SetErrorCode(ErrorCode::PARAMETER_ERROR); + return 0; + } + auto vmGcMap = GetVmGcMap(); + auto target = vmGcMap.find(param); + if (target == vmGcMap.end()) { + std::string paramErrorMessage = "Invalid parameter, unknown property."; + AniUtil::ThrowErrorMessage(env, paramErrorMessage, ErrorCode::PARAMETER_ERROR); + apiInvokeRecorder.SetErrorCode(ErrorCode::PARAMETER_ERROR); + return 0; + } + return static_cast((target->second)(g_currentVm)); +} + +static std::string StartCpuProfiler(const std::string& fileName) +{ + auto context = OHOS::AbilityRuntime::Context::GetApplicationContext(); + if (context == nullptr) { + return "Get ApplicationContext failed."; + } + std::string filesDir = context->GetFilesDir(); + if (filesDir.empty()) { + return "Get App files dir failed."; + } + std::string filePath = filesDir + SLASH_STR + fileName + JSON_FILE; + if (!IsLegalPath(filePath)) { + return "input fileName is illegal."; + } + if (!CreateFile(filePath)) { + return "file created failed."; + } + if (!ark::ArkDebugNativeAPI::StartProfiling(filePath)) { + return "failed start profiler."; + } + return ""; +} + +static void StartJsCpuProfiling(ani_env *env, ani_string fileNameAni) +{ + ApiInvokeRecorder apiInvokeRecorder("startJsCpuProfiling"); + std::string fileName; + if (!GetTheOnlyStringParam(env, fileNameAni, fileName)) { + apiInvokeRecorder.SetErrorCode(ErrorCode::PARAMETER_ERROR); + std::string paramErrorMessage = "Invalid parameter, require a string parameter."; + AniUtil::ThrowErrorMessage(env, paramErrorMessage, ErrorCode::PARAMETER_ERROR); + return; + } + HILOG_INFO(LOG_CORE, "filename: %{public}s.", fileName.c_str()); + auto errMsg = StartCpuProfiler(fileName); + if (!errMsg.empty()) { + apiInvokeRecorder.SetErrorCode(ErrorCode::SYSTEM_STATUS_ABNORMAL); + AniUtil::ThrowErrorMessage(env, errMsg, ErrorCode::SYSTEM_STATUS_ABNORMAL); + return; + } +} + +static void StopJsCpuProfiling(ani_env *env) +{ + ApiInvokeRecorder apiInvokeRecorder("stopJsCpuProfiling"); + if (!ark::ArkDebugNativeAPI::StopProfiling()) { + HILOG_ERROR(LOG_CORE, "failed stopJsCpuProfiling"); + } +} + +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + g_currentVm = vm; + ani_env *env = nullptr; + if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) { + return ANI_ERROR; + } + ani_namespace nameSpace = nullptr; + if (ANI_OK != env->FindNamespace("@ohos.hidebug.hidebug", &nameSpace)) { + return ANI_ERROR; + } + std::array methods = { + ani_native_function {"getAppVMMemoryInfo", ":C{@ohos.hidebug.hidebug.VMMemoryInfo}", + reinterpret_cast(GetAppVMMemoryInfo)}, + ani_native_function {"getAppMemoryLimit", ":C{@ohos.hidebug.hidebug.MemoryLimit}", + reinterpret_cast(GetAppMemoryLimit)}, + ani_native_function {"getVMRuntimeStats", ":C{escompat.Record}", reinterpret_cast(GetVMRuntimeStats)}, + ani_native_function {"getVMRuntimeStat", "C{std.core.String}:l", reinterpret_cast(GetVMRuntimeStat)}, + ani_native_function {"getPss", ":C{escompat.BigInt}", reinterpret_cast(GetPss)}, + ani_native_function {"getSharedDirty", ":C{escompat.BigInt}", reinterpret_cast(GetSharedDirty)}, + ani_native_function {"getPrivateDirty", ":C{escompat.BigInt}", reinterpret_cast(GetPrivateDirty)}, + ani_native_function {"getCpuUsage", ":d", reinterpret_cast(GetCpuUsage)}, + ani_native_function {"getServiceDump", "iiC{escompat.Array}:", reinterpret_cast(GetServiceDump)}, + ani_native_function {"getNativeHeapSize", ":C{escompat.BigInt}", reinterpret_cast(GetNativeHeapSize)}, + ani_native_function {"getNativeHeapAllocatedSize", ":C{escompat.BigInt}", + reinterpret_cast(GetNativeHeapAllocatedSize)}, + ani_native_function {"getNativeHeapFreeSize", ":C{escompat.BigInt}", + reinterpret_cast(GetNativeHeapFreeSize)}, + ani_native_function {"getVss", ":C{escompat.BigInt}", reinterpret_cast(GetVss)}, + ani_native_function {"getAppThreadCpuUsage", ":C{escompat.Array}", + reinterpret_cast(GetAppThreadCpuUsage)}, + ani_native_function {"getSystemCpuUsage", ":d", reinterpret_cast(GetSystemCpuUsage)}, + ani_native_function {"getAppNativeMemInfo", ":C{@ohos.hidebug.hidebug.NativeMemInfo}", + reinterpret_cast(GetAppNativeMemInfo)}, + ani_native_function {"getSystemMemInfo", ":C{@ohos.hidebug.hidebug.SystemMemInfo}", + reinterpret_cast(GetSystemMemInfo)}, + ani_native_function {"startAppTraceCapture", + "C{escompat.Array}C{@ohos.hidebug.hidebug.TraceFlag}i:C{std.core.String}", + reinterpret_cast(StartAppTraceCapture)}, + ani_native_function {"isDebugState", ":z", reinterpret_cast(IsDebugState)}, + ani_native_function {"stopAppTraceCapture", ":", reinterpret_cast(StopAppTraceCapture)}, + ani_native_function {"startJsCpuProfiling", "C{std.core.String}:", + reinterpret_cast(StartJsCpuProfiling)}, + ani_native_function {"stopJsCpuProfiling", ":", reinterpret_cast(StopJsCpuProfiling)}, + ani_native_function {"getGraphicsMemorySync", ":i", reinterpret_cast(GetGraphicsMemorySync)}, + }; + auto retCode = env->Namespace_BindNativeFunctions(nameSpace, methods.data(), methods.size()); + if (ANI_OK != retCode) { + return retCode; + } + *result = ANI_VERSION_1; + return ANI_OK; +} diff --git a/hidebug/interfaces/ets/ani/hidebug/src/ani_util.cpp b/hidebug/interfaces/ets/ani/hidebug/src/ani_util.cpp new file mode 100644 index 000000000..3f952c2ec --- /dev/null +++ b/hidebug/interfaces/ets/ani/hidebug/src/ani_util.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ani_util.h" + +namespace OHOS { +namespace HiviewDFX { +void AniUtil::ThrowErrorMessage(ani_env *env, const std::string &msg, int32_t errCode) +{ + ani_module hiDebugModule = nullptr; + if (env->FindModule("@ohos.hidebug", &hiDebugModule) != ANI_OK) { + return; + } + ani_function createErrorFn = nullptr; + if (env->Module_FindFunction(hiDebugModule, "createVoidBusinessError", + "dC{std.core.String}:C{@ohos.base.BusinessError}", &createErrorFn) != ANI_OK) { + return; + } + ani_double errCodeAni = static_cast(errCode); + ani_string msgAni = nullptr; + if (ANI_OK != env->String_NewUTF8(msg.c_str(), msg.size(), &msgAni)) { + return; + } + ani_ref errRef = nullptr; + if (env->Function_Call_Ref(createErrorFn, &errRef, errCodeAni, msgAni) != ANI_OK) { + return; + } + env->ThrowError(static_cast(errRef)); +} + +ani_object AniUtil::CreateUndefined(ani_env *env) +{ + ani_ref undefinedRef = nullptr; + if (env->GetUndefined(&undefinedRef) != ANI_OK) { + return nullptr; + } + return static_cast(undefinedRef); +} + +ani_status AniUtil::ToAniBigInt(ani_env *env, uint64_t uint64Val, ani_object &aniBigInt) +{ + ani_class bigIntCls = nullptr; + ani_status status = env->FindClass("escompat.BigInt", &bigIntCls); + if (status != ANI_OK) { + return status; + } + ani_method ctorMethod = nullptr; + status = env->Class_FindMethod(bigIntCls, "", "C{std.core.String}:", &ctorMethod); + if (status != ANI_OK) { + return status; + } + ani_string aniBigIntStr = nullptr; + status = env->String_NewUTF8(std::to_string(uint64Val).c_str(), std::to_string(uint64Val).size(), &aniBigIntStr); + if (status != ANI_OK) { + return status; + } + return env->Object_New(bigIntCls, ctorMethod, &aniBigInt, aniBigIntStr); +} + +ani_status AniUtil::ParseAniString(ani_env *env, ani_string aniStr, std::string &str) +{ + ani_size srcSize = 0; + ani_status status = env->String_GetUTF8Size(aniStr, &srcSize); + if (status != ANI_OK) { + return status; + } + std::vector buffer(srcSize + 1); + ani_size dstSize = 0; + status = env->String_GetUTF8SubString(aniStr, 0, srcSize, buffer.data(), buffer.size(), &dstSize); + if (status != ANI_OK || srcSize != dstSize) { + return status; + } + str.assign(buffer.data(), dstSize); + return ANI_OK; +} + +ani_status AniUtil::ParseAniEnum(ani_env *env, ani_enum_item enumItem, uint32_t &value) +{ + ani_int aniInt = 0; + ani_status status = env->EnumItem_GetValue_Int(enumItem, &aniInt); + if (status != ANI_OK) { + return status; + } + value = static_cast(aniInt); + return ANI_OK; +} + +ani_status AniUtil::SetNamedPropertyNumber(ani_env *env, ani_object object, const std::string& name, double value) +{ + ani_double aniNumber = static_cast(value); + ani_status status = env->Object_SetPropertyByName_Double(object, name.c_str(), aniNumber); + return status; +} + +ani_status AniUtil::SetNamedPropertyBigInt(ani_env *env, ani_object object, const std::string& name, uint64_t value) +{ + ani_object aniBigInt = nullptr; + ani_status status = AniUtil::ToAniBigInt(env, value, aniBigInt); + if (status != ANI_OK) { + return status; + } + status = env->Object_SetPropertyByName_Ref(object, name.c_str(), static_cast(aniBigInt)); + return status; +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/hidebug/interfaces/ets/ani/hidebug/src/hiappevent_util.cpp b/hidebug/interfaces/ets/ani/hidebug/src/hiappevent_util.cpp new file mode 100644 index 000000000..05f1dd519 --- /dev/null +++ b/hidebug/interfaces/ets/ani/hidebug/src/hiappevent_util.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "hiappevent_util.h" + +#include +#include + +#include "app_event.h" +#include "app_event_processor_mgr.h" +#include "ffrt.h" +#include "hidebug_util.h" +#include "hilog/log.h" + +namespace OHOS { +namespace HiviewDFX { + +#undef LOG_DOMAIN +#define LOG_DOMAIN 0xD002D0A +#undef LOG_TAG +#define LOG_TAG "HIAPPEVENT_UTIL" + +int64_t ApiInvokeRecorder::processId_ = -1; + +ApiInvokeRecorder::ApiInvokeRecorder(std::string apiName) : apiName_(std::move(apiName)), + beginTime_(GetElapsedNanoSecondsSinceBoot()) {} + +ApiInvokeRecorder::~ApiInvokeRecorder() +{ + if (processId_ < 0 || beginTime_ < 0) { + return; + } + const int64_t costTime = GetElapsedNanoSecondsSinceBoot() - beginTime_; + if (costTime < 0) { + return; + } + int64_t realEndTime = GetRealNanoSecondsTimestamp(); + int64_t realBeginTime = realEndTime - costTime; + if (realBeginTime < 0 || realEndTime < 0) { + return; + } + std::string apiName(std::move(apiName_)); + int64_t beginTime(beginTime_); + int errorCode(errorCode_); + auto task = [apiName, realEndTime, realBeginTime, errorCode] { + HiAppEvent::Event event("api_diagnostic", "api_exec_end", HiAppEvent::BEHAVIOR); + event.AddParam("trans_id", std::string("transId_") + std::to_string(realBeginTime)); + event.AddParam("api_name", apiName); + event.AddParam("sdk_name", std::string("PerformanceAnalysisKit")); + constexpr int milliSecondsToNanoseconds = 1000 * 1000; + event.AddParam("begin_time", realBeginTime / milliSecondsToNanoseconds); + event.AddParam("end_time", realEndTime / milliSecondsToNanoseconds); + event.AddParam("result", static_cast(errorCode == 0)); + event.AddParam("error_code", errorCode); + Write(event); + }; + ffrt::submit(task, {}, {}); +} + +void ApiInvokeRecorder::SetErrorCode(int errorCode) +{ + errorCode_ = errorCode; +} + +void ApiInvokeRecorder::InitProcessor() +{ + ffrt::submit([] { + using namespace HiAppEvent; + ReportConfig config; + config.name = "ha_app_event"; + config.appId = "com_huawei_hmos_sdk_ocg"; + config.routeInfo = "AUTO"; + constexpr int triggerTimeOut = 90; + config.triggerCond.timeout = triggerTimeOut; + constexpr int triggerRow = 30; + config.triggerCond.row = triggerRow; + config.eventConfigs.clear(); + config.eventConfigs.push_back({ + .domain = "api_diagnostic", + .name = "api_exec_end", + .isRealTime = false, + }); + config.eventConfigs.push_back({ + .domain = "api_diagnostic", + .name = "api_called_stat", + .isRealTime = true, + }); + config.eventConfigs.push_back({ + .domain = "api_diagnostic", + .name = "api_called_stat_cnt", + .isRealTime = true, + }); + processId_ = AppEventProcessorMgr::AddProcessor(config); + if (processId_ < 0) { + HILOG_ERROR(LOG_CORE, "failed to init processor and ret: %{public}" PRId64, processId_); + } + }, {}, {}); +} +} +} -- Gitee