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