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, [¶m] { 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