1 /*
2 * Copyright (c) 2025 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 <array>
17 #include <iostream>
18 #include <ani.h>
19 #include <hilog/log.h>
20 #include <string>
21 #include "hitrace_meter.h"
22
23 #ifdef LOG_DOMAIN
24 #undef LOG_DOMAIN
25 #define LOG_DOMAIN 0xD002D33
26 #endif
27 #ifdef LOG_TAG
28 #undef LOG_TAG
29 #define LOG_TAG "HitraceMeterAni"
30 #endif
31
32 using namespace OHOS::HiviewDFX;
33 static const char NAMESPACE_HITRACEMETER[] = "L@ohos/hiTraceMeter/hiTraceMeter;";
34 constexpr size_t MIN_SIZE = 1;
35 constexpr size_t MAX_SIZE = 1024;
36
AniStringToStdString(ani_env * env,ani_string aniStr,std::string & content)37 static bool AniStringToStdString(ani_env* env, ani_string aniStr, std::string& content)
38 {
39 ani_size strSize = 0;
40 env->String_GetUTF8Size(aniStr, &strSize);
41
42 if (strSize < MIN_SIZE || strSize > MAX_SIZE) {
43 return false;
44 }
45 std::vector<char> buffer(strSize + 1);
46 char* charBuffer = buffer.data();
47
48 ani_size bytesWritten = 0;
49 env->String_GetUTF8(aniStr, charBuffer, strSize + 1, &bytesWritten);
50
51 charBuffer[bytesWritten] = '\0';
52 content = std::string(charBuffer);
53 return true;
54 }
55
AniEnumToInt32(ani_env * env,ani_enum_item enumItem,int32_t & value)56 static bool AniEnumToInt32(ani_env* env, ani_enum_item enumItem, int32_t& value)
57 {
58 ani_int aniInt = 0;
59 if (env->EnumItem_GetValue_Int(enumItem, &aniInt) != ANI_OK) {
60 HILOG_ERROR(LOG_CORE, "Failed to get the int32 value of enum.");
61 return false;
62 }
63 value = static_cast<int32_t>(aniInt);
64 return true;
65 }
66
IsRefUndefined(ani_env * env,ani_ref value)67 static bool IsRefUndefined(ani_env* env, ani_ref value)
68 {
69 ani_boolean isUndefined = ANI_FALSE;
70 env->Reference_IsUndefined(value, &isUndefined);
71 return isUndefined;
72 }
73
EtsStartTrace(ani_env * env,ani_string name,ani_double taskId)74 static void EtsStartTrace(ani_env* env, ani_string name, ani_double taskId)
75 {
76 std::string nameStr = "";
77 if (!AniStringToStdString(env, name, nameStr)) {
78 HILOG_ERROR(LOG_CORE, "AniStringToStdString failed.");
79 return;
80 }
81 StartAsyncTraceEx(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_APP, nameStr.c_str(), static_cast<int32_t>(taskId), "", "");
82 }
83
EtsFinishTrace(ani_env * env,ani_string name,ani_double taskId)84 static void EtsFinishTrace(ani_env* env, ani_string name, ani_double taskId)
85 {
86 std::string nameStr = "";
87 if (!AniStringToStdString(env, name, nameStr)) {
88 HILOG_ERROR(LOG_CORE, "AniStringToStdString failed.");
89 return;
90 }
91 FinishAsyncTraceEx(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_APP, nameStr.c_str(), static_cast<int32_t>(taskId));
92 }
93
EtsCountTrace(ani_env * env,ani_string name,ani_double count)94 static void EtsCountTrace(ani_env* env, ani_string name, ani_double count)
95 {
96 std::string nameStr = "";
97 if (!AniStringToStdString(env, name, nameStr)) {
98 HILOG_ERROR(LOG_CORE, "AniStringToStdString failed.");
99 return;
100 }
101 CountTraceEx(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_APP, nameStr.c_str(), static_cast<int64_t>(count));
102 }
103
EtsTraceByValue(ani_env * env,ani_enum_item level,ani_string name,ani_double count)104 static void EtsTraceByValue(ani_env* env, ani_enum_item level, ani_string name, ani_double count)
105 {
106 int32_t levelVal = 0;
107 if (!AniEnumToInt32(env, level, levelVal)) {
108 return;
109 }
110 std::string nameStr = "";
111 if (!AniStringToStdString(env, name, nameStr)) {
112 HILOG_ERROR(LOG_CORE, "AniStringToStdString failed.");
113 return;
114 }
115 CountTraceEx(static_cast<HiTraceOutputLevel>(levelVal), HITRACE_TAG_APP, nameStr.c_str(),
116 static_cast<int64_t>(count));
117 }
118
EtsStartSyncTrace(ani_env * env,ani_enum_item level,ani_string name,ani_object customArgs)119 static void EtsStartSyncTrace(ani_env* env, ani_enum_item level, ani_string name, ani_object customArgs)
120 {
121 int32_t levelVal = 0;
122 if (!AniEnumToInt32(env, level, levelVal)) {
123 return;
124 }
125 std::string nameStr = "";
126 if (!AniStringToStdString(env, name, nameStr)) {
127 HILOG_ERROR(LOG_CORE, "AniStringToStdString failed.");
128 return;
129 }
130 std::string customArgsStr = "";
131 if (!IsRefUndefined(env, static_cast<ani_ref>(customArgs))) {
132 if (!AniStringToStdString(env, static_cast<ani_string>(customArgs), customArgsStr)) {
133 HILOG_ERROR(LOG_CORE, "AniStringToStdString failed.");
134 return;
135 }
136 }
137 StartTraceEx(static_cast<HiTraceOutputLevel>(levelVal), HITRACE_TAG_APP, nameStr.c_str(), customArgsStr.c_str());
138 }
139
EtsFinishSyncTrace(ani_env * env,ani_enum_item level)140 static void EtsFinishSyncTrace(ani_env* env, ani_enum_item level)
141 {
142 int32_t levelVal = 0;
143 if (!AniEnumToInt32(env, level, levelVal)) {
144 return;
145 }
146 FinishTraceEx(static_cast<HiTraceOutputLevel>(levelVal), HITRACE_TAG_APP);
147 }
148
EtsStartAsyncTrace(ani_env * env,ani_enum_item level,ani_string name,ani_double taskId,ani_string customCategory,ani_object customArgs)149 static void EtsStartAsyncTrace(ani_env* env, ani_enum_item level, ani_string name, ani_double taskId,
150 ani_string customCategory, ani_object customArgs)
151 {
152 int32_t levelVal = 0;
153 if (!AniEnumToInt32(env, level, levelVal)) {
154 return;
155 }
156 std::string nameStr = "";
157 if (!AniStringToStdString(env, name, nameStr)) {
158 HILOG_ERROR(LOG_CORE, "AniStringToStdString failed.");
159 return;
160 }
161 std::string customCategoryStr = "";
162 if (!AniStringToStdString(env, customCategory, customCategoryStr)) {
163 HILOG_ERROR(LOG_CORE, "AniStringToStdString failed.");
164 return;
165 }
166 std::string customArgsStr = "";
167 if (!IsRefUndefined(env, static_cast<ani_ref>(customArgs))) {
168 if (!AniStringToStdString(env, static_cast<ani_string>(customArgs), customArgsStr)) {
169 HILOG_ERROR(LOG_CORE, "AniStringToStdString failed.");
170 return;
171 }
172 }
173 StartAsyncTraceEx(static_cast<HiTraceOutputLevel>(levelVal), HITRACE_TAG_APP, nameStr.c_str(),
174 static_cast<int32_t>(taskId), customCategoryStr.c_str(), customArgsStr.c_str());
175 }
176
EtsFinishAsyncTrace(ani_env * env,ani_enum_item level,ani_string name,ani_double taskId)177 static void EtsFinishAsyncTrace(ani_env* env, ani_enum_item level, ani_string name, ani_double taskId)
178 {
179 int32_t levelVal = 0;
180 if (!AniEnumToInt32(env, level, levelVal)) {
181 return;
182 }
183 std::string nameStr = "";
184 if (!AniStringToStdString(env, name, nameStr)) {
185 HILOG_ERROR(LOG_CORE, "AniStringToStdString failed.");
186 return;
187 }
188 FinishAsyncTraceEx(static_cast<HiTraceOutputLevel>(levelVal), HITRACE_TAG_APP, nameStr.c_str(),
189 static_cast<int32_t>(taskId));
190 }
191
EtsIsTraceEnabled(ani_env * env)192 static ani_boolean EtsIsTraceEnabled(ani_env* env)
193 {
194 return static_cast<ani_boolean>(IsTagEnabled(HITRACE_TAG_APP));
195 }
196
ANI_Constructor(ani_vm * vm,uint32_t * result)197 ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result)
198 {
199 ani_env* env;
200 if (vm->GetEnv(ANI_VERSION_1, &env) != ANI_OK) {
201 return ANI_ERROR;
202 }
203
204 ani_namespace ns;
205 if (env->FindNamespace(NAMESPACE_HITRACEMETER, &ns) != ANI_OK) {
206 return ANI_ERROR;
207 }
208
209 std::array methods = {
210 ani_native_function {"startTrace", nullptr, reinterpret_cast<void *>(EtsStartTrace)},
211 ani_native_function {"finishTrace", nullptr, reinterpret_cast<void *>(EtsFinishTrace)},
212 ani_native_function {"traceByValue", "Lstd/core/String;D:V", reinterpret_cast<void *>(EtsCountTrace)},
213 ani_native_function {"traceByValue", "L@ohos/hiTraceMeter/hiTraceMeter/HiTraceOutputLevel;Lstd/core/String;D:V",
214 reinterpret_cast<void *>(EtsTraceByValue)},
215 ani_native_function {"startSyncTrace", nullptr, reinterpret_cast<void *>(EtsStartSyncTrace)},
216 ani_native_function {"finishSyncTrace", nullptr, reinterpret_cast<void *>(EtsFinishSyncTrace)},
217 ani_native_function {"startAsyncTrace", nullptr, reinterpret_cast<void *>(EtsStartAsyncTrace)},
218 ani_native_function {"finishAsyncTrace", nullptr, reinterpret_cast<void *>(EtsFinishAsyncTrace)},
219 ani_native_function {"isTraceEnabled", nullptr, reinterpret_cast<void *>(EtsIsTraceEnabled)},
220 };
221
222 if (env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size()) != ANI_OK) {
223 return ANI_ERROR;
224 };
225
226 *result = ANI_VERSION_1;
227 return ANI_OK;
228 }
229