• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &paramArray));
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