• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "napi_remote_object_holder.h"
17 #include "napi_remote_object_internal.h"
18 
19 #include <hitrace_meter.h>
20 #include <string_ex.h>
21 #include <uv.h>
22 
23 #include "ipc_debug.h"
24 #include "ipc_process_skeleton.h"
25 #include "ipc_thread_skeleton.h"
26 #include "iremote_invoker.h"
27 #include "log_tags.h"
28 #include "napi/native_api.h"
29 #include "napi/native_node_api.h"
30 #include "napi_message_parcel.h"
31 #include "napi_message_sequence.h"
32 #include "napi_remote_proxy_holder.h"
33 #include "napi_rpc_error.h"
34 #include "native_engine/native_value.h"
35 #include "napi_process_skeleton.h"
36 
37 namespace OHOS {
38 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC_NAPI, "napi_remoteObject" };
39 
40 static const size_t ARGV_INDEX_0 = 0;
41 static const size_t ARGV_INDEX_1 = 1;
42 static const size_t ARGV_INDEX_2 = 2;
43 static const size_t ARGV_INDEX_3 = 3;
44 static const size_t ARGV_INDEX_4 = 4;
45 
46 static const size_t ARGV_LENGTH_1 = 1;
47 static const size_t ARGV_LENGTH_2 = 2;
48 static const size_t ARGV_LENGTH_4 = 4;
49 static const size_t ARGV_LENGTH_5 = 5;
50 
51 static const size_t DEVICE_ID_LENGTH = 64;
52 
53 static const uint64_t HITRACE_TAG_RPC = (1ULL << 46); // RPC and IPC tag.
54 
55 static std::atomic<int32_t> bytraceId = 1000;
56 static NapiError napiErr;
57 
IsValidParamWithNotify(napi_value value,CallbackParam * param,const char * errDesc)58 static bool IsValidParamWithNotify(napi_value value, CallbackParam *param, const char *errDesc)
59 {
60     if (value == nullptr) {
61         ZLOGE(LOG_LABEL, "%{public}s", errDesc);
62         param->result = IPC_INVALID_PARAM_ERR;
63         std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
64         param->lockInfo->ready = true;
65         param->lockInfo->condition.notify_all();
66         return false;
67     }
68     return true;
69 }
70 
GetJsOnRemoteRequestCallback(CallbackParam * param,const napi_value thisVar,napi_value & onRemoteRequest,bool & isOnRemoteMessageRequest)71 static bool GetJsOnRemoteRequestCallback(CallbackParam *param, const napi_value thisVar, napi_value &onRemoteRequest,
72     bool &isOnRemoteMessageRequest)
73 {
74     napi_get_named_property(param->env, thisVar, "onRemoteMessageRequest", &onRemoteRequest);
75     if (!IsValidParamWithNotify(onRemoteRequest, param, "get function onRemoteMessageRequest failed")) {
76         return false;
77     }
78     isOnRemoteMessageRequest = true;
79 
80     napi_valuetype type = napi_undefined;
81     napi_typeof(param->env, onRemoteRequest, &type);
82     if (type != napi_function) {
83         napi_get_named_property(param->env, thisVar, "onRemoteRequest", &onRemoteRequest);
84         if (!IsValidParamWithNotify(onRemoteRequest, param, "get function onRemoteRequest failed")) {
85             return false;
86         }
87         isOnRemoteMessageRequest = false;
88     }
89     return true;
90 }
91 
CreateJsOption(CallbackParam * param,const napi_value global,napi_value & jsOption)92 static bool CreateJsOption(CallbackParam *param, const napi_value global, napi_value &jsOption)
93 {
94     napi_value jsOptionConstructor = nullptr;
95     napi_get_named_property(param->env, global, "IPCOptionConstructor_", &jsOptionConstructor);
96     if (!IsValidParamWithNotify(jsOptionConstructor, param, "jsOption constructor is null")) {
97         return false;
98     }
99 
100     size_t argc = ARGV_LENGTH_2;
101     napi_value flags = nullptr;
102     napi_create_int32(param->env, param->option->GetFlags(), &flags);
103     napi_value waittime = nullptr;
104     napi_create_int32(param->env, param->option->GetWaitTime(), &waittime);
105     napi_value argv[ARGV_LENGTH_2] = { flags, waittime };
106     napi_new_instance(param->env, jsOptionConstructor, argc, argv, &jsOption);
107     if (!IsValidParamWithNotify(jsOption, param, "new jsOption failed")) {
108         return false;
109     }
110     return true;
111 }
112 
GetJsParcelConstructor(CallbackParam * param,const napi_value global,bool isOnRemoteMessageRequest,napi_value & jsParcelConstructor)113 static bool GetJsParcelConstructor(CallbackParam *param, const napi_value global, bool isOnRemoteMessageRequest,
114     napi_value &jsParcelConstructor)
115 {
116     if (isOnRemoteMessageRequest) {
117         napi_get_named_property(param->env, global, "IPCSequenceConstructor_", &jsParcelConstructor);
118     } else {
119         napi_get_named_property(param->env, global, "IPCParcelConstructor_", &jsParcelConstructor);
120     }
121     if (!IsValidParamWithNotify(jsParcelConstructor, param, "jsParcel constructor is null")) {
122         return false;
123     }
124     return true;
125 }
126 
CreateJsParcel(CallbackParam * param,const napi_value jsParcelConstructor,napi_value & jsParcel,bool isJsDataParcel)127 static bool CreateJsParcel(CallbackParam *param, const napi_value jsParcelConstructor, napi_value &jsParcel,
128     bool isJsDataParcel)
129 {
130     napi_value parcel;
131     napi_create_object(param->env, &parcel);
132     napi_wrap(param->env, parcel, isJsDataParcel ? param->data : param->reply,
133         [](napi_env env, void *data, void *hint) {}, nullptr, nullptr);
134 
135     if (!IsValidParamWithNotify(parcel, param, "create js parcel object failed")) {
136         return false;
137     }
138 
139     size_t argc = 1;
140     napi_value argv[1] = { parcel };
141     napi_new_instance(param->env, jsParcelConstructor, argc, argv, &jsParcel);
142     if (!IsValidParamWithNotify(parcel, param,
143         isJsDataParcel ? "create js data parcel failed" : "create js reply parcel failed")) {
144         return false;
145     }
146     return true;
147 }
148 
IsPromiseResult(CallbackParam * param,const napi_value returnVal)149 static bool IsPromiseResult(CallbackParam *param, const napi_value returnVal)
150 {
151     bool isPromise = false;
152     napi_is_promise(param->env, returnVal, &isPromise);
153     if (!isPromise) {
154         ZLOGD(LOG_LABEL, "onRemoteRequest is synchronous");
155         bool result = false;
156         napi_get_value_bool(param->env, returnVal, &result);
157         if (!result) {
158             uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
159                 std::chrono::steady_clock::now().time_since_epoch()).count());
160             ZLOGE(LOG_LABEL, "OnRemoteRequest result:false, time:%{public}" PRIu64, curTime);
161             param->result = ERR_UNKNOWN_TRANSACTION;
162         } else {
163             param->result = ERR_NONE;
164         }
165         return false;
166     }
167     return true;
168 }
169 
GetPromiseThen(CallbackParam * param,const napi_value returnVal,napi_value & promiseThen)170 static bool GetPromiseThen(CallbackParam *param, const napi_value returnVal, napi_value &promiseThen)
171 {
172     napi_get_named_property(param->env, returnVal, "then", &promiseThen);
173     if (promiseThen == nullptr) {
174         ZLOGE(LOG_LABEL, "get promiseThen failed");
175         param->result = IPC_INVALID_PARAM_ERR;
176         return false;
177     }
178     return true;
179 }
180 
NAPI_RemoteObject_saveOldCallingInfoInner(napi_env env,CallingInfo & oldCallingInfo)181 static void NAPI_RemoteObject_saveOldCallingInfoInner(napi_env env, CallingInfo &oldCallingInfo)
182 {
183     napi_value global = nullptr;
184     napi_get_global(env, &global);
185     napi_value value = nullptr;
186     napi_get_named_property(env, global, "callingPid_", &value);
187     napi_get_value_int32(env, value, &oldCallingInfo.callingPid);
188     napi_get_named_property(env, global, "callingUid_", &value);
189     napi_get_value_int32(env, value, &oldCallingInfo.callingUid);
190     napi_get_named_property(env, global, "callingTokenId_", &value);
191     napi_get_value_uint32(env, value, &oldCallingInfo.callingTokenId);
192     napi_get_named_property(env, global, "callingDeviceID_", &value);
193     char deviceID[DEVICE_ID_LENGTH + 1] = { 0 };
194     size_t deviceLength = 0;
195     napi_get_value_string_utf8(env, global, deviceID, DEVICE_ID_LENGTH + 1, &deviceLength);
196     oldCallingInfo.callingDeviceID = deviceID;
197     char localDeviceID[DEVICE_ID_LENGTH + 1] = { 0 };
198     napi_get_named_property(env, global, "localDeviceID_", &value);
199     napi_get_value_string_utf8(env, global, localDeviceID, DEVICE_ID_LENGTH + 1, &deviceLength);
200     oldCallingInfo.localDeviceID = localDeviceID;
201     napi_get_named_property(env, global, "isLocalCalling_", &value);
202     napi_get_value_bool(env, value, &oldCallingInfo.isLocalCalling);
203     napi_get_named_property(env, global, "activeStatus_", &value);
204     napi_get_value_int32(env, value, &oldCallingInfo.activeStatus);
205 }
206 
NAPI_RemoteObject_resetOldCallingInfoInner(napi_env env,CallingInfo & oldCallingInfo)207 static void NAPI_RemoteObject_resetOldCallingInfoInner(napi_env env, CallingInfo &oldCallingInfo)
208 {
209     NAPI_RemoteObject_setNewCallingInfo(env, oldCallingInfo);
210 }
ThenCallback(napi_env env,napi_callback_info info)211 static napi_value ThenCallback(napi_env env, napi_callback_info info)
212 {
213     uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
214         std::chrono::steady_clock::now().time_since_epoch()).count());
215     ZLOGD(LOG_LABEL, "call js onRemoteRequest done, time:%{public}" PRIu64, curTime);
216     size_t argc = 1;
217     napi_value argv[ARGV_LENGTH_1] = {nullptr};
218     void* data = nullptr;
219     napi_get_cb_info(env, info, &argc, argv, nullptr, &data);
220     napi_value res;
221     CallbackParam *param = static_cast<CallbackParam *>(data);
222     if (param == nullptr) {
223         ZLOGE(LOG_LABEL, "param is null");
224         napi_get_undefined(env, &res);
225         return res;
226     }
227     bool result = false;
228     napi_get_value_bool(param->env, argv[ARGV_INDEX_0], &result);
229     if (!result) {
230         uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
231             std::chrono::steady_clock::now().time_since_epoch()).count());
232         ZLOGE(LOG_LABEL, "OnRemoteRequest result:false time:%{public}" PRIu64, curTime);
233         param->result = ERR_UNKNOWN_TRANSACTION;
234     } else {
235         param->result = ERR_NONE;
236     }
237 
238     // Reset old calling pid, uid, device id
239     NAPI_RemoteObject_resetOldCallingInfoInner(param->env, param->oldCallingInfo);
240     std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
241     param->lockInfo->ready = true;
242     param->lockInfo->condition.notify_all();
243     napi_get_undefined(env, &res);
244     return res;
245 }
246 
CreateThenCallback(CallbackParam * param,napi_value & thenValue)247 static bool CreateThenCallback(CallbackParam *param, napi_value &thenValue)
248 {
249     napi_status ret = napi_create_function(param->env, "thenCallback",
250         NAPI_AUTO_LENGTH, ThenCallback, param, &thenValue);
251     if (ret != napi_ok) {
252         ZLOGE(LOG_LABEL, "thenCallback got exception");
253         param->result = ERR_UNKNOWN_TRANSACTION;
254         return false;
255     }
256     return true;
257 }
258 
CatchCallback(napi_env env,napi_callback_info info)259 static napi_value CatchCallback(napi_env env, napi_callback_info info)
260 {
261     ZLOGD(LOG_LABEL, "call js onRemoteRequest got exception");
262     size_t argc = 1;
263     napi_value argv[ARGV_LENGTH_1] = {nullptr};
264     void* data = nullptr;
265     napi_get_cb_info(env, info, &argc, argv, nullptr, &data);
266     napi_value res;
267     CallbackParam *param = static_cast<CallbackParam *>(data);
268     if (param == nullptr) {
269         ZLOGE(LOG_LABEL, "param is null");
270         napi_get_undefined(env, &res);
271         return res;
272     }
273 
274     // Reset old calling pid, uid, device id
275     NAPI_RemoteObject_resetOldCallingInfoInner(param->env, param->oldCallingInfo);
276     param->result = ERR_UNKNOWN_TRANSACTION;
277     std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
278     param->lockInfo->ready = true;
279     param->lockInfo->condition.notify_all();
280     napi_get_undefined(env, &res);
281     return res;
282 }
283 
CreateCatchCallback(CallbackParam * param,napi_value & catchValue)284 static bool CreateCatchCallback(CallbackParam *param, napi_value &catchValue)
285 {
286     napi_status ret = napi_create_function(param->env, "catchCallback",
287         NAPI_AUTO_LENGTH, CatchCallback, param, &catchValue);
288     if (ret != napi_ok) {
289         ZLOGE(LOG_LABEL, "catchCallback got exception");
290         param->result = ERR_UNKNOWN_TRANSACTION;
291         return false;
292     }
293     return true;
294 }
295 
CallPromiseThen(CallbackParam * param,napi_value & thenValue,napi_value & catchValue,napi_value & returnVal,napi_value & promiseThen)296 static bool CallPromiseThen(CallbackParam *param, napi_value &thenValue, napi_value &catchValue,
297     napi_value &returnVal, napi_value &promiseThen)
298 {
299     napi_env env = param->env;
300     napi_value thenReturnValue;
301     constexpr uint32_t THEN_ARGC = 2;
302     napi_value thenArgv[THEN_ARGC] = { thenValue, catchValue };
303     napi_status ret = napi_call_function(env, returnVal, promiseThen, THEN_ARGC, thenArgv, &thenReturnValue);
304     if (ret != napi_ok) {
305         ZLOGE(LOG_LABEL, "PromiseThen got exception ret:%{public}d", ret);
306         param->result = ERR_UNKNOWN_TRANSACTION;
307         return false;
308     }
309     return true;
310 }
311 
CallJsOnRemoteRequestCallback(CallbackParam * param,napi_value & onRemoteRequest,napi_value & thisVar,const napi_value * argv)312 static void CallJsOnRemoteRequestCallback(CallbackParam *param, napi_value &onRemoteRequest, napi_value &thisVar,
313     const napi_value *argv)
314 {
315     NAPI_RemoteObject_saveOldCallingInfoInner(param->env, param->oldCallingInfo);
316     NAPI_RemoteObject_setNewCallingInfo(param->env, param->callingInfo);
317 
318     // start to call onRemoteRequest
319     napi_value returnVal;
320     napi_status ret = napi_call_function(param->env, thisVar, onRemoteRequest, ARGV_LENGTH_4, argv, &returnVal);
321 
322     do {
323         if (ret != napi_ok) {
324             ZLOGD(LOG_LABEL, "OnRemoteRequest got exception. ret:%{public}d", ret);
325             param->result = ERR_UNKNOWN_TRANSACTION;
326             break;
327         }
328 
329         if (!IsPromiseResult(param, returnVal)) {
330             break;
331         }
332 
333         napi_value promiseThen = nullptr;
334         if (!GetPromiseThen(param, returnVal, promiseThen)) {
335             break;
336         }
337 
338         napi_value thenValue = nullptr;
339         if (!CreateThenCallback(param, thenValue)) {
340             break;
341         }
342 
343         napi_value catchValue = nullptr;
344         if (!CreateCatchCallback(param, catchValue)) {
345             break;
346         }
347 
348         // Start to call promiseThen
349         if (!CallPromiseThen(param, thenValue, catchValue, returnVal, promiseThen)) {
350             break;
351         }
352         return;
353     } while (0);
354 
355     // Reset old calling pid, uid, device id
356     NAPI_RemoteObject_resetOldCallingInfoInner(param->env, param->oldCallingInfo);
357     std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
358     param->lockInfo->ready = true;
359     param->lockInfo->condition.notify_all();
360 }
361 
OnJsRemoteRequestCallBack(CallbackParam * param,std::string & desc)362 static void OnJsRemoteRequestCallBack(CallbackParam *param, std::string &desc)
363 {
364     uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
365         std::chrono::steady_clock::now().time_since_epoch()).count());
366 
367     ZLOGD(LOG_LABEL, "enter thread pool desc:%{public}s, time:%{public}" PRIu64, desc.c_str(), curTime);
368 
369     NapiScope napiScope(param->env);
370     if (!napiScope.IsValid()) {
371         return;
372     }
373 
374     napi_value thisVar = nullptr;
375     napi_get_reference_value(param->env, param->thisVarRef, &thisVar);
376     if (!IsValidParamWithNotify(thisVar, param, "thisVar is null")) {
377         return;
378     }
379 
380     napi_value onRemoteRequest = nullptr;
381     bool isOnRemoteMessageRequest = true;
382     if (!GetJsOnRemoteRequestCallback(param, thisVar, onRemoteRequest, isOnRemoteMessageRequest)) {
383         return;
384     }
385 
386     napi_value jsCode;
387     napi_create_uint32(param->env, param->code, &jsCode);
388 
389     napi_value global = nullptr;
390     napi_get_global(param->env, &global);
391     if (!IsValidParamWithNotify(global, param, "get napi global failed")) {
392         return;
393     }
394 
395     napi_value jsOption = nullptr;
396     napi_value jsParcelConstructor = nullptr;
397     napi_value jsData = nullptr;
398     napi_value jsReply = nullptr;
399     if (!CreateJsOption(param, global, jsOption) ||
400         !GetJsParcelConstructor(param, global, isOnRemoteMessageRequest, jsParcelConstructor) ||
401         !CreateJsParcel(param, jsParcelConstructor, jsData, true) ||
402         !CreateJsParcel(param, jsParcelConstructor, jsReply, false)) {
403         return;
404     }
405 
406     napi_value argv[ARGV_LENGTH_4] = { jsCode, jsData, jsReply, jsOption };
407     CallJsOnRemoteRequestCallback(param, onRemoteRequest, thisVar, argv);
408 }
409 
RemoteObjectHolderFinalizeCb(napi_env env,void * data,void * hint)410 static void RemoteObjectHolderFinalizeCb(napi_env env, void *data, void *hint)
411 {
412     NAPIRemoteObjectHolder *holder = reinterpret_cast<NAPIRemoteObjectHolder *>(data);
413     if (holder == nullptr) {
414         ZLOGW(LOG_LABEL, "RemoteObjectHolderFinalizeCb null holder");
415         return;
416     }
417     holder->Lock();
418     int32_t curAttachCount = holder->DecAttachCount();
419     holder->Unlock();
420     ZLOGD(LOG_LABEL, "NAPIRemoteObjectHolder destructed by js callback, curAttachCount:%{public}d", curAttachCount);
421     if (curAttachCount == 0) {
422         delete holder;
423     }
424 }
425 
DecreaseJsObjectRef(napi_env env,napi_ref ref)426 static void DecreaseJsObjectRef(napi_env env, napi_ref ref)
427 {
428     if (ref == nullptr) {
429         ZLOGI(LOG_LABEL, "ref is nullptr, do nothing");
430         return;
431     }
432 
433     uint32_t result;
434     napi_status napiStatus = napi_reference_unref(env, ref, &result);
435     NAPI_ASSERT_RETURN_VOID(env, napiStatus == napi_ok, "failed to decrease ref to js RemoteObject");
436 }
437 
IncreaseJsObjectRef(napi_env env,napi_ref ref)438 static void IncreaseJsObjectRef(napi_env env, napi_ref ref)
439 {
440     uint32_t result;
441     napi_status napiStatus = napi_reference_ref(env, ref, &result);
442     NAPI_ASSERT_RETURN_VOID(env, napiStatus == napi_ok, "failed to increase ref to js RemoteObject");
443 }
444 
RemoteObjectHolderRefCb(napi_env env,void * data,void * hint)445 static void RemoteObjectHolderRefCb(napi_env env, void *data, void *hint)
446 {
447     NAPIRemoteObjectHolder *holder = reinterpret_cast<NAPIRemoteObjectHolder *>(data);
448     NAPI_ASSERT_RETURN_VOID(env, holder != nullptr, "holder is nullptr");
449 
450     holder->Lock();
451     int32_t curAttachCount = holder->DecAttachCount();
452     holder->Unlock();
453     ZLOGD(LOG_LABEL, "RemoteObjectHolderRefCb, curAttachCount:%{public}d", curAttachCount);
454 
455     napi_ref ref = holder->GetJsObjectRef();
456     NAPI_ASSERT_RETURN_VOID(env, ref != nullptr, "ref is nullptr");
457     napi_env workerEnv = holder->GetJsObjectEnv();
458     NAPI_ASSERT_RETURN_VOID(env, workerEnv != nullptr, "workerEnv is nullptr");
459 
460     OperateJsRefParam *param = new (std::nothrow) OperateJsRefParam {
461         .env = workerEnv,
462         .thisVarRef = ref
463     };
464     NAPI_ASSERT_RETURN_VOID(workerEnv, param != nullptr, "new OperateJsRefParam failed");
465 
466     auto task = [param]() {
467         ZLOGI(LOG_LABEL, "decrease");
468         napi_handle_scope scope = nullptr;
469         napi_open_handle_scope(param->env, &scope);
470         DecreaseJsObjectRef(param->env, param->thisVarRef);
471         napi_close_handle_scope(param->env, scope);
472         delete param;
473     };
474     napi_status sendRet = napi_send_event(env, task, napi_eprio_high);
475     if (sendRet != napi_ok) {
476         ZLOGE(LOG_LABEL, "napi_send_event failed, ret:%{public}d", sendRet);
477         delete param;
478     }
479 }
480 
RemoteObjectDetachCb(napi_env engine,void * value,void * hint)481 static void *RemoteObjectDetachCb(napi_env engine, void *value, void *hint)
482 {
483     (void)hint;
484     napi_env env = engine;
485     NAPIRemoteObjectHolder *holder = reinterpret_cast<NAPIRemoteObjectHolder *>(value);
486     napi_ref ref = holder->GetJsObjectRef();
487 
488     uint32_t result;
489     napi_status napiStatus = napi_reference_ref(env, ref, &result);
490     if (napiStatus != napi_ok) {
491         ZLOGE(LOG_LABEL, "RemoteObjectDetachCb, failed to increase ref");
492     } else {
493         ZLOGI(LOG_LABEL, "RemoteObjectDetachCb, ref result:%{public}u", result);
494     }
495     return value;
496 }
497 
RemoteObjectAttachCb(napi_env engine,void * value,void * hint)498 static napi_value RemoteObjectAttachCb(napi_env engine, void *value, void *hint)
499 {
500     (void)hint;
501     NAPIRemoteObjectHolder *holder = reinterpret_cast<NAPIRemoteObjectHolder *>(value);
502     if (holder == nullptr) {
503         ZLOGE(LOG_LABEL, "holder is nullptr when attach");
504         return nullptr;
505     }
506     holder->Lock();
507     ZLOGI(LOG_LABEL, "create js remote object when attach");
508     napi_env env = engine;
509     // retrieve js remote object constructor
510     napi_value global = nullptr;
511     napi_status status = napi_get_global(env, &global);
512     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
513     napi_value constructor = nullptr;
514     status = napi_get_named_property(env, global, "IPCStubConstructor_", &constructor);
515     NAPI_ASSERT(env, status == napi_ok, "get stub constructor failed");
516     NAPI_ASSERT(env, constructor != nullptr, "failed to get js RemoteObject constructor");
517     // retrieve descriptor and it's length
518     std::u16string descriptor = holder->GetDescriptor();
519     std::string desc = Str16ToStr8(descriptor);
520     napi_value jsDesc = nullptr;
521     napi_create_string_utf8(env, desc.c_str(), desc.length(), &jsDesc);
522     // create a new js remote object
523     size_t argc = 1;
524     napi_value argv[ARGV_LENGTH_1] = { jsDesc };
525     napi_value jsRemoteObject = nullptr;
526     status = napi_new_instance(env, constructor, argc, argv, &jsRemoteObject);
527     NAPI_ASSERT(env, status == napi_ok, "failed to  construct js RemoteObject when attach");
528     // retrieve and remove create holder
529     NAPIRemoteObjectHolder *createHolder = nullptr;
530     status = napi_remove_wrap(env, jsRemoteObject, (void **)&createHolder);
531     NAPI_ASSERT(env, status == napi_ok && createHolder != nullptr, "failed to remove create holder when attach");
532     status = napi_wrap(env, jsRemoteObject, holder, RemoteObjectHolderRefCb, nullptr, nullptr);
533     NAPI_ASSERT(env, status == napi_ok, "wrap js RemoteObject and native holder failed when attach");
534     holder->IncAttachCount();
535     holder->Unlock();
536     return jsRemoteObject;
537 }
538 
RemoteObject_JS_Constructor(napi_env env,napi_callback_info info)539 napi_value RemoteObject_JS_Constructor(napi_env env, napi_callback_info info)
540 {
541     // new napi remote object
542     size_t argc = 2;
543     size_t expectedArgc = 1;
544     napi_value argv[ARGV_LENGTH_2] = { 0 };
545     napi_value thisVar = nullptr;
546     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
547     NAPI_ASSERT(env, argc >= expectedArgc, "requires at least 1 parameters");
548     napi_valuetype valueType = napi_null;
549     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
550     NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1");
551     size_t bufferSize = 0;
552     size_t maxLen = 40960;
553     napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], nullptr, 0, &bufferSize);
554     NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
555     char stringValue[bufferSize + 1];
556     size_t jsStringLength = 0;
557     napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], stringValue, bufferSize + 1, &jsStringLength);
558     NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
559     std::string descriptor = stringValue;
560     auto holder = new (std::nothrow) NAPIRemoteObjectHolder(env, Str8ToStr16(descriptor), thisVar);
561     NAPI_ASSERT(env, holder != nullptr, "new NAPIRemoteObjectHolder failed");
562     napi_status status = napi_coerce_to_native_binding_object(env, thisVar, RemoteObjectDetachCb, RemoteObjectAttachCb,
563         holder, nullptr);
564     if (status != napi_ok) {
565         delete holder;
566         NAPI_ASSERT(env, false, "bind native RemoteObject failed");
567     }
568     // connect native object to js thisVar
569     status = napi_wrap(env, thisVar, holder, RemoteObjectHolderFinalizeCb, nullptr, nullptr);
570     if (status != napi_ok) {
571         delete holder;
572         NAPI_ASSERT(env, false, "wrap js RemoteObject and native holder failed");
573     }
574     return thisVar;
575 }
576 
NapiScope(napi_env env)577 NapiScope::NapiScope(napi_env env) : env_(env)
578 {
579     napi_status status = napi_open_handle_scope(env_, &scope_);
580     if (status != napi_ok) {
581         ZLOGE(LOG_LABEL, "open handle scope failed, status:%{public}d", status);
582         isValid_ = false;
583     } else {
584         isValid_ = true;
585     }
586 }
587 
~NapiScope()588 NapiScope::~NapiScope()
589 {
590     if (isValid_) {
591         napi_status status = napi_close_handle_scope(env_, scope_);
592         if (status != napi_ok) {
593             ZLOGE(LOG_LABEL, "close handle scope failed, status:%{public}d", status);
594         }
595     }
596 }
597 
IsValid()598 bool NapiScope::IsValid()
599 {
600     return isValid_;
601 }
602 
NAPIRemoteObject(std::thread::id jsThreadId,napi_env env,napi_ref jsObjectRef,const std::u16string & descriptor)603 NAPIRemoteObject::NAPIRemoteObject(std::thread::id jsThreadId, napi_env env, napi_ref jsObjectRef,
604     const std::u16string &descriptor)
605     : IPCObjectStub(descriptor), jsThreadId_(jsThreadId)
606 {
607     desc_ = Str16ToStr8(descriptor_);
608     ZLOGD(LOG_LABEL, "created, desc:%{public}s", desc_.c_str());
609     env_ = env;
610     thisVarRef_ = jsObjectRef;
611 
612     if ((jsThreadId_ == std::this_thread::get_id()) &&
613         (IPCThreadSkeleton::GetThreadType() != ThreadType::IPC_THREAD)) {
614         IncreaseJsObjectRef(env_, jsObjectRef);
615     } else {
616         std::shared_ptr<struct ThreadLockInfo> lockInfo = std::make_shared<struct ThreadLockInfo>();
617         OperateJsRefParam *param = new (std::nothrow) OperateJsRefParam {
618             .env = env_,
619             .thisVarRef = jsObjectRef,
620             .lockInfo = lockInfo.get()
621         };
622         NAPI_ASSERT_RETURN_VOID(env_, param != nullptr, "new OperateJsRefParam failed");
623 
624         auto task = [param]() {
625             napi_handle_scope scope = nullptr;
626             napi_open_handle_scope(param->env, &scope);
627             IncreaseJsObjectRef(param->env, param->thisVarRef);
628             std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
629             param->lockInfo->ready = true;
630             param->lockInfo->condition.notify_all();
631             napi_close_handle_scope(param->env, scope);
632         };
633         napi_status sendRet = napi_send_event(env_, task, napi_eprio_high);
634         if (sendRet != napi_ok) {
635             ZLOGE(LOG_LABEL, "napi_send_event failed, ret:%{public}d", sendRet);
636         } else {
637             std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
638             param->lockInfo->condition.wait(lock, [&param] { return param->lockInfo->ready; });
639         }
640         delete param;
641     }
642 }
643 
~NAPIRemoteObject()644 NAPIRemoteObject::~NAPIRemoteObject()
645 {
646     ZLOGD(LOG_LABEL, "destoryed, desc:%{public}s", desc_.c_str());
647     if (thisVarRef_ != nullptr && env_ != nullptr) {
648         if ((jsThreadId_ == std::this_thread::get_id()) &&
649             (IPCThreadSkeleton::GetThreadType() != ThreadType::IPC_THREAD)) {
650             DecreaseJsObjectRef(env_, thisVarRef_);
651         } else {
652             OperateJsRefParam *param = new (std::nothrow) OperateJsRefParam {
653                 .env = env_,
654                 .thisVarRef = thisVarRef_
655             };
656             if (param == nullptr) {
657                 thisVarRef_ = nullptr;
658                 NAPI_ASSERT_RETURN_VOID(env_, false, "new OperateJsRefParam failed");
659             }
660 
661             auto task = [param]() {
662                 napi_handle_scope scope = nullptr;
663                 napi_open_handle_scope(param->env, &scope);
664                 DecreaseJsObjectRef(param->env, param->thisVarRef);
665                 napi_close_handle_scope(param->env, scope);
666                 delete param;
667             };
668             napi_status sendRet = napi_send_event(env_, task, napi_eprio_high);
669             if (sendRet != napi_ok) {
670                 ZLOGE(LOG_LABEL, "napi_send_event failed, ret:%{public}d", sendRet);
671                 delete param;
672             }
673         }
674         thisVarRef_ = nullptr;
675     }
676 }
677 
CheckObjectLegality() const678 bool NAPIRemoteObject::CheckObjectLegality() const
679 {
680     return true;
681 }
682 
GetObjectType() const683 int NAPIRemoteObject::GetObjectType() const
684 {
685     return OBJECT_TYPE_JAVASCRIPT;
686 }
687 
GetJsObjectRef() const688 napi_ref NAPIRemoteObject::GetJsObjectRef() const
689 {
690     return thisVarRef_;
691 }
692 
ResetJsEnv()693 void NAPIRemoteObject::ResetJsEnv()
694 {
695     env_ = nullptr;
696     thisVarRef_ = nullptr;
697 }
698 
NAPI_RemoteObject_getCallingInfo(CallingInfo & newCallingInfoParam)699 void NAPI_RemoteObject_getCallingInfo(CallingInfo &newCallingInfoParam)
700 {
701     IRemoteInvoker *invoker = IPCThreadSkeleton::GetActiveInvoker();
702     if (invoker != nullptr) {
703         newCallingInfoParam.callingPid = invoker->GetCallerPid();
704         newCallingInfoParam.callingUid = invoker->GetCallerUid();
705         newCallingInfoParam.callingTokenId = static_cast<uint32_t>(invoker->GetCallerTokenID());
706     } else {
707         newCallingInfoParam.callingPid = getpid();
708         newCallingInfoParam.callingUid = getuid();
709         newCallingInfoParam.callingTokenId = static_cast<uint32_t>(IPCSkeleton::GetSelfTokenID());
710     }
711     newCallingInfoParam.callingDeviceID = IPCSkeleton::GetCallingDeviceID();
712     newCallingInfoParam.localDeviceID = IPCSkeleton::GetLocalDeviceID();
713     newCallingInfoParam.isLocalCalling = IPCSkeleton::IsLocalCalling();
714     newCallingInfoParam.activeStatus = IRemoteInvoker::ACTIVE_INVOKER;
715 };
716 
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)717 int NAPIRemoteObject::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
718 {
719     ZLOGD(LOG_LABEL, "enter OnRemoteRequest");
720     if (code == DUMP_TRANSACTION) {
721         ZLOGE(LOG_LABEL, "DUMP_TRANSACTION data size:%{public}zu", data.GetReadableBytes());
722     }
723     std::shared_ptr<struct ThreadLockInfo> lockInfo = std::make_shared<struct ThreadLockInfo>();
724     CallbackParam *param = new (std::nothrow) CallbackParam {
725         .env = env_,
726         .thisVarRef = thisVarRef_,
727         .code = code,
728         .data = &data,
729         .reply = &reply,
730         .option = &option,
731         .lockInfo = lockInfo.get(),
732         .result = 0
733     };
734     if (param == nullptr) {
735         ZLOGE(LOG_LABEL, "new CallbackParam failed");
736         return ERR_ALLOC_MEMORY;
737     }
738 
739     NAPI_RemoteObject_getCallingInfo(param->callingInfo);
740     ZLOGD(LOG_LABEL, "callingPid:%{public}u callingUid:%{public}u "
741         "callingDeviceID:%{public}s localDeviceId:%{public}s localCalling:%{public}d",
742         param->callingInfo.callingPid, param->callingInfo.callingUid,
743         IPCProcessSkeleton::ConvertToSecureString(param->callingInfo.callingDeviceID).c_str(),
744         IPCProcessSkeleton::ConvertToSecureString(param->callingInfo.localDeviceID).c_str(),
745         param->callingInfo.isLocalCalling);
746     int ret = OnJsRemoteRequest(param);
747     if (ret != 0) {
748         uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
749             std::chrono::steady_clock::now().time_since_epoch()).count());
750         ZLOGE(LOG_LABEL, "OnJsRemoteRequest failed, ret:%{public}d time:%{public}" PRIu64, ret, curTime);
751     }
752     delete param;
753     return ret;
754 }
755 
NAPI_RemoteObject_saveOldCallingInfo(napi_env env,NAPI_CallingInfo & oldCallingInfo)756 void NAPI_RemoteObject_saveOldCallingInfo(napi_env env, NAPI_CallingInfo &oldCallingInfo)
757 {
758     napi_value global = nullptr;
759     napi_get_global(env, &global);
760     napi_get_named_property(env, global, "callingPid_", &oldCallingInfo.callingPid);
761     napi_get_named_property(env, global, "callingUid_", &oldCallingInfo.callingUid);
762     napi_get_named_property(env, global, "callingTokenId_", &oldCallingInfo.callingTokenId);
763     napi_get_named_property(env, global, "callingDeviceID_", &oldCallingInfo.callingDeviceID);
764     napi_get_named_property(env, global, "localDeviceID_", &oldCallingInfo.localDeviceID);
765     napi_get_named_property(env, global, "isLocalCalling_", &oldCallingInfo.isLocalCalling);
766     napi_get_named_property(env, global, "isLocalCalling_", &oldCallingInfo.isLocalCalling);
767     napi_get_named_property(env, global, "activeStatus_", &oldCallingInfo.activeStatus);
768 }
769 
NAPI_RemoteObject_setNewCallingInfo(napi_env env,const CallingInfo & newCallingInfoParam)770 void NAPI_RemoteObject_setNewCallingInfo(napi_env env, const CallingInfo &newCallingInfoParam)
771 {
772     napi_value global = nullptr;
773     napi_get_global(env, &global);
774     napi_value newPid = nullptr;
775     napi_create_int32(env, static_cast<int32_t>(newCallingInfoParam.callingPid), &newPid);
776     napi_set_named_property(env, global, "callingPid_", newPid);
777     napi_value newUid = nullptr;
778     napi_create_int32(env, static_cast<int32_t>(newCallingInfoParam.callingUid), &newUid);
779     napi_set_named_property(env, global, "callingUid_", newUid);
780     napi_value newCallingTokenId = nullptr;
781     napi_create_uint32(env, newCallingInfoParam.callingTokenId, &newCallingTokenId);
782     napi_set_named_property(env, global, "callingTokenId_", newCallingTokenId);
783     napi_value newDeviceID = nullptr;
784     napi_create_string_utf8(env, newCallingInfoParam.callingDeviceID.c_str(), NAPI_AUTO_LENGTH, &newDeviceID);
785     napi_set_named_property(env, global, "callingDeviceID_", newDeviceID);
786     napi_value newLocalDeviceID = nullptr;
787     napi_create_string_utf8(env, newCallingInfoParam.localDeviceID.c_str(), NAPI_AUTO_LENGTH, &newLocalDeviceID);
788     napi_set_named_property(env, global, "localDeviceID_", newLocalDeviceID);
789     napi_value newIsLocalCalling = nullptr;
790     napi_get_boolean(env, newCallingInfoParam.isLocalCalling, &newIsLocalCalling);
791     napi_set_named_property(env, global, "isLocalCalling_", newIsLocalCalling);
792     napi_value newActiveStatus = nullptr;
793     napi_create_int32(env, newCallingInfoParam.activeStatus, &newActiveStatus);
794     napi_set_named_property(env, global, "activeStatus_", newActiveStatus);
795 }
796 
NAPI_RemoteObject_resetOldCallingInfo(napi_env env,NAPI_CallingInfo & oldCallingInfo)797 void NAPI_RemoteObject_resetOldCallingInfo(napi_env env, NAPI_CallingInfo &oldCallingInfo)
798 {
799     napi_value global = nullptr;
800     napi_get_global(env, &global);
801     napi_set_named_property(env, global, "callingPid_", oldCallingInfo.callingPid);
802     napi_set_named_property(env, global, "callingUid_", oldCallingInfo.callingUid);
803     napi_set_named_property(env, global, "callingTokenId_", oldCallingInfo.callingTokenId);
804     napi_set_named_property(env, global, "callingDeviceID_", oldCallingInfo.callingDeviceID);
805     napi_set_named_property(env, global, "localDeviceID_", oldCallingInfo.localDeviceID);
806     napi_set_named_property(env, global, "isLocalCalling_", oldCallingInfo.isLocalCalling);
807     napi_set_named_property(env, global, "activeStatus_", oldCallingInfo.activeStatus);
808 }
809 
OnJsRemoteRequest(CallbackParam * jsParam)810 int NAPIRemoteObject::OnJsRemoteRequest(CallbackParam *jsParam)
811 {
812     if (jsParam == nullptr) {
813         ZLOGE(LOG_LABEL, "Js Param is null");
814         return ERR_UNKNOWN_REASON;
815     }
816     if (thisVarRef_ == nullptr || env_ == nullptr) {
817         ZLOGE(LOG_LABEL, "Js env has been destructed");
818         return ERR_UNKNOWN_REASON;
819     }
820 
821     uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
822         std::chrono::steady_clock::now().time_since_epoch()).count());
823     ZLOGD(LOG_LABEL, "start nv queue work loop. desc:%{public}s time:%{public}" PRIu64,
824         desc_.c_str(), curTime);
825 
826     std::string descriptor = desc_;
827     auto task = [jsParam, &descriptor]() {
828         OnJsRemoteRequestCallBack(jsParam, descriptor);
829     };
830     napi_status sendRet = napi_send_event(env_, task, napi_eprio_immediate);
831     if (sendRet != napi_ok) {
832         ZLOGE(LOG_LABEL, "napi_send_event failed, ret:%{public}d", sendRet);
833         return ERR_SEND_EVENT;
834     }
835 
836     std::unique_lock<std::mutex> lock(jsParam->lockInfo->mutex);
837     jsParam->lockInfo->condition.wait(lock, [&jsParam] { return jsParam->lockInfo->ready; });
838     return jsParam->result;
839 }
840 
CreateJsProxyRemoteObject(napi_env env,const sptr<IRemoteObject> target)841 napi_value CreateJsProxyRemoteObject(napi_env env, const sptr<IRemoteObject> target)
842 {
843     napi_value global = nullptr;
844     napi_status status = napi_get_global(env, &global);
845     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
846     napi_value constructor = nullptr;
847     status = napi_get_named_property(env, global, "IPCProxyConstructor_", &constructor);
848     NAPI_ASSERT(env, status == napi_ok, "get proxy constructor failed");
849     napi_value jsRemoteProxy;
850     status = napi_new_instance(env, constructor, 0, nullptr, &jsRemoteProxy);
851     NAPI_ASSERT(env, status == napi_ok, "failed to  construct js RemoteProxy");
852     NAPIRemoteProxyHolder *proxyHolder = NAPI_ohos_rpc_getRemoteProxyHolder(env, jsRemoteProxy);
853     if (proxyHolder == nullptr) {
854         ZLOGE(LOG_LABEL, "proxyHolder null");
855         return nullptr;
856     }
857     proxyHolder->object_ = target;
858     proxyHolder->list_ = new (std::nothrow) NAPIDeathRecipientList();
859     NAPI_ASSERT(env, proxyHolder->list_ != nullptr, "new NAPIDeathRecipientList failed");
860 
861     return jsRemoteProxy;
862 }
863 
CreateJsStubRemoteObject(napi_env env,const sptr<IRemoteObject> target)864 napi_value CreateJsStubRemoteObject(napi_env env, const sptr<IRemoteObject> target)
865 {
866     // retrieve js remote object constructor
867     napi_value global = nullptr;
868     napi_status status = napi_get_global(env, &global);
869     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
870     napi_value constructor = nullptr;
871     status = napi_get_named_property(env, global, "IPCStubConstructor_", &constructor);
872     NAPI_ASSERT(env, status == napi_ok, "set stub constructor failed");
873     NAPI_ASSERT(env, constructor != nullptr, "failed to get js RemoteObject constructor");
874     // retrieve descriptor and it's length
875     std::u16string descriptor = target->GetObjectDescriptor();
876     std::string desc = Str16ToStr8(descriptor);
877     napi_value jsDesc = nullptr;
878     napi_create_string_utf8(env, desc.c_str(), desc.length(), &jsDesc);
879     // create a new js remote object
880     size_t argc = 1;
881     napi_value argv[ARGV_LENGTH_1] = { jsDesc };
882     napi_value jsRemoteObject = nullptr;
883     status = napi_new_instance(env, constructor, argc, argv, &jsRemoteObject);
884     NAPI_ASSERT(env, status == napi_ok, "failed to  construct js RemoteObject");
885     // retrieve holder and set object
886     NAPIRemoteObjectHolder *holder = nullptr;
887     napi_unwrap(env, jsRemoteObject, (void **)&holder);
888     NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
889     holder->Set(target);
890     return jsRemoteObject;
891 }
892 
GetJsStubRemoteObjectByRef(napi_env env,const sptr<IRemoteObject> target)893 napi_value GetJsStubRemoteObjectByRef(napi_env env, const sptr<IRemoteObject> target)
894 {
895     NAPIRemoteObject *object = static_cast<NAPIRemoteObject *>(target.GetRefPtr());
896     NAPI_ASSERT(env, object != nullptr, "get NAPIRemoteObject failed");
897     if (std::this_thread::get_id() != object->GetJSThreadId()) {
898         return CreateJsStubRemoteObject(env, target);
899     }
900     napi_value jsRemoteObject = nullptr;
901     napi_get_reference_value(env, object->GetJsObjectRef(), &jsRemoteObject);
902     if (jsRemoteObject == nullptr) {
903         ZLOGW(LOG_LABEL, "jsRemoteObject is nullptr");
904     }
905     return jsRemoteObject;
906 }
907 
NAPI_ohos_rpc_CreateJsRemoteObject(napi_env env,const sptr<IRemoteObject> target)908 napi_value NAPI_ohos_rpc_CreateJsRemoteObject(napi_env env, const sptr<IRemoteObject> target)
909 {
910     if (target == nullptr) {
911         uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
912             std::chrono::steady_clock::now().time_since_epoch()).count());
913         ZLOGE(LOG_LABEL, "RemoteObject is null time:%{public}" PRIu64, curTime);
914         return nullptr;
915     }
916 
917     if (!target->IsProxyObject()) {
918         IPCObjectStub *tmp = static_cast<IPCObjectStub *>(target.GetRefPtr());
919         uint32_t objectType = static_cast<uint32_t>(tmp->GetObjectType());
920         ZLOGD(LOG_LABEL, "create js object, type:%{public}d", objectType);
921         if (objectType == IPCObjectStub::OBJECT_TYPE_JAVASCRIPT) {
922             return GetJsStubRemoteObjectByRef(env, target);
923         } else if (objectType == IPCObjectStub::OBJECT_TYPE_NATIVE) {
924             return CreateJsStubRemoteObject(env, target);
925         } else {
926             ZLOGE(LOG_LABEL, "invalid type:%{public}d", objectType);
927             return nullptr;
928         }
929     }
930 
931     return CreateJsProxyRemoteObject(env, target);
932 }
933 
NAPI_ohos_rpc_ClearNativeRemoteProxy(napi_env env,napi_value jsRemoteProxy)934 bool NAPI_ohos_rpc_ClearNativeRemoteProxy(napi_env env, napi_value jsRemoteProxy)
935 {
936     NAPIRemoteProxyHolder *holder = NAPI_ohos_rpc_getRemoteProxyHolder(env, jsRemoteProxy);
937     if (holder == nullptr) {
938         ZLOGE(LOG_LABEL, "holder null");
939         return false;
940     }
941     ZLOGI(LOG_LABEL, "clear native remote proxy");
942     holder->object_ = nullptr;
943     return true;
944 }
945 
NAPI_ohos_rpc_getNativeRemoteObject(napi_env env,napi_value object)946 sptr<IRemoteObject> NAPI_ohos_rpc_getNativeRemoteObject(napi_env env, napi_value object)
947 {
948     if (object != nullptr) {
949         napi_value global = nullptr;
950         napi_status status = napi_get_global(env, &global);
951         NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
952         napi_value stubConstructor = nullptr;
953         status = napi_get_named_property(env, global, "IPCStubConstructor_", &stubConstructor);
954         NAPI_ASSERT(env, status == napi_ok, "get stub constructor failed");
955         bool instanceOfStub = false;
956         status = napi_instanceof(env, object, stubConstructor, &instanceOfStub);
957         NAPI_ASSERT(env, status == napi_ok, "failed to check js object type");
958         if (instanceOfStub) {
959             NAPIRemoteObjectHolder *holder = nullptr;
960             napi_unwrap(env, object, (void **)&holder);
961             NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
962             return holder != nullptr ? holder->Get() : nullptr;
963         }
964 
965         napi_value proxyConstructor = nullptr;
966         status = napi_get_named_property(env, global, "IPCProxyConstructor_", &proxyConstructor);
967         NAPI_ASSERT(env, status == napi_ok, "get proxy constructor failed");
968         bool instanceOfProxy = false;
969         status = napi_instanceof(env, object, proxyConstructor, &instanceOfProxy);
970         NAPI_ASSERT(env, status == napi_ok, "failed to check js object type");
971         if (instanceOfProxy) {
972             NAPIRemoteProxyHolder *holder = NAPI_ohos_rpc_getRemoteProxyHolder(env, object);
973             return holder != nullptr ? holder->object_ : nullptr;
974         }
975     }
976     ZLOGW(LOG_LABEL, "napi object is nullptr");
977     return nullptr;
978 }
979 
NAPI_RemoteObject_queryLocalInterface(napi_env env,napi_callback_info info)980 static napi_value NAPI_RemoteObject_queryLocalInterface(napi_env env, napi_callback_info info)
981 {
982     size_t argc = 1;
983     size_t expectedArgc = 1;
984     napi_value argv[ARGV_LENGTH_1] = {nullptr};
985     napi_value thisVar = nullptr;
986     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
987     NAPI_ASSERT(env, argc == expectedArgc, "requires 1 parameters");
988     napi_valuetype valueType = napi_null;
989     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
990     NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1");
991     size_t bufferSize = 0;
992     size_t maxLen = 40960;
993     napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], nullptr, 0, &bufferSize);
994     NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
995     char stringValue[bufferSize + 1];
996     size_t jsStringLength = 0;
997     napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], stringValue, bufferSize + 1, &jsStringLength);
998     NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
999     std::string descriptor = stringValue;
1000     NAPIRemoteObjectHolder *holder = nullptr;
1001     napi_unwrap(env, thisVar, (void **)&holder);
1002     NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
1003     napi_value ret = holder->queryLocalInterface(descriptor);
1004     return ret;
1005 }
1006 
NAPI_RemoteObject_getLocalInterface(napi_env env,napi_callback_info info)1007 static napi_value NAPI_RemoteObject_getLocalInterface(napi_env env, napi_callback_info info)
1008 {
1009     size_t argc = 1;
1010     size_t expectedArgc = 1;
1011     napi_value argv[ARGV_LENGTH_1] = {nullptr};
1012     napi_value thisVar = nullptr;
1013     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1014     if (argc != expectedArgc) {
1015         ZLOGE(LOG_LABEL, "requires 1 parameters");
1016         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1017     }
1018     napi_valuetype valueType = napi_null;
1019     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1020     if (valueType != napi_string) {
1021         ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
1022         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1023     }
1024     size_t bufferSize = 0;
1025     size_t maxLen = 40960;
1026     napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], nullptr, 0, &bufferSize);
1027     if (bufferSize >= maxLen) {
1028         ZLOGE(LOG_LABEL, "string length too large");
1029         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1030     }
1031     char stringValue[bufferSize + 1];
1032     size_t jsStringLength = 0;
1033     napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], stringValue, bufferSize + 1, &jsStringLength);
1034     if (jsStringLength != bufferSize) {
1035         ZLOGE(LOG_LABEL, "string length wrong");
1036         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1037     }
1038     std::string descriptor = stringValue;
1039     NAPIRemoteObjectHolder *holder = nullptr;
1040     napi_unwrap(env, thisVar, (void **)&holder);
1041     if (holder == nullptr) {
1042         ZLOGE(LOG_LABEL, "failed to get napi remote object holder");
1043         return nullptr;
1044     }
1045     napi_value ret = holder->queryLocalInterface(descriptor);
1046     return ret;
1047 }
1048 
NAPI_RemoteObject_getInterfaceDescriptor(napi_env env,napi_callback_info info)1049 static napi_value NAPI_RemoteObject_getInterfaceDescriptor(napi_env env, napi_callback_info info)
1050 {
1051     napi_value result = nullptr;
1052     napi_value thisVar = nullptr;
1053     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
1054     sptr<IRemoteObject> nativeObject = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1055     NAPI_ASSERT(env, nativeObject != nullptr, "nativeObject is NULL.");
1056     std::u16string descriptor = nativeObject->GetObjectDescriptor();
1057     napi_create_string_utf8(env, Str16ToStr8(descriptor).c_str(), NAPI_AUTO_LENGTH, &result);
1058     return result;
1059 }
1060 
NAPI_RemoteObject_getDescriptor(napi_env env,napi_callback_info info)1061 static napi_value NAPI_RemoteObject_getDescriptor(napi_env env, napi_callback_info info)
1062 {
1063     napi_value result = nullptr;
1064     napi_value thisVar = nullptr;
1065     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
1066     sptr<IRemoteObject> nativeObject = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1067     if (nativeObject == nullptr) {
1068         ZLOGE(LOG_LABEL, "native stub object is nullptr");
1069         return napiErr.ThrowError(env, errorDesc::PROXY_OR_REMOTE_OBJECT_INVALID_ERROR);
1070     }
1071     std::u16string descriptor = nativeObject->GetObjectDescriptor();
1072     napi_create_string_utf8(env, Str16ToStr8(descriptor).c_str(), NAPI_AUTO_LENGTH, &result);
1073     return result;
1074 }
1075 
NAPI_RemoteObject_getCallingPid(napi_env env,napi_callback_info info)1076 static napi_value NAPI_RemoteObject_getCallingPid(napi_env env, napi_callback_info info)
1077 {
1078     return NAPI_getCallingPid(env, info);
1079 }
1080 
NAPI_RemoteObject_getCallingUid(napi_env env,napi_callback_info info)1081 static napi_value NAPI_RemoteObject_getCallingUid(napi_env env, napi_callback_info info)
1082 {
1083     return NAPI_getCallingUid(env, info);
1084 }
1085 
MakeSendRequestResult(SendRequestParam * param)1086 napi_value MakeSendRequestResult(SendRequestParam *param)
1087 {
1088     if (param == nullptr) {
1089         ZLOGE(LOG_LABEL, "send request param is null");
1090         return nullptr;
1091     }
1092     napi_value errCode = nullptr;
1093     napi_create_int32(param->env, param->errCode, &errCode);
1094     napi_value code = nullptr;
1095     napi_get_reference_value(param->env, param->jsCodeRef, &code);
1096     napi_value data = nullptr;
1097     napi_get_reference_value(param->env, param->jsDataRef, &data);
1098     napi_value reply = nullptr;
1099     napi_get_reference_value(param->env, param->jsReplyRef, &reply);
1100     napi_value result = nullptr;
1101     napi_create_object(param->env, &result);
1102     napi_set_named_property(param->env, result, "errCode", errCode);
1103     napi_set_named_property(param->env, result, "code", code);
1104     napi_set_named_property(param->env, result, "data", data);
1105     napi_set_named_property(param->env, result, "reply", reply);
1106     return result;
1107 }
1108 
AfterWorkCallback(SendRequestParam * param)1109 static void AfterWorkCallback(SendRequestParam *param)
1110 {
1111     if (param->callback != nullptr) {
1112         ZLOGI(LOG_LABEL, "callback started");
1113         napi_handle_scope scope = nullptr;
1114         napi_open_handle_scope(param->env, &scope);
1115         napi_value result = MakeSendRequestResult(param);
1116         napi_value callbackValue = nullptr;
1117         napi_get_reference_value(param->env, param->callback, &callbackValue);
1118         napi_value cbResult = nullptr;
1119         napi_call_function(param->env, nullptr, callbackValue, 1, &result, &cbResult);
1120         napi_delete_reference(param->env, param->jsCodeRef);
1121         napi_delete_reference(param->env, param->jsDataRef);
1122         napi_delete_reference(param->env, param->jsReplyRef);
1123         napi_delete_reference(param->env, param->jsOptionRef);
1124         napi_delete_reference(param->env, param->callback);
1125         napi_close_handle_scope(param->env, scope);
1126     } else {
1127         uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
1128             std::chrono::steady_clock::now().time_since_epoch()).count());
1129         ZLOGI(LOG_LABEL, "promise fulfilled time:%{public}" PRIu64, curTime);
1130         napi_handle_scope scope = nullptr;
1131         napi_open_handle_scope(param->env, &scope);
1132         napi_value result = MakeSendRequestResult(param);
1133         if (param->errCode == 0) {
1134             napi_resolve_deferred(param->env, param->deferred, result);
1135         } else {
1136             napi_reject_deferred(param->env, param->deferred, result);
1137         }
1138         napi_delete_reference(param->env, param->jsCodeRef);
1139         napi_delete_reference(param->env, param->jsDataRef);
1140         napi_delete_reference(param->env, param->jsReplyRef);
1141         napi_delete_reference(param->env, param->jsOptionRef);
1142         napi_close_handle_scope(param->env, scope);
1143     }
1144     delete param;
1145 }
1146 
StubExecuteSendRequest(napi_env env,SendRequestParam * param)1147 void StubExecuteSendRequest(napi_env env, SendRequestParam *param)
1148 {
1149     if (param == nullptr) {
1150         ZLOGE(LOG_LABEL, "param is null");
1151         return;
1152     }
1153     param->errCode = param->target->SendRequest(param->code,
1154         *(param->data.get()), *(param->reply.get()), param->option);
1155     uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
1156         std::chrono::steady_clock::now().time_since_epoch()).count());
1157     ZLOGI(LOG_LABEL, "sendRequest done, errCode:%{public}d time:%{public}" PRIu64, param->errCode, curTime);
1158     if (param->traceId != 0) {
1159         FinishAsyncTrace(HITRACE_TAG_RPC, (param->traceValue).c_str(), param->traceId);
1160     }
1161 
1162     auto task = [param]() {
1163         AfterWorkCallback(param);
1164     };
1165     napi_status sendRet = napi_send_event(env, task, napi_eprio_high);
1166     if (sendRet != napi_ok) {
1167         ZLOGE(LOG_LABEL, "napi_send_event failed, ret:%{public}d", sendRet);
1168         delete param;
1169     }
1170 }
1171 
StubSendRequestAsync(napi_env env,sptr<IRemoteObject> target,uint32_t code,std::shared_ptr<MessageParcel> data,std::shared_ptr<MessageParcel> reply,MessageOption & option,napi_value * argv)1172 napi_value StubSendRequestAsync(napi_env env, sptr<IRemoteObject> target, uint32_t code,
1173     std::shared_ptr<MessageParcel> data, std::shared_ptr<MessageParcel> reply,
1174     MessageOption &option, napi_value *argv)
1175 {
1176     napi_value result = nullptr;
1177     SendRequestParam *sendRequestParam = new (std::nothrow) SendRequestParam {
1178         .target = target,
1179         .code = code,
1180         .data = data,
1181         .reply = reply,
1182         .option = option,
1183         .asyncWork = nullptr,
1184         .deferred = nullptr,
1185         .errCode = -1,
1186         .jsCodeRef = nullptr,
1187         .jsDataRef = nullptr,
1188         .jsReplyRef = nullptr,
1189         .jsOptionRef = nullptr,
1190         .callback = nullptr,
1191         .env = env,
1192         .traceId = 0,
1193     };
1194     NAPI_ASSERT(env, sendRequestParam != nullptr, "new SendRequestParam failed");
1195     if (target != nullptr) {
1196         std::string remoteDescriptor = Str16ToStr8(target->GetObjectDescriptor());
1197         if (!remoteDescriptor.empty()) {
1198             sendRequestParam->traceValue = remoteDescriptor + std::to_string(code);
1199             sendRequestParam->traceId = bytraceId.fetch_add(1, std::memory_order_seq_cst);
1200             StartAsyncTrace(HITRACE_TAG_RPC, (sendRequestParam->traceValue).c_str(), sendRequestParam->traceId);
1201         }
1202     }
1203     napi_create_reference(env, argv[ARGV_INDEX_0], 1, &sendRequestParam->jsCodeRef);
1204     napi_create_reference(env, argv[ARGV_INDEX_1], 1, &sendRequestParam->jsDataRef);
1205     napi_create_reference(env, argv[ARGV_INDEX_2], 1, &sendRequestParam->jsReplyRef);
1206     napi_create_reference(env, argv[ARGV_INDEX_3], 1, &sendRequestParam->jsOptionRef);
1207     napi_create_reference(env, argv[ARGV_INDEX_4], 1, &sendRequestParam->callback);
1208     std::thread t(StubExecuteSendRequest, env, sendRequestParam);
1209     t.detach();
1210     napi_get_undefined(env, &result);
1211     return result;
1212 }
1213 
StubSendRequestPromise(napi_env env,sptr<IRemoteObject> target,uint32_t code,std::shared_ptr<MessageParcel> data,std::shared_ptr<MessageParcel> reply,MessageOption & option,napi_value * argv)1214 napi_value StubSendRequestPromise(napi_env env, sptr<IRemoteObject> target, uint32_t code,
1215     std::shared_ptr<MessageParcel> data, std::shared_ptr<MessageParcel> reply,
1216     MessageOption &option, napi_value *argv)
1217 {
1218     napi_deferred deferred = nullptr;
1219     napi_value promise = nullptr;
1220     NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
1221     SendRequestParam *sendRequestParam = new (std::nothrow) SendRequestParam {
1222         .target = target,
1223         .code = code,
1224         .data = data,
1225         .reply = reply,
1226         .option = option,
1227         .asyncWork = nullptr,
1228         .deferred = deferred,
1229         .errCode = -1,
1230         .jsCodeRef = nullptr,
1231         .jsDataRef = nullptr,
1232         .jsReplyRef = nullptr,
1233         .jsOptionRef = nullptr,
1234         .callback = nullptr,
1235         .env = env,
1236         .traceId = 0,
1237     };
1238     NAPI_ASSERT(env, sendRequestParam != nullptr, "new SendRequestParam failed");
1239     if (target != nullptr) {
1240         std::string remoteDescriptor = Str16ToStr8(target->GetObjectDescriptor());
1241         if (!remoteDescriptor.empty()) {
1242             sendRequestParam->traceValue = remoteDescriptor + std::to_string(code);
1243             sendRequestParam->traceId = bytraceId.fetch_add(1, std::memory_order_seq_cst);
1244             StartAsyncTrace(HITRACE_TAG_RPC, (sendRequestParam->traceValue).c_str(), sendRequestParam->traceId);
1245         }
1246     }
1247     napi_create_reference(env, argv[ARGV_INDEX_0], 1, &sendRequestParam->jsCodeRef);
1248     napi_create_reference(env, argv[ARGV_INDEX_1], 1, &sendRequestParam->jsDataRef);
1249     napi_create_reference(env, argv[ARGV_INDEX_2], 1, &sendRequestParam->jsReplyRef);
1250     napi_create_reference(env, argv[ARGV_INDEX_3], 1, &sendRequestParam->jsOptionRef);
1251     std::thread t(StubExecuteSendRequest, env, sendRequestParam);
1252     t.detach();
1253     return promise;
1254 }
1255 
NAPI_RemoteObject_sendRequest(napi_env env,napi_callback_info info)1256 static napi_value NAPI_RemoteObject_sendRequest(napi_env env, napi_callback_info info)
1257 {
1258     size_t argc = 4;
1259     size_t argcCallback = 5;
1260     size_t argcPromise = 4;
1261     napi_value argv[ARGV_LENGTH_5] = { 0 };
1262     napi_value thisVar = nullptr;
1263     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1264     NAPI_ASSERT(env, argc == argcPromise || argc == argcCallback, "requires 4 or 5 parameters");
1265     napi_valuetype valueType = napi_null;
1266     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1267     NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
1268     napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1269     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 2");
1270     napi_typeof(env, argv[ARGV_INDEX_2], &valueType);
1271     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 3");
1272     napi_typeof(env, argv[ARGV_INDEX_3], &valueType);
1273     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 4");
1274 
1275     NAPI_MessageParcel *data = nullptr;
1276     napi_status status = napi_unwrap(env, argv[ARGV_INDEX_1], (void **)&data);
1277     NAPI_ASSERT(env, status == napi_ok, "failed to get data message parcel");
1278     NAPI_MessageParcel *reply = nullptr;
1279     status = napi_unwrap(env, argv[ARGV_INDEX_2], (void **)&reply);
1280     NAPI_ASSERT(env, status == napi_ok, "failed to get reply message parcel");
1281     MessageOption *option = nullptr;
1282     status = napi_unwrap(env, argv[ARGV_INDEX_3], (void **)&option);
1283     NAPI_ASSERT(env, status == napi_ok, "failed to get message option");
1284     int32_t code = 0;
1285     napi_get_value_int32(env, argv[ARGV_INDEX_0], &code);
1286 
1287     sptr<IRemoteObject> target = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1288     NAPI_ASSERT(env, target != nullptr, "target is nullptr, failed to get native remote object");
1289     if (argc == argcCallback) {
1290         napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1291         napi_valuetype valuetype = napi_undefined;
1292         napi_typeof(env, argv[argcPromise], &valuetype);
1293         if (valuetype == napi_function) {
1294             return StubSendRequestAsync(env, target, code, data->GetMessageParcel(),
1295                 reply->GetMessageParcel(), *option, argv);
1296         }
1297     }
1298     return StubSendRequestPromise(env, target, code, data->GetMessageParcel(),
1299         reply->GetMessageParcel(), *option, argv);
1300 }
1301 
NAPI_RemoteObject_checkSendMessageRequestArgs(napi_env env,size_t argc,size_t argcCallback,size_t argcPromise,napi_value * argv)1302 napi_value NAPI_RemoteObject_checkSendMessageRequestArgs(napi_env env,
1303                                                          size_t argc,
1304                                                          size_t argcCallback,
1305                                                          size_t argcPromise,
1306                                                          napi_value* argv)
1307 {
1308     if (argc != argcPromise && argc != argcCallback) {
1309         ZLOGE(LOG_LABEL, "requires 4 or 5 parameters");
1310         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1311     }
1312     napi_valuetype valueType = napi_null;
1313     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1314     if (valueType != napi_number) {
1315         ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
1316         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1317     }
1318     napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1319     if (valueType != napi_object) {
1320         ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
1321         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1322     }
1323     napi_typeof(env, argv[ARGV_INDEX_2], &valueType);
1324     if (valueType != napi_object) {
1325         ZLOGE(LOG_LABEL, "type mismatch for parameter 3");
1326         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1327     }
1328     napi_typeof(env, argv[ARGV_INDEX_3], &valueType);
1329     if (valueType != napi_object) {
1330         ZLOGE(LOG_LABEL, "type mismatch for parameter 4");
1331         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1332     }
1333     napi_value result = nullptr;
1334     napi_get_undefined(env, &result);
1335     return result;
1336 }
1337 
NAPI_RemoteObject_sendMessageRequest(napi_env env,napi_callback_info info)1338 static napi_value NAPI_RemoteObject_sendMessageRequest(napi_env env, napi_callback_info info)
1339 {
1340     size_t argc = 4;
1341     size_t argcCallback = 5;
1342     size_t argcPromise = 4;
1343     napi_value argv[ARGV_LENGTH_5] = { 0 };
1344     napi_value thisVar = nullptr;
1345     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1346     napi_value checkArgsResult = NAPI_RemoteObject_checkSendMessageRequestArgs(env, argc, argcCallback, argcPromise,
1347                                                                                argv);
1348     if (checkArgsResult == nullptr) {
1349         return checkArgsResult;
1350     }
1351     NAPI_MessageSequence *data = nullptr;
1352     napi_status status = napi_unwrap(env, argv[ARGV_INDEX_1], (void **)&data);
1353     if (status != napi_ok) {
1354         ZLOGE(LOG_LABEL, "failed to get data message sequence");
1355         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1356     }
1357     NAPI_MessageSequence *reply = nullptr;
1358     status = napi_unwrap(env, argv[ARGV_INDEX_2], (void **)&reply);
1359     if (status != napi_ok) {
1360         ZLOGE(LOG_LABEL, "failed to get data message sequence");
1361         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1362     }
1363     MessageOption *option = nullptr;
1364     status = napi_unwrap(env, argv[ARGV_INDEX_3], (void **)&option);
1365     if (status != napi_ok) {
1366         ZLOGE(LOG_LABEL, "failed to get message option");
1367         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1368     }
1369     int32_t code = 0;
1370     napi_get_value_int32(env, argv[ARGV_INDEX_0], &code);
1371 
1372     sptr<IRemoteObject> target = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1373     NAPI_ASSERT(env, target != nullptr, "target is nullptr, failed to get native remote object");
1374     if (argc == argcCallback) {
1375         napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1376         napi_valuetype valuetype = napi_undefined;
1377         napi_typeof(env, argv[argcPromise], &valuetype);
1378         if (valuetype == napi_function) {
1379             return StubSendRequestAsync(env, target, code, data->GetMessageParcel(),
1380                 reply->GetMessageParcel(), *option, argv);
1381         }
1382     }
1383     return StubSendRequestPromise(env, target, code, data->GetMessageParcel(),
1384         reply->GetMessageParcel(), *option, argv);
1385 }
1386 
NAPI_RemoteObject_attachLocalInterface(napi_env env,napi_callback_info info)1387 static napi_value NAPI_RemoteObject_attachLocalInterface(napi_env env, napi_callback_info info)
1388 {
1389     size_t argc = 2;
1390     size_t expectedArgc = 2;
1391     napi_value argv[ARGV_LENGTH_2] = { 0 };
1392     napi_value thisVar = nullptr;
1393     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1394     NAPI_ASSERT(env, argc == expectedArgc, "requires 2 parameters");
1395     napi_valuetype valueType = napi_null;
1396     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1397     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1");
1398     napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1399     NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 2");
1400     size_t bufferSize = 0;
1401     size_t maxLen = 40960;
1402     napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], nullptr, 0, &bufferSize);
1403     NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
1404     char stringValue[bufferSize + 1];
1405     size_t jsStringLength = 0;
1406     napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], stringValue, bufferSize + 1, &jsStringLength);
1407     NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
1408     std::string descriptor = stringValue;
1409 
1410     NAPIRemoteObjectHolder *holder = nullptr;
1411     napi_unwrap(env, thisVar, (void* *)&holder);
1412     NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
1413     holder->attachLocalInterface(argv[ARGV_INDEX_0], descriptor);
1414 
1415     napi_value result = nullptr;
1416     napi_get_undefined(env, &result);
1417     return result;
1418 }
1419 
NAPI_RemoteObject_checkModifyLocalInterfaceArgs(napi_env env,size_t argc,napi_value * argv)1420 napi_value NAPI_RemoteObject_checkModifyLocalInterfaceArgs(napi_env env, size_t argc, napi_value* argv)
1421 {
1422     size_t expectedArgc = 2;
1423 
1424     if (argc != expectedArgc) {
1425         ZLOGE(LOG_LABEL, "requires 2 parameters");
1426         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1427     }
1428     napi_valuetype valueType = napi_null;
1429     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1430     if (valueType != napi_object) {
1431         ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
1432         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1433     }
1434     napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1435     if (valueType != napi_string) {
1436         ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
1437         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1438     }
1439     napi_value result = nullptr;
1440     napi_get_undefined(env, &result);
1441     return result;
1442 }
1443 
NAPI_RemoteObject_modifyLocalInterface(napi_env env,napi_callback_info info)1444 static napi_value NAPI_RemoteObject_modifyLocalInterface(napi_env env, napi_callback_info info)
1445 {
1446     size_t argc = 2;
1447     napi_value argv[ARGV_LENGTH_2] = { 0 };
1448     napi_value thisVar = nullptr;
1449     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1450     napi_value checkArgsResult = NAPI_RemoteObject_checkModifyLocalInterfaceArgs(env, argc, argv);
1451     if (checkArgsResult == nullptr) {
1452         return checkArgsResult;
1453     }
1454     size_t bufferSize = 0;
1455     size_t maxLen = 40960;
1456     napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], nullptr, 0, &bufferSize);
1457     if (bufferSize >= maxLen) {
1458         ZLOGE(LOG_LABEL, "string length too large");
1459         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1460     }
1461     char stringValue[bufferSize + 1];
1462     size_t jsStringLength = 0;
1463     napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], stringValue, bufferSize + 1, &jsStringLength);
1464     if (jsStringLength != bufferSize) {
1465         ZLOGE(LOG_LABEL, "string length wrong");
1466         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1467     }
1468     std::string descriptor = stringValue;
1469 
1470     NAPIRemoteObjectHolder *holder = nullptr;
1471     napi_unwrap(env, thisVar, (void* *)&holder);
1472     if (holder == nullptr) {
1473         ZLOGE(LOG_LABEL, "failed to get napi remote object holder");
1474         return nullptr;
1475     }
1476     holder->attachLocalInterface(argv[ARGV_INDEX_0], descriptor);
1477 
1478     napi_value result = nullptr;
1479     napi_get_undefined(env, &result);
1480     return result;
1481 }
1482 
NAPI_RemoteObject_addDeathRecipient(napi_env env,napi_callback_info info)1483 static napi_value NAPI_RemoteObject_addDeathRecipient(napi_env env, napi_callback_info info)
1484 {
1485     napi_value result = nullptr;
1486     napi_get_boolean(env, false, &result);
1487     return result;
1488 }
1489 
NAPI_RemoteObject_registerDeathRecipient(napi_env env,napi_callback_info info)1490 static napi_value NAPI_RemoteObject_registerDeathRecipient(napi_env env, napi_callback_info info)
1491 {
1492     ZLOGD(LOG_LABEL, "only proxy object permitted");
1493     return napiErr.ThrowError(env, errorDesc::ONLY_PROXY_OBJECT_PERMITTED_ERROR);
1494 }
1495 
NAPI_RemoteObject_removeDeathRecipient(napi_env env,napi_callback_info info)1496 static napi_value NAPI_RemoteObject_removeDeathRecipient(napi_env env, napi_callback_info info)
1497 {
1498     napi_value result = nullptr;
1499     napi_get_boolean(env, false, &result);
1500     return result;
1501 }
1502 
NAPI_RemoteObject_unregisterDeathRecipient(napi_env env,napi_callback_info info)1503 static napi_value NAPI_RemoteObject_unregisterDeathRecipient(napi_env env, napi_callback_info info)
1504 {
1505     ZLOGD(LOG_LABEL, "only proxy object permitted");
1506     return napiErr.ThrowError(env, errorDesc::ONLY_PROXY_OBJECT_PERMITTED_ERROR);
1507 }
1508 
NAPI_RemoteObject_isObjectDead(napi_env env,napi_callback_info info)1509 static napi_value NAPI_RemoteObject_isObjectDead(napi_env env, napi_callback_info info)
1510 {
1511     napi_value result = nullptr;
1512     napi_get_boolean(env, false, &result);
1513     return result;
1514 }
1515 
NAPI_RemoteObject_Reclaim(napi_env env,napi_callback_info info)1516 static napi_value NAPI_RemoteObject_Reclaim(napi_env env, napi_callback_info info)
1517 {
1518     napi_value result = nullptr;
1519     napi_get_undefined(env, &result);
1520     return result;
1521 }
1522 
1523 EXTERN_C_START
1524 /*
1525  * function for module exports
1526  */
NAPIRemoteObjectExport(napi_env env,napi_value exports)1527 napi_value NAPIRemoteObjectExport(napi_env env, napi_value exports)
1528 {
1529     const std::string className = "RemoteObject";
1530     napi_property_descriptor properties[] = {
1531         DECLARE_NAPI_FUNCTION("sendRequest", NAPI_RemoteObject_sendRequest),
1532         DECLARE_NAPI_FUNCTION("sendMessageRequest", NAPI_RemoteObject_sendMessageRequest),
1533         DECLARE_NAPI_FUNCTION("getCallingPid", NAPI_RemoteObject_getCallingPid),
1534         DECLARE_NAPI_FUNCTION("getCallingUid", NAPI_RemoteObject_getCallingUid),
1535         DECLARE_NAPI_FUNCTION("getInterfaceDescriptor", NAPI_RemoteObject_getInterfaceDescriptor),
1536         DECLARE_NAPI_FUNCTION("getDescriptor", NAPI_RemoteObject_getDescriptor),
1537         DECLARE_NAPI_FUNCTION("attachLocalInterface", NAPI_RemoteObject_attachLocalInterface),
1538         DECLARE_NAPI_FUNCTION("modifyLocalInterface", NAPI_RemoteObject_modifyLocalInterface),
1539         DECLARE_NAPI_FUNCTION("queryLocalInterface", NAPI_RemoteObject_queryLocalInterface),
1540         DECLARE_NAPI_FUNCTION("getLocalInterface", NAPI_RemoteObject_getLocalInterface),
1541         DECLARE_NAPI_FUNCTION("addDeathRecipient", NAPI_RemoteObject_addDeathRecipient),
1542         DECLARE_NAPI_FUNCTION("registerDeathRecipient", NAPI_RemoteObject_registerDeathRecipient),
1543         DECLARE_NAPI_FUNCTION("removeDeathRecipient", NAPI_RemoteObject_removeDeathRecipient),
1544         DECLARE_NAPI_FUNCTION("unregisterDeathRecipient", NAPI_RemoteObject_unregisterDeathRecipient),
1545         DECLARE_NAPI_FUNCTION("isObjectDead", NAPI_RemoteObject_isObjectDead),
1546         DECLARE_NAPI_FUNCTION("reclaim", NAPI_RemoteObject_Reclaim),
1547     };
1548     napi_value constructor = nullptr;
1549     napi_define_class(env, className.c_str(), className.length(), RemoteObject_JS_Constructor, nullptr,
1550         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
1551     NAPI_ASSERT(env, constructor != nullptr, "define js class RemoteObject failed");
1552     napi_status status = napi_set_named_property(env, exports, "RemoteObject", constructor);
1553     NAPI_ASSERT(env, status == napi_ok, "set property RemoteObject to exports failed");
1554     napi_value global = nullptr;
1555     status = napi_get_global(env, &global);
1556     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
1557     status = napi_set_named_property(env, global, "IPCStubConstructor_", constructor);
1558     NAPI_ASSERT(env, status == napi_ok, "set stub constructor failed");
1559     return exports;
1560 }
1561 EXTERN_C_END
1562 } // namespace OHOS
1563