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