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 "iremote_invoker.h"
25 #include "log_tags.h"
26 #include "napi/native_api.h"
27 #include "napi/native_node_api.h"
28 #include "napi_message_parcel.h"
29 #include "napi_message_sequence.h"
30 #include "napi_remote_proxy_holder.h"
31 #include "napi_rpc_error.h"
32 #include "native_engine/native_value.h"
33 #include "napi_process_skeleton.h"
34
35 namespace OHOS {
36 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC_NAPI, "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 size_t ARGV_INDEX_4 = 4;
43
44 static const size_t ARGV_LENGTH_1 = 1;
45 static const size_t ARGV_LENGTH_2 = 2;
46 static const size_t ARGV_LENGTH_5 = 5;
47 static const uint64_t HITRACE_TAG_RPC = (1ULL << 46); // RPC and IPC tag.
48
49 static std::atomic<int32_t> bytraceId = 1000;
50 static NapiError napiErr;
51
RemoteObjectHolderFinalizeCb(napi_env env,void * data,void * hint)52 static void RemoteObjectHolderFinalizeCb(napi_env env, void *data, void *hint)
53 {
54 NAPIRemoteObjectHolder *holder = reinterpret_cast<NAPIRemoteObjectHolder *>(data);
55 if (holder == nullptr) {
56 ZLOGW(LOG_LABEL, "RemoteObjectHolderFinalizeCb null holder");
57 return;
58 }
59 holder->Lock();
60 int32_t curAttachCount = holder->DecAttachCount();
61 ZLOGD(LOG_LABEL, "NAPIRemoteObjectHolder destructed by js callback, curAttachCount:%{public}d", curAttachCount);
62 if (curAttachCount == 0) {
63 delete holder;
64 }
65 }
66
DecreaseJsObjectRef(napi_env env,napi_ref ref)67 static void DecreaseJsObjectRef(napi_env env, napi_ref ref)
68 {
69 if (ref == nullptr) {
70 ZLOGI(LOG_LABEL, "ref is nullptr, do nothing");
71 return;
72 }
73
74 uint32_t result;
75 napi_status napiStatus = napi_reference_unref(env, ref, &result);
76 NAPI_ASSERT_RETURN_VOID(env, napiStatus == napi_ok, "failed to decrease ref to js RemoteObject");
77 }
78
IncreaseJsObjectRef(napi_env env,napi_ref ref)79 static void IncreaseJsObjectRef(napi_env env, napi_ref ref)
80 {
81 uint32_t result;
82 napi_status napiStatus = napi_reference_ref(env, ref, &result);
83 NAPI_ASSERT_RETURN_VOID(env, napiStatus == napi_ok, "failed to increase ref to js RemoteObject");
84 }
85
RemoteObjectHolderRefCb(napi_env env,void * data,void * hint)86 static void RemoteObjectHolderRefCb(napi_env env, void *data, void *hint)
87 {
88 NAPIRemoteObjectHolder *holder = reinterpret_cast<NAPIRemoteObjectHolder *>(data);
89 if (holder == nullptr) {
90 ZLOGW(LOG_LABEL, "RemoteObjectHolderRefCb holder is nullptr");
91 return;
92 }
93 holder->Lock();
94 int32_t curAttachCount = holder->DecAttachCount();
95 holder->Unlock();
96 ZLOGD(LOG_LABEL, "RemoteObjectHolderRefCb, curAttachCount:%{public}d", curAttachCount);
97
98 napi_ref ref = holder->GetJsObjectRef();
99 napi_env workerEnv = holder->GetJsObjectEnv();
100 if (ref == nullptr || workerEnv == nullptr) {
101 ZLOGE(LOG_LABEL, "ref or env is null");
102 return;
103 }
104 uv_loop_s *loop = nullptr;
105 napi_get_uv_event_loop(workerEnv, &loop);
106 uv_work_t *work = new(std::nothrow) uv_work_t;
107 NAPI_ASSERT_RETURN_VOID(workerEnv, work != nullptr, "cb failed to new work");
108 OperateJsRefParam *param = new OperateJsRefParam {
109 .env = workerEnv,
110 .thisVarRef = ref
111 };
112 work->data = reinterpret_cast<void *>(param);
113 uv_queue_work(loop, work, [](uv_work_t *work) {}, [](uv_work_t *work, int status) {
114 ZLOGI(LOG_LABEL, "decrease on uv work thread");
115 OperateJsRefParam *param = reinterpret_cast<OperateJsRefParam *>(work->data);
116 napi_handle_scope scope = nullptr;
117 napi_open_handle_scope(param->env, &scope);
118 DecreaseJsObjectRef(param->env, param->thisVarRef);
119 napi_close_handle_scope(param->env, scope);
120 delete param;
121 delete work;
122 });
123 }
124
RemoteObjectDetachCb(napi_env engine,void * value,void * hint)125 static void *RemoteObjectDetachCb(napi_env engine, void *value, void *hint)
126 {
127 (void)hint;
128 napi_env env = engine;
129 NAPIRemoteObjectHolder *holder = reinterpret_cast<NAPIRemoteObjectHolder *>(value);
130 napi_ref ref = holder->GetJsObjectRef();
131
132 uint32_t result;
133 napi_status napiStatus = napi_reference_ref(env, ref, &result);
134 if (napiStatus != napi_ok) {
135 ZLOGE(LOG_LABEL, "RemoteObjectDetachCb, failed to increase ref");
136 } else {
137 ZLOGI(LOG_LABEL, "RemoteObjectDetachCb, ref result:%{public}u", result);
138 }
139 return value;
140 }
141
RemoteObjectAttachCb(napi_env engine,void * value,void * hint)142 static napi_value RemoteObjectAttachCb(napi_env engine, void *value, void *hint)
143 {
144 (void)hint;
145 NAPIRemoteObjectHolder *holder = reinterpret_cast<NAPIRemoteObjectHolder *>(value);
146 if (holder == nullptr) {
147 ZLOGE(LOG_LABEL, "holder is nullptr when attach");
148 return nullptr;
149 }
150 holder->Lock();
151 ZLOGI(LOG_LABEL, "create js remote object when attach");
152 napi_env env = engine;
153 // retrieve js remote object constructor
154 napi_value global = nullptr;
155 napi_status status = napi_get_global(env, &global);
156 NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
157 napi_value constructor = nullptr;
158 status = napi_get_named_property(env, global, "IPCStubConstructor_", &constructor);
159 NAPI_ASSERT(env, status == napi_ok, "get stub constructor failed");
160 NAPI_ASSERT(env, constructor != nullptr, "failed to get js RemoteObject constructor");
161 // retrieve descriptor and it's length
162 std::u16string descriptor = holder->GetDescriptor();
163 std::string desc = Str16ToStr8(descriptor);
164 napi_value jsDesc = nullptr;
165 napi_create_string_utf8(env, desc.c_str(), desc.length(), &jsDesc);
166 // create a new js remote object
167 size_t argc = 1;
168 napi_value argv[ARGV_LENGTH_1] = { jsDesc };
169 napi_value jsRemoteObject = nullptr;
170 status = napi_new_instance(env, constructor, argc, argv, &jsRemoteObject);
171 NAPI_ASSERT(env, status == napi_ok, "failed to construct js RemoteObject when attach");
172 // retrieve and remove create holder
173 NAPIRemoteObjectHolder *createHolder = nullptr;
174 status = napi_remove_wrap(env, jsRemoteObject, (void **)&createHolder);
175 NAPI_ASSERT(env, status == napi_ok && createHolder != nullptr, "failed to remove create holder when attach");
176 status = napi_wrap(env, jsRemoteObject, holder, RemoteObjectHolderRefCb, nullptr, nullptr);
177 NAPI_ASSERT(env, status == napi_ok, "wrap js RemoteObject and native holder failed when attach");
178 holder->IncAttachCount();
179 holder->Unlock();
180 return jsRemoteObject;
181 }
182
RemoteObject_JS_Constructor(napi_env env,napi_callback_info info)183 napi_value RemoteObject_JS_Constructor(napi_env env, napi_callback_info info)
184 {
185 // new napi remote object
186 size_t argc = 2;
187 size_t expectedArgc = 1;
188 napi_value argv[ARGV_LENGTH_2] = { 0 };
189 napi_value thisVar = nullptr;
190 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
191 NAPI_ASSERT(env, argc >= expectedArgc, "requires at least 1 parameters");
192 napi_valuetype valueType = napi_null;
193 napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
194 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1");
195 size_t bufferSize = 0;
196 size_t maxLen = 40960;
197 napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], nullptr, 0, &bufferSize);
198 NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
199 char stringValue[bufferSize + 1];
200 size_t jsStringLength = 0;
201 napi_get_value_string_utf8(env, argv[ARGV_INDEX_0], stringValue, bufferSize + 1, &jsStringLength);
202 NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
203 std::string descriptor = stringValue;
204 auto holder = new NAPIRemoteObjectHolder(env, Str8ToStr16(descriptor), thisVar);
205 napi_coerce_to_native_binding_object(env, thisVar, RemoteObjectDetachCb, RemoteObjectAttachCb, holder, nullptr);
206 // connect native object to js thisVar
207 napi_status status = napi_wrap(env, thisVar, holder, RemoteObjectHolderFinalizeCb, nullptr, nullptr);
208 NAPI_ASSERT(env, status == napi_ok, "wrap js RemoteObject and native holder failed");
209 return thisVar;
210 }
211
NAPIRemoteObject(std::thread::id jsThreadId,napi_env env,napi_ref jsObjectRef,const std::u16string & descriptor)212 NAPIRemoteObject::NAPIRemoteObject(std::thread::id jsThreadId, napi_env env, napi_ref jsObjectRef,
213 const std::u16string &descriptor)
214 : IPCObjectStub(descriptor)
215 {
216 ZLOGD(LOG_LABEL, "created, desc:%{public}s", Str16ToStr8(descriptor_).c_str());
217 env_ = env;
218 jsThreadId_ = jsThreadId;
219 thisVarRef_ = jsObjectRef;
220
221 if (jsThreadId_ == std::this_thread::get_id()) {
222 IncreaseJsObjectRef(env, jsObjectRef);
223 } else {
224 uv_loop_s *loop = nullptr;
225 napi_get_uv_event_loop(env_, &loop);
226 uv_work_t *work = new(std::nothrow) uv_work_t;
227 NAPI_ASSERT_RETURN_VOID(env_, work != nullptr, "create NAPIRemoteObject, new work failed");
228 std::shared_ptr<struct ThreadLockInfo> lockInfo = std::make_shared<struct ThreadLockInfo>();
229 OperateJsRefParam *param = new OperateJsRefParam {
230 .env = env_,
231 .thisVarRef = jsObjectRef,
232 .lockInfo = lockInfo.get()
233 };
234
235 work->data = reinterpret_cast<void *>(param);
236 uv_queue_work(loop, work, [](uv_work_t *work) {}, [](uv_work_t *work, int status) {
237 OperateJsRefParam *param = reinterpret_cast<OperateJsRefParam *>(work->data);
238 napi_handle_scope scope = nullptr;
239 napi_open_handle_scope(param->env, &scope);
240 IncreaseJsObjectRef(param->env, param->thisVarRef);
241 std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
242 param->lockInfo->ready = true;
243 param->lockInfo->condition.notify_all();
244 napi_close_handle_scope(param->env, scope);
245 });
246 std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
247 param->lockInfo->condition.wait(lock, [¶m] { return param->lockInfo->ready; });
248 delete param;
249 delete work;
250 }
251 }
252
~NAPIRemoteObject()253 NAPIRemoteObject::~NAPIRemoteObject()
254 {
255 ZLOGD(LOG_LABEL, "destoryed, desc:%{public}s", Str16ToStr8(descriptor_).c_str());
256 if (thisVarRef_ != nullptr && env_ != nullptr) {
257 if (jsThreadId_ == std::this_thread::get_id()) {
258 DecreaseJsObjectRef(env_, thisVarRef_);
259 } else {
260 uv_loop_s *loop = nullptr;
261 napi_get_uv_event_loop(env_, &loop);
262 uv_work_t *work = new(std::nothrow) uv_work_t;
263 NAPI_ASSERT_RETURN_VOID(env_, work != nullptr, "release NAPIRemoteObject, new work failed");
264 OperateJsRefParam *param = new OperateJsRefParam {
265 .env = env_,
266 .thisVarRef = thisVarRef_
267 };
268 work->data = reinterpret_cast<void *>(param);
269 uv_queue_work(loop, work, [](uv_work_t *work) {}, [](uv_work_t *work, int status) {
270 OperateJsRefParam *param = reinterpret_cast<OperateJsRefParam *>(work->data);
271 napi_handle_scope scope = nullptr;
272 napi_open_handle_scope(param->env, &scope);
273 DecreaseJsObjectRef(param->env, param->thisVarRef);
274 napi_close_handle_scope(param->env, scope);
275 delete param;
276 delete work;
277 });
278 }
279 thisVarRef_ = nullptr;
280 }
281 }
282
CheckObjectLegality() const283 bool NAPIRemoteObject::CheckObjectLegality() const
284 {
285 return true;
286 }
287
GetObjectType() const288 int NAPIRemoteObject::GetObjectType() const
289 {
290 return OBJECT_TYPE_JAVASCRIPT;
291 }
292
GetJsObjectRef() const293 napi_ref NAPIRemoteObject::GetJsObjectRef() const
294 {
295 return thisVarRef_;
296 }
297
ResetJsEnv()298 void NAPIRemoteObject::ResetJsEnv()
299 {
300 env_ = nullptr;
301 thisVarRef_ = nullptr;
302 }
303
NAPI_RemoteObject_getCallingInfo(CallingInfo & newCallingInfoParam)304 void NAPI_RemoteObject_getCallingInfo(CallingInfo &newCallingInfoParam)
305 {
306 newCallingInfoParam.callingPid = IPCSkeleton::GetCallingPid();
307 newCallingInfoParam.callingUid = IPCSkeleton::GetCallingUid();
308 newCallingInfoParam.callingTokenId = IPCSkeleton::GetCallingTokenID();
309 newCallingInfoParam.callingDeviceID = IPCSkeleton::GetCallingDeviceID();
310 newCallingInfoParam.localDeviceID = IPCSkeleton::GetLocalDeviceID();
311 newCallingInfoParam.isLocalCalling = IPCSkeleton::IsLocalCalling();
312 newCallingInfoParam.activeStatus = IRemoteInvoker::ACTIVE_INVOKER;
313 };
314
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)315 int NAPIRemoteObject::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
316 {
317 ZLOGD(LOG_LABEL, "enter OnRemoteRequest");
318 if (code == DUMP_TRANSACTION) {
319 ZLOGE(LOG_LABEL, "DUMP_TRANSACTION data size:%{public}zu", data.GetReadableBytes());
320 }
321 std::shared_ptr<struct ThreadLockInfo> lockInfo = std::make_shared<struct ThreadLockInfo>();
322 CallbackParam *param = new CallbackParam {
323 .env = env_,
324 .thisVarRef = thisVarRef_,
325 .code = code,
326 .data = &data,
327 .reply = &reply,
328 .option = &option,
329 .lockInfo = lockInfo.get(),
330 .result = 0
331 };
332
333 NAPI_RemoteObject_getCallingInfo(param->callingInfo);
334 ZLOGD(LOG_LABEL, "callingPid:%{public}u callingUid:%{public}u "
335 "callingDeviceID:%{public}s localDeviceId:%{public}s localCalling:%{public}d",
336 param->callingInfo.callingPid, param->callingInfo.callingUid,
337 param->callingInfo.callingDeviceID.c_str(), param->callingInfo.localDeviceID.c_str(),
338 param->callingInfo.isLocalCalling);
339 int ret = OnJsRemoteRequest(param);
340 ZLOGI(LOG_LABEL, "OnJsRemoteRequest done, ret:%{public}d", ret);
341 return ret;
342 }
343
ThenCallback(napi_env env,napi_callback_info info)344 napi_value NAPIRemoteObject::ThenCallback(napi_env env, napi_callback_info info)
345 {
346 ZLOGD(LOG_LABEL, "call js onRemoteRequest done");
347 size_t argc = 1;
348 napi_value argv[ARGV_LENGTH_1] = {nullptr};
349 void* data = nullptr;
350 napi_get_cb_info(env, info, &argc, argv, nullptr, &data);
351 CallbackParam *param = static_cast<CallbackParam *>(data);
352 bool result = false;
353 napi_get_value_bool(param->env, argv[ARGV_INDEX_0], &result);
354 if (!result) {
355 ZLOGE(LOG_LABEL, "OnRemoteRequest res:%{public}s", result ? "true" : "false");
356 param->result = ERR_UNKNOWN_TRANSACTION;
357 } else {
358 param->result = ERR_NONE;
359 }
360 std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
361 param->lockInfo->ready = true;
362 param->lockInfo->condition.notify_all();
363 napi_value res;
364 napi_get_undefined(env, &res);
365 return res;
366 }
367
CatchCallback(napi_env env,napi_callback_info info)368 napi_value NAPIRemoteObject::CatchCallback(napi_env env, napi_callback_info info)
369 {
370 ZLOGI(LOG_LABEL, "Async onReomteReuqest's returnVal is rejected");
371 size_t argc = 1;
372 napi_value argv[ARGV_LENGTH_1] = {nullptr};
373 void* data = nullptr;
374 napi_get_cb_info(env, info, &argc, argv, nullptr, &data);
375 CallbackParam *param = static_cast<CallbackParam *>(data);
376 param->result = ERR_UNKNOWN_TRANSACTION;
377 std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
378 param->lockInfo->ready = true;
379 param->lockInfo->condition.notify_all();
380 napi_value res;
381 napi_get_undefined(env, &res);
382 return res;
383 }
384
NAPI_RemoteObject_saveOldCallingInfo(napi_env env,NAPI_CallingInfo & oldCallingInfo)385 void NAPI_RemoteObject_saveOldCallingInfo(napi_env env, NAPI_CallingInfo &oldCallingInfo)
386 {
387 napi_value global = nullptr;
388 napi_get_global(env, &global);
389 napi_get_named_property(env, global, "callingPid_", &oldCallingInfo.callingPid);
390 napi_get_named_property(env, global, "callingUid_", &oldCallingInfo.callingUid);
391 napi_get_named_property(env, global, "callingTokenId_", &oldCallingInfo.callingTokenId);
392 napi_get_named_property(env, global, "callingDeviceID_", &oldCallingInfo.callingDeviceID);
393 napi_get_named_property(env, global, "localDeviceID_", &oldCallingInfo.localDeviceID);
394 napi_get_named_property(env, global, "isLocalCalling_", &oldCallingInfo.isLocalCalling);
395 napi_get_named_property(env, global, "isLocalCalling_", &oldCallingInfo.isLocalCalling);
396 napi_get_named_property(env, global, "activeStatus_", &oldCallingInfo.activeStatus);
397 }
398
NAPI_RemoteObject_setNewCallingInfo(napi_env env,const CallingInfo & newCallingInfoParam)399 void NAPI_RemoteObject_setNewCallingInfo(napi_env env, const CallingInfo &newCallingInfoParam)
400 {
401 napi_value global = nullptr;
402 napi_get_global(env, &global);
403 napi_value newPid;
404 napi_create_int32(env, static_cast<int32_t>(newCallingInfoParam.callingPid), &newPid);
405 napi_set_named_property(env, global, "callingPid_", newPid);
406 napi_value newUid;
407 napi_create_int32(env, static_cast<int32_t>(newCallingInfoParam.callingUid), &newUid);
408 napi_set_named_property(env, global, "callingUid_", newUid);
409 napi_value newCallingTokenId;
410 napi_create_uint32(env, newCallingInfoParam.callingTokenId, &newCallingTokenId);
411 napi_set_named_property(env, global, "callingTokenId_", newCallingTokenId);
412 napi_value newDeviceID;
413 napi_create_string_utf8(env, newCallingInfoParam.callingDeviceID.c_str(), NAPI_AUTO_LENGTH, &newDeviceID);
414 napi_set_named_property(env, global, "callingDeviceID_", newDeviceID);
415 napi_value newLocalDeviceID;
416 napi_create_string_utf8(env, newCallingInfoParam.localDeviceID.c_str(), NAPI_AUTO_LENGTH, &newLocalDeviceID);
417 napi_set_named_property(env, global, "localDeviceID_", newLocalDeviceID);
418 napi_value newIsLocalCalling;
419 napi_get_boolean(env, newCallingInfoParam.isLocalCalling, &newIsLocalCalling);
420 napi_set_named_property(env, global, "isLocalCalling_", newIsLocalCalling);
421 napi_value newActiveStatus;
422 napi_create_int32(env, newCallingInfoParam.activeStatus, &newActiveStatus);
423 napi_set_named_property(env, global, "activeStatus_", newActiveStatus);
424 }
425
NAPI_RemoteObject_resetOldCallingInfo(napi_env env,NAPI_CallingInfo & oldCallingInfo)426 void NAPI_RemoteObject_resetOldCallingInfo(napi_env env, NAPI_CallingInfo &oldCallingInfo)
427 {
428 napi_value global = nullptr;
429 napi_get_global(env, &global);
430 napi_set_named_property(env, global, "callingPid_", oldCallingInfo.callingPid);
431 napi_set_named_property(env, global, "callingUid_", oldCallingInfo.callingUid);
432 napi_set_named_property(env, global, "callingTokenId_", oldCallingInfo.callingTokenId);
433 napi_set_named_property(env, global, "callingDeviceID_", oldCallingInfo.callingDeviceID);
434 napi_set_named_property(env, global, "localDeviceID_", oldCallingInfo.localDeviceID);
435 napi_set_named_property(env, global, "isLocalCalling_", oldCallingInfo.isLocalCalling);
436 napi_set_named_property(env, global, "activeStatus_", oldCallingInfo.activeStatus);
437 }
438
OnJsRemoteRequest(CallbackParam * jsParam)439 int NAPIRemoteObject::OnJsRemoteRequest(CallbackParam *jsParam)
440 {
441 if (jsParam == nullptr) {
442 ZLOGE(LOG_LABEL, "Js Param is null");
443 return ERR_UNKNOWN_REASON;
444 }
445 if (thisVarRef_ == nullptr || env_ == nullptr) {
446 ZLOGE(LOG_LABEL, "Js env has been destructed");
447 return ERR_UNKNOWN_REASON;
448 }
449 uv_loop_s *loop = nullptr;
450 napi_get_uv_event_loop(env_, &loop);
451
452 uv_work_t *work = new(std::nothrow) uv_work_t;
453 if (work == nullptr) {
454 ZLOGE(LOG_LABEL, "failed to new uv_work_t");
455 delete jsParam;
456 return -1;
457 }
458 work->data = reinterpret_cast<void *>(jsParam);
459 ZLOGI(LOG_LABEL, "start nv queue work loop. desc:%{public}s", Str16ToStr8(descriptor_).c_str());
460 uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {
461 ZLOGI(LOG_LABEL, "enter work pool. code:%{public}u", (reinterpret_cast<CallbackParam *>(work->data))->code);
462 }, [](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[ARGV_LENGTH_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 }, uv_qos_user_initiated);
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[ARGV_LENGTH_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[ARGV_LENGTH_1] = {nullptr};
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[ARGV_INDEX_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[ARGV_INDEX_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[ARGV_INDEX_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[ARGV_LENGTH_1] = {nullptr};
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[ARGV_INDEX_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[ARGV_INDEX_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[ARGV_INDEX_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 if (param == nullptr) {
898 ZLOGE(LOG_LABEL, "send request param is null");
899 return nullptr;
900 }
901 napi_value errCode = nullptr;
902 napi_create_int32(param->env, param->errCode, &errCode);
903 napi_value code = nullptr;
904 napi_get_reference_value(param->env, param->jsCodeRef, &code);
905 napi_value data = nullptr;
906 napi_get_reference_value(param->env, param->jsDataRef, &data);
907 napi_value reply = nullptr;
908 napi_get_reference_value(param->env, param->jsReplyRef, &reply);
909 napi_value result = nullptr;
910 napi_create_object(param->env, &result);
911 napi_set_named_property(param->env, result, "errCode", errCode);
912 napi_set_named_property(param->env, result, "code", code);
913 napi_set_named_property(param->env, result, "data", data);
914 napi_set_named_property(param->env, result, "reply", reply);
915 return result;
916 }
917
StubExecuteSendRequest(napi_env env,SendRequestParam * param)918 void StubExecuteSendRequest(napi_env env, SendRequestParam *param)
919 {
920 if (param == nullptr) {
921 ZLOGE(LOG_LABEL, "param is null");
922 return;
923 }
924 param->errCode = param->target->SendRequest(param->code,
925 *(param->data.get()), *(param->reply.get()), param->option);
926 ZLOGI(LOG_LABEL, "sendRequest done, errCode:%{public}d", param->errCode);
927 if (param->traceId != 0) {
928 FinishAsyncTrace(HITRACE_TAG_RPC, (param->traceValue).c_str(), param->traceId);
929 }
930 uv_loop_s *loop = nullptr;
931 napi_get_uv_event_loop(env, &loop);
932 uv_work_t *work = new uv_work_t;
933 work->data = reinterpret_cast<void *>(param);
934 uv_after_work_cb afterWorkCb = nullptr;
935 if (param->callback != nullptr) {
936 afterWorkCb = [](uv_work_t *work, int status) {
937 ZLOGI(LOG_LABEL, "callback started");
938 SendRequestParam *param = reinterpret_cast<SendRequestParam *>(work->data);
939 napi_handle_scope scope = nullptr;
940 napi_open_handle_scope(param->env, &scope);
941 napi_value result = MakeSendRequestResult(param);
942 napi_value callback = nullptr;
943 napi_get_reference_value(param->env, param->callback, &callback);
944 napi_value cbResult = nullptr;
945 napi_call_function(param->env, nullptr, callback, 1, &result, &cbResult);
946 napi_delete_reference(param->env, param->jsCodeRef);
947 napi_delete_reference(param->env, param->jsDataRef);
948 napi_delete_reference(param->env, param->jsReplyRef);
949 napi_delete_reference(param->env, param->jsOptionRef);
950 napi_delete_reference(param->env, param->callback);
951 napi_close_handle_scope(param->env, scope);
952 delete param;
953 delete work;
954 };
955 } else {
956 afterWorkCb = [](uv_work_t *work, int status) {
957 ZLOGI(LOG_LABEL, "promise fullfilled");
958 SendRequestParam *param = reinterpret_cast<SendRequestParam *>(work->data);
959 napi_handle_scope scope = nullptr;
960 napi_open_handle_scope(param->env, &scope);
961 napi_value result = MakeSendRequestResult(param);
962 if (param->errCode == 0) {
963 napi_resolve_deferred(param->env, param->deferred, result);
964 } else {
965 napi_reject_deferred(param->env, param->deferred, result);
966 }
967 napi_delete_reference(param->env, param->jsCodeRef);
968 napi_delete_reference(param->env, param->jsDataRef);
969 napi_delete_reference(param->env, param->jsReplyRef);
970 napi_delete_reference(param->env, param->jsOptionRef);
971 napi_close_handle_scope(param->env, scope);
972 delete param;
973 delete work;
974 };
975 }
976 uv_queue_work(loop, work, [](uv_work_t *work) {}, afterWorkCb);
977 }
978
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)979 napi_value StubSendRequestAsync(napi_env env, sptr<IRemoteObject> target, uint32_t code,
980 std::shared_ptr<MessageParcel> data, std::shared_ptr<MessageParcel> reply,
981 MessageOption &option, napi_value *argv)
982 {
983 SendRequestParam *sendRequestParam = new SendRequestParam {
984 .target = target,
985 .code = code,
986 .data = data,
987 .reply = reply,
988 .option = option,
989 .asyncWork = nullptr,
990 .deferred = nullptr,
991 .errCode = -1,
992 .jsCodeRef = nullptr,
993 .jsDataRef = nullptr,
994 .jsReplyRef = nullptr,
995 .jsOptionRef = nullptr,
996 .callback = nullptr,
997 .env = env,
998 .traceId = 0,
999 };
1000 if (target != nullptr) {
1001 std::string remoteDescriptor = Str16ToStr8(target->GetObjectDescriptor());
1002 if (!remoteDescriptor.empty()) {
1003 sendRequestParam->traceValue = remoteDescriptor + std::to_string(code);
1004 sendRequestParam->traceId = bytraceId.fetch_add(1, std::memory_order_seq_cst);
1005 StartAsyncTrace(HITRACE_TAG_RPC, (sendRequestParam->traceValue).c_str(), sendRequestParam->traceId);
1006 }
1007 }
1008 napi_create_reference(env, argv[ARGV_INDEX_0], 1, &sendRequestParam->jsCodeRef);
1009 napi_create_reference(env, argv[ARGV_INDEX_1], 1, &sendRequestParam->jsDataRef);
1010 napi_create_reference(env, argv[ARGV_INDEX_2], 1, &sendRequestParam->jsReplyRef);
1011 napi_create_reference(env, argv[ARGV_INDEX_3], 1, &sendRequestParam->jsOptionRef);
1012 napi_create_reference(env, argv[ARGV_INDEX_4], 1, &sendRequestParam->callback);
1013 std::thread t(StubExecuteSendRequest, env, sendRequestParam);
1014 t.detach();
1015 napi_value result = nullptr;
1016 napi_get_undefined(env, &result);
1017 return result;
1018 }
1019
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)1020 napi_value StubSendRequestPromise(napi_env env, sptr<IRemoteObject> target, uint32_t code,
1021 std::shared_ptr<MessageParcel> data, std::shared_ptr<MessageParcel> reply,
1022 MessageOption &option, napi_value *argv)
1023 {
1024 napi_deferred deferred = nullptr;
1025 napi_value promise = nullptr;
1026 NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
1027 SendRequestParam *sendRequestParam = new SendRequestParam {
1028 .target = target,
1029 .code = code,
1030 .data = data,
1031 .reply = reply,
1032 .option = option,
1033 .asyncWork = nullptr,
1034 .deferred = deferred,
1035 .errCode = -1,
1036 .jsCodeRef = nullptr,
1037 .jsDataRef = nullptr,
1038 .jsReplyRef = nullptr,
1039 .jsOptionRef = nullptr,
1040 .callback = nullptr,
1041 .env = env,
1042 .traceId = 0,
1043 };
1044 if (target != nullptr) {
1045 std::string remoteDescriptor = Str16ToStr8(target->GetObjectDescriptor());
1046 if (!remoteDescriptor.empty()) {
1047 sendRequestParam->traceValue = remoteDescriptor + std::to_string(code);
1048 sendRequestParam->traceId = bytraceId.fetch_add(1, std::memory_order_seq_cst);
1049 StartAsyncTrace(HITRACE_TAG_RPC, (sendRequestParam->traceValue).c_str(), sendRequestParam->traceId);
1050 }
1051 }
1052 napi_create_reference(env, argv[ARGV_INDEX_0], 1, &sendRequestParam->jsCodeRef);
1053 napi_create_reference(env, argv[ARGV_INDEX_1], 1, &sendRequestParam->jsDataRef);
1054 napi_create_reference(env, argv[ARGV_INDEX_2], 1, &sendRequestParam->jsReplyRef);
1055 napi_create_reference(env, argv[ARGV_INDEX_3], 1, &sendRequestParam->jsOptionRef);
1056 std::thread t(StubExecuteSendRequest, env, sendRequestParam);
1057 t.detach();
1058 return promise;
1059 }
1060
NAPI_RemoteObject_sendRequest(napi_env env,napi_callback_info info)1061 static napi_value NAPI_RemoteObject_sendRequest(napi_env env, napi_callback_info info)
1062 {
1063 size_t argc = 4;
1064 size_t argcCallback = 5;
1065 size_t argcPromise = 4;
1066 napi_value argv[ARGV_LENGTH_5] = { 0 };
1067 napi_value thisVar = nullptr;
1068 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1069 NAPI_ASSERT(env, argc == argcPromise || argc == argcCallback, "requires 4 or 5 parameters");
1070 napi_valuetype valueType = napi_null;
1071 napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1072 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
1073 napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1074 NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 2");
1075 napi_typeof(env, argv[ARGV_INDEX_2], &valueType);
1076 NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 3");
1077 napi_typeof(env, argv[ARGV_INDEX_3], &valueType);
1078 NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 4");
1079
1080 NAPI_MessageParcel *data = nullptr;
1081 napi_status status = napi_unwrap(env, argv[ARGV_INDEX_1], (void **)&data);
1082 NAPI_ASSERT(env, status == napi_ok, "failed to get data message parcel");
1083 NAPI_MessageParcel *reply = nullptr;
1084 status = napi_unwrap(env, argv[ARGV_INDEX_2], (void **)&reply);
1085 NAPI_ASSERT(env, status == napi_ok, "failed to get reply message parcel");
1086 MessageOption *option = nullptr;
1087 status = napi_unwrap(env, argv[ARGV_INDEX_3], (void **)&option);
1088 NAPI_ASSERT(env, status == napi_ok, "failed to get message option");
1089 int32_t code = 0;
1090 napi_get_value_int32(env, argv[ARGV_INDEX_0], &code);
1091
1092 sptr<IRemoteObject> target = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1093 if (argc == argcCallback) {
1094 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1095 napi_valuetype valuetype = napi_undefined;
1096 napi_typeof(env, argv[argcPromise], &valuetype);
1097 if (valuetype == napi_function) {
1098 return StubSendRequestAsync(env, target, code, data->GetMessageParcel(),
1099 reply->GetMessageParcel(), *option, argv);
1100 }
1101 }
1102 return StubSendRequestPromise(env, target, code, data->GetMessageParcel(),
1103 reply->GetMessageParcel(), *option, argv);
1104 }
1105
NAPI_RemoteObject_checkSendMessageRequestArgs(napi_env env,size_t argc,size_t argcCallback,size_t argcPromise,napi_value * argv)1106 napi_value NAPI_RemoteObject_checkSendMessageRequestArgs(napi_env env,
1107 size_t argc,
1108 size_t argcCallback,
1109 size_t argcPromise,
1110 napi_value* argv)
1111 {
1112 if (argc != argcPromise && argc != argcCallback) {
1113 ZLOGE(LOG_LABEL, "requires 4 or 5 parameters");
1114 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1115 }
1116 napi_valuetype valueType = napi_null;
1117 napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1118 if (valueType != napi_number) {
1119 ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
1120 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1121 }
1122 napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1123 if (valueType != napi_object) {
1124 ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
1125 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1126 }
1127 napi_typeof(env, argv[ARGV_INDEX_2], &valueType);
1128 if (valueType != napi_object) {
1129 ZLOGE(LOG_LABEL, "type mismatch for parameter 3");
1130 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1131 }
1132 napi_typeof(env, argv[ARGV_INDEX_3], &valueType);
1133 if (valueType != napi_object) {
1134 ZLOGE(LOG_LABEL, "type mismatch for parameter 4");
1135 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1136 }
1137 napi_value result = nullptr;
1138 napi_get_undefined(env, &result);
1139 return result;
1140 }
1141
NAPI_RemoteObject_sendMessageRequest(napi_env env,napi_callback_info info)1142 static napi_value NAPI_RemoteObject_sendMessageRequest(napi_env env, napi_callback_info info)
1143 {
1144 size_t argc = 4;
1145 size_t argcCallback = 5;
1146 size_t argcPromise = 4;
1147 napi_value argv[ARGV_LENGTH_5] = { 0 };
1148 napi_value thisVar = nullptr;
1149 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1150 napi_value checkArgsResult = NAPI_RemoteObject_checkSendMessageRequestArgs(env, argc, argcCallback, argcPromise,
1151 argv);
1152 if (checkArgsResult == nullptr) {
1153 return checkArgsResult;
1154 }
1155 NAPI_MessageSequence *data = nullptr;
1156 napi_status status = napi_unwrap(env, argv[ARGV_INDEX_1], (void **)&data);
1157 if (status != napi_ok) {
1158 ZLOGE(LOG_LABEL, "failed to get data message sequence");
1159 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1160 }
1161 NAPI_MessageSequence *reply = nullptr;
1162 status = napi_unwrap(env, argv[ARGV_INDEX_2], (void **)&reply);
1163 if (status != napi_ok) {
1164 ZLOGE(LOG_LABEL, "failed to get data message sequence");
1165 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1166 }
1167 MessageOption *option = nullptr;
1168 status = napi_unwrap(env, argv[ARGV_INDEX_3], (void **)&option);
1169 if (status != napi_ok) {
1170 ZLOGE(LOG_LABEL, "failed to get message option");
1171 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1172 }
1173 int32_t code = 0;
1174 napi_get_value_int32(env, argv[ARGV_INDEX_0], &code);
1175
1176 sptr<IRemoteObject> target = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1177 if (argc == argcCallback) {
1178 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1179 napi_valuetype valuetype = napi_undefined;
1180 napi_typeof(env, argv[argcPromise], &valuetype);
1181 if (valuetype == napi_function) {
1182 return StubSendRequestAsync(env, target, code, data->GetMessageParcel(),
1183 reply->GetMessageParcel(), *option, argv);
1184 }
1185 }
1186 return StubSendRequestPromise(env, target, code, data->GetMessageParcel(),
1187 reply->GetMessageParcel(), *option, argv);
1188 }
1189
NAPI_RemoteObject_attachLocalInterface(napi_env env,napi_callback_info info)1190 static napi_value NAPI_RemoteObject_attachLocalInterface(napi_env env, napi_callback_info info)
1191 {
1192 size_t argc = 2;
1193 size_t expectedArgc = 2;
1194 napi_value argv[ARGV_LENGTH_2] = { 0 };
1195 napi_value thisVar = nullptr;
1196 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1197 NAPI_ASSERT(env, argc == expectedArgc, "requires 2 parameters");
1198 napi_valuetype valueType = napi_null;
1199 napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1200 NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1");
1201 napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1202 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 2");
1203 size_t bufferSize = 0;
1204 size_t maxLen = 40960;
1205 napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], nullptr, 0, &bufferSize);
1206 NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
1207 char stringValue[bufferSize + 1];
1208 size_t jsStringLength = 0;
1209 napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], stringValue, bufferSize + 1, &jsStringLength);
1210 NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
1211 std::string descriptor = stringValue;
1212
1213 NAPIRemoteObjectHolder *holder = nullptr;
1214 napi_unwrap(env, thisVar, (void* *)&holder);
1215 NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
1216 holder->attachLocalInterface(argv[ARGV_INDEX_0], descriptor);
1217
1218 napi_value result = nullptr;
1219 napi_get_undefined(env, &result);
1220 return result;
1221 }
1222
NAPI_RemoteObject_checkModifyLocalInterfaceArgs(napi_env env,size_t argc,napi_value * argv)1223 napi_value NAPI_RemoteObject_checkModifyLocalInterfaceArgs(napi_env env, size_t argc, napi_value* argv)
1224 {
1225 size_t expectedArgc = 2;
1226
1227 if (argc != expectedArgc) {
1228 ZLOGE(LOG_LABEL, "requires 2 parameters");
1229 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1230 }
1231 napi_valuetype valueType = napi_null;
1232 napi_typeof(env, argv[ARGV_INDEX_0], &valueType);
1233 if (valueType != napi_object) {
1234 ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
1235 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1236 }
1237 napi_typeof(env, argv[ARGV_INDEX_1], &valueType);
1238 if (valueType != napi_string) {
1239 ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
1240 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1241 }
1242 napi_value result = nullptr;
1243 napi_get_undefined(env, &result);
1244 return result;
1245 }
1246
NAPI_RemoteObject_modifyLocalInterface(napi_env env,napi_callback_info info)1247 static napi_value NAPI_RemoteObject_modifyLocalInterface(napi_env env, napi_callback_info info)
1248 {
1249 size_t argc = 2;
1250 napi_value argv[ARGV_LENGTH_2] = { 0 };
1251 napi_value thisVar = nullptr;
1252 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1253 napi_value checkArgsResult = NAPI_RemoteObject_checkModifyLocalInterfaceArgs(env, argc, argv);
1254 if (checkArgsResult == nullptr) {
1255 return checkArgsResult;
1256 }
1257 size_t bufferSize = 0;
1258 size_t maxLen = 40960;
1259 napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], nullptr, 0, &bufferSize);
1260 if (bufferSize >= maxLen) {
1261 ZLOGE(LOG_LABEL, "string length too large");
1262 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1263 }
1264 char stringValue[bufferSize + 1];
1265 size_t jsStringLength = 0;
1266 napi_get_value_string_utf8(env, argv[ARGV_INDEX_1], stringValue, bufferSize + 1, &jsStringLength);
1267 if (jsStringLength != bufferSize) {
1268 ZLOGE(LOG_LABEL, "string length wrong");
1269 return napiErr.ThrowError(env, errorDesc::CHECK_PARAM_ERROR);
1270 }
1271 std::string descriptor = stringValue;
1272
1273 NAPIRemoteObjectHolder *holder = nullptr;
1274 napi_unwrap(env, thisVar, (void* *)&holder);
1275 if (holder == nullptr) {
1276 ZLOGE(LOG_LABEL, "failed to get napi remote object holder");
1277 return nullptr;
1278 }
1279 holder->attachLocalInterface(argv[ARGV_INDEX_0], descriptor);
1280
1281 napi_value result = nullptr;
1282 napi_get_undefined(env, &result);
1283 return result;
1284 }
1285
NAPI_RemoteObject_addDeathRecipient(napi_env env,napi_callback_info info)1286 static napi_value NAPI_RemoteObject_addDeathRecipient(napi_env env, napi_callback_info info)
1287 {
1288 napi_value result = nullptr;
1289 napi_get_boolean(env, false, &result);
1290 return result;
1291 }
1292
NAPI_RemoteObject_registerDeathRecipient(napi_env env,napi_callback_info info)1293 static napi_value NAPI_RemoteObject_registerDeathRecipient(napi_env env, napi_callback_info info)
1294 {
1295 ZLOGE(LOG_LABEL, "only proxy object permitted");
1296 return napiErr.ThrowError(env, errorDesc::ONLY_PROXY_OBJECT_PERMITTED_ERROR);
1297 }
1298
NAPI_RemoteObject_removeDeathRecipient(napi_env env,napi_callback_info info)1299 static napi_value NAPI_RemoteObject_removeDeathRecipient(napi_env env, napi_callback_info info)
1300 {
1301 napi_value result = nullptr;
1302 napi_get_boolean(env, false, &result);
1303 return result;
1304 }
1305
NAPI_RemoteObject_unregisterDeathRecipient(napi_env env,napi_callback_info info)1306 static napi_value NAPI_RemoteObject_unregisterDeathRecipient(napi_env env, napi_callback_info info)
1307 {
1308 ZLOGE(LOG_LABEL, "only proxy object permitted");
1309 return napiErr.ThrowError(env, errorDesc::ONLY_PROXY_OBJECT_PERMITTED_ERROR);
1310 }
1311
NAPI_RemoteObject_isObjectDead(napi_env env,napi_callback_info info)1312 static napi_value NAPI_RemoteObject_isObjectDead(napi_env env, napi_callback_info info)
1313 {
1314 napi_value result = nullptr;
1315 napi_get_boolean(env, false, &result);
1316 return result;
1317 }
1318
1319 EXTERN_C_START
1320 /*
1321 * function for module exports
1322 */
NAPIRemoteObjectExport(napi_env env,napi_value exports)1323 napi_value NAPIRemoteObjectExport(napi_env env, napi_value exports)
1324 {
1325 const std::string className = "RemoteObject";
1326 napi_property_descriptor properties[] = {
1327 DECLARE_NAPI_FUNCTION("sendRequest", NAPI_RemoteObject_sendRequest),
1328 DECLARE_NAPI_FUNCTION("sendMessageRequest", NAPI_RemoteObject_sendMessageRequest),
1329 DECLARE_NAPI_FUNCTION("getCallingPid", NAPI_RemoteObject_getCallingPid),
1330 DECLARE_NAPI_FUNCTION("getCallingUid", NAPI_RemoteObject_getCallingUid),
1331 DECLARE_NAPI_FUNCTION("getInterfaceDescriptor", NAPI_RemoteObject_getInterfaceDescriptor),
1332 DECLARE_NAPI_FUNCTION("getDescriptor", NAPI_RemoteObject_getDescriptor),
1333 DECLARE_NAPI_FUNCTION("attachLocalInterface", NAPI_RemoteObject_attachLocalInterface),
1334 DECLARE_NAPI_FUNCTION("modifyLocalInterface", NAPI_RemoteObject_modifyLocalInterface),
1335 DECLARE_NAPI_FUNCTION("queryLocalInterface", NAPI_RemoteObject_queryLocalInterface),
1336 DECLARE_NAPI_FUNCTION("getLocalInterface", NAPI_RemoteObject_getLocalInterface),
1337 DECLARE_NAPI_FUNCTION("addDeathRecipient", NAPI_RemoteObject_addDeathRecipient),
1338 DECLARE_NAPI_FUNCTION("registerDeathRecipient", NAPI_RemoteObject_registerDeathRecipient),
1339 DECLARE_NAPI_FUNCTION("removeDeathRecipient", NAPI_RemoteObject_removeDeathRecipient),
1340 DECLARE_NAPI_FUNCTION("unregisterDeathRecipient", NAPI_RemoteObject_unregisterDeathRecipient),
1341 DECLARE_NAPI_FUNCTION("isObjectDead", NAPI_RemoteObject_isObjectDead),
1342 };
1343 napi_value constructor = nullptr;
1344 napi_define_class(env, className.c_str(), className.length(), RemoteObject_JS_Constructor, nullptr,
1345 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
1346 NAPI_ASSERT(env, constructor != nullptr, "define js class RemoteObject failed");
1347 napi_status status = napi_set_named_property(env, exports, "RemoteObject", constructor);
1348 NAPI_ASSERT(env, status == napi_ok, "set property RemoteObject to exports failed");
1349 napi_value global = nullptr;
1350 status = napi_get_global(env, &global);
1351 NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
1352 status = napi_set_named_property(env, global, "IPCStubConstructor_", constructor);
1353 NAPI_ASSERT(env, status == napi_ok, "set stub constructor failed");
1354 return exports;
1355 }
1356 EXTERN_C_END
1357 } // namespace OHOS
1358