1 /*
2 * Copyright (c) 2021-2022 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 <future>
17 #include <napi/native_api.h>
18 #include <napi/native_node_api.h>
19 #include <queue>
20 #include <set>
21 #include <string>
22 #include <unistd.h>
23 #include "json.hpp"
24 #include "common_utilities_hpp.h"
25 #include "frontend_api_defines.h"
26 #include "ipc_transactor.h"
27
28 namespace OHOS::uitest {
29 using namespace nlohmann;
30 using namespace std;
31
32 static constexpr size_t NAPI_MAX_BUF_LEN = 1024;
33 static constexpr size_t NAPI_MAX_ARG_COUNT = 8;
34 static constexpr size_t BACKEND_OBJ_GC_BATCH = 100;
35 // type of unexpected or napi-internal error
36 static constexpr napi_status NAPI_ERR = napi_status::napi_generic_failure;
37 // the name of property that represents the objectRef of the backend object
38 static constexpr char PROP_BACKEND_OBJ_REF[] = "backendObjRef";
39 /**For dfx usage, records the uncalled js apis. */
40 static set<string> g_unCalledJsFuncNames;
41 /**For gc usage, records the backend objRefs about to delete. */
42 static queue<string> g_backendObjsAboutToDelete;
43 static mutex g_gcQueueMutex;
44 /**IPC client. */
45 static ApiTransactor g_apiTransactClient(false);
46 static future<void> g_establishConnectionFuture;
47
48 /** Convert js string to cpp string.*/
JsStrToCppStr(napi_env env,napi_value jsStr)49 static string JsStrToCppStr(napi_env env, napi_value jsStr)
50 {
51 if (jsStr == nullptr) {
52 return "";
53 }
54 napi_valuetype type;
55 NAPI_CALL_BASE(env, napi_typeof(env, jsStr, &type), "");
56 if (type == napi_undefined || type == napi_null) {
57 return "";
58 }
59 size_t bufSize = 0;
60 char buf[NAPI_MAX_BUF_LEN] = {0};
61 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, jsStr, buf, NAPI_MAX_BUF_LEN, &bufSize), "");
62 return string(buf, bufSize);
63 }
64
65 /**Lifecycle function, establish connection async, called externally.*/
ScheduleEstablishConnection(napi_env env,napi_callback_info info)66 static napi_value ScheduleEstablishConnection(napi_env env, napi_callback_info info)
67 {
68 size_t argc = 1;
69 napi_value value = nullptr;
70 napi_value argv[1] = {0};
71 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &value, nullptr));
72 NAPI_ASSERT(env, argc > 0, "Need session token argument!");
73 auto token = JsStrToCppStr(env, argv[0]);
74 g_establishConnectionFuture = async(launch::async, [token]() {
75 auto result = g_apiTransactClient.InitAndConnectPeer(token, nullptr);
76 LOG_I("End setup transaction connection, result=%{public}d", result);
77 });
78 return nullptr;
79 }
80
81 /**Wait connection result sync if need.*/
WaitForConnectionIfNeed()82 static void WaitForConnectionIfNeed()
83 {
84 if (g_establishConnectionFuture.valid()) {
85 LOG_I("Begin WaitForConnection");
86 g_establishConnectionFuture.get();
87 }
88 }
89
90 /**Encapsulates the data objects needed in once api transaction.*/
91 struct TransactionContext {
92 napi_value jsThis_ = nullptr;
93 ApiCallInfo callInfo_;
94 };
95
CreateJsException(napi_env env,uint32_t code,string_view msg)96 static napi_value CreateJsException(napi_env env, uint32_t code, string_view msg)
97 {
98 napi_value codeValue, msgValue, errorValue;
99 napi_create_uint32(env, code, &codeValue);
100 napi_create_string_utf8(env, msg.data(), NAPI_AUTO_LENGTH, &msgValue);
101 napi_create_error(env, nullptr, msgValue, &errorValue);
102 napi_set_named_property(env, errorValue, "code", codeValue);
103 return errorValue;
104 }
105
106 /**Set object constructor function to global as attribute.*/
MountJsConstructorToGlobal(napi_env env,string_view typeName,napi_value function)107 static napi_status MountJsConstructorToGlobal(napi_env env, string_view typeName, napi_value function)
108 {
109 NAPI_ASSERT_BASE(env, function != nullptr, "Null constructor function", napi_invalid_arg);
110 const string name = "constructor_" + string(typeName);
111 napi_value global = nullptr;
112 NAPI_CALL_BASE(env, napi_get_global(env, &global), NAPI_ERR);
113 NAPI_CALL_BASE(env, napi_set_named_property(env, global, name.c_str(), function), NAPI_ERR);
114 return napi_ok;
115 }
116
117 /**Get object constructor function from global as attribute.*/
GetJsConstructorFromGlobal(napi_env env,string_view typeName,napi_value * pFunction)118 static napi_status GetJsConstructorFromGlobal(napi_env env, string_view typeName, napi_value *pFunction)
119 {
120 NAPI_ASSERT_BASE(env, pFunction != nullptr, "Null constructor receiver", napi_invalid_arg);
121 const string name = "constructor_" + string(typeName);
122 napi_value global = nullptr;
123 NAPI_CALL_BASE(env, napi_get_global(env, &global), NAPI_ERR);
124 NAPI_CALL_BASE(env, napi_get_named_property(env, global, name.c_str(), pFunction), NAPI_ERR);
125 return napi_ok;
126 }
127
128 /**Conversion between value and string, using the builtin JSON methods.*/
ValueStringConvert(napi_env env,napi_value in,napi_value * out,bool stringify)129 static napi_status ValueStringConvert(napi_env env, napi_value in, napi_value *out, bool stringify)
130 {
131 if (in == nullptr || out == nullptr) {
132 return napi_invalid_arg;
133 }
134 napi_value global = nullptr;
135 napi_value jsonProp = nullptr;
136 napi_value jsonFunc = nullptr;
137 NAPI_CALL_BASE(env, napi_get_global(env, &global), NAPI_ERR);
138 NAPI_CALL_BASE(env, napi_get_named_property(env, global, "JSON", &jsonProp), NAPI_ERR);
139 if (stringify) {
140 NAPI_CALL_BASE(env, napi_get_named_property(env, jsonProp, "stringify", &jsonFunc), NAPI_ERR);
141 } else {
142 NAPI_CALL_BASE(env, napi_get_named_property(env, jsonProp, "parse", &jsonFunc), NAPI_ERR);
143 }
144 napi_value argv[1] = {in};
145 NAPI_CALL_BASE(env, napi_call_function(env, jsonProp, jsonFunc, 1, argv, out), NAPI_ERR);
146 return napi_ok;
147 }
148
149 /**Unmarshal object from json, throw error and return false if the object cannot be deserialized.*/
UnmarshalObject(napi_env env,const json & in,napi_value * pOut,napi_value jsThis)150 static napi_status UnmarshalObject(napi_env env, const json &in, napi_value *pOut, napi_value jsThis)
151 {
152 NAPI_ASSERT_BASE(env, pOut != nullptr, "Illegal arguments", napi_invalid_arg);
153 const auto type = in.type();
154 if (type == nlohmann::detail::value_t::null) { // return null
155 NAPI_CALL_BASE(env, napi_get_null(env, pOut), NAPI_ERR);
156 return napi_ok;
157 }
158 if (type != nlohmann::detail::value_t::string) { // non-string value, convert and return object
159 NAPI_CALL_BASE(env, napi_create_string_utf8(env, in.dump().c_str(), NAPI_AUTO_LENGTH, pOut), NAPI_ERR);
160 NAPI_CALL_BASE(env, ValueStringConvert(env, *pOut, pOut, false), NAPI_ERR);
161 return napi_ok;
162 }
163 const auto cppString = in.get<string>();
164 string frontendTypeName;
165 bool bindJsThis = false;
166 for (const auto &classDef : FRONTEND_CLASS_DEFS) {
167 const auto objRefFormat = string(classDef->name_) + "#";
168 if (cppString.find(objRefFormat) == 0) {
169 frontendTypeName = string(classDef->name_);
170 bindJsThis = classDef->bindUiDriver_;
171 break;
172 }
173 }
174 NAPI_CALL_BASE(env, napi_create_string_utf8(env, cppString.c_str(), NAPI_AUTO_LENGTH, pOut), NAPI_ERR);
175 if (frontendTypeName.empty()) { // plain string, return it
176 return napi_ok;
177 }
178 LOG_D("Convert to frontend object: '%{public}s'", frontendTypeName.c_str());
179 // covert to wrapper object and bind the backend objectRef
180 napi_value refValue = *pOut;
181 napi_value constructor = nullptr;
182 NAPI_CALL_BASE(env, GetJsConstructorFromGlobal(env, frontendTypeName, &constructor), NAPI_ERR);
183 NAPI_CALL_BASE(env, napi_new_instance(env, constructor, 1, &refValue, pOut), NAPI_ERR);
184 NAPI_CALL_BASE(env, napi_set_named_property(env, *pOut, PROP_BACKEND_OBJ_REF, refValue), NAPI_ERR);
185 if (bindJsThis) { // bind the jsThis object
186 LOG_D("Bind jsThis");
187 NAPI_ASSERT_BASE(env, jsThis != nullptr, "null jsThis", NAPI_ERR);
188 NAPI_CALL_BASE(env, napi_set_named_property(env, *pOut, "boundObject", jsThis), NAPI_ERR);
189 }
190 return napi_ok;
191 }
192
193 /**Evaluate and convert transaction reply to object. Return the exception raised during the
194 * transaction if any, else return the result object. */
UnmarshalReply(napi_env env,const TransactionContext & ctx,const ApiReplyInfo & reply)195 static napi_value UnmarshalReply(napi_env env, const TransactionContext &ctx, const ApiReplyInfo &reply)
196 {
197 LOG_D("Start to Unmarshal transaction result");
198 const auto &message = reply.exception_.message_;
199 ErrCode code = reply.exception_.code_;
200 if (code == INTERNAL_ERROR || code == ERR_INTERNAL) {
201 LOG_E("ErrorInfo: code='%{public}u', message='%{public}s'", code, message.c_str());
202 } else if (reply.exception_.code_ != NO_ERROR) {
203 LOG_I("ErrorInfo: code='%{public}u', message='%{public}s'", code, message.c_str());
204 return CreateJsException(env, code, message);
205 }
206 LOG_D("Start to Unmarshal return value: %{public}s", reply.resultValue_.dump().c_str());
207 const auto resultType = reply.resultValue_.type();
208 napi_value result = nullptr;
209 if (resultType == nlohmann::detail::value_t::null) { // return null
210 NAPI_CALL(env, napi_get_null(env, &result));
211 } else if (resultType == nlohmann::detail::value_t::array) { // return array
212 NAPI_CALL(env, napi_create_array_with_length(env, reply.resultValue_.size(), &result));
213 for (size_t idx = 0; idx < reply.resultValue_.size(); idx++) {
214 napi_value item = nullptr;
215 NAPI_CALL(env, UnmarshalObject(env, reply.resultValue_.at(idx), &item, ctx.jsThis_));
216 NAPI_CALL(env, napi_set_element(env, result, idx, item));
217 }
218 } else { // return single value
219 NAPI_CALL(env, UnmarshalObject(env, reply.resultValue_, &result, ctx.jsThis_));
220 }
221 return result;
222 }
223
224 /**Call api with parameters out, wait for and return result value or throw raised exception.*/
TransactSync(napi_env env,TransactionContext & ctx)225 napi_value TransactSync(napi_env env, TransactionContext &ctx)
226 {
227 WaitForConnectionIfNeed();
228 LOG_D("TargetApi=%{public}s", ctx.callInfo_.apiId_.data());
229 auto reply = ApiReplyInfo();
230 g_apiTransactClient.Transact(ctx.callInfo_, reply);
231 auto resultValue = UnmarshalReply(env, ctx, reply);
232 auto isError = false;
233 NAPI_CALL(env, napi_is_error(env, resultValue, &isError));
234 if (isError) {
235 NAPI_CALL(env, napi_throw(env, resultValue));
236 NAPI_CALL(env, napi_get_undefined(env, &resultValue)); // return undefined it's error
237 }
238 // notify backend objects deleting
239 if (g_backendObjsAboutToDelete.size() >= BACKEND_OBJ_GC_BATCH) {
240 auto gcCall = ApiCallInfo {.apiId_ = "BackendObjectsCleaner"};
241 unique_lock<mutex> lock(g_gcQueueMutex);
242 for (size_t count = 0; count < BACKEND_OBJ_GC_BATCH; count++) {
243 gcCall.paramList_.emplace_back(g_backendObjsAboutToDelete.front());
244 g_backendObjsAboutToDelete.pop();
245 }
246 lock.unlock();
247 auto gcReply = ApiReplyInfo();
248 g_apiTransactClient.Transact(gcCall, gcReply);
249 }
250 return resultValue;
251 }
252
253 /**Encapsulates the data objects needed for async transaction.*/
254 struct AsyncTransactionCtx {
255 TransactionContext ctx_;
256 ApiReplyInfo reply_;
257 napi_async_work asyncWork_ = nullptr;
258 napi_deferred deferred_ = nullptr;
259 napi_ref jsThisRef_ = nullptr;
260 };
261
262 /**Call api with parameters out, return a promise.*/
TransactAsync(napi_env env,TransactionContext & ctx)263 static napi_value TransactAsync(napi_env env, TransactionContext &ctx)
264 {
265 constexpr uint32_t refCount = 1;
266 LOG_D("TargetApi=%{public}s", ctx.callInfo_.apiId_.data());
267 napi_value resName;
268 NAPI_CALL(env, napi_create_string_latin1(env, __FUNCTION__, NAPI_AUTO_LENGTH, &resName));
269 auto aCtx = new AsyncTransactionCtx();
270 aCtx->ctx_ = ctx;
271 napi_value promise;
272 NAPI_CALL(env, napi_create_promise(env, &(aCtx->deferred_), &promise));
273 NAPI_CALL(env, napi_create_reference(env, ctx.jsThis_, refCount, &(aCtx->jsThisRef_)));
274 napi_create_async_work(
275 env, nullptr, resName,
276 [](napi_env env, void *data) {
277 auto aCtx = reinterpret_cast<AsyncTransactionCtx *>(data);
278 // NOT:: use 'auto&' rather than 'auto', or the result will be set to copy-constructed temp-object
279 auto &ctx = aCtx->ctx_;
280 g_apiTransactClient.Transact(ctx.callInfo_, aCtx->reply_);
281 },
282 [](napi_env env, napi_status status, void *data) {
283 auto aCtx = reinterpret_cast<AsyncTransactionCtx *>(data);
284 napi_get_reference_value(env, aCtx->jsThisRef_, &(aCtx->ctx_.jsThis_));
285 auto resultValue = UnmarshalReply(env, aCtx->ctx_, aCtx->reply_);
286 napi_delete_reference(env, aCtx->jsThisRef_);
287 auto isError = false;
288 napi_is_error(env, resultValue, &isError);
289 if (isError) {
290 napi_reject_deferred(env, aCtx->deferred_, resultValue);
291 } else {
292 napi_resolve_deferred(env, aCtx->deferred_, resultValue);
293 }
294 delete aCtx;
295 },
296 (void *)aCtx, &(aCtx->asyncWork_));
297 napi_queue_async_work(env, aCtx->asyncWork_);
298 return promise;
299 }
300
GetBackendObjRefProp(napi_env env,napi_value value,napi_value * pOut)301 static napi_status GetBackendObjRefProp(napi_env env, napi_value value, napi_value* pOut)
302 {
303 napi_valuetype type = napi_undefined;
304 NAPI_CALL_BASE(env, napi_typeof(env, value, &type), NAPI_ERR);
305 if (type != napi_object) {
306 *pOut = nullptr;
307 return napi_ok;
308 }
309 bool hasRef = false;
310 NAPI_CALL_BASE(env, napi_has_named_property(env, value, PROP_BACKEND_OBJ_REF, &hasRef), NAPI_ERR);
311 if (!hasRef) {
312 *pOut = nullptr;
313 } else {
314 NAPI_CALL_BASE(env, napi_get_named_property(env, value, PROP_BACKEND_OBJ_REF, pOut), NAPI_ERR);
315 }
316 return napi_ok;
317 }
318
319 /**Generic js-api callback.*/
GenericCallback(napi_env env,napi_callback_info info)320 static napi_value GenericCallback(napi_env env, napi_callback_info info)
321 {
322 // extract callback data
323 TransactionContext ctx;
324 napi_value argv[NAPI_MAX_ARG_COUNT] = {nullptr};
325 auto count = NAPI_MAX_ARG_COUNT;
326 void *pData = nullptr;
327 NAPI_CALL(env, napi_get_cb_info(env, info, &count, argv, &(ctx.jsThis_), &pData));
328 NAPI_ASSERT(env, pData != nullptr, "Null methodDef");
329 auto methodDef = reinterpret_cast<const FrontendMethodDef *>(pData);
330 g_unCalledJsFuncNames.erase(string(methodDef->name_)); // api used
331 // 1. marshal parameters into json-array
332 napi_value paramArray = nullptr;
333 NAPI_CALL(env, napi_create_array_with_length(env, count, ¶mArray));
334 if (count > NAPI_MAX_ARG_COUNT) {
335 count = NAPI_MAX_ARG_COUNT;
336 }
337 for (size_t idx = 0; idx < count; idx++) {
338 napi_value item = nullptr; // convert to backendObjRef if any
339 NAPI_CALL(env, GetBackendObjRefProp(env, argv[idx], &item));
340 if (item == nullptr) {
341 item = argv[idx];
342 }
343 NAPI_CALL(env, napi_set_element(env, paramArray, idx, item));
344 }
345 napi_value jsTempObj = nullptr;
346 NAPI_CALL(env, ValueStringConvert(env, paramArray, &jsTempObj, true));
347 ctx.callInfo_.paramList_ = nlohmann::json::parse(JsStrToCppStr(env, jsTempObj));
348 // 2. marshal jsThis into json (backendObjRef)
349 if (!methodDef->static_) {
350 NAPI_CALL(env, GetBackendObjRefProp(env, ctx.jsThis_, &jsTempObj));
351 ctx.callInfo_.callerObjRef_ = JsStrToCppStr(env, jsTempObj);
352 }
353 // 3. fill-in apiId
354 ctx.callInfo_.apiId_ = methodDef->name_;
355 // 4. call out, sync or async
356 if (methodDef->fast_) {
357 return TransactSync(env, ctx);
358 } else {
359 return TransactAsync(env, ctx);
360 }
361 }
362
363 /**Exports uitest js wrapper-classes and its global constructor.*/
ExportClass(napi_env env,napi_value exports,const FrontEndClassDef & classDef)364 static napi_status ExportClass(napi_env env, napi_value exports, const FrontEndClassDef &classDef)
365 {
366 NAPI_ASSERT_BASE(env, exports != nullptr, "Illegal export params", NAPI_ERR);
367 const auto name = classDef.name_.data();
368 const auto methodNeatNameOffset = classDef.name_.length() + 1;
369 auto descs = make_unique<napi_property_descriptor[]>(classDef.methodCount_);
370 for (size_t idx = 0; idx < classDef.methodCount_; idx++) {
371 const auto &methodDef = classDef.methods_[idx];
372 g_unCalledJsFuncNames.insert(string(methodDef.name_));
373 const auto neatName = methodDef.name_.substr(methodNeatNameOffset);
374 napi_property_descriptor desc = DECLARE_NAPI_FUNCTION(neatName.data(), GenericCallback);
375 if (methodDef.static_) {
376 desc.attributes = napi_static;
377 }
378 desc.data = (void *)(&methodDef);
379 descs[idx] = desc;
380 }
381 constexpr auto initializer = [](napi_env env, napi_callback_info info) {
382 auto argc = NAPI_MAX_ARG_COUNT;
383 napi_value argv[NAPI_MAX_ARG_COUNT] = { nullptr };
384 napi_value jsThis = nullptr;
385 NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr), jsThis);
386 auto ref = make_unique<string>(argc <= 0 ? "" : JsStrToCppStr(env, argv[0]));
387 auto finalizer = [](napi_env env, void *data, void *hint) {
388 auto ref = reinterpret_cast<string *>(data);
389 if (ref->length() > 0) {
390 LOG_D("Finalizing object: %{public}s", ref->c_str());
391 unique_lock<mutex> lock(g_gcQueueMutex);
392 g_backendObjsAboutToDelete.push(*ref);
393 }
394 delete ref;
395 };
396 NAPI_CALL_BASE(env, napi_wrap(env, jsThis, ref.release(), finalizer, nullptr, nullptr), jsThis);
397 return jsThis;
398 };
399 // define class, provide the js-class members(property) and initializer.
400 napi_value ctor = nullptr;
401 NAPI_CALL_BASE(env, napi_define_class(env, name, NAPI_AUTO_LENGTH, initializer, nullptr,
402 classDef.methodCount_, descs.get(), &ctor), NAPI_ERR);
403 NAPI_CALL_BASE(env, napi_set_named_property(env, exports, name, ctor), NAPI_ERR);
404 NAPI_CALL_BASE(env, MountJsConstructorToGlobal(env, name, ctor), NAPI_ERR);
405 if (string_view(name) == "On" || string_view(name) == "By") {
406 // create seed-On/By with special objectRef and mount to exporter
407 auto seedName = string_view(name) == "On" ? "ON" : "BY";
408 auto seedRef = string_view(name) == "On" ? REF_SEED_ON.data() : REF_SEED_BY.data();
409 napi_value seed = nullptr;
410 NAPI_CALL_BASE(env, napi_new_instance(env, ctor, 0, nullptr, &seed), NAPI_ERR);
411 napi_value prop = nullptr;
412 NAPI_CALL_BASE(env, napi_create_string_utf8(env, seedRef, NAPI_AUTO_LENGTH, &prop), NAPI_ERR);
413 NAPI_CALL_BASE(env, napi_set_named_property(env, seed, PROP_BACKEND_OBJ_REF, prop), NAPI_ERR);
414 NAPI_CALL_BASE(env, napi_set_named_property(env, exports, seedName, seed), NAPI_ERR);
415 }
416 return napi_ok;
417 }
418
419 /**Exports enumerator class.*/
ExportEnumerator(napi_env env,napi_value exports,const FrontendEnumeratorDef & enumDef)420 static napi_status ExportEnumerator(napi_env env, napi_value exports, const FrontendEnumeratorDef &enumDef)
421 {
422 NAPI_ASSERT_BASE(env, exports != nullptr, "Illegal export params", NAPI_ERR);
423 napi_value enumerator;
424 NAPI_CALL_BASE(env, napi_create_object(env, &enumerator), NAPI_ERR);
425 for (size_t idx = 0; idx < enumDef.valueCount_; idx++) {
426 const auto &def = enumDef.values_[idx];
427 napi_value prop = nullptr;
428 NAPI_CALL_BASE(env, napi_create_string_utf8(env, def.valueJson_.data(), NAPI_AUTO_LENGTH, &prop), NAPI_ERR);
429 NAPI_CALL_BASE(env, ValueStringConvert(env, prop, &prop, false), NAPI_ERR);
430 NAPI_CALL_BASE(env, napi_set_named_property(env, enumerator, def.name_.data(), prop), NAPI_ERR);
431 }
432 NAPI_CALL_BASE(env, napi_set_named_property(env, exports, enumDef.name_.data(), enumerator), NAPI_ERR);
433 return napi_ok;
434 }
435
436 /**Function used for statistics, return an array of uncalled js-api names.*/
GetUnCalledJsApis(napi_env env,napi_callback_info info)437 static napi_value GetUnCalledJsApis(napi_env env, napi_callback_info info)
438 {
439 napi_value nameArray;
440 NAPI_CALL(env, napi_create_array_with_length(env, g_unCalledJsFuncNames.size(), &nameArray));
441 size_t idx = 0;
442 for (auto &name : g_unCalledJsFuncNames) {
443 napi_value nameItem = nullptr;
444 NAPI_CALL(env, napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &nameItem));
445 NAPI_CALL(env, napi_set_element(env, nameArray, idx, nameItem));
446 idx++;
447 }
448 return nameArray;
449 }
450
Export(napi_env env,napi_value exports)451 napi_value Export(napi_env env, napi_value exports)
452 {
453 LOG_I("Begin export uitest apis");
454 // export transaction-environment-lifecycle callbacks and dfx functions
455 napi_property_descriptor props[] = {
456 DECLARE_NAPI_STATIC_FUNCTION("scheduleEstablishConnection", ScheduleEstablishConnection),
457 DECLARE_NAPI_STATIC_FUNCTION("getUnCalledJsApis", GetUnCalledJsApis),
458 };
459 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(props) / sizeof(props[0]), props));
460 NAPI_CALL(env, ExportClass(env, exports, BY_DEF));
461 NAPI_CALL(env, ExportClass(env, exports, UI_DRIVER_DEF));
462 NAPI_CALL(env, ExportClass(env, exports, UI_COMPONENT_DEF));
463 NAPI_CALL(env, ExportClass(env, exports, ON_DEF));
464 NAPI_CALL(env, ExportClass(env, exports, DRIVER_DEF));
465 NAPI_CALL(env, ExportClass(env, exports, COMPONENT_DEF));
466 NAPI_CALL(env, ExportClass(env, exports, UI_WINDOW_DEF));
467 NAPI_CALL(env, ExportClass(env, exports, POINTER_MATRIX_DEF));
468 NAPI_CALL(env, ExportEnumerator(env, exports, MATCH_PATTERN_DEF));
469 NAPI_CALL(env, ExportEnumerator(env, exports, RESIZE_DIRECTION_DEF));
470 NAPI_CALL(env, ExportEnumerator(env, exports, WINDOW_MODE_DEF));
471 NAPI_CALL(env, ExportEnumerator(env, exports, DISPLAY_ROTATION_DEF));
472 LOG_I("End export uitest apis");
473 return exports;
474 }
475
476 static napi_module module = {
477 .nm_version = 1,
478 .nm_flags = 0,
479 .nm_filename = nullptr,
480 .nm_register_func = Export,
481 .nm_modname = "UiTest",
482 .nm_priv = ((void *)0),
483 .reserved = {0},
484 };
485
RegisterModule(void)486 extern "C" __attribute__((constructor)) void RegisterModule(void)
487 {
488 napi_module_register(&module);
489 }
490 } // namespace OHOS::uitest
491
492 // put register functions out of namespace to ensure C-linkage
493 extern const char _binary_uitest_exporter_js_start[];
494 extern const char _binary_uitest_exporter_js_end[];
495 extern const char _binary_uitest_exporter_abc_start[];
496 extern const char _binary_uitest_exporter_abc_end[];
497
NAPI_UiTest_GetJSCode(const char ** buf,int * bufLen)498 extern "C" __attribute__((visibility("default"))) void NAPI_UiTest_GetJSCode(const char **buf, int *bufLen)
499 {
500 if (buf != nullptr) {
501 *buf = _binary_uitest_exporter_js_start;
502 }
503 if (bufLen != nullptr) {
504 *bufLen = _binary_uitest_exporter_js_end - _binary_uitest_exporter_js_start;
505 }
506 }
507
NAPI_UiTest_GetABCCode(const char ** buf,int * bufLen)508 extern "C" __attribute__((visibility("default"))) void NAPI_UiTest_GetABCCode(const char **buf, int *bufLen)
509 {
510 if (buf != nullptr) {
511 *buf = _binary_uitest_exporter_abc_start;
512 }
513 if (bufLen != nullptr) {
514 *bufLen = _binary_uitest_exporter_abc_end - _binary_uitest_exporter_abc_start;
515 }
516 }
517