1 /*
2 * Copyright (c) 2022-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 #include "napi_app_event_holder.h"
16
17 #include <cinttypes>
18
19 #include "app_event_store.h"
20 #include "hilog/log.h"
21 #include "napi_error.h"
22 #include "napi_util.h"
23
24 #undef LOG_DOMAIN
25 #define LOG_DOMAIN 0xD002D07
26
27 #undef LOG_TAG
28 #define LOG_TAG "NapiHolder"
29
30 namespace OHOS {
31 namespace HiviewDFX {
32 namespace {
33 constexpr size_t PARAM_NUM = 1;
34 constexpr int DEFAULT_ROW_NUM = 1;
35 constexpr int DEFAULT_SIZE = 512 * 1024; // 512 * 1024: 512KB
36 const std::string HOLDER_CLASS_NAME = "AppEventPackageHolder";
37
GetObserverSeqByName(const std::string& name)38 int64_t GetObserverSeqByName(const std::string& name)
39 {
40 int64_t observerSeq = -1;
41 if (observerSeq = AppEventStore::GetInstance().QueryObserverSeq(name); observerSeq <= 0) {
42 HILOG_WARN(LOG_CORE, "failed to query seq by name=%{public}s", name.c_str());
43 return -1;
44 }
45 return observerSeq;
46 }
47 }
48 thread_local napi_ref NapiAppEventHolder::constructor_ = nullptr;
49
NapiAppEventHolder(const std::string& name, int64_t observerSeq)50 NapiAppEventHolder::NapiAppEventHolder(const std::string& name, int64_t observerSeq)
51 : name_(name), observerSeq_(observerSeq), hasSetRow_(false), hasSetSize_(false)
52 {
53 takeRow_ = DEFAULT_ROW_NUM;
54 takeSize_ = DEFAULT_SIZE;
55 packageId_ = 0; // id is incremented from 0
56
57 // if the seq is invalid, need to get seq by the name(for js constructor)
58 if (observerSeq_ <= 0) {
59 observerSeq_ = GetObserverSeqByName(name_);
60 }
61 }
62
NapiConstructor(napi_env env, napi_callback_info info)63 napi_value NapiAppEventHolder::NapiConstructor(napi_env env, napi_callback_info info)
64 {
65 size_t paramNum = PARAM_NUM;
66 napi_value params[PARAM_NUM] = { 0 };
67 napi_value thisVar = nullptr;
68 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisVar, nullptr));
69
70 if (paramNum < PARAM_NUM) {
71 HILOG_ERROR(LOG_CORE, "hodler failed to construct: invalid param num");
72 return thisVar;
73 }
74 auto holder = new(std::nothrow) NapiAppEventHolder(NapiUtil::GetString(env, params[0]));
75 if (holder == nullptr) {
76 return thisVar;
77 }
78 napi_wrap(
79 env, thisVar, holder,
80 [](napi_env env, void* data, void* hint) {
81 NapiAppEventHolder* holder = (NapiAppEventHolder*)data;
82 delete holder;
83 },
84 nullptr, nullptr);
85 return thisVar;
86 }
87
NapiExport(napi_env env, napi_value exports)88 napi_value NapiAppEventHolder::NapiExport(napi_env env, napi_value exports)
89 {
90 napi_property_descriptor properties[] = {
91 DECLARE_NAPI_FUNCTION("setRow", NapiSetRow),
92 DECLARE_NAPI_FUNCTION("setSize", NapiSetSize),
93 DECLARE_NAPI_FUNCTION("takeNext", NapiTakeNext)
94 };
95 napi_value holderClass = nullptr;
96 napi_define_class(env, HOLDER_CLASS_NAME.c_str(), HOLDER_CLASS_NAME.size(), NapiConstructor, nullptr,
97 sizeof(properties) / sizeof(properties[0]), properties, &holderClass);
98 NapiUtil::SetNamedProperty(env, exports, HOLDER_CLASS_NAME, holderClass);
99 constructor_ = NapiUtil::CreateReference(env, holderClass);
100 return exports;
101 }
102
NapiSetRow(napi_env env, napi_callback_info info)103 napi_value NapiAppEventHolder::NapiSetRow(napi_env env, napi_callback_info info)
104 {
105 size_t paramNum = PARAM_NUM;
106 napi_value params[PARAM_NUM] = { 0 };
107 napi_value thisVar = nullptr;
108 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisVar, nullptr));
109 if (paramNum < PARAM_NUM) {
110 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("size"));
111 return nullptr;
112 }
113 if (!NapiUtil::IsNumber(env, params[0])) {
114 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("size", "number"));
115 return nullptr;
116 }
117 if (int num = NapiUtil::GetInt32(env, params[0]); num > 0) {
118 NapiAppEventHolder* holder = nullptr;
119 napi_unwrap(env, thisVar, (void**)&holder);
120 holder->SetRow(num);
121 } else {
122 NapiUtil::ThrowError(env, NapiError::ERR_INVALID_SIZE, "Invalid size value.");
123 }
124 return NapiUtil::CreateUndefined(env);
125 }
126
NapiSetSize(napi_env env, napi_callback_info info)127 napi_value NapiAppEventHolder::NapiSetSize(napi_env env, napi_callback_info info)
128 {
129 size_t paramNum = PARAM_NUM;
130 napi_value params[PARAM_NUM] = { 0 };
131 napi_value thisVar = nullptr;
132 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisVar, nullptr));
133 if (paramNum < PARAM_NUM) {
134 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("size"));
135 return nullptr;
136 }
137 if (!NapiUtil::IsNumber(env, params[0])) {
138 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("size", "number"));
139 return nullptr;
140 }
141 if (int num = NapiUtil::GetInt32(env, params[0]); num >= 0) {
142 NapiAppEventHolder* holder = nullptr;
143 napi_unwrap(env, thisVar, (void**)&holder);
144 holder->SetSize(num);
145 } else {
146 NapiUtil::ThrowError(env, NapiError::ERR_INVALID_SIZE, "Invalid size value.");
147 }
148 return NapiUtil::CreateUndefined(env);
149 }
150
NapiTakeNext(napi_env env, napi_callback_info info)151 napi_value NapiAppEventHolder::NapiTakeNext(napi_env env, napi_callback_info info)
152 {
153 napi_value thisVar = nullptr;
154 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
155 NapiAppEventHolder* holder = nullptr;
156 napi_unwrap(env, thisVar, (void**)&holder);
157 auto package = holder->TakeNext();
158 if (package == nullptr) {
159 return NapiUtil::CreateNull(env);
160 }
161 napi_value packageObj = NapiUtil::CreateObject(env);
162 NapiUtil::SetNamedProperty(env, packageObj, "packageId", NapiUtil::CreateInt32(env, package->packageId));
163 NapiUtil::SetNamedProperty(env, packageObj, "row", NapiUtil::CreateInt32(env, package->row));
164 NapiUtil::SetNamedProperty(env, packageObj, "size", NapiUtil::CreateInt32(env, package->size));
165 NapiUtil::SetNamedProperty(env, packageObj, "data", NapiUtil::CreateStrings(env, package->data));
166 NapiUtil::SetNamedProperty(env, packageObj, "appEventInfos", NapiUtil::CreateEventInfoArray(env, package->events));
167 return packageObj;
168 }
169
SetRow(int row)170 void NapiAppEventHolder::SetRow(int row)
171 {
172 HILOG_INFO(LOG_CORE, "hodler seq=%{public}" PRId64 " set row=%{public}d", observerSeq_, row);
173 takeRow_ = row;
174 hasSetRow_ = true;
175 }
176
SetSize(int size)177 void NapiAppEventHolder::SetSize(int size)
178 {
179 HILOG_INFO(LOG_CORE, "hodler seq=%{public}" PRId64 " set size=%{public}d", observerSeq_, size);
180 takeSize_ = size;
181 hasSetSize_ = true;
182 }
183
TakeNext()184 std::shared_ptr<AppEventPackage> NapiAppEventHolder::TakeNext()
185 {
186 std::vector<std::shared_ptr<AppEventPack>> events;
187 bool shouldTakeSize = hasSetSize_ && !hasSetRow_;
188 int rowNum = shouldTakeSize ? 0 : takeRow_;
189 if (AppEventStore::GetInstance().QueryEvents(events, observerSeq_, rowNum) != 0) {
190 HILOG_WARN(LOG_CORE, "failed to query events, seq=%{public}" PRId64, observerSeq_);
191 return nullptr;
192 }
193 if (events.empty()) {
194 HILOG_DEBUG(LOG_CORE, "end to query events, seq=%{public}" PRId64, observerSeq_);
195 return nullptr;
196 }
197
198 std::vector<int64_t> eventSeqs;
199 std::vector<std::string> eventStrs;
200 size_t totalSize = 0;
201 auto package = std::make_shared<AppEventPackage>();
202 for (auto event : events) {
203 std::string eventStr = event->GetEventStr();
204 if (shouldTakeSize && static_cast<int>(totalSize + eventStr.size()) > takeSize_) {
205 HILOG_INFO(LOG_CORE, "stop to take data, totalSize=%{public}zu, takeSize=%{public}d",
206 totalSize, takeSize_);
207 break;
208 }
209 totalSize += eventStr.size();
210 eventStrs.emplace_back(eventStr);
211 eventSeqs.emplace_back(event->GetSeq());
212 package->events.emplace_back(event);
213 }
214 if (eventStrs.empty()) {
215 HILOG_INFO(LOG_CORE, "take data is empty, seq=%{public}" PRId64, observerSeq_);
216 return nullptr;
217 }
218 if (!AppEventStore::GetInstance().DeleteData(observerSeq_, eventSeqs)) {
219 HILOG_INFO(LOG_CORE, "failed to delete mapping data, seq=%{public}" PRId64, observerSeq_);
220 return nullptr;
221 }
222
223 package->packageId = packageId_++;
224 package->row = static_cast<int>(eventStrs.size());
225 package->size = static_cast<int>(totalSize);
226 package->data = eventStrs;
227 return package;
228 }
229 } // namespace HiviewDFX
230 } // namespace OHOS
231