• 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     ZLOGI(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     ZLOGI(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             ZLOGE(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     ZLOGI(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     newCallingInfoParam.callingPid = IPCSkeleton::GetCallingPid();
702     newCallingInfoParam.callingUid = IPCSkeleton::GetCallingUid();
703     newCallingInfoParam.callingTokenId = IPCSkeleton::GetCallingTokenID();
704     newCallingInfoParam.callingDeviceID = IPCSkeleton::GetCallingDeviceID();
705     newCallingInfoParam.localDeviceID = IPCSkeleton::GetLocalDeviceID();
706     newCallingInfoParam.isLocalCalling = IPCSkeleton::IsLocalCalling();
707     newCallingInfoParam.activeStatus = IRemoteInvoker::ACTIVE_INVOKER;
708 };
709 
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)710 int NAPIRemoteObject::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
711 {
712     ZLOGD(LOG_LABEL, "enter OnRemoteRequest");
713     if (code == DUMP_TRANSACTION) {
714         ZLOGE(LOG_LABEL, "DUMP_TRANSACTION data size:%{public}zu", data.GetReadableBytes());
715     }
716     std::shared_ptr<struct ThreadLockInfo> lockInfo = std::make_shared<struct ThreadLockInfo>();
717     CallbackParam *param = new (std::nothrow) CallbackParam {
718         .env = env_,
719         .thisVarRef = thisVarRef_,
720         .code = code,
721         .data = &data,
722         .reply = &reply,
723         .option = &option,
724         .lockInfo = lockInfo.get(),
725         .result = 0
726     };
727     if (param == nullptr) {
728         ZLOGE(LOG_LABEL, "new CallbackParam failed");
729         return ERR_ALLOC_MEMORY;
730     }
731 
732     NAPI_RemoteObject_getCallingInfo(param->callingInfo);
733     ZLOGD(LOG_LABEL, "callingPid:%{public}u callingUid:%{public}u "
734         "callingDeviceID:%{public}s localDeviceId:%{public}s localCalling:%{public}d",
735         param->callingInfo.callingPid, param->callingInfo.callingUid,
736         IPCProcessSkeleton::ConvertToSecureString(param->callingInfo.callingDeviceID).c_str(),
737         IPCProcessSkeleton::ConvertToSecureString(param->callingInfo.localDeviceID).c_str(),
738         param->callingInfo.isLocalCalling);
739     int ret = OnJsRemoteRequest(param);
740     if (ret != 0) {
741         uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
742             std::chrono::steady_clock::now().time_since_epoch()).count());
743         ZLOGE(LOG_LABEL, "OnJsRemoteRequest failed, ret:%{public}d time:%{public}" PRIu64, ret, curTime);
744     }
745     delete param;
746     return ret;
747 }
748 
NAPI_RemoteObject_saveOldCallingInfo(napi_env env,NAPI_CallingInfo & oldCallingInfo)749 void NAPI_RemoteObject_saveOldCallingInfo(napi_env env, NAPI_CallingInfo &oldCallingInfo)
750 {
751     napi_value global = nullptr;
752     napi_get_global(env, &global);
753     napi_get_named_property(env, global, "callingPid_", &oldCallingInfo.callingPid);
754     napi_get_named_property(env, global, "callingUid_", &oldCallingInfo.callingUid);
755     napi_get_named_property(env, global, "callingTokenId_", &oldCallingInfo.callingTokenId);
756     napi_get_named_property(env, global, "callingDeviceID_", &oldCallingInfo.callingDeviceID);
757     napi_get_named_property(env, global, "localDeviceID_", &oldCallingInfo.localDeviceID);
758     napi_get_named_property(env, global, "isLocalCalling_", &oldCallingInfo.isLocalCalling);
759     napi_get_named_property(env, global, "isLocalCalling_", &oldCallingInfo.isLocalCalling);
760     napi_get_named_property(env, global, "activeStatus_", &oldCallingInfo.activeStatus);
761 }
762 
NAPI_RemoteObject_setNewCallingInfo(napi_env env,const CallingInfo & newCallingInfoParam)763 void NAPI_RemoteObject_setNewCallingInfo(napi_env env, const CallingInfo &newCallingInfoParam)
764 {
765     napi_value global = nullptr;
766     napi_get_global(env, &global);
767     napi_value newPid = nullptr;
768     napi_create_int32(env, static_cast<int32_t>(newCallingInfoParam.callingPid), &newPid);
769     napi_set_named_property(env, global, "callingPid_", newPid);
770     napi_value newUid = nullptr;
771     napi_create_int32(env, static_cast<int32_t>(newCallingInfoParam.callingUid), &newUid);
772     napi_set_named_property(env, global, "callingUid_", newUid);
773     napi_value newCallingTokenId = nullptr;
774     napi_create_uint32(env, newCallingInfoParam.callingTokenId, &newCallingTokenId);
775     napi_set_named_property(env, global, "callingTokenId_", newCallingTokenId);
776     napi_value newDeviceID = nullptr;
777     napi_create_string_utf8(env, newCallingInfoParam.callingDeviceID.c_str(), NAPI_AUTO_LENGTH, &newDeviceID);
778     napi_set_named_property(env, global, "callingDeviceID_", newDeviceID);
779     napi_value newLocalDeviceID = nullptr;
780     napi_create_string_utf8(env, newCallingInfoParam.localDeviceID.c_str(), NAPI_AUTO_LENGTH, &newLocalDeviceID);
781     napi_set_named_property(env, global, "localDeviceID_", newLocalDeviceID);
782     napi_value newIsLocalCalling = nullptr;
783     napi_get_boolean(env, newCallingInfoParam.isLocalCalling, &newIsLocalCalling);
784     napi_set_named_property(env, global, "isLocalCalling_", newIsLocalCalling);
785     napi_value newActiveStatus = nullptr;
786     napi_create_int32(env, newCallingInfoParam.activeStatus, &newActiveStatus);
787     napi_set_named_property(env, global, "activeStatus_", newActiveStatus);
788 }
789 
NAPI_RemoteObject_resetOldCallingInfo(napi_env env,NAPI_CallingInfo & oldCallingInfo)790 void NAPI_RemoteObject_resetOldCallingInfo(napi_env env, NAPI_CallingInfo &oldCallingInfo)
791 {
792     napi_value global = nullptr;
793     napi_get_global(env, &global);
794     napi_set_named_property(env, global, "callingPid_", oldCallingInfo.callingPid);
795     napi_set_named_property(env, global, "callingUid_", oldCallingInfo.callingUid);
796     napi_set_named_property(env, global, "callingTokenId_", oldCallingInfo.callingTokenId);
797     napi_set_named_property(env, global, "callingDeviceID_", oldCallingInfo.callingDeviceID);
798     napi_set_named_property(env, global, "localDeviceID_", oldCallingInfo.localDeviceID);
799     napi_set_named_property(env, global, "isLocalCalling_", oldCallingInfo.isLocalCalling);
800     napi_set_named_property(env, global, "activeStatus_", oldCallingInfo.activeStatus);
801 }
802 
OnJsRemoteRequest(CallbackParam * jsParam)803 int NAPIRemoteObject::OnJsRemoteRequest(CallbackParam *jsParam)
804 {
805     if (jsParam == nullptr) {
806         ZLOGE(LOG_LABEL, "Js Param is null");
807         return ERR_UNKNOWN_REASON;
808     }
809     if (thisVarRef_ == nullptr || env_ == nullptr) {
810         ZLOGE(LOG_LABEL, "Js env has been destructed");
811         return ERR_UNKNOWN_REASON;
812     }
813 
814     uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
815         std::chrono::steady_clock::now().time_since_epoch()).count());
816     ZLOGD(LOG_LABEL, "start nv queue work loop. desc:%{public}s time:%{public}" PRIu64,
817         desc_.c_str(), curTime);
818 
819     std::string descriptor = desc_;
820     auto task = [jsParam, &descriptor]() {
821         OnJsRemoteRequestCallBack(jsParam, descriptor);
822     };
823     napi_status sendRet = napi_send_event(env_, task, napi_eprio_immediate);
824     if (sendRet != napi_ok) {
825         ZLOGE(LOG_LABEL, "napi_send_event failed, ret:%{public}d", sendRet);
826         return ERR_SEND_EVENT;
827     }
828 
829     std::unique_lock<std::mutex> lock(jsParam->lockInfo->mutex);
830     jsParam->lockInfo->condition.wait(lock, [&jsParam] { return jsParam->lockInfo->ready; });
831     return jsParam->result;
832 }
833 
CreateJsProxyRemoteObject(napi_env env,const sptr<IRemoteObject> target)834 napi_value CreateJsProxyRemoteObject(napi_env env, const sptr<IRemoteObject> target)
835 {
836     napi_value global = nullptr;
837     napi_status status = napi_get_global(env, &global);
838     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
839     napi_value constructor = nullptr;
840     status = napi_get_named_property(env, global, "IPCProxyConstructor_", &constructor);
841     NAPI_ASSERT(env, status == napi_ok, "get proxy constructor failed");
842     napi_value jsRemoteProxy;
843     status = napi_new_instance(env, constructor, 0, nullptr, &jsRemoteProxy);
844     NAPI_ASSERT(env, status == napi_ok, "failed to  construct js RemoteProxy");
845     NAPIRemoteProxyHolder *proxyHolder = NAPI_ohos_rpc_getRemoteProxyHolder(env, jsRemoteProxy);
846     if (proxyHolder == nullptr) {
847         ZLOGE(LOG_LABEL, "proxyHolder null");
848         return nullptr;
849     }
850     proxyHolder->object_ = target;
851     proxyHolder->list_ = new (std::nothrow) NAPIDeathRecipientList();
852     NAPI_ASSERT(env, proxyHolder->list_ != nullptr, "new NAPIDeathRecipientList failed");
853 
854     return jsRemoteProxy;
855 }
856 
CreateJsStubRemoteObject(napi_env env,const sptr<IRemoteObject> target)857 napi_value CreateJsStubRemoteObject(napi_env env, const sptr<IRemoteObject> target)
858 {
859     // retrieve js remote object constructor
860     napi_value global = nullptr;
861     napi_status status = napi_get_global(env, &global);
862     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
863     napi_value constructor = nullptr;
864     status = napi_get_named_property(env, global, "IPCStubConstructor_", &constructor);
865     NAPI_ASSERT(env, status == napi_ok, "set stub constructor failed");
866     NAPI_ASSERT(env, constructor != nullptr, "failed to get js RemoteObject constructor");
867     // retrieve descriptor and it's length
868     std::u16string descriptor = target->GetObjectDescriptor();
869     std::string desc = Str16ToStr8(descriptor);
870     napi_value jsDesc = nullptr;
871     napi_create_string_utf8(env, desc.c_str(), desc.length(), &jsDesc);
872     // create a new js remote object
873     size_t argc = 1;
874     napi_value argv[ARGV_LENGTH_1] = { jsDesc };
875     napi_value jsRemoteObject = nullptr;
876     status = napi_new_instance(env, constructor, argc, argv, &jsRemoteObject);
877     NAPI_ASSERT(env, status == napi_ok, "failed to  construct js RemoteObject");
878     // retrieve holder and set object
879     NAPIRemoteObjectHolder *holder = nullptr;
880     napi_unwrap(env, jsRemoteObject, (void **)&holder);
881     NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
882     holder->Set(target);
883     return jsRemoteObject;
884 }
885 
GetJsStubRemoteObjectByRef(napi_env env,const sptr<IRemoteObject> target)886 napi_value GetJsStubRemoteObjectByRef(napi_env env, const sptr<IRemoteObject> target)
887 {
888     NAPIRemoteObject *object = static_cast<NAPIRemoteObject *>(target.GetRefPtr());
889     NAPI_ASSERT(env, object != nullptr, "get NAPIRemoteObject failed");
890     if (std::this_thread::get_id() != object->GetJSThreadId()) {
891         return CreateJsStubRemoteObject(env, target);
892     }
893     napi_value jsRemoteObject = nullptr;
894     napi_get_reference_value(env, object->GetJsObjectRef(), &jsRemoteObject);
895     return jsRemoteObject;
896 }
897 
NAPI_ohos_rpc_CreateJsRemoteObject(napi_env env,const sptr<IRemoteObject> target)898 napi_value NAPI_ohos_rpc_CreateJsRemoteObject(napi_env env, const sptr<IRemoteObject> target)
899 {
900     if (target == nullptr) {
901         uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
902             std::chrono::steady_clock::now().time_since_epoch()).count());
903         ZLOGE(LOG_LABEL, "RemoteObject is null time:%{public}" PRIu64, curTime);
904         return nullptr;
905     }
906 
907     if (!target->IsProxyObject()) {
908         IPCObjectStub *tmp = static_cast<IPCObjectStub *>(target.GetRefPtr());
909         uint32_t objectType = static_cast<uint32_t>(tmp->GetObjectType());
910         ZLOGD(LOG_LABEL, "create js object, type:%{public}d", objectType);
911         if (objectType == IPCObjectStub::OBJECT_TYPE_JAVASCRIPT) {
912             return GetJsStubRemoteObjectByRef(env, target);
913         } else if (objectType == IPCObjectStub::OBJECT_TYPE_NATIVE) {
914             return CreateJsStubRemoteObject(env, target);
915         } else {
916             ZLOGE(LOG_LABEL, "invalid type:%{public}d", objectType);
917             return nullptr;
918         }
919     }
920 
921     return CreateJsProxyRemoteObject(env, target);
922 }
923 
NAPI_ohos_rpc_ClearNativeRemoteProxy(napi_env env,napi_value jsRemoteProxy)924 bool NAPI_ohos_rpc_ClearNativeRemoteProxy(napi_env env, napi_value jsRemoteProxy)
925 {
926     NAPIRemoteProxyHolder *holder = NAPI_ohos_rpc_getRemoteProxyHolder(env, jsRemoteProxy);
927     if (holder == nullptr) {
928         ZLOGE(LOG_LABEL, "holder null");
929         return false;
930     }
931     ZLOGI(LOG_LABEL, "clear native remote proxy");
932     holder->object_ = nullptr;
933     return true;
934 }
935 
NAPI_ohos_rpc_getNativeRemoteObject(napi_env env,napi_value object)936 sptr<IRemoteObject> NAPI_ohos_rpc_getNativeRemoteObject(napi_env env, napi_value object)
937 {
938     if (object != nullptr) {
939         napi_value global = nullptr;
940         napi_status status = napi_get_global(env, &global);
941         NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
942         napi_value stubConstructor = nullptr;
943         status = napi_get_named_property(env, global, "IPCStubConstructor_", &stubConstructor);
944         NAPI_ASSERT(env, status == napi_ok, "get stub constructor failed");
945         bool instanceOfStub = false;
946         status = napi_instanceof(env, object, stubConstructor, &instanceOfStub);
947         NAPI_ASSERT(env, status == napi_ok, "failed to check js object type");
948         if (instanceOfStub) {
949             NAPIRemoteObjectHolder *holder = nullptr;
950             napi_unwrap(env, object, (void **)&holder);
951             NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
952             return holder != nullptr ? holder->Get() : nullptr;
953         }
954 
955         napi_value proxyConstructor = nullptr;
956         status = napi_get_named_property(env, global, "IPCProxyConstructor_", &proxyConstructor);
957         NAPI_ASSERT(env, status == napi_ok, "get proxy constructor failed");
958         bool instanceOfProxy = false;
959         status = napi_instanceof(env, object, proxyConstructor, &instanceOfProxy);
960         NAPI_ASSERT(env, status == napi_ok, "failed to check js object type");
961         if (instanceOfProxy) {
962             NAPIRemoteProxyHolder *holder = NAPI_ohos_rpc_getRemoteProxyHolder(env, object);
963             return holder != nullptr ? holder->object_ : nullptr;
964         }
965     }
966     return nullptr;
967 }
968 
NAPI_RemoteObject_queryLocalInterface(napi_env env,napi_callback_info info)969 static napi_value NAPI_RemoteObject_queryLocalInterface(napi_env env, napi_callback_info info)
970 {
971     size_t argc = 1;
972     size_t expectedArgc = 1;
973     napi_value argv[ARGV_LENGTH_1] = {nullptr};
974     napi_value thisVar = nullptr;
975     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
976     NAPI_ASSERT(env, argc == expectedArgc, "requires 1 parameters");
977     napi_valuetype valueType = napi_null;
978     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
979     NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1");
980     size_t bufferSize = 0;
981     size_t maxLen = 40960;
982     napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], nullptr, 0, &bufferSize);
983     NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
984     char stringValue[bufferSize + 1];
985     size_t jsStringLength = 0;
986     napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], stringValue, bufferSize + 1, &jsStringLength);
987     NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
988     std::string descriptor = stringValue;
989     NAPIRemoteObjectHolder *holder = nullptr;
990     napi_unwrap(env, thisVar, (void **)&holder);
991     NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
992     napi_value ret = holder->queryLocalInterface(descriptor);
993     return ret;
994 }
995 
NAPI_RemoteObject_getLocalInterface(napi_env env,napi_callback_info info)996 static napi_value NAPI_RemoteObject_getLocalInterface(napi_env env, napi_callback_info info)
997 {
998     size_t argc = 1;
999     size_t expectedArgc = 1;
1000     napi_value argv[ARGV_LENGTH_1] = {nullptr};
1001     napi_value thisVar = nullptr;
1002     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1003     if (argc != expectedArgc) {
1004         ZLOGE(LOG_LABEL, "requires 1 parameters");
1005         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1006     }
1007     napi_valuetype valueType = napi_null;
1008     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1009     if (valueType != napi_string) {
1010         ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
1011         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1012     }
1013     size_t bufferSize = 0;
1014     size_t maxLen = 40960;
1015     napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], nullptr, 0, &bufferSize);
1016     if (bufferSize >= maxLen) {
1017         ZLOGE(LOG_LABEL, "string length too large");
1018         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1019     }
1020     char stringValue[bufferSize + 1];
1021     size_t jsStringLength = 0;
1022     napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], stringValue, bufferSize + 1, &jsStringLength);
1023     if (jsStringLength != bufferSize) {
1024         ZLOGE(LOG_LABEL, "string length wrong");
1025         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1026     }
1027     std::string descriptor = stringValue;
1028     NAPIRemoteObjectHolder *holder = nullptr;
1029     napi_unwrap(env, thisVar, (void **)&holder);
1030     if (holder == nullptr) {
1031         ZLOGE(LOG_LABEL, "failed to get napi remote object holder");
1032         return nullptr;
1033     }
1034     napi_value ret = holder->queryLocalInterface(descriptor);
1035     return ret;
1036 }
1037 
NAPI_RemoteObject_getInterfaceDescriptor(napi_env env,napi_callback_info info)1038 static napi_value NAPI_RemoteObject_getInterfaceDescriptor(napi_env env, napi_callback_info info)
1039 {
1040     napi_value result = nullptr;
1041     napi_value thisVar = nullptr;
1042     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
1043     sptr<IRemoteObject> nativeObject = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1044     NAPI_ASSERT(env, nativeObject != nullptr, "nativeObject is NULL.");
1045     std::u16string descriptor = nativeObject->GetObjectDescriptor();
1046     napi_create_string_utf8(env, Str16ToStr8(descriptor).c_str(), NAPI_AUTO_LENGTH, &result);
1047     return result;
1048 }
1049 
NAPI_RemoteObject_getDescriptor(napi_env env,napi_callback_info info)1050 static napi_value NAPI_RemoteObject_getDescriptor(napi_env env, napi_callback_info info)
1051 {
1052     napi_value result = nullptr;
1053     napi_value thisVar = nullptr;
1054     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
1055     sptr<IRemoteObject> nativeObject = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1056     if (nativeObject == nullptr) {
1057         ZLOGE(LOG_LABEL, "native stub object is nullptr");
1058         return napiErr.ThrowError(env, errorDesc::PROXY_OR_REMOTE_OBJECT_INVALID_ERROR);
1059     }
1060     std::u16string descriptor = nativeObject->GetObjectDescriptor();
1061     napi_create_string_utf8(env, Str16ToStr8(descriptor).c_str(), NAPI_AUTO_LENGTH, &result);
1062     return result;
1063 }
1064 
NAPI_RemoteObject_getCallingPid(napi_env env,napi_callback_info info)1065 static napi_value NAPI_RemoteObject_getCallingPid(napi_env env, napi_callback_info info)
1066 {
1067     return NAPI_getCallingPid(env, info);
1068 }
1069 
NAPI_RemoteObject_getCallingUid(napi_env env,napi_callback_info info)1070 static napi_value NAPI_RemoteObject_getCallingUid(napi_env env, napi_callback_info info)
1071 {
1072     return NAPI_getCallingUid(env, info);
1073 }
1074 
MakeSendRequestResult(SendRequestParam * param)1075 napi_value MakeSendRequestResult(SendRequestParam *param)
1076 {
1077     if (param == nullptr) {
1078         ZLOGE(LOG_LABEL, "send request param is null");
1079         return nullptr;
1080     }
1081     napi_value errCode = nullptr;
1082     napi_create_int32(param->env, param->errCode, &errCode);
1083     napi_value code = nullptr;
1084     napi_get_reference_value(param->env, param->jsCodeRef, &code);
1085     napi_value data = nullptr;
1086     napi_get_reference_value(param->env, param->jsDataRef, &data);
1087     napi_value reply = nullptr;
1088     napi_get_reference_value(param->env, param->jsReplyRef, &reply);
1089     napi_value result = nullptr;
1090     napi_create_object(param->env, &result);
1091     napi_set_named_property(param->env, result, "errCode", errCode);
1092     napi_set_named_property(param->env, result, "code", code);
1093     napi_set_named_property(param->env, result, "data", data);
1094     napi_set_named_property(param->env, result, "reply", reply);
1095     return result;
1096 }
1097 
AfterWorkCallback(SendRequestParam * param)1098 static void AfterWorkCallback(SendRequestParam *param)
1099 {
1100     if (param->callback != nullptr) {
1101         ZLOGI(LOG_LABEL, "callback started");
1102         napi_handle_scope scope = nullptr;
1103         napi_open_handle_scope(param->env, &scope);
1104         napi_value result = MakeSendRequestResult(param);
1105         napi_value callbackValue = nullptr;
1106         napi_get_reference_value(param->env, param->callback, &callbackValue);
1107         napi_value cbResult = nullptr;
1108         napi_call_function(param->env, nullptr, callbackValue, 1, &result, &cbResult);
1109         napi_delete_reference(param->env, param->jsCodeRef);
1110         napi_delete_reference(param->env, param->jsDataRef);
1111         napi_delete_reference(param->env, param->jsReplyRef);
1112         napi_delete_reference(param->env, param->jsOptionRef);
1113         napi_delete_reference(param->env, param->callback);
1114         napi_close_handle_scope(param->env, scope);
1115     } else {
1116         uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
1117             std::chrono::steady_clock::now().time_since_epoch()).count());
1118         ZLOGI(LOG_LABEL, "promise fulfilled time:%{public}" PRIu64, curTime);
1119         napi_handle_scope scope = nullptr;
1120         napi_open_handle_scope(param->env, &scope);
1121         napi_value result = MakeSendRequestResult(param);
1122         if (param->errCode == 0) {
1123             napi_resolve_deferred(param->env, param->deferred, result);
1124         } else {
1125             napi_reject_deferred(param->env, param->deferred, result);
1126         }
1127         napi_delete_reference(param->env, param->jsCodeRef);
1128         napi_delete_reference(param->env, param->jsDataRef);
1129         napi_delete_reference(param->env, param->jsReplyRef);
1130         napi_delete_reference(param->env, param->jsOptionRef);
1131         napi_close_handle_scope(param->env, scope);
1132     }
1133     delete param;
1134 }
1135 
StubExecuteSendRequest(napi_env env,SendRequestParam * param)1136 void StubExecuteSendRequest(napi_env env, SendRequestParam *param)
1137 {
1138     if (param == nullptr) {
1139         ZLOGE(LOG_LABEL, "param is null");
1140         return;
1141     }
1142     param->errCode = param->target->SendRequest(param->code,
1143         *(param->data.get()), *(param->reply.get()), param->option);
1144     uint64_t curTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
1145         std::chrono::steady_clock::now().time_since_epoch()).count());
1146     ZLOGI(LOG_LABEL, "sendRequest done, errCode:%{public}d time:%{public}" PRIu64, param->errCode, curTime);
1147     if (param->traceId != 0) {
1148         FinishAsyncTrace(HITRACE_TAG_RPC, (param->traceValue).c_str(), param->traceId);
1149     }
1150 
1151     auto task = [param]() {
1152         AfterWorkCallback(param);
1153     };
1154     napi_status sendRet = napi_send_event(env, task, napi_eprio_high);
1155     if (sendRet != napi_ok) {
1156         ZLOGE(LOG_LABEL, "napi_send_event failed, ret:%{public}d", sendRet);
1157         delete param;
1158     }
1159 }
1160 
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)1161 napi_value StubSendRequestAsync(napi_env env, sptr<IRemoteObject> target, uint32_t code,
1162     std::shared_ptr<MessageParcel> data, std::shared_ptr<MessageParcel> reply,
1163     MessageOption &option, napi_value *argv)
1164 {
1165     napi_value result = nullptr;
1166     SendRequestParam *sendRequestParam = new (std::nothrow) SendRequestParam {
1167         .target = target,
1168         .code = code,
1169         .data = data,
1170         .reply = reply,
1171         .option = option,
1172         .asyncWork = nullptr,
1173         .deferred = nullptr,
1174         .errCode = -1,
1175         .jsCodeRef = nullptr,
1176         .jsDataRef = nullptr,
1177         .jsReplyRef = nullptr,
1178         .jsOptionRef = nullptr,
1179         .callback = nullptr,
1180         .env = env,
1181         .traceId = 0,
1182     };
1183     NAPI_ASSERT(env, sendRequestParam != nullptr, "new SendRequestParam failed");
1184     if (target != nullptr) {
1185         std::string remoteDescriptor = Str16ToStr8(target->GetObjectDescriptor());
1186         if (!remoteDescriptor.empty()) {
1187             sendRequestParam->traceValue = remoteDescriptor + std::to_string(code);
1188             sendRequestParam->traceId = bytraceId.fetch_add(1, std::memory_order_seq_cst);
1189             StartAsyncTrace(HITRACE_TAG_RPC, (sendRequestParam->traceValue).c_str(), sendRequestParam->traceId);
1190         }
1191     }
1192     napi_create_reference(env, argv[ARGV_INDEX_0], 1, &sendRequestParam->jsCodeRef);
1193     napi_create_reference(env, argv[ARGV_INDEX_1], 1, &sendRequestParam->jsDataRef);
1194     napi_create_reference(env, argv[ARGV_INDEX_2], 1, &sendRequestParam->jsReplyRef);
1195     napi_create_reference(env, argv[ARGV_INDEX_3], 1, &sendRequestParam->jsOptionRef);
1196     napi_create_reference(env, argv[ARGV_INDEX_4], 1, &sendRequestParam->callback);
1197     std::thread t(StubExecuteSendRequest, env, sendRequestParam);
1198     t.detach();
1199     napi_get_undefined(env, &result);
1200     return result;
1201 }
1202 
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)1203 napi_value StubSendRequestPromise(napi_env env, sptr<IRemoteObject> target, uint32_t code,
1204     std::shared_ptr<MessageParcel> data, std::shared_ptr<MessageParcel> reply,
1205     MessageOption &option, napi_value *argv)
1206 {
1207     napi_deferred deferred = nullptr;
1208     napi_value promise = nullptr;
1209     NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
1210     SendRequestParam *sendRequestParam = new (std::nothrow) SendRequestParam {
1211         .target = target,
1212         .code = code,
1213         .data = data,
1214         .reply = reply,
1215         .option = option,
1216         .asyncWork = nullptr,
1217         .deferred = deferred,
1218         .errCode = -1,
1219         .jsCodeRef = nullptr,
1220         .jsDataRef = nullptr,
1221         .jsReplyRef = nullptr,
1222         .jsOptionRef = nullptr,
1223         .callback = nullptr,
1224         .env = env,
1225         .traceId = 0,
1226     };
1227     NAPI_ASSERT(env, sendRequestParam != nullptr, "new SendRequestParam failed");
1228     if (target != nullptr) {
1229         std::string remoteDescriptor = Str16ToStr8(target->GetObjectDescriptor());
1230         if (!remoteDescriptor.empty()) {
1231             sendRequestParam->traceValue = remoteDescriptor + std::to_string(code);
1232             sendRequestParam->traceId = bytraceId.fetch_add(1, std::memory_order_seq_cst);
1233             StartAsyncTrace(HITRACE_TAG_RPC, (sendRequestParam->traceValue).c_str(), sendRequestParam->traceId);
1234         }
1235     }
1236     napi_create_reference(env, argv[ARGV_INDEX_0], 1, &sendRequestParam->jsCodeRef);
1237     napi_create_reference(env, argv[ARGV_INDEX_1], 1, &sendRequestParam->jsDataRef);
1238     napi_create_reference(env, argv[ARGV_INDEX_2], 1, &sendRequestParam->jsReplyRef);
1239     napi_create_reference(env, argv[ARGV_INDEX_3], 1, &sendRequestParam->jsOptionRef);
1240     std::thread t(StubExecuteSendRequest, env, sendRequestParam);
1241     t.detach();
1242     return promise;
1243 }
1244 
NAPI_RemoteObject_sendRequest(napi_env env,napi_callback_info info)1245 static napi_value NAPI_RemoteObject_sendRequest(napi_env env, napi_callback_info info)
1246 {
1247     size_t argc = 4;
1248     size_t argcCallback = 5;
1249     size_t argcPromise = 4;
1250     napi_value argv[ARGV_LENGTH_5] = { 0 };
1251     napi_value thisVar = nullptr;
1252     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1253     NAPI_ASSERT(env, argc == argcPromise || argc == argcCallback, "requires 4 or 5 parameters");
1254     napi_valuetype valueType = napi_null;
1255     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1256     NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
1257     napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1258     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 2");
1259     napi_typeof(env, argv[ARGV_INDEX_2], &valueType);
1260     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 3");
1261     napi_typeof(env, argv[ARGV_INDEX_3], &valueType);
1262     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 4");
1263 
1264     NAPI_MessageParcel *data = nullptr;
1265     napi_status status = napi_unwrap(env, argv[ARGV_INDEX_1], (void **)&data);
1266     NAPI_ASSERT(env, status == napi_ok, "failed to get data message parcel");
1267     NAPI_MessageParcel *reply = nullptr;
1268     status = napi_unwrap(env, argv[ARGV_INDEX_2], (void **)&reply);
1269     NAPI_ASSERT(env, status == napi_ok, "failed to get reply message parcel");
1270     MessageOption *option = nullptr;
1271     status = napi_unwrap(env, argv[ARGV_INDEX_3], (void **)&option);
1272     NAPI_ASSERT(env, status == napi_ok, "failed to get message option");
1273     int32_t code = 0;
1274     napi_get_value_int32(env, argv[ARGV_INDEX_0], &code);
1275 
1276     sptr<IRemoteObject> target = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1277     if (argc == argcCallback) {
1278         napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1279         napi_valuetype valuetype = napi_undefined;
1280         napi_typeof(env, argv[argcPromise], &valuetype);
1281         if (valuetype == napi_function) {
1282             return StubSendRequestAsync(env, target, code, data->GetMessageParcel(),
1283                 reply->GetMessageParcel(), *option, argv);
1284         }
1285     }
1286     return StubSendRequestPromise(env, target, code, data->GetMessageParcel(),
1287         reply->GetMessageParcel(), *option, argv);
1288 }
1289 
NAPI_RemoteObject_checkSendMessageRequestArgs(napi_env env,size_t argc,size_t argcCallback,size_t argcPromise,napi_value * argv)1290 napi_value NAPI_RemoteObject_checkSendMessageRequestArgs(napi_env env,
1291                                                          size_t argc,
1292                                                          size_t argcCallback,
1293                                                          size_t argcPromise,
1294                                                          napi_value* argv)
1295 {
1296     if (argc != argcPromise && argc != argcCallback) {
1297         ZLOGE(LOG_LABEL, "requires 4 or 5 parameters");
1298         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1299     }
1300     napi_valuetype valueType = napi_null;
1301     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1302     if (valueType != napi_number) {
1303         ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
1304         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1305     }
1306     napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1307     if (valueType != napi_object) {
1308         ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
1309         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1310     }
1311     napi_typeof(env, argv[ARGV_INDEX_2], &valueType);
1312     if (valueType != napi_object) {
1313         ZLOGE(LOG_LABEL, "type mismatch for parameter 3");
1314         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1315     }
1316     napi_typeof(env, argv[ARGV_INDEX_3], &valueType);
1317     if (valueType != napi_object) {
1318         ZLOGE(LOG_LABEL, "type mismatch for parameter 4");
1319         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1320     }
1321     napi_value result = nullptr;
1322     napi_get_undefined(env, &result);
1323     return result;
1324 }
1325 
NAPI_RemoteObject_sendMessageRequest(napi_env env,napi_callback_info info)1326 static napi_value NAPI_RemoteObject_sendMessageRequest(napi_env env, napi_callback_info info)
1327 {
1328     size_t argc = 4;
1329     size_t argcCallback = 5;
1330     size_t argcPromise = 4;
1331     napi_value argv[ARGV_LENGTH_5] = { 0 };
1332     napi_value thisVar = nullptr;
1333     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1334     napi_value checkArgsResult = NAPI_RemoteObject_checkSendMessageRequestArgs(env, argc, argcCallback, argcPromise,
1335                                                                                argv);
1336     if (checkArgsResult == nullptr) {
1337         return checkArgsResult;
1338     }
1339     NAPI_MessageSequence *data = nullptr;
1340     napi_status status = napi_unwrap(env, argv[ARGV_INDEX_1], (void **)&data);
1341     if (status != napi_ok) {
1342         ZLOGE(LOG_LABEL, "failed to get data message sequence");
1343         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1344     }
1345     NAPI_MessageSequence *reply = nullptr;
1346     status = napi_unwrap(env, argv[ARGV_INDEX_2], (void **)&reply);
1347     if (status != napi_ok) {
1348         ZLOGE(LOG_LABEL, "failed to get data message sequence");
1349         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1350     }
1351     MessageOption *option = nullptr;
1352     status = napi_unwrap(env, argv[ARGV_INDEX_3], (void **)&option);
1353     if (status != napi_ok) {
1354         ZLOGE(LOG_LABEL, "failed to get message option");
1355         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1356     }
1357     int32_t code = 0;
1358     napi_get_value_int32(env, argv[ARGV_INDEX_0], &code);
1359 
1360     sptr<IRemoteObject> target = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1361     if (argc == argcCallback) {
1362         napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1363         napi_valuetype valuetype = napi_undefined;
1364         napi_typeof(env, argv[argcPromise], &valuetype);
1365         if (valuetype == napi_function) {
1366             return StubSendRequestAsync(env, target, code, data->GetMessageParcel(),
1367                 reply->GetMessageParcel(), *option, argv);
1368         }
1369     }
1370     return StubSendRequestPromise(env, target, code, data->GetMessageParcel(),
1371         reply->GetMessageParcel(), *option, argv);
1372 }
1373 
NAPI_RemoteObject_attachLocalInterface(napi_env env,napi_callback_info info)1374 static napi_value NAPI_RemoteObject_attachLocalInterface(napi_env env, napi_callback_info info)
1375 {
1376     size_t argc = 2;
1377     size_t expectedArgc = 2;
1378     napi_value argv[ARGV_LENGTH_2] = { 0 };
1379     napi_value thisVar = nullptr;
1380     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1381     NAPI_ASSERT(env, argc == expectedArgc, "requires 2 parameters");
1382     napi_valuetype valueType = napi_null;
1383     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1384     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1");
1385     napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1386     NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 2");
1387     size_t bufferSize = 0;
1388     size_t maxLen = 40960;
1389     napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], nullptr, 0, &bufferSize);
1390     NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
1391     char stringValue[bufferSize + 1];
1392     size_t jsStringLength = 0;
1393     napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], stringValue, bufferSize + 1, &jsStringLength);
1394     NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
1395     std::string descriptor = stringValue;
1396 
1397     NAPIRemoteObjectHolder *holder = nullptr;
1398     napi_unwrap(env, thisVar, (void* *)&holder);
1399     NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
1400     holder->attachLocalInterface(argv[ARGV_INDEX_0], descriptor);
1401 
1402     napi_value result = nullptr;
1403     napi_get_undefined(env, &result);
1404     return result;
1405 }
1406 
NAPI_RemoteObject_checkModifyLocalInterfaceArgs(napi_env env,size_t argc,napi_value * argv)1407 napi_value NAPI_RemoteObject_checkModifyLocalInterfaceArgs(napi_env env, size_t argc, napi_value* argv)
1408 {
1409     size_t expectedArgc = 2;
1410 
1411     if (argc != expectedArgc) {
1412         ZLOGE(LOG_LABEL, "requires 2 parameters");
1413         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1414     }
1415     napi_valuetype valueType = napi_null;
1416     napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1417     if (valueType != napi_object) {
1418         ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
1419         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1420     }
1421     napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1422     if (valueType != napi_string) {
1423         ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
1424         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1425     }
1426     napi_value result = nullptr;
1427     napi_get_undefined(env, &result);
1428     return result;
1429 }
1430 
NAPI_RemoteObject_modifyLocalInterface(napi_env env,napi_callback_info info)1431 static napi_value NAPI_RemoteObject_modifyLocalInterface(napi_env env, napi_callback_info info)
1432 {
1433     size_t argc = 2;
1434     napi_value argv[ARGV_LENGTH_2] = { 0 };
1435     napi_value thisVar = nullptr;
1436     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1437     napi_value checkArgsResult = NAPI_RemoteObject_checkModifyLocalInterfaceArgs(env, argc, argv);
1438     if (checkArgsResult == nullptr) {
1439         return checkArgsResult;
1440     }
1441     size_t bufferSize = 0;
1442     size_t maxLen = 40960;
1443     napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], nullptr, 0, &bufferSize);
1444     if (bufferSize >= maxLen) {
1445         ZLOGE(LOG_LABEL, "string length too large");
1446         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1447     }
1448     char stringValue[bufferSize + 1];
1449     size_t jsStringLength = 0;
1450     napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], stringValue, bufferSize + 1, &jsStringLength);
1451     if (jsStringLength != bufferSize) {
1452         ZLOGE(LOG_LABEL, "string length wrong");
1453         return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1454     }
1455     std::string descriptor = stringValue;
1456 
1457     NAPIRemoteObjectHolder *holder = nullptr;
1458     napi_unwrap(env, thisVar, (void* *)&holder);
1459     if (holder == nullptr) {
1460         ZLOGE(LOG_LABEL, "failed to get napi remote object holder");
1461         return nullptr;
1462     }
1463     holder->attachLocalInterface(argv[ARGV_INDEX_0], descriptor);
1464 
1465     napi_value result = nullptr;
1466     napi_get_undefined(env, &result);
1467     return result;
1468 }
1469 
NAPI_RemoteObject_addDeathRecipient(napi_env env,napi_callback_info info)1470 static napi_value NAPI_RemoteObject_addDeathRecipient(napi_env env, napi_callback_info info)
1471 {
1472     napi_value result = nullptr;
1473     napi_get_boolean(env, false, &result);
1474     return result;
1475 }
1476 
NAPI_RemoteObject_registerDeathRecipient(napi_env env,napi_callback_info info)1477 static napi_value NAPI_RemoteObject_registerDeathRecipient(napi_env env, napi_callback_info info)
1478 {
1479     ZLOGE(LOG_LABEL, "only proxy object permitted");
1480     return napiErr.ThrowError(env, errorDesc::ONLY_PROXY_OBJECT_PERMITTED_ERROR);
1481 }
1482 
NAPI_RemoteObject_removeDeathRecipient(napi_env env,napi_callback_info info)1483 static napi_value NAPI_RemoteObject_removeDeathRecipient(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_unregisterDeathRecipient(napi_env env,napi_callback_info info)1490 static napi_value NAPI_RemoteObject_unregisterDeathRecipient(napi_env env, napi_callback_info info)
1491 {
1492     ZLOGE(LOG_LABEL, "only proxy object permitted");
1493     return napiErr.ThrowError(env, errorDesc::ONLY_PROXY_OBJECT_PERMITTED_ERROR);
1494 }
1495 
NAPI_RemoteObject_isObjectDead(napi_env env,napi_callback_info info)1496 static napi_value NAPI_RemoteObject_isObjectDead(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_Reclaim(napi_env env,napi_callback_info info)1503 static napi_value NAPI_RemoteObject_Reclaim(napi_env env, napi_callback_info info)
1504 {
1505     napi_value result = nullptr;
1506     napi_get_undefined(env, &result);
1507     return result;
1508 }
1509 
1510 EXTERN_C_START
1511 /*
1512  * function for module exports
1513  */
NAPIRemoteObjectExport(napi_env env,napi_value exports)1514 napi_value NAPIRemoteObjectExport(napi_env env, napi_value exports)
1515 {
1516     const std::string className = "RemoteObject";
1517     napi_property_descriptor properties[] = {
1518         DECLARE_NAPI_FUNCTION("sendRequest", NAPI_RemoteObject_sendRequest),
1519         DECLARE_NAPI_FUNCTION("sendMessageRequest", NAPI_RemoteObject_sendMessageRequest),
1520         DECLARE_NAPI_FUNCTION("getCallingPid", NAPI_RemoteObject_getCallingPid),
1521         DECLARE_NAPI_FUNCTION("getCallingUid", NAPI_RemoteObject_getCallingUid),
1522         DECLARE_NAPI_FUNCTION("getInterfaceDescriptor", NAPI_RemoteObject_getInterfaceDescriptor),
1523         DECLARE_NAPI_FUNCTION("getDescriptor", NAPI_RemoteObject_getDescriptor),
1524         DECLARE_NAPI_FUNCTION("attachLocalInterface", NAPI_RemoteObject_attachLocalInterface),
1525         DECLARE_NAPI_FUNCTION("modifyLocalInterface", NAPI_RemoteObject_modifyLocalInterface),
1526         DECLARE_NAPI_FUNCTION("queryLocalInterface", NAPI_RemoteObject_queryLocalInterface),
1527         DECLARE_NAPI_FUNCTION("getLocalInterface", NAPI_RemoteObject_getLocalInterface),
1528         DECLARE_NAPI_FUNCTION("addDeathRecipient", NAPI_RemoteObject_addDeathRecipient),
1529         DECLARE_NAPI_FUNCTION("registerDeathRecipient", NAPI_RemoteObject_registerDeathRecipient),
1530         DECLARE_NAPI_FUNCTION("removeDeathRecipient", NAPI_RemoteObject_removeDeathRecipient),
1531         DECLARE_NAPI_FUNCTION("unregisterDeathRecipient", NAPI_RemoteObject_unregisterDeathRecipient),
1532         DECLARE_NAPI_FUNCTION("isObjectDead", NAPI_RemoteObject_isObjectDead),
1533         DECLARE_NAPI_FUNCTION("reclaim", NAPI_RemoteObject_Reclaim),
1534     };
1535     napi_value constructor = nullptr;
1536     napi_define_class(env, className.c_str(), className.length(), RemoteObject_JS_Constructor, nullptr,
1537         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
1538     NAPI_ASSERT(env, constructor != nullptr, "define js class RemoteObject failed");
1539     napi_status status = napi_set_named_property(env, exports, "RemoteObject", constructor);
1540     NAPI_ASSERT(env, status == napi_ok, "set property RemoteObject to exports failed");
1541     napi_value global = nullptr;
1542     status = napi_get_global(env, &global);
1543     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
1544     status = napi_set_named_property(env, global, "IPCStubConstructor_", constructor);
1545     NAPI_ASSERT(env, status == napi_ok, "set stub constructor failed");
1546     return exports;
1547 }
1548 EXTERN_C_END
1549 } // namespace OHOS
1550