• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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.h"
17 #include <mutex>
18 #include <set>
19 #include <cstring>
20 #include <thread>
21 #include <unistd.h>
22 #include <uv.h>
23 #include "access_token_adapter.h"
24 #include "hilog/log.h"
25 #include "ipc_object_proxy.h"
26 #include "ipc_object_stub.h"
27 #include "ipc_skeleton.h"
28 #include "ipc_thread_skeleton.h"
29 #include "ipc_types.h"
30 #include "log_tags.h"
31 #include "napi_message_option.h"
32 #include "napi_message_parcel.h"
33 #include "rpc_bytrace.h"
34 #include "string_ex.h"
35 
36 
37 namespace OHOS {
38 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC, "napi_remoteObject" };
39 #ifndef TITLE
40 #define TITLE __PRETTY_FUNCTION__
41 #endif
42 #define DBINDER_LOGE(fmt, args...) \
43     (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args)
44 #define DBINDER_LOGI(fmt, args...) \
45     (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args)
46 
47 /*
48  * The native DeathRecipient container.
49  * As an recipient of obituary of service death,
50  * and pass the message to js Layer.
51  */
52 class NAPIDeathRecipient : public IRemoteObject::DeathRecipient {
53 public:
54     explicit NAPIDeathRecipient(napi_env env, napi_value jsRecipient);
55 
56     void OnRemoteDied(const wptr<IRemoteObject> &object) override;
57 
58     bool Matches(napi_value jsRecipient);
59 
60 protected:
61     virtual ~NAPIDeathRecipient();
62 
63 private:
64     struct OnRemoteDiedParam {
65         napi_env env;
66         napi_ref deathRecipientRef;
67     };
68     napi_env env_ = nullptr;
69     napi_ref deathRecipientRef_ = nullptr;
70 };
71 
NAPIDeathRecipient(napi_env env,napi_value jsDeathRecipient)72 NAPIDeathRecipient::NAPIDeathRecipient(napi_env env, napi_value jsDeathRecipient)
73 {
74     env_ = env;
75     napi_status status = napi_create_reference(env_, jsDeathRecipient, 1, &deathRecipientRef_);
76     NAPI_ASSERT_RETURN_VOID(env, status == napi_ok, "failed to create ref to js death recipient");
77 }
78 
~NAPIDeathRecipient()79 NAPIDeathRecipient::~NAPIDeathRecipient()
80 {
81     if (env_ != nullptr) {
82         if (deathRecipientRef_ != nullptr) {
83             napi_status status = napi_delete_reference(env_, deathRecipientRef_);
84             NAPI_ASSERT_RETURN_VOID(env_, status == napi_ok, "failed to delete ref to js death recipient");
85             deathRecipientRef_ = nullptr;
86         }
87     }
88 }
89 
OnRemoteDied(const wptr<IRemoteObject> & object)90 void NAPIDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
91 {
92     if (deathRecipientRef_ == nullptr) {
93         DBINDER_LOGE("js death recipient has already removed");
94         return;
95     }
96 
97     uv_loop_s *loop = nullptr;
98     napi_get_uv_event_loop(env_, &loop);
99     uv_work_t *work = new(std::nothrow) uv_work_t;
100     if (work == nullptr) {
101         DBINDER_LOGE("failed to new uv_work_t");
102         return;
103     };
104     OnRemoteDiedParam *param = new OnRemoteDiedParam {
105         .env = env_,
106         .deathRecipientRef = deathRecipientRef_
107     };
108     work->data = reinterpret_cast<void *>(param);
109     DBINDER_LOGI("start to queue");
110     uv_queue_work(loop, work, [](uv_work_t *work) {}, [](uv_work_t *work, int status) {
111         DBINDER_LOGI("start to call onRmeoteDied");
112         OnRemoteDiedParam *param = reinterpret_cast<OnRemoteDiedParam *>(work->data);
113         napi_value jsDeathRecipient = nullptr;
114         napi_get_reference_value(param->env, param->deathRecipientRef, &jsDeathRecipient);
115         NAPI_ASSERT_RETURN_VOID(param->env, jsDeathRecipient != nullptr, "failed to get js death recipient");
116         napi_value onRemoteDied = nullptr;
117         napi_get_named_property(param->env, jsDeathRecipient, "onRemoteDied", &onRemoteDied);
118         NAPI_ASSERT_RETURN_VOID(param->env, onRemoteDied != nullptr, "failed to get property onRemoteDied");
119         napi_value return_val = nullptr;
120         napi_call_function(param->env, jsDeathRecipient, onRemoteDied, 0, nullptr, &return_val);
121         if (return_val == nullptr) {
122             DBINDER_LOGE("failed to call function onRemoteDied");
123         }
124         delete param;
125         delete work;
126     });
127 }
128 
Matches(napi_value object)129 bool NAPIDeathRecipient::Matches(napi_value object)
130 {
131     bool result = false;
132     if (object != nullptr) {
133         if (deathRecipientRef_ != nullptr) {
134             napi_value jsDeathRecipient = nullptr;
135             napi_get_reference_value(env_, deathRecipientRef_, &jsDeathRecipient);
136             napi_status status = napi_strict_equals(env_, object, jsDeathRecipient, &result);
137             if (status != napi_ok) {
138                 DBINDER_LOGI("compares death recipients failed");
139             }
140         }
141     }
142     return result;
143 }
144 
145 /*
146  * List of native NAPIDeathRecipient
147  */
148 class NAPIDeathRecipientList : public RefBase {
149 public:
150     NAPIDeathRecipientList();
151 
152     ~NAPIDeathRecipientList();
153 
154     bool Add(const sptr<NAPIDeathRecipient> &recipient);
155 
156     bool Remove(const sptr<NAPIDeathRecipient> &recipient);
157 
158     sptr<NAPIDeathRecipient> Find(napi_value jsRecipient);
159 private:
160     std::mutex mutex_;
161     std::set<sptr<NAPIDeathRecipient>> set_;
162 };
163 
NAPIDeathRecipientList()164 NAPIDeathRecipientList::NAPIDeathRecipientList() {}
165 
~NAPIDeathRecipientList()166 NAPIDeathRecipientList::~NAPIDeathRecipientList()
167 {
168     std::lock_guard<std::mutex> lockGuard(mutex_);
169     set_.clear();
170 }
171 
Add(const sptr<NAPIDeathRecipient> & recipient)172 bool NAPIDeathRecipientList::Add(const sptr<NAPIDeathRecipient> &recipient)
173 {
174     std::lock_guard<std::mutex> lockGuard(mutex_);
175     auto ret = set_.insert(recipient);
176     return ret.second;
177 }
178 
Remove(const sptr<NAPIDeathRecipient> & recipient)179 bool NAPIDeathRecipientList::Remove(const sptr<NAPIDeathRecipient> &recipient)
180 {
181     std::lock_guard<std::mutex> lockGuard(mutex_);
182     return (set_.erase(recipient) > 0);
183 }
184 
Find(napi_value jsRecipient)185 sptr<NAPIDeathRecipient> NAPIDeathRecipientList::Find(napi_value jsRecipient)
186 {
187     std::lock_guard<std::mutex> lockGuard(mutex_);
188     for (auto it = set_.begin(); it != set_.end(); it++) {
189         if ((*it)->Matches(jsRecipient)) {
190             return *it;
191         }
192     }
193     return nullptr;
194 }
195 
196 class NAPIRemoteProxyHolder {
197 public:
198     NAPIRemoteProxyHolder();
199     ~NAPIRemoteProxyHolder();
200     sptr<NAPIDeathRecipientList> list_;
201     sptr<IRemoteObject> object_;
202 };
203 
NAPIRemoteProxyHolder()204 NAPIRemoteProxyHolder::NAPIRemoteProxyHolder() : list_(nullptr), object_(nullptr) {}
205 
~NAPIRemoteProxyHolder()206 NAPIRemoteProxyHolder::~NAPIRemoteProxyHolder()
207 {
208     list_ = nullptr;
209     object_ = nullptr;
210 }
211 
RemoteProxy_JS_Constructor(napi_env env,napi_callback_info info)212 napi_value RemoteProxy_JS_Constructor(napi_env env, napi_callback_info info)
213 {
214     napi_value thisVar = nullptr;
215     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
216     // new napi proxy holder instance
217     auto proxyHolder = new NAPIRemoteProxyHolder();
218     // connect native object to js thisVar
219     napi_status status = napi_wrap(
220         env, thisVar, proxyHolder,
221         [](napi_env env, void *data, void *hint) {
222             DBINDER_LOGI("proxy holder destructed by js callback");
223             delete (reinterpret_cast<NAPIRemoteProxyHolder *>(data));
224         },
225         nullptr, nullptr);
226     NAPI_ASSERT(env, status == napi_ok, "wrap js RemoteProxy and native holder failed");
227     return thisVar;
228 }
229 
230 EXTERN_C_START
231 /*
232  * function for module exports
233  */
NAPIRemoteProxyExport(napi_env env,napi_value exports)234 napi_value NAPIRemoteProxyExport(napi_env env, napi_value exports)
235 {
236     const std::string className = "RemoteProxy";
237     napi_value pingTransaction = nullptr;
238     napi_create_int32(env, PING_TRANSACTION, &pingTransaction);
239     napi_value dumpTransaction = nullptr;
240     napi_create_int32(env, DUMP_TRANSACTION, &dumpTransaction);
241     napi_value interfaceTransaction = nullptr;
242     napi_create_int32(env, INTERFACE_TRANSACTION, &interfaceTransaction);
243     napi_value minTransactionId = nullptr;
244     napi_create_int32(env, MIN_TRANSACTION_ID, &minTransactionId);
245     napi_value maxTransactionId = nullptr;
246     napi_create_int32(env, MAX_TRANSACTION_ID, &maxTransactionId);
247     napi_property_descriptor properties[] = {
248         DECLARE_NAPI_FUNCTION("queryLocalInterface", NAPI_RemoteProxy_queryLocalInterface),
249         DECLARE_NAPI_FUNCTION("addDeathRecipient", NAPI_RemoteProxy_addDeathRecipient),
250         DECLARE_NAPI_FUNCTION("removeDeathRecipient", NAPI_RemoteProxy_removeDeathRecipient),
251         DECLARE_NAPI_FUNCTION("getInterfaceDescriptor", NAPI_RemoteProxy_getInterfaceDescriptor),
252         DECLARE_NAPI_FUNCTION("sendRequest", NAPI_RemoteProxy_sendRequest),
253         DECLARE_NAPI_FUNCTION("isObjectDead", NAPI_RemoteProxy_isObjectDead),
254         DECLARE_NAPI_STATIC_PROPERTY("PING_TRANSACTION", pingTransaction),
255         DECLARE_NAPI_STATIC_PROPERTY("DUMP_TRANSACTION", dumpTransaction),
256         DECLARE_NAPI_STATIC_PROPERTY("INTERFACE_TRANSACTION", interfaceTransaction),
257         DECLARE_NAPI_STATIC_PROPERTY("MIN_TRANSACTION_ID", minTransactionId),
258         DECLARE_NAPI_STATIC_PROPERTY("MAX_TRANSACTION_ID", maxTransactionId),
259     };
260     napi_value constructor = nullptr;
261     napi_define_class(env, className.c_str(), className.length(), RemoteProxy_JS_Constructor, nullptr,
262         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
263     NAPI_ASSERT(env, constructor != nullptr, "define js class RemoteProxy failed");
264     napi_status status = napi_set_named_property(env, exports, "RemoteProxy", constructor);
265     NAPI_ASSERT(env, status == napi_ok, "set property RemoteProxy to exports failed");
266     napi_value global = nullptr;
267     status = napi_get_global(env, &global);
268     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
269     status = napi_set_named_property(env, global, "IPCProxyConstructor_", constructor);
270     NAPI_ASSERT(env, status == napi_ok, "set proxy constructor failed");
271     return exports;
272 }
273 EXTERN_C_END
274 
275 /*
276  * The native NAPIRemoteObject act as bridger between js and native.
277  * It received the request from client and pass it js Layer.
278  */
279 class NAPIRemoteObject : public IPCObjectStub {
280 public:
281     NAPIRemoteObject(napi_env env, napi_value thisVar, const std::u16string &descriptor);
282 
283     ~NAPIRemoteObject() override;
284 
285     bool CheckObjectLegality() const override;
286 
287     int GetObjectType() const override;
288 
289     int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
290 
291     napi_ref GetJsObjectRef() const;
292 private:
293     napi_env env_ = nullptr;
294     napi_value thisVar_ = nullptr;
295     napi_ref thisVarRef_ = nullptr;
296     struct ThreadLockInfo {
297         std::mutex mutex;
298         std::condition_variable condition;
299         bool ready = false;
300     };
301     struct CallbackParam {
302         napi_env env;
303         napi_ref thisVarRef;
304         uint32_t code;
305         MessageParcel *data;
306         MessageParcel *reply;
307         MessageOption *option;
308         pid_t callingPid;
309         pid_t callingUid;
310         uint32_t callingTokenId;
311         std::string callingDeviceID;
312         std::string localDeviceID;
313         bool isLocalCalling;
314         int activeStatus;
315         ThreadLockInfo *lockInfo;
316         int result;
317     };
318     int OnJsRemoteRequest(CallbackParam *param);
319 };
320 
321 /*
322  * To ensure a better consistency of the life time of
323  * js RemoteObject and native object, we designed
324  * a container to save the native object.
325  */
326 class NAPIRemoteObjectHolder : public RefBase {
327 public:
328     explicit NAPIRemoteObjectHolder(napi_env env, const std::u16string &descriptor);
329     ~NAPIRemoteObjectHolder();
330     sptr<NAPIRemoteObject> Get(napi_value object);
331     void Set(sptr<NAPIRemoteObject> object);
332     void attachLocalInterface(napi_value localInterface, std::string &descriptor);
333     napi_value queryLocalInterface(std::string &descriptor);
334 private:
335     std::mutex mutex_;
336     napi_env env_ = nullptr;
337     std::u16string descriptor_;
338     sptr<NAPIRemoteObject> cachedObject_;
339     napi_ref localInterfaceRef_;
340 };
341 
NAPIRemoteObjectHolder(napi_env env,const std::u16string & descriptor)342 NAPIRemoteObjectHolder::NAPIRemoteObjectHolder(napi_env env, const std::u16string &descriptor)
343     : env_(env), descriptor_(descriptor), cachedObject_(nullptr), localInterfaceRef_(nullptr)
344 {}
345 
~NAPIRemoteObjectHolder()346 NAPIRemoteObjectHolder::~NAPIRemoteObjectHolder()
347 {
348     // free the reference of object.
349     cachedObject_ = nullptr;
350     if (localInterfaceRef_ != nullptr) {
351         napi_delete_reference(env_, localInterfaceRef_);
352     }
353 }
354 
Get(napi_value jsRemoteObject)355 sptr<NAPIRemoteObject> NAPIRemoteObjectHolder::Get(napi_value jsRemoteObject)
356 {
357     std::lock_guard<std::mutex> lockGuard(mutex_);
358     // grab an strong reference to the object,
359     // so it will not be freed util this reference released.
360     sptr<NAPIRemoteObject> remoteObject = nullptr;
361     if (cachedObject_ != nullptr) {
362         remoteObject = cachedObject_;
363     }
364 
365     if (remoteObject == nullptr) {
366         remoteObject = new NAPIRemoteObject(env_, jsRemoteObject, descriptor_);
367         cachedObject_ = remoteObject;
368     }
369     return remoteObject;
370 }
371 
Set(sptr<NAPIRemoteObject> object)372 void NAPIRemoteObjectHolder::Set(sptr<NAPIRemoteObject> object)
373 {
374     std::lock_guard<std::mutex> lockGuard(mutex_);
375     cachedObject_ = object;
376 }
377 
attachLocalInterface(napi_value localInterface,std::string & descriptor)378 void NAPIRemoteObjectHolder::attachLocalInterface(napi_value localInterface, std::string &descriptor)
379 {
380     if (localInterfaceRef_ != nullptr) {
381         napi_delete_reference(env_, localInterfaceRef_);
382     }
383     napi_create_reference(env_, localInterface, 1, &localInterfaceRef_);
384     descriptor_ = Str8ToStr16(descriptor);
385 }
386 
queryLocalInterface(std::string & descriptor)387 napi_value NAPIRemoteObjectHolder::queryLocalInterface(std::string &descriptor)
388 {
389     if (!descriptor_.empty() && strcmp(Str16ToStr8(descriptor_).c_str(), descriptor.c_str()) == 0) {
390         napi_value ret = nullptr;
391         napi_get_reference_value(env_, localInterfaceRef_, &ret);
392         return ret;
393     }
394     napi_value result = nullptr;
395     napi_get_null(env_, &result);
396     return result;
397 }
398 
RemoteObject_JS_Constructor(napi_env env,napi_callback_info info)399 napi_value RemoteObject_JS_Constructor(napi_env env, napi_callback_info info)
400 {
401     // new napi remote object
402     size_t argc = 2;
403     size_t expectedArgc = 1;
404     napi_value argv[2] = { 0 };
405     napi_value thisVar = nullptr;
406     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
407     NAPI_ASSERT(env, argc >= expectedArgc, "requires at least 1 parameters");
408     napi_valuetype valueType = napi_null;
409     napi_typeof(env, argv[0], &valueType);
410     NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1");
411     size_t bufferSize = 0;
412     size_t maxLen = 40960;
413     napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize);
414     NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
415     char stringValue[bufferSize + 1];
416     size_t jsStringLength = 0;
417     napi_get_value_string_utf8(env, argv[0], stringValue, bufferSize + 1, &jsStringLength);
418     NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
419     std::string descriptor = stringValue;
420     auto holder = new NAPIRemoteObjectHolder(env, Str8ToStr16(descriptor));
421     // connect native object to js thisVar
422     napi_status status = napi_wrap(
423         env, thisVar, holder,
424         [](napi_env env, void *data, void *hint) {
425             DBINDER_LOGI("NAPIRemoteObjectHolder destructed by js callback");
426             delete (reinterpret_cast<NAPIRemoteObjectHolder *>(data));
427         },
428         nullptr, nullptr);
429     NAPI_ASSERT(env, status == napi_ok, "wrap js RemoteObject and native holder failed");
430     return thisVar;
431 }
432 
433 EXTERN_C_START
434 /*
435  * function for module exports
436  */
NAPIRemoteObjectExport(napi_env env,napi_value exports)437 napi_value NAPIRemoteObjectExport(napi_env env, napi_value exports)
438 {
439     const std::string className = "RemoteObject";
440     napi_property_descriptor properties[] = {
441         DECLARE_NAPI_FUNCTION("sendRequest", NAPI_RemoteObject_sendRequest),
442         DECLARE_NAPI_FUNCTION("getCallingPid", NAPI_RemoteObject_getCallingPid),
443         DECLARE_NAPI_FUNCTION("getCallingUid", NAPI_RemoteObject_getCallingUid),
444         DECLARE_NAPI_FUNCTION("getInterfaceDescriptor", NAPI_RemoteObject_getInterfaceDescriptor),
445         DECLARE_NAPI_FUNCTION("attachLocalInterface", NAPI_RemoteObject_attachLocalInterface),
446         DECLARE_NAPI_FUNCTION("queryLocalInterface", NAPI_RemoteObject_queryLocalInterface),
447         DECLARE_NAPI_FUNCTION("addDeathRecipient", NAPI_RemoteObject_addDeathRecipient),
448         DECLARE_NAPI_FUNCTION("removeDeathRecipient", NAPI_RemoteObject_removeDeathRecipient),
449         DECLARE_NAPI_FUNCTION("isObjectDead", NAPI_RemoteObject_isObjectDead),
450     };
451     napi_value constructor = nullptr;
452     napi_define_class(env, className.c_str(), className.length(), RemoteObject_JS_Constructor, nullptr,
453         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
454     NAPI_ASSERT(env, constructor != nullptr, "define js class RemoteObject failed");
455     napi_status status = napi_set_named_property(env, exports, "RemoteObject", constructor);
456     NAPI_ASSERT(env, status == napi_ok, "set property RemoteObject to exports failed");
457     napi_value global = nullptr;
458     status = napi_get_global(env, &global);
459     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
460     status = napi_set_named_property(env, global, "IPCStubConstructor_", constructor);
461     NAPI_ASSERT(env, status == napi_ok, "set stub constructor failed");
462     return exports;
463 }
464 EXTERN_C_END
465 
NAPIRemoteObject(napi_env env,napi_value thisVar,const std::u16string & descriptor)466 NAPIRemoteObject::NAPIRemoteObject(napi_env env, napi_value thisVar, const std::u16string &descriptor)
467     : IPCObjectStub(descriptor)
468 {
469     env_ = env;
470     thisVar_ = thisVar;
471     napi_create_reference(env, thisVar_, 1, &thisVarRef_);
472     NAPI_ASSERT_RETURN_VOID(env, thisVarRef_ != nullptr, "failed to create ref to js RemoteObject");
473 }
474 
~NAPIRemoteObject()475 NAPIRemoteObject::~NAPIRemoteObject()
476 {
477     DBINDER_LOGI("NAPIRemoteObject Destructor");
478     if (thisVarRef_ != nullptr) {
479         napi_status status = napi_delete_reference(env_, thisVarRef_);
480         NAPI_ASSERT_RETURN_VOID(env_, status == napi_ok, "failed to delete ref to js RemoteObject");
481         thisVarRef_ = nullptr;
482     }
483 }
484 
CheckObjectLegality() const485 bool NAPIRemoteObject::CheckObjectLegality() const
486 {
487     return true;
488 }
489 
GetObjectType() const490 int NAPIRemoteObject::GetObjectType() const
491 {
492     return OBJECT_TYPE_JAVASCRIPT;
493 }
494 
GetJsObjectRef() const495 napi_ref NAPIRemoteObject::GetJsObjectRef() const
496 {
497     return thisVarRef_;
498 }
499 
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)500 int NAPIRemoteObject::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
501 {
502     DBINDER_LOGI("enter OnRemoteRequest");
503     if (code == DUMP_TRANSACTION) {
504         DBINDER_LOGE("DUMP_TRANSACTION data size:%zu", data.GetReadableBytes());
505     }
506     pid_t callingPid = IPCSkeleton::GetCallingPid();
507     pid_t callingUid = IPCSkeleton::GetCallingUid();
508     uint32_t callingTokenId = IPCSkeleton::GetCallingTokenID();
509     std::string callingDeviceID = IPCSkeleton::GetCallingDeviceID();
510     std::string localDeviceID = IPCSkeleton::GetLocalDeviceID();
511     bool isLocalCalling = IPCSkeleton::IsLocalCalling();
512     DBINDER_LOGI("callingPid:%{public}u, callingUid:%{public}u, callingDeviceID:%{public}s,\
513         localDeviceId:%{public}s, localCalling:%{public}d",
514         callingPid, callingUid, callingDeviceID.c_str(), localDeviceID.c_str(), isLocalCalling);
515     std::shared_ptr<struct ThreadLockInfo> lockInfo = std::make_shared<struct ThreadLockInfo>();
516     CallbackParam *param = new CallbackParam {
517         .env = env_,
518         .thisVarRef = thisVarRef_,
519         .code = code,
520         .data = &data,
521         .reply = &reply,
522         .option = &option,
523         .callingPid = callingPid,
524         .callingUid = callingUid,
525         .callingTokenId = callingTokenId,
526         .callingDeviceID = callingDeviceID,
527         .localDeviceID = localDeviceID,
528         .isLocalCalling = isLocalCalling,
529         .activeStatus = IRemoteInvoker::ACTIVE_INVOKER,
530         .lockInfo = lockInfo.get(),
531         .result = 0
532     };
533     int ret = OnJsRemoteRequest(param);
534     DBINDER_LOGI("OnJsRemoteRequest done, ret:%{public}d", ret);
535     return ret;
536 }
537 
OnJsRemoteRequest(CallbackParam * jsParam)538 int NAPIRemoteObject::OnJsRemoteRequest(CallbackParam *jsParam)
539 {
540     uv_loop_s *loop = nullptr;
541     napi_get_uv_event_loop(env_, &loop);
542 
543     uv_work_t *work = new(std::nothrow) uv_work_t;
544     if (work == nullptr) {
545         DBINDER_LOGE("failed to new uv_work_t");
546         delete jsParam;
547         return -1;
548     }
549     work->data = reinterpret_cast<void *>(jsParam);
550     DBINDER_LOGI("start nv queue work loop");
551     uv_queue_work(loop, work, [](uv_work_t *work) {}, [](uv_work_t *work, int status) {
552         DBINDER_LOGI("enter thread pool");
553         CallbackParam *param = reinterpret_cast<CallbackParam *>(work->data);
554         napi_value onRemoteRequest = nullptr;
555         napi_value thisVar = nullptr;
556         napi_get_reference_value(param->env, param->thisVarRef, &thisVar);
557         if (thisVar == nullptr) {
558             DBINDER_LOGE("thisVar is null");
559             param->result = -1;
560             std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
561             param->lockInfo->ready = true;
562             param->lockInfo->condition.notify_all();
563             return;
564         }
565         napi_get_named_property(param->env, thisVar, "onRemoteRequest", &onRemoteRequest);
566         if (onRemoteRequest == nullptr) {
567             DBINDER_LOGE("get founction onRemoteRequest failed");
568             param->result = -1;
569             std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
570             param->lockInfo->ready = true;
571             param->lockInfo->condition.notify_all();
572             return;
573         }
574         napi_value jsCode;
575         napi_create_uint32(param->env, param->code, &jsCode);
576 
577         napi_value global = nullptr;
578         napi_get_global(param->env, &global);
579         if (global == nullptr) {
580             DBINDER_LOGE("get napi global 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             return;
586         }
587         napi_value jsOptionConstructor = nullptr;
588         napi_get_named_property(param->env, global, "IPCOptionConstructor_", &jsOptionConstructor);
589         if (jsOptionConstructor == nullptr) {
590             DBINDER_LOGE("jsOption constructor is null");
591             param->result = -1;
592             std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
593             param->lockInfo->ready = true;
594             param->lockInfo->condition.notify_all();
595             return;
596         }
597         napi_value jsOption;
598         size_t argc = 2;
599         napi_value flags = nullptr;
600         napi_create_int32(param->env, param->option->GetFlags(), &flags);
601         napi_value waittime = nullptr;
602         napi_create_int32(param->env, param->option->GetWaitTime(), &waittime);
603         napi_value argv[2] = { flags, waittime };
604         napi_new_instance(param->env, jsOptionConstructor, argc, argv, &jsOption);
605         if (jsOption == nullptr) {
606             DBINDER_LOGE("new jsOption 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             return;
612         }
613         napi_value jsParcelConstructor = nullptr;
614         napi_get_named_property(param->env, global, "IPCParcelConstructor_", &jsParcelConstructor);
615         if (jsParcelConstructor == nullptr) {
616             DBINDER_LOGE("jsParcel constructor is null");
617             param->result = -1;
618             std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
619             param->lockInfo->ready = true;
620             param->lockInfo->condition.notify_all();
621             return;
622         }
623         napi_value jsData;
624         napi_value dataParcel;
625         napi_create_int64(param->env, reinterpret_cast<int64_t>(param->data), &dataParcel);
626         if (dataParcel == nullptr) {
627             DBINDER_LOGE("create js object for data parcel address failed");
628             param->result = -1;
629             std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
630             param->lockInfo->ready = true;
631             param->lockInfo->condition.notify_all();
632             return;
633         }
634         size_t argc3 = 1;
635         napi_value argv3[1] = { dataParcel };
636         napi_new_instance(param->env, jsParcelConstructor, argc3, argv3, &jsData);
637         if (jsData == nullptr) {
638             DBINDER_LOGE("create js data parcel failed");
639             param->result = -1;
640             std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
641             param->lockInfo->ready = true;
642             param->lockInfo->condition.notify_all();
643             return;
644         }
645         napi_value jsReply;
646         napi_value replyParcel;
647         napi_create_int64(param->env, reinterpret_cast<int64_t>(param->reply), &replyParcel);
648         if (replyParcel == nullptr) {
649             DBINDER_LOGE("create js object for reply parcel address failed");
650             param->result = -1;
651             std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
652             param->lockInfo->ready = true;
653             param->lockInfo->condition.notify_all();
654             return;
655         }
656         size_t argc4 = 1;
657         napi_value argv4[1] = { replyParcel };
658         napi_new_instance(param->env, jsParcelConstructor, argc4, argv4, &jsReply);
659         if (jsReply == nullptr) {
660             DBINDER_LOGE("create js reply parcel failed");
661             param->result = -1;
662             std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
663             param->lockInfo->ready = true;
664             param->lockInfo->condition.notify_all();
665             return;
666         }
667         // save old calling pid, uid, device id
668         napi_get_global(param->env, &global);
669         napi_value oldPid;
670         napi_get_named_property(param->env, global, "callingPid_", &oldPid);
671         napi_value oldUid;
672         napi_get_named_property(param->env, global, "callingUid_", &oldUid);
673         napi_value oldCallingTokenId;
674         napi_get_named_property(param->env, global, "callingTokenId_", &oldCallingTokenId);
675         napi_value oldCallingDeviceID;
676         napi_get_named_property(param->env, global, "callingDeviceID_", &oldCallingDeviceID);
677         napi_value oldLocalDeviceID;
678         napi_get_named_property(param->env, global, "localDeviceID_", &oldLocalDeviceID);
679         napi_value oldIsLocalCalling;
680         napi_get_named_property(param->env, global, "isLocalCalling_", &oldIsLocalCalling);
681         napi_value oldActiveStatus;
682         napi_get_named_property(param->env, global, "activeStatus_", &oldActiveStatus);
683 
684         // set new calling pid, uid, device id
685         napi_value newPid;
686         napi_create_int32(param->env, static_cast<int32_t>(param->callingPid), &newPid);
687         napi_set_named_property(param->env, global, "callingPid_", newPid);
688         napi_value newUid;
689         napi_create_int32(param->env, static_cast<int32_t>(param->callingUid), &newUid);
690         napi_set_named_property(param->env, global, "callingUid_", newUid);
691         napi_value newCallingTokenId;
692         napi_create_uint32(param->env, param->callingTokenId, &newCallingTokenId);
693         napi_set_named_property(param->env, global, "callingTokenId_", newCallingTokenId);
694         napi_value newDeviceID;
695         napi_create_string_utf8(param->env, param->callingDeviceID.c_str(), NAPI_AUTO_LENGTH, &newDeviceID);
696         napi_set_named_property(param->env, global, "callingDeviceID_", newDeviceID);
697         napi_value newLocalDeviceID;
698         napi_create_string_utf8(param->env, param->localDeviceID.c_str(), NAPI_AUTO_LENGTH, &newLocalDeviceID);
699         napi_set_named_property(param->env, global, "localDeviceID_", newLocalDeviceID);
700         napi_value newIsLocalCalling;
701         napi_get_boolean(param->env, param->isLocalCalling, &newIsLocalCalling);
702         napi_set_named_property(param->env, global, "isLocalCalling_", newIsLocalCalling);
703         napi_value newActiveStatus;
704         napi_create_int32(param->env, param->activeStatus, &newActiveStatus);
705         napi_set_named_property(param->env, global, "activeStatus_", newActiveStatus);
706 
707         // start to call onRemoteRequest
708         size_t argc2 = 4;
709         napi_value argv2[] = { jsCode, jsData, jsReply, jsOption };
710         napi_value return_val;
711         napi_status ret = napi_call_function(param->env, thisVar, onRemoteRequest, argc2, argv2, &return_val);
712         DBINDER_LOGI("call js onRemoteRequest done");
713         if (ret != napi_ok) {
714             DBINDER_LOGE("OnRemoteRequest got exception");
715             param->result = ERR_UNKNOWN_TRANSACTION;
716         } else {
717             bool result = false;
718             napi_get_value_bool(param->env, return_val, &result);
719             if (!result) {
720                 DBINDER_LOGE("OnRemoteRequest res:%{public}s", result ? "true" : "false");
721                 param->result = ERR_UNKNOWN_TRANSACTION;
722             } else {
723                 param->result = ERR_NONE;
724             }
725         }
726 
727         napi_set_named_property(param->env, global, "callingPid_", oldPid);
728         napi_set_named_property(param->env, global, "callingUid_", oldUid);
729         napi_set_named_property(param->env, global, "callingTokenId_", oldCallingTokenId);
730         napi_set_named_property(param->env, global, "callingDeviceID_", oldCallingDeviceID);
731         napi_set_named_property(param->env, global, "localDeviceID_", oldLocalDeviceID);
732         napi_set_named_property(param->env, global, "isLocalCalling_", oldIsLocalCalling);
733         napi_set_named_property(param->env, global, "activeStatus_", oldActiveStatus);
734         std::unique_lock<std::mutex> lock(param->lockInfo->mutex);
735         param->lockInfo->ready = true;
736         param->lockInfo->condition.notify_all();
737     });
738     std::unique_lock<std::mutex> lock(jsParam->lockInfo->mutex);
739     jsParam->lockInfo->condition.wait(lock, [&jsParam] { return jsParam->lockInfo->ready; });
740     int ret = jsParam->result;
741     delete jsParam;
742     delete work;
743     return ret;
744 }
745 
NAPI_ohos_rpc_getRemoteProxyHolder(napi_env env,napi_value jsRemoteProxy)746 NAPIRemoteProxyHolder *NAPI_ohos_rpc_getRemoteProxyHolder(napi_env env, napi_value jsRemoteProxy)
747 {
748     NAPIRemoteProxyHolder *proxyHolder = nullptr;
749     napi_unwrap(env, jsRemoteProxy, (void **)&proxyHolder);
750     NAPI_ASSERT(env, proxyHolder != nullptr, "failed to get napi remote proxy holder");
751     return proxyHolder;
752 }
753 
NAPI_ohos_rpc_CreateJsRemoteObject(napi_env env,const sptr<IRemoteObject> target)754 napi_value NAPI_ohos_rpc_CreateJsRemoteObject(napi_env env, const sptr<IRemoteObject> target)
755 {
756     if (target == nullptr) {
757         DBINDER_LOGE("RemoteObject is null");
758         return nullptr;
759     }
760 
761     if (target->CheckObjectLegality()) {
762         IPCObjectStub *tmp = static_cast<IPCObjectStub *>(target.GetRefPtr());
763         DBINDER_LOGI("object type:%{public}d", tmp->GetObjectType());
764         if (tmp->GetObjectType() == IPCObjectStub::OBJECT_TYPE_JAVASCRIPT) {
765             DBINDER_LOGI("napi create js remote object");
766             sptr<NAPIRemoteObject> object = static_cast<NAPIRemoteObject *>(target.GetRefPtr());
767             // retrieve js remote object constructor
768             napi_value global = nullptr;
769             napi_status status = napi_get_global(env, &global);
770             NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
771             napi_value constructor = nullptr;
772             status = napi_get_named_property(env, global, "IPCStubConstructor_", &constructor);
773             NAPI_ASSERT(env, status == napi_ok, "set stub constructor failed");
774             NAPI_ASSERT(env, constructor != nullptr, "failed to get js RemoteObject constructor");
775             // retrieve descriptor and it's length
776             std::u16string descriptor = object->GetObjectDescriptor();
777             std::string desc = Str16ToStr8(descriptor);
778             napi_value jsDesc = nullptr;
779             napi_create_string_utf8(env, desc.c_str(), desc.length(), &jsDesc);
780             // create a new js remote object
781             size_t argc = 1;
782             napi_value argv[1] = { jsDesc };
783             napi_value jsRemoteObject = nullptr;
784             status = napi_new_instance(env, constructor, argc, argv, &jsRemoteObject);
785             NAPI_ASSERT(env, status == napi_ok, "failed to  construct js RemoteObject");
786             // retrieve holder and set object
787             NAPIRemoteObjectHolder *holder = nullptr;
788             napi_unwrap(env, jsRemoteObject, (void **)&holder);
789             NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
790             holder->Set(object);
791             return jsRemoteObject;
792         }
793     }
794 
795     napi_value global = nullptr;
796     napi_status status = napi_get_global(env, &global);
797     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
798     napi_value constructor = nullptr;
799     status = napi_get_named_property(env, global, "IPCProxyConstructor_", &constructor);
800     NAPI_ASSERT(env, status == napi_ok, "get proxy constructor failed");
801     napi_value jsRemoteProxy;
802     status = napi_new_instance(env, constructor, 0, nullptr, &jsRemoteProxy);
803     NAPI_ASSERT(env, status == napi_ok, "failed to  construct js RemoteProxy");
804     NAPIRemoteProxyHolder *proxyHolder = NAPI_ohos_rpc_getRemoteProxyHolder(env, jsRemoteProxy);
805     proxyHolder->object_ = target;
806     proxyHolder->list_ = new NAPIDeathRecipientList();
807 
808     return jsRemoteProxy;
809 }
810 
NAPI_ohos_rpc_getNativeRemoteObject(napi_env env,napi_value object)811 sptr<IRemoteObject> NAPI_ohos_rpc_getNativeRemoteObject(napi_env env, napi_value object)
812 {
813     if (object != nullptr) {
814         napi_value global = nullptr;
815         napi_status status = napi_get_global(env, &global);
816         NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
817         napi_value stubConstructor = nullptr;
818         status = napi_get_named_property(env, global, "IPCStubConstructor_", &stubConstructor);
819         NAPI_ASSERT(env, status == napi_ok, "get stub constructor failed");
820         bool instanceOfStub = false;
821         status = napi_instanceof(env, object, stubConstructor, &instanceOfStub);
822         NAPI_ASSERT(env, status == napi_ok, "failed to check js object type");
823         if (instanceOfStub) {
824             NAPIRemoteObjectHolder *holder = nullptr;
825             napi_unwrap(env, object, (void **)&holder);
826             NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
827             return holder != nullptr ? holder->Get(object) : nullptr;
828         }
829 
830         napi_value proxyConstructor = nullptr;
831         status = napi_get_named_property(env, global, "IPCProxyConstructor_", &proxyConstructor);
832         NAPI_ASSERT(env, status == napi_ok, "get proxy constructor failed");
833         bool instanceOfProxy = false;
834         status = napi_instanceof(env, object, proxyConstructor, &instanceOfProxy);
835         NAPI_ASSERT(env, status == napi_ok, "failed to check js object type");
836         if (instanceOfProxy) {
837             NAPIRemoteProxyHolder *holder = NAPI_ohos_rpc_getRemoteProxyHolder(env, object);
838             return holder != nullptr ? holder->object_ : nullptr;
839         }
840     }
841     return nullptr;
842 }
843 
NAPI_IPCSkeleton_getContextObject(napi_env env,napi_callback_info info)844 napi_value NAPI_IPCSkeleton_getContextObject(napi_env env, napi_callback_info info)
845 {
846     sptr<IRemoteObject> object = IPCSkeleton::GetContextObject();
847     if (object == nullptr) {
848         DBINDER_LOGE("fatal error, could not get registry object");
849         return nullptr;
850     }
851     return NAPI_ohos_rpc_CreateJsRemoteObject(env, object);
852 }
853 
NAPI_IPCSkeleton_getCallingPid(napi_env env,napi_callback_info info)854 napi_value NAPI_IPCSkeleton_getCallingPid(napi_env env, napi_callback_info info)
855 {
856     napi_value global = nullptr;
857     napi_get_global(env, &global);
858     napi_value napiActiveStatus = nullptr;
859     napi_get_named_property(env, global, "activeStatus_", &napiActiveStatus);
860     if (napiActiveStatus != nullptr) {
861         int32_t activeStatus = IRemoteInvoker::IDLE_INVOKER;
862         napi_get_value_int32(env, napiActiveStatus, &activeStatus);
863         if (activeStatus == IRemoteInvoker::ACTIVE_INVOKER) {
864             napi_value callingPid = nullptr;
865             napi_get_named_property(env, global, "callingPid_", &callingPid);
866             return callingPid;
867         }
868     }
869     pid_t pid = getpid();
870     napi_value result = nullptr;
871     napi_create_int32(env, static_cast<int32_t>(pid), &result);
872     return result;
873 }
874 
NAPI_IPCSkeleton_getCallingUid(napi_env env,napi_callback_info info)875 napi_value NAPI_IPCSkeleton_getCallingUid(napi_env env, napi_callback_info info)
876 {
877     napi_value global = nullptr;
878     napi_get_global(env, &global);
879     napi_value napiActiveStatus = nullptr;
880     napi_get_named_property(env, global, "activeStatus_", &napiActiveStatus);
881     if (napiActiveStatus != nullptr) {
882         int32_t activeStatus = IRemoteInvoker::IDLE_INVOKER;
883         napi_get_value_int32(env, napiActiveStatus, &activeStatus);
884         if (activeStatus == IRemoteInvoker::ACTIVE_INVOKER) {
885             napi_value callingUid = nullptr;
886             napi_get_named_property(env, global, "callingUid_", &callingUid);
887             return callingUid;
888         }
889     }
890     uint32_t uid = getuid();
891     napi_value result = nullptr;
892     napi_create_int32(env, static_cast<int32_t>(uid), &result);
893     return result;
894 }
895 
NAPI_IPCSkeleton_getCallingTokenId(napi_env env,napi_callback_info info)896 napi_value NAPI_IPCSkeleton_getCallingTokenId(napi_env env, napi_callback_info info)
897 {
898     napi_value global = nullptr;
899     napi_get_global(env, &global);
900     napi_value napiActiveStatus = nullptr;
901     napi_get_named_property(env, global, "activeStatus_", &napiActiveStatus);
902     if (napiActiveStatus != nullptr) {
903         int32_t activeStatus = IRemoteInvoker::IDLE_INVOKER;
904         napi_get_value_int32(env, napiActiveStatus, &activeStatus);
905         if (activeStatus == IRemoteInvoker::ACTIVE_INVOKER) {
906             napi_value callingTokenId = nullptr;
907             napi_get_named_property(env, global, "callingTokenId_", &callingTokenId);
908             return callingTokenId;
909         }
910     }
911     uint64_t TokenId = RpcGetSelfTokenID();
912     napi_value result = nullptr;
913     napi_create_uint32(env, static_cast<uint32_t>(TokenId), &result);
914     return result;
915 }
916 
NAPI_IPCSkeleton_getCallingDeviceID(napi_env env,napi_callback_info info)917 napi_value NAPI_IPCSkeleton_getCallingDeviceID(napi_env env, napi_callback_info info)
918 {
919     napi_value global = nullptr;
920     napi_get_global(env, &global);
921     napi_value napiActiveStatus = nullptr;
922     napi_get_named_property(env, global, "activeStatus_", &napiActiveStatus);
923     if (napiActiveStatus != nullptr) {
924         int32_t activeStatus = IRemoteInvoker::IDLE_INVOKER;
925         napi_get_value_int32(env, napiActiveStatus, &activeStatus);
926         if (activeStatus == IRemoteInvoker::ACTIVE_INVOKER) {
927             napi_value callingDeviceID = nullptr;
928             napi_get_named_property(env, global, "callingDeviceID_", &callingDeviceID);
929             return callingDeviceID;
930         }
931     }
932     napi_value result = nullptr;
933     napi_create_string_utf8(env, "", 0, &result);
934     return result;
935 }
936 
NAPI_IPCSkeleton_getLocalDeviceID(napi_env env,napi_callback_info info)937 napi_value NAPI_IPCSkeleton_getLocalDeviceID(napi_env env, napi_callback_info info)
938 {
939     napi_value global = nullptr;
940     napi_get_global(env, &global);
941     napi_value napiActiveStatus = nullptr;
942     napi_get_named_property(env, global, "activeStatus_", &napiActiveStatus);
943     if (napiActiveStatus != nullptr) {
944         int32_t activeStatus = IRemoteInvoker::IDLE_INVOKER;
945         napi_get_value_int32(env, napiActiveStatus, &activeStatus);
946         if (activeStatus == IRemoteInvoker::ACTIVE_INVOKER) {
947             napi_value localDeviceID = nullptr;
948             napi_get_named_property(env, global, "localDeviceID_", &localDeviceID);
949             return localDeviceID;
950         }
951     }
952     napi_value result = nullptr;
953     napi_create_string_utf8(env, "", 0, &result);
954     return result;
955 }
956 
NAPI_IPCSkeleton_isLocalCalling(napi_env env,napi_callback_info info)957 napi_value NAPI_IPCSkeleton_isLocalCalling(napi_env env, napi_callback_info info)
958 {
959     napi_value global = nullptr;
960     napi_get_global(env, &global);
961     napi_value napiActiveStatus = nullptr;
962     napi_get_named_property(env, global, "activeStatus_", &napiActiveStatus);
963     if (napiActiveStatus != nullptr) {
964         int32_t activeStatus = IRemoteInvoker::IDLE_INVOKER;
965         napi_get_value_int32(env, napiActiveStatus, &activeStatus);
966         if (activeStatus == IRemoteInvoker::ACTIVE_INVOKER) {
967             napi_value isLocalCalling = nullptr;
968             napi_get_named_property(env, global, "isLocalCalling_", &isLocalCalling);
969             return isLocalCalling;
970         }
971     }
972     napi_value result = nullptr;
973     napi_get_boolean(env, true, &result);
974     return result;
975 }
976 
NAPI_IPCSkeleton_flushCommands(napi_env env,napi_callback_info info)977 napi_value NAPI_IPCSkeleton_flushCommands(napi_env env, napi_callback_info info)
978 {
979     size_t argc = 1;
980     napi_value argv[1] = {0};
981     napi_value thisVar = nullptr;
982     void *data = nullptr;
983     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
984     NAPI_ASSERT(env, argc == 1, "requires 1 parameter");
985 
986     napi_valuetype valueType = napi_null;
987     napi_typeof(env, argv[0], &valueType);
988     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1");
989 
990     sptr<IRemoteObject> target = NAPI_ohos_rpc_getNativeRemoteObject(env, argv[0]);
991     int32_t result = IPCSkeleton::FlushCommands(target);
992     napi_value napiValue = nullptr;
993     NAPI_CALL(env, napi_create_int32(env, result, &napiValue));
994     return napiValue;
995 }
996 
NAPI_IPCSkeleton_resetCallingIdentity(napi_env env,napi_callback_info info)997 napi_value NAPI_IPCSkeleton_resetCallingIdentity(napi_env env, napi_callback_info info)
998 {
999     napi_value global = nullptr;
1000     napi_get_global(env, &global);
1001     napi_value napiActiveStatus = nullptr;
1002     napi_get_named_property(env, global, "activeStatus_", &napiActiveStatus);
1003     int32_t activeStatus = IRemoteInvoker::IDLE_INVOKER;
1004     napi_get_value_int32(env, napiActiveStatus, &activeStatus);
1005     if (activeStatus != IRemoteInvoker::ACTIVE_INVOKER) {
1006         napi_value result = nullptr;
1007         napi_create_string_utf8(env, "", 0, &result);
1008         return result;
1009     }
1010     napi_value napiCallingPid = nullptr;
1011     napi_get_named_property(env, global, "callingPid_", &napiCallingPid);
1012     int32_t callerPid;
1013     napi_get_value_int32(env, napiCallingPid, &callerPid);
1014     napi_value napiCallingUid = nullptr;
1015     napi_get_named_property(env, global, "callingUid_", &napiCallingUid);
1016     uint32_t callerUid;
1017     napi_get_value_uint32(env, napiCallingUid, &callerUid);
1018     napi_value napiIsLocalCalling = nullptr;
1019     napi_get_named_property(env, global, "isLocalCalling_", &napiIsLocalCalling);
1020     bool isLocalCalling = true;
1021     napi_get_value_bool(env, napiIsLocalCalling, &isLocalCalling);
1022     if (isLocalCalling) {
1023         int64_t identity = (static_cast<uint64_t>(callerUid) << PID_LEN) | static_cast<uint64_t>(callerPid);
1024         callerPid = getpid();
1025         callerUid = getuid();
1026         napi_value newCallingPid;
1027         napi_create_int32(env, callerPid, &newCallingPid);
1028         napi_set_named_property(env, global, "callingPid_", newCallingPid);
1029         napi_value newCallingUid;
1030         napi_create_uint32(env, callerUid, &newCallingUid);
1031         napi_set_named_property(env, global, "callingUid_", newCallingUid);
1032         napi_value result = nullptr;
1033         napi_create_string_utf8(env, std::to_string(identity).c_str(), NAPI_AUTO_LENGTH, &result);
1034         return result;
1035     } else {
1036         napi_value napiCallingDeviceID = nullptr;
1037         napi_get_named_property(env, global, "callingDeviceID_", &napiCallingDeviceID);
1038         size_t bufferSize = 0;
1039         size_t maxLen = 4096;
1040         napi_get_value_string_utf8(env, napiCallingDeviceID, nullptr, 0, &bufferSize);
1041         NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
1042         char stringValue[bufferSize + 1];
1043         size_t jsStringLength = 0;
1044         napi_get_value_string_utf8(env, napiCallingDeviceID, stringValue, bufferSize + 1, &jsStringLength);
1045         NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
1046         std::string callerDeviceID = stringValue;
1047         std::string token = std::to_string(((static_cast<uint64_t>(callerUid) << PID_LEN)
1048             | static_cast<uint64_t>(callerPid)));
1049         std::string identity = callerDeviceID + token;
1050         callerUid = getuid();
1051         napi_value newCallingUid;
1052         napi_create_uint32(env, callerUid, &newCallingUid);
1053         napi_set_named_property(env, global, "callingUid_", newCallingUid);
1054         callerPid = getpid();
1055         napi_value newCallingPid;
1056         napi_create_int32(env, callerPid, &newCallingPid);
1057         napi_set_named_property(env, global, "callingPid_", newCallingPid);
1058         napi_value newCallingDeviceID = nullptr;
1059         napi_get_named_property(env, global, "localDeviceID_", &newCallingDeviceID);
1060         napi_set_named_property(env, global, "callingDeviceID_", newCallingDeviceID);
1061 
1062         napi_value result = nullptr;
1063         napi_create_string_utf8(env, identity.c_str(), NAPI_AUTO_LENGTH, &result);
1064         return result;
1065     }
1066 }
1067 
NAPI_IPCSkeleton_setCallingIdentity(napi_env env,napi_callback_info info)1068 napi_value NAPI_IPCSkeleton_setCallingIdentity(napi_env env, napi_callback_info info)
1069 {
1070     napi_value global = nullptr;
1071     napi_get_global(env, &global);
1072     napi_value napiActiveStatus = nullptr;
1073     napi_get_named_property(env, global, "activeStatus_", &napiActiveStatus);
1074     int32_t activeStatus = IRemoteInvoker::IDLE_INVOKER;
1075     napi_get_value_int32(env, napiActiveStatus, &activeStatus);
1076     if (activeStatus != IRemoteInvoker::ACTIVE_INVOKER) {
1077         napi_value result = nullptr;
1078         napi_get_boolean(env, true, &result);
1079         return result;
1080     }
1081 
1082     napi_value retValue = nullptr;
1083     napi_get_boolean(env, false, &retValue);
1084 
1085     size_t argc = 1;
1086     size_t expectedArgc = 1;
1087     napi_value argv[1] = { 0 };
1088     napi_value thisVar = nullptr;
1089     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1090     NAPI_ASSERT_BASE(env, argc == expectedArgc, "requires 1 parameters", retValue);
1091     napi_valuetype valueType = napi_null;
1092     napi_typeof(env, argv[0], &valueType);
1093     NAPI_ASSERT_BASE(env, valueType == napi_string, "type mismatch for parameter 1", retValue);
1094     size_t bufferSize = 0;
1095     size_t maxLen = 40960;
1096     napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize);
1097     NAPI_ASSERT_BASE(env, bufferSize < maxLen, "string length too large", retValue);
1098     char stringValue[bufferSize + 1];
1099     size_t jsStringLength = 0;
1100     napi_get_value_string_utf8(env, argv[0], stringValue, bufferSize + 1, &jsStringLength);
1101     NAPI_ASSERT_BASE(env, jsStringLength == bufferSize, "string length wrong", retValue);
1102 
1103     std::string identity = stringValue;
1104     napi_value napiIsLocalCalling = nullptr;
1105     napi_get_named_property(env, global, "isLocalCalling_", &napiIsLocalCalling);
1106     bool isLocalCalling = true;
1107     napi_get_value_bool(env, napiIsLocalCalling, &isLocalCalling);
1108     napi_value result;
1109     if (isLocalCalling) {
1110         if (identity.empty()) {
1111             napi_get_boolean(env, false, &result);
1112             return result;
1113         }
1114 
1115         int64_t token = std::atoll(identity.c_str());
1116         int callerUid = static_cast<int>((static_cast<uint64_t>(token)) >> PID_LEN);
1117         int callerPid = static_cast<int>(token);
1118         napi_value napiCallingPid;
1119         napi_create_int32(env, callerPid, &napiCallingPid);
1120         napi_set_named_property(env, global, "callingPid_", napiCallingPid);
1121         napi_value napiCallingUid;
1122         napi_create_int32(env, callerUid, &napiCallingUid);
1123         napi_set_named_property(env, global, "callingUid_", napiCallingUid);
1124         napi_get_boolean(env, true, &result);
1125         return result;
1126     } else {
1127         if (identity.empty() || identity.length() <= DEVICEID_LENGTH) {
1128             napi_get_boolean(env, false, &result);
1129             return result;
1130         }
1131 
1132         std::string deviceId = identity.substr(0, DEVICEID_LENGTH);
1133         int64_t token = std::atoll(identity.substr(DEVICEID_LENGTH, identity.length() - DEVICEID_LENGTH).c_str());
1134         int callerUid = static_cast<int>((static_cast<uint64_t>(token)) >> PID_LEN);
1135         int callerPid = static_cast<int>(token);
1136         napi_value napiCallingPid;
1137         napi_create_int32(env, callerPid, &napiCallingPid);
1138         napi_set_named_property(env, global, "callingPid_", napiCallingPid);
1139         napi_value napiCallingUid;
1140         napi_create_int32(env, callerUid, &napiCallingUid);
1141         napi_set_named_property(env, global, "callingUid_", napiCallingUid);
1142         napi_value napiCallingDeviceID = nullptr;
1143         napi_create_string_utf8(env, deviceId.c_str(), NAPI_AUTO_LENGTH, &napiCallingDeviceID);
1144         napi_set_named_property(env, global, "callingDeviceID_", napiCallingDeviceID);
1145         napi_get_boolean(env, true, &result);
1146         return result;
1147     }
1148 }
1149 
NAPI_RemoteObject_queryLocalInterface(napi_env env,napi_callback_info info)1150 napi_value NAPI_RemoteObject_queryLocalInterface(napi_env env, napi_callback_info info)
1151 {
1152     size_t argc = 1;
1153     size_t expectedArgc = 1;
1154     napi_value argv[1] = { 0 };
1155     napi_value thisVar = nullptr;
1156     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1157     NAPI_ASSERT(env, argc == expectedArgc, "requires 1 parameters");
1158     napi_valuetype valueType = napi_null;
1159     napi_typeof(env, argv[0], &valueType);
1160     NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1");
1161     size_t bufferSize = 0;
1162     size_t maxLen = 40960;
1163     napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize);
1164     NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
1165     char stringValue[bufferSize + 1];
1166     size_t jsStringLength = 0;
1167     napi_get_value_string_utf8(env, argv[0], stringValue, bufferSize + 1, &jsStringLength);
1168     NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
1169     std::string descriptor = stringValue;
1170     NAPIRemoteObjectHolder *holder = nullptr;
1171     napi_unwrap(env, thisVar, (void **)&holder);
1172     NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
1173     napi_value ret = holder->queryLocalInterface(descriptor);
1174     return ret;
1175 }
1176 
NAPI_RemoteObject_getInterfaceDescriptor(napi_env env,napi_callback_info info)1177 napi_value NAPI_RemoteObject_getInterfaceDescriptor(napi_env env, napi_callback_info info)
1178 {
1179     napi_value result = nullptr;
1180     napi_value thisVar = nullptr;
1181     napi_get_cb_info(env, info, 0, nullptr, &thisVar, nullptr);
1182     sptr<IRemoteObject> nativeObject = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1183     std::u16string descriptor = nativeObject->GetObjectDescriptor();
1184     napi_create_string_utf8(env, Str16ToStr8(descriptor).c_str(), NAPI_AUTO_LENGTH, &result);
1185     return result;
1186 }
1187 
NAPI_RemoteObject_getCallingPid(napi_env env,napi_callback_info info)1188 napi_value NAPI_RemoteObject_getCallingPid(napi_env env, napi_callback_info info)
1189 {
1190     return NAPI_IPCSkeleton_getCallingPid(env, info);
1191 }
1192 
NAPI_RemoteObject_getCallingUid(napi_env env,napi_callback_info info)1193 napi_value NAPI_RemoteObject_getCallingUid(napi_env env, napi_callback_info info)
1194 {
1195     return NAPI_IPCSkeleton_getCallingUid(env, info);
1196 }
1197 
MakeSendRequestResult(SendRequestParam * param)1198 napi_value MakeSendRequestResult(SendRequestParam *param)
1199 {
1200     napi_value errCode = nullptr;
1201     napi_create_int32(param->env, param->errCode, &errCode);
1202     napi_value code = nullptr;
1203     napi_get_reference_value(param->env, param->jsCodeRef, &code);
1204     napi_value data = nullptr;
1205     napi_get_reference_value(param->env, param->jsDataRef, &data);
1206     napi_value reply = nullptr;
1207     napi_get_reference_value(param->env, param->jsReplyRef, &reply);
1208     napi_value result = nullptr;
1209     napi_create_object(param->env, &result);
1210     napi_set_named_property(param->env, result, "errCode", errCode);
1211     napi_set_named_property(param->env, result, "code", code);
1212     napi_set_named_property(param->env, result, "data", data);
1213     napi_set_named_property(param->env, result, "reply", reply);
1214     return result;
1215 }
1216 
StubExecuteSendRequest(napi_env env,SendRequestParam * param)1217 void StubExecuteSendRequest(napi_env env, SendRequestParam *param)
1218 {
1219     param->errCode = param->target->SendRequest(param->code,
1220         *(param->data.get()), *(param->reply.get()), param->option);
1221     DBINDER_LOGI("sendRequest done, errCode:%{public}d", param->errCode);
1222     uv_loop_s *loop = nullptr;
1223     napi_get_uv_event_loop(env, &loop);
1224     uv_work_t *work = new uv_work_t;
1225     work->data = reinterpret_cast<void *>(param);
1226     uv_after_work_cb afterWorkCb = nullptr;
1227     if (param->callback != nullptr) {
1228         afterWorkCb = [](uv_work_t *work, int status) {
1229             DBINDER_LOGI("callback started");
1230             SendRequestParam *param = reinterpret_cast<SendRequestParam *>(work->data);
1231             napi_value result = MakeSendRequestResult(param);
1232             napi_value callback = nullptr;
1233             napi_get_reference_value(param->env, param->callback, &callback);
1234             napi_value cbResult = nullptr;
1235             napi_call_function(param->env, nullptr, callback, 1, &result, &cbResult);
1236             napi_delete_reference(param->env, param->jsCodeRef);
1237             napi_delete_reference(param->env, param->jsDataRef);
1238             napi_delete_reference(param->env, param->jsReplyRef);
1239             napi_delete_reference(param->env, param->callback);
1240             delete param;
1241             delete work;
1242         };
1243     } else {
1244         afterWorkCb = [](uv_work_t *work, int status) {
1245             DBINDER_LOGI("promise fullfilled");
1246             SendRequestParam *param = reinterpret_cast<SendRequestParam *>(work->data);
1247             napi_value result = MakeSendRequestResult(param);
1248             if (param->errCode == 0) {
1249                 napi_resolve_deferred(param->env, param->deferred, result);
1250             } else {
1251                 napi_reject_deferred(param->env, param->deferred, result);
1252             }
1253             napi_delete_reference(param->env, param->jsCodeRef);
1254             napi_delete_reference(param->env, param->jsDataRef);
1255             napi_delete_reference(param->env, param->jsReplyRef);
1256             delete param;
1257             delete work;
1258         };
1259     }
1260     uv_queue_work(loop, work, [](uv_work_t *work) {}, afterWorkCb);
1261 }
1262 
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)1263 napi_value StubSendRequestAsync(napi_env env, sptr<IRemoteObject> target, uint32_t code,
1264     std::shared_ptr<MessageParcel> data, std::shared_ptr<MessageParcel> reply,
1265     MessageOption &option, napi_value *argv)
1266 {
1267     SendRequestParam *sendRequestParam = new SendRequestParam {
1268         .target = target,
1269         .code = code,
1270         .data = data,
1271         .reply = reply,
1272         .option = option,
1273         .asyncWork = nullptr,
1274         .deferred = nullptr,
1275         .errCode = -1,
1276         .jsCodeRef = nullptr,
1277         .jsDataRef = nullptr,
1278         .jsReplyRef = nullptr,
1279         .callback = nullptr,
1280         .env = env,
1281     };
1282     napi_create_reference(env, argv[0], 1, &sendRequestParam->jsCodeRef);
1283     napi_create_reference(env, argv[1], 1, &sendRequestParam->jsDataRef);
1284     napi_create_reference(env, argv[2], 1, &sendRequestParam->jsReplyRef);
1285     napi_create_reference(env, argv[4], 1, &sendRequestParam->callback);
1286     std::thread t(StubExecuteSendRequest, env, sendRequestParam);
1287     t.detach();
1288     napi_value result = nullptr;
1289     napi_get_undefined(env, &result);
1290     return result;
1291 }
1292 
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)1293 napi_value StubSendRequestPromise(napi_env env, sptr<IRemoteObject> target, uint32_t code,
1294     std::shared_ptr<MessageParcel> data, std::shared_ptr<MessageParcel> reply,
1295     MessageOption &option, napi_value *argv)
1296 {
1297     napi_deferred deferred = nullptr;
1298     napi_value promise = nullptr;
1299     NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
1300     SendRequestParam *sendRequestParam = new SendRequestParam {
1301         .target = target,
1302         .code = code,
1303         .data = data,
1304         .reply = reply,
1305         .option = option,
1306         .asyncWork = nullptr,
1307         .deferred = deferred,
1308         .errCode = -1,
1309         .jsCodeRef = nullptr,
1310         .jsDataRef = nullptr,
1311         .jsReplyRef = nullptr,
1312         .callback = nullptr,
1313         .env = env,
1314     };
1315     napi_create_reference(env, argv[0], 1, &sendRequestParam->jsCodeRef);
1316     napi_create_reference(env, argv[1], 1, &sendRequestParam->jsDataRef);
1317     napi_create_reference(env, argv[2], 1, &sendRequestParam->jsReplyRef);
1318     std::thread t(StubExecuteSendRequest, env, sendRequestParam);
1319     t.detach();
1320     return promise;
1321 }
1322 
NAPI_RemoteObject_sendRequest(napi_env env,napi_callback_info info)1323 napi_value NAPI_RemoteObject_sendRequest(napi_env env, napi_callback_info info)
1324 {
1325     size_t argc = 4;
1326     size_t argcCallback = 5;
1327     size_t argcPromise = 4;
1328     napi_value argv[5] = { 0 };
1329     napi_value thisVar = nullptr;
1330     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1331     NAPI_ASSERT(env, argc == argcPromise || argc == argcCallback, "requires 4 or 5 parameters");
1332     napi_valuetype valueType = napi_null;
1333     napi_typeof(env, argv[0], &valueType);
1334     NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
1335     napi_typeof(env, argv[1], &valueType);
1336     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 2");
1337     napi_typeof(env, argv[2], &valueType);
1338     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 3");
1339     napi_typeof(env, argv[3], &valueType);
1340     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 4");
1341 
1342     NAPI_MessageParcel *data = nullptr;
1343     napi_status status = napi_unwrap(env, argv[1], (void **)&data);
1344     NAPI_ASSERT(env, status == napi_ok, "failed to get data message parcel");
1345     NAPI_MessageParcel *reply = nullptr;
1346     status = napi_unwrap(env, argv[2], (void **)&reply);
1347     NAPI_ASSERT(env, status == napi_ok, "failed to get reply message parcel");
1348     MessageOption *option = nullptr;
1349     status = napi_unwrap(env, argv[3], (void **)&option);
1350     NAPI_ASSERT(env, status == napi_ok, "failed to get message option");
1351     int32_t code = 0;
1352     napi_get_value_int32(env, argv[0], &code);
1353 
1354     sptr<IRemoteObject> target = NAPI_ohos_rpc_getNativeRemoteObject(env, thisVar);
1355     if (argc == argcCallback) {
1356         napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1357         napi_valuetype valuetype = napi_undefined;
1358         napi_typeof(env, argv[argcPromise], &valuetype);
1359         if (valuetype == napi_function) {
1360             return StubSendRequestAsync(env, target, code, data->GetMessageParcel(),
1361                 reply->GetMessageParcel(), *option, argv);
1362         }
1363     }
1364     return StubSendRequestPromise(env, target, code, data->GetMessageParcel(),
1365         reply->GetMessageParcel(), *option, argv);
1366 }
1367 
NAPI_RemoteObject_attachLocalInterface(napi_env env,napi_callback_info info)1368 napi_value NAPI_RemoteObject_attachLocalInterface(napi_env env, napi_callback_info info)
1369 {
1370     size_t argc = 2;
1371     size_t expectedArgc = 2;
1372     napi_value argv[2] = { 0 };
1373     napi_value thisVar = nullptr;
1374     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1375     NAPI_ASSERT(env, argc == expectedArgc, "requires 2 parameters");
1376     napi_valuetype valueType = napi_null;
1377     napi_typeof(env, argv[0], &valueType);
1378     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1");
1379     napi_typeof(env, argv[1], &valueType);
1380     NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 2");
1381     size_t bufferSize = 0;
1382     size_t maxLen = 40960;
1383     napi_get_value_string_utf8(env, argv[1], nullptr, 0, &bufferSize);
1384     NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
1385     char stringValue[bufferSize + 1];
1386     size_t jsStringLength = 0;
1387     napi_get_value_string_utf8(env, argv[1], stringValue, bufferSize + 1, &jsStringLength);
1388     NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
1389     std::string descriptor = stringValue;
1390 
1391     NAPIRemoteObjectHolder *holder = nullptr;
1392     napi_unwrap(env, thisVar, (void* *)&holder);
1393     NAPI_ASSERT(env, holder != nullptr, "failed to get napi remote object holder");
1394     holder->attachLocalInterface(argv[0], descriptor);
1395 
1396     napi_value result = nullptr;
1397     napi_get_undefined(env, &result);
1398     return result;
1399 }
1400 
NAPI_RemoteObject_addDeathRecipient(napi_env env,napi_callback_info info)1401 napi_value NAPI_RemoteObject_addDeathRecipient(napi_env env, napi_callback_info info)
1402 {
1403     napi_value result = nullptr;
1404     napi_get_boolean(env, false, &result);
1405     return result;
1406 }
1407 
NAPI_RemoteObject_removeDeathRecipient(napi_env env,napi_callback_info info)1408 napi_value NAPI_RemoteObject_removeDeathRecipient(napi_env env, napi_callback_info info)
1409 {
1410     napi_value result = nullptr;
1411     napi_get_boolean(env, false, &result);
1412     return result;
1413 }
1414 
NAPI_RemoteObject_isObjectDead(napi_env env,napi_callback_info info)1415 napi_value NAPI_RemoteObject_isObjectDead(napi_env env, napi_callback_info info)
1416 {
1417     napi_value result = nullptr;
1418     napi_get_boolean(env, false, &result);
1419     return result;
1420 }
1421 
1422 // This method runs on a worker thread, no access to the JavaScript
ExecuteSendRequest(napi_env env,void * data)1423 void ExecuteSendRequest(napi_env env, void *data)
1424 {
1425     SendRequestParam *param = reinterpret_cast<SendRequestParam *>(data);
1426     param->errCode = param->target->SendRequest(param->code,
1427         *(param->data.get()), *(param->reply.get()), param->option);
1428     DBINDER_LOGI("sendRequest done, errCode:%{public}d", param->errCode);
1429 }
1430 
1431 // This method runs on the main thread after 'ExecuteSendRequest' exits
SendRequestCbComplete(napi_env env,napi_status status,void * data)1432 void SendRequestCbComplete(napi_env env, napi_status status, void *data)
1433 {
1434     SendRequestParam *param = reinterpret_cast<SendRequestParam *>(data);
1435     DBINDER_LOGI("sendRequestCallback completed, errCode:%{public}d", param->errCode);
1436     napi_value result = MakeSendRequestResult(param);
1437     napi_value callback = nullptr;
1438     napi_get_reference_value(env, param->callback, &callback);
1439     napi_value cbResult = nullptr;
1440     napi_call_function(env, nullptr, callback, 1, &result, &cbResult);
1441     napi_delete_reference(env, param->jsCodeRef);
1442     napi_delete_reference(env, param->jsDataRef);
1443     napi_delete_reference(env, param->jsReplyRef);
1444     napi_delete_reference(env, param->callback);
1445     napi_delete_async_work(env, param->asyncWork);
1446     delete param;
1447 }
1448 
1449 // This method runs on the main thread after 'ExecuteSendRequest' exits
SendRequestPromiseComplete(napi_env env,napi_status status,void * data)1450 void SendRequestPromiseComplete(napi_env env, napi_status status, void *data)
1451 {
1452     SendRequestParam *param = reinterpret_cast<SendRequestParam *>(data);
1453     DBINDER_LOGI("sendRequestPromise completed, errCode:%{public}d", param->errCode);
1454     napi_value result = MakeSendRequestResult(param);
1455     if (param->errCode == 0) {
1456         napi_resolve_deferred(env, param->deferred, result);
1457     } else {
1458         napi_reject_deferred(env, param->deferred, result);
1459     }
1460     napi_delete_reference(env, param->jsCodeRef);
1461     napi_delete_reference(env, param->jsDataRef);
1462     napi_delete_reference(env, param->jsReplyRef);
1463     napi_delete_async_work(env, param->asyncWork);
1464     delete param;
1465 }
1466 
SendRequestAsync(napi_env env,sptr<IRemoteObject> target,uint32_t code,std::shared_ptr<MessageParcel> data,std::shared_ptr<MessageParcel> reply,MessageOption & option,napi_value * argv)1467 napi_value SendRequestAsync(napi_env env, sptr<IRemoteObject> target, uint32_t code,
1468     std::shared_ptr<MessageParcel> data, std::shared_ptr<MessageParcel> reply,
1469     MessageOption &option, napi_value *argv)
1470 {
1471     napi_value result = nullptr;
1472     SendRequestParam *sendRequestParam = new SendRequestParam {
1473         .target = target,
1474         .code = code,
1475         .data = data,
1476         .reply = reply,
1477         .option = option,
1478         .asyncWork = nullptr,
1479         .deferred = nullptr,
1480         .errCode = -1,
1481         .jsCodeRef = nullptr,
1482         .jsDataRef = nullptr,
1483         .jsReplyRef = nullptr,
1484         .callback = nullptr,
1485         .env = env,
1486     };
1487     napi_create_reference(env, argv[0], 1, &sendRequestParam->jsCodeRef);
1488     napi_create_reference(env, argv[1], 1, &sendRequestParam->jsDataRef);
1489     napi_create_reference(env, argv[2], 1, &sendRequestParam->jsReplyRef);
1490     napi_create_reference(env, argv[4], 1, &sendRequestParam->callback);
1491     napi_value resourceName = nullptr;
1492     NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
1493     NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteSendRequest,
1494         SendRequestCbComplete, (void *)sendRequestParam, &sendRequestParam->asyncWork));
1495     NAPI_CALL(env, napi_queue_async_work(env, sendRequestParam->asyncWork));
1496     napi_get_undefined(env, &result);
1497     return result;
1498 }
1499 
SendRequestPromise(napi_env env,sptr<IRemoteObject> target,uint32_t code,std::shared_ptr<MessageParcel> data,std::shared_ptr<MessageParcel> reply,MessageOption & option,napi_value * argv)1500 napi_value SendRequestPromise(napi_env env, sptr<IRemoteObject> target, uint32_t code,
1501     std::shared_ptr<MessageParcel> data, std::shared_ptr<MessageParcel> reply,
1502     MessageOption &option, napi_value *argv)
1503 {
1504     napi_deferred deferred = nullptr;
1505     napi_value promise = nullptr;
1506     napi_create_promise(env, &deferred, &promise);
1507     SendRequestParam *sendRequestParam = new SendRequestParam {
1508         .target = target,
1509         .code = code,
1510         .data = data,
1511         .reply = reply,
1512         .option = option,
1513         .asyncWork = nullptr,
1514         .deferred = deferred,
1515         .errCode = -1,
1516         .jsCodeRef = nullptr,
1517         .jsDataRef = nullptr,
1518         .jsReplyRef = nullptr,
1519         .callback = nullptr,
1520         .env = env,
1521     };
1522     napi_create_reference(env, argv[0], 1, &sendRequestParam->jsCodeRef);
1523     napi_create_reference(env, argv[1], 1, &sendRequestParam->jsDataRef);
1524     napi_create_reference(env, argv[2], 1, &sendRequestParam->jsReplyRef);
1525     napi_value resourceName = nullptr;
1526     NAPI_CALL(env, napi_create_string_utf8(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
1527     NAPI_CALL(env, napi_create_async_work(env, nullptr, resourceName, ExecuteSendRequest,
1528         SendRequestPromiseComplete, (void *)sendRequestParam, &sendRequestParam->asyncWork));
1529     NAPI_CALL(env, napi_queue_async_work(env, sendRequestParam->asyncWork));
1530     return promise;
1531 }
1532 
NAPI_RemoteProxy_sendRequest(napi_env env,napi_callback_info info)1533 napi_value NAPI_RemoteProxy_sendRequest(napi_env env, napi_callback_info info)
1534 {
1535     size_t argc = 4;
1536     size_t argcCallback = 5;
1537     size_t argcPromise = 4;
1538     napi_value argv[5] = { 0 };
1539     napi_value thisVar = nullptr;
1540     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1541     NAPI_ASSERT(env, argc == argcPromise || argc == argcCallback, "requires 4 or 5 parameters");
1542     napi_valuetype valueType = napi_null;
1543     napi_typeof(env, argv[0], &valueType);
1544     NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
1545     napi_typeof(env, argv[1], &valueType);
1546     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 2");
1547     napi_typeof(env, argv[2], &valueType);
1548     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 3");
1549     napi_typeof(env, argv[3], &valueType);
1550     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 4");
1551 
1552     NAPI_MessageParcel *data = nullptr;
1553     napi_status status = napi_unwrap(env, argv[1], (void **)&data);
1554     NAPI_ASSERT(env, status == napi_ok, "failed to get data message parcel");
1555     NAPI_MessageParcel *reply = nullptr;
1556     status = napi_unwrap(env, argv[2], (void **)&reply);
1557     NAPI_ASSERT(env, status == napi_ok, "failed to get reply message parcel");
1558     MessageOption *option = nullptr;
1559     status = napi_unwrap(env, argv[3], (void **)&option);
1560     NAPI_ASSERT(env, status == napi_ok, "failed to get message option");
1561     int32_t code = 0;
1562     napi_get_value_int32(env, argv[0], &code);
1563 
1564     NAPIRemoteProxyHolder *proxyHolder = nullptr;
1565     status = napi_unwrap(env, thisVar, (void **)&proxyHolder);
1566     NAPI_ASSERT(env, proxyHolder != nullptr, "failed to get proxy holder");
1567     sptr<IRemoteObject> target = proxyHolder->object_;
1568     NAPI_ASSERT(env, target != nullptr, "invalid proxy object");
1569     if (argc == argcCallback) {
1570         napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1571         napi_valuetype valuetype = napi_undefined;
1572         napi_typeof(env, argv[argcPromise], &valuetype);
1573         if (valuetype == napi_function) {
1574             return SendRequestAsync(env, target, code, data->GetMessageParcel(),
1575                 reply->GetMessageParcel(), *option, argv);
1576         }
1577     }
1578     return SendRequestPromise(env, target, code, data->GetMessageParcel(),
1579         reply->GetMessageParcel(), *option, argv);
1580 }
1581 
NAPI_RemoteProxy_queryLocalInterface(napi_env env,napi_callback_info info)1582 napi_value NAPI_RemoteProxy_queryLocalInterface(napi_env env, napi_callback_info info)
1583 {
1584     napi_value result = nullptr;
1585     napi_get_null(env, &result);
1586     return result;
1587 }
1588 
NAPI_RemoteProxy_addDeathRecipient(napi_env env,napi_callback_info info)1589 napi_value NAPI_RemoteProxy_addDeathRecipient(napi_env env, napi_callback_info info)
1590 {
1591     DBINDER_LOGI("add death recipient");
1592     size_t argc = 2;
1593     size_t expectedArgc = 2;
1594     napi_value argv[2] = { 0 };
1595     napi_value thisVar = nullptr;
1596     void *data = nullptr;
1597     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1598     NAPI_ASSERT(env, argc == expectedArgc, "requires 2 parameter");
1599     napi_valuetype valueType = napi_null;
1600     napi_typeof(env, argv[0], &valueType);
1601     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1");
1602     napi_typeof(env, argv[1], &valueType);
1603     NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2");
1604     int32_t flag = 0;
1605     napi_get_value_int32(env, argv[1], &flag);
1606 
1607     napi_value result;
1608     if (argv[0] == nullptr) {
1609         napi_get_boolean(env, false, &result);
1610         return result;
1611     }
1612 
1613     NAPIRemoteProxyHolder *proxyHolder = nullptr;
1614     napi_status status = napi_unwrap(env, thisVar, (void **)&proxyHolder);
1615     NAPI_ASSERT(env, status == napi_ok, "failed to get proxy holder");
1616     if (proxyHolder == nullptr) {
1617         napi_get_boolean(env, false, &result);
1618         return result;
1619     }
1620     sptr<IRemoteObject> target = proxyHolder->object_;
1621     if ((target == nullptr) || !target->IsProxyObject()) {
1622         DBINDER_LOGE("could not add recipient from invalid target");
1623         napi_get_boolean(env, false, &result);
1624         return result;
1625     }
1626 
1627     sptr<NAPIDeathRecipient> nativeRecipient = new NAPIDeathRecipient(env, argv[0]);
1628     if (target->AddDeathRecipient(nativeRecipient)) {
1629         NAPIDeathRecipientList *list = proxyHolder->list_;
1630         if (list->Add(nativeRecipient)) {
1631             napi_get_boolean(env, true, &result);
1632             return result;
1633         }
1634     }
1635     napi_get_boolean(env, false, &result);
1636     return result;
1637 }
1638 
NAPI_RemoteProxy_removeDeathRecipient(napi_env env,napi_callback_info info)1639 napi_value NAPI_RemoteProxy_removeDeathRecipient(napi_env env, napi_callback_info info)
1640 {
1641     DBINDER_LOGI("remove death recipient");
1642     size_t argc = 2;
1643     napi_value argv[2] = { 0 };
1644     napi_value thisVar = nullptr;
1645     void *data = nullptr;
1646     size_t expectedArgc = 2;
1647     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1648     NAPI_ASSERT(env, argc == expectedArgc, "requires 2 parameter");
1649     napi_valuetype valueType = napi_null;
1650     napi_typeof(env, argv[0], &valueType);
1651     NAPI_ASSERT(env, valueType == napi_object, "type mismatch for parameter 1");
1652     napi_typeof(env, argv[1], &valueType);
1653     NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2");
1654     napi_value result;
1655     if (argv[0] == nullptr) {
1656         napi_get_boolean(env, false, &result);
1657         return result;
1658     }
1659     int32_t flag = 0;
1660     napi_get_value_int32(env, argv[1], &flag);
1661 
1662     NAPIRemoteProxyHolder *proxyHolder = nullptr;
1663     napi_status status = napi_unwrap(env, thisVar, (void **)&proxyHolder);
1664     NAPI_ASSERT(env, status == napi_ok, "failed to get proxy holder");
1665     if (proxyHolder == nullptr) {
1666         napi_get_boolean(env, false, &result);
1667         return result;
1668     }
1669     sptr<IRemoteObject> target = proxyHolder->object_;
1670     if ((target == nullptr) || !target->IsProxyObject()) {
1671         DBINDER_LOGE("could not remove recipient from invalid target");
1672         napi_get_boolean(env, false, &result);
1673         return result;
1674     }
1675     sptr<NAPIDeathRecipientList> list = proxyHolder->list_;
1676     sptr<NAPIDeathRecipient> nativeRecipient = list->Find(argv[0]);
1677     if (nativeRecipient == nullptr) {
1678         DBINDER_LOGE("recipient not found");
1679         napi_get_boolean(env, false, &result);
1680         return result;
1681     }
1682     target->RemoveDeathRecipient(nativeRecipient);
1683     if (list->Remove(nativeRecipient)) {
1684         napi_get_boolean(env, true, &result);
1685         return result;
1686     } else {
1687         napi_get_boolean(env, false, &result);
1688         return result;
1689     }
1690 }
1691 
NAPI_RemoteProxy_getInterfaceDescriptor(napi_env env,napi_callback_info info)1692 napi_value NAPI_RemoteProxy_getInterfaceDescriptor(napi_env env, napi_callback_info info)
1693 {
1694     napi_value thisVar = nullptr;
1695     napi_get_cb_info(env, info, 0, 0, &thisVar, nullptr);
1696     NAPIRemoteProxyHolder *holder = nullptr;
1697     napi_status status = napi_unwrap(env, thisVar, (void **)&holder);
1698     NAPI_ASSERT(env, status == napi_ok, "failed to get proxy holder");
1699     napi_value result;
1700     if (holder == nullptr) {
1701         napi_create_string_utf8(env, "", 0, &result);
1702         return result;
1703     }
1704     IPCObjectProxy *target = reinterpret_cast<IPCObjectProxy *>(holder->object_.GetRefPtr());
1705     if (target == nullptr) {
1706         DBINDER_LOGE("Invalid proxy object");
1707         napi_create_string_utf8(env, "", 0, &result);
1708         return result;
1709     }
1710     std::u16string remoteDescriptor = target->GetInterfaceDescriptor();
1711     napi_create_string_utf8(env, Str16ToStr8(remoteDescriptor).c_str(), NAPI_AUTO_LENGTH, &result);
1712     return result;
1713 }
1714 
NAPI_RemoteProxy_isObjectDead(napi_env env,napi_callback_info info)1715 napi_value NAPI_RemoteProxy_isObjectDead(napi_env env, napi_callback_info info)
1716 {
1717     DBINDER_LOGI("call isObjectDead");
1718     napi_value thisVar = nullptr;
1719     napi_get_cb_info(env, info, 0, 0, &thisVar, nullptr);
1720     NAPIRemoteProxyHolder *holder = nullptr;
1721     napi_status status = napi_unwrap(env, thisVar, (void **)&holder);
1722     NAPI_ASSERT(env, status == napi_ok, "failed to get proxy holder");
1723     napi_value result;
1724     if (holder == nullptr) {
1725         napi_get_boolean(env, false, &result);
1726         return result;
1727     }
1728     IPCObjectProxy *target = reinterpret_cast<IPCObjectProxy *>(holder->object_.GetRefPtr());
1729     if (target == nullptr) {
1730         DBINDER_LOGE("Invalid proxy object");
1731         napi_get_boolean(env, false, &result);
1732         return result;
1733     }
1734 
1735     if (target->IsObjectDead()) {
1736         napi_get_boolean(env, true, &result);
1737         return result;
1738     } else {
1739         napi_get_boolean(env, false, &result);
1740         return result;
1741     }
1742 }
1743 
NAPIIPCSkeleton_JS_Constructor(napi_env env,napi_callback_info info)1744 napi_value NAPIIPCSkeleton_JS_Constructor(napi_env env, napi_callback_info info)
1745 {
1746     napi_value thisArg = nullptr;
1747     void *data = nullptr;
1748     napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
1749     napi_value global = nullptr;
1750     napi_get_global(env, &global);
1751     return thisArg;
1752 }
1753 
1754 EXTERN_C_START
1755 /*
1756  * function for module exports
1757  */
NAPIIPCSkeletonExport(napi_env env,napi_value exports)1758 napi_value NAPIIPCSkeletonExport(napi_env env, napi_value exports)
1759 {
1760     DBINDER_LOGI("napi_moudule IPCSkeleton Init start...");
1761     napi_property_descriptor desc[] = {
1762         DECLARE_NAPI_STATIC_FUNCTION("getContextObject", NAPI_IPCSkeleton_getContextObject),
1763         DECLARE_NAPI_STATIC_FUNCTION("getCallingPid", NAPI_IPCSkeleton_getCallingPid),
1764         DECLARE_NAPI_STATIC_FUNCTION("getCallingUid", NAPI_IPCSkeleton_getCallingUid),
1765         DECLARE_NAPI_STATIC_FUNCTION("getCallingDeviceID", NAPI_IPCSkeleton_getCallingDeviceID),
1766         DECLARE_NAPI_STATIC_FUNCTION("getLocalDeviceID", NAPI_IPCSkeleton_getLocalDeviceID),
1767         DECLARE_NAPI_STATIC_FUNCTION("isLocalCalling", NAPI_IPCSkeleton_isLocalCalling),
1768         DECLARE_NAPI_STATIC_FUNCTION("flushCommands", NAPI_IPCSkeleton_flushCommands),
1769         DECLARE_NAPI_STATIC_FUNCTION("resetCallingIdentity", NAPI_IPCSkeleton_resetCallingIdentity),
1770         DECLARE_NAPI_STATIC_FUNCTION("setCallingIdentity", NAPI_IPCSkeleton_setCallingIdentity),
1771         DECLARE_NAPI_STATIC_FUNCTION("getCallingTokenId", NAPI_IPCSkeleton_getCallingTokenId),
1772     };
1773     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
1774     napi_value result = nullptr;
1775     napi_define_class(env, "IPCSkeleton", NAPI_AUTO_LENGTH, NAPIIPCSkeleton_JS_Constructor, nullptr,
1776         sizeof(desc) / sizeof(desc[0]), desc, &result);
1777     napi_status status = napi_set_named_property(env, exports, "IPCSkeleton", result);
1778     NAPI_ASSERT(env, status == napi_ok, "create ref to js RemoteObject constructor failed");
1779     DBINDER_LOGI("napi_moudule IPCSkeleton Init end...");
1780     return exports;
1781 }
1782 EXTERN_C_END
1783 
1784 
NAPIMessageOption_JS_Constructor(napi_env env,napi_callback_info info)1785 napi_value NAPIMessageOption_JS_Constructor(napi_env env, napi_callback_info info)
1786 {
1787     size_t argc = 2;
1788     napi_value argv[2] = { 0 };
1789     napi_value thisVar = nullptr;
1790     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1791     NAPI_ASSERT(env, argc >= 0, "invalid parameter number");
1792     int flags = 0;
1793     int waittime = 0;
1794     if (argc == 0) {
1795         flags = MessageOption::TF_SYNC;
1796         waittime = MessageOption::TF_WAIT_TIME;
1797     } else if (argc == 1) {
1798         napi_valuetype valueType;
1799         napi_typeof(env, argv[0], &valueType);
1800         NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
1801         int32_t jsFlags = 0;
1802         napi_get_value_int32(env, argv[1], &jsFlags);
1803         flags = jsFlags;
1804         waittime = MessageOption::TF_WAIT_TIME;
1805     } else {
1806         napi_valuetype valueType = napi_null;
1807         napi_typeof(env, argv[0], &valueType);
1808         NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
1809         napi_typeof(env, argv[1], &valueType);
1810         NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2");
1811         int32_t jsFlags = 0;
1812         napi_get_value_int32(env, argv[0], &jsFlags);
1813         int32_t jsWaittime = 0;
1814         napi_get_value_int32(env, argv[1], &jsWaittime);
1815         flags = jsFlags;
1816         waittime = jsWaittime;
1817     }
1818 
1819     auto messageOption = new MessageOption(flags, waittime);
1820     // connect native message option to js thisVar
1821     napi_status status = napi_wrap(
1822         env, thisVar, messageOption,
1823         [](napi_env env, void *data, void *hint) {
1824             DBINDER_LOGI("NAPIMessageOption destructed by js callback");
1825             delete (reinterpret_cast<MessageOption *>(data));
1826         },
1827         nullptr, nullptr);
1828     NAPI_ASSERT(env, status == napi_ok, "wrap js MessageOption and native option failed");
1829     return thisVar;
1830 }
1831 
1832 EXTERN_C_START
1833 /*
1834  * function for module exports
1835  */
NAPIMessageOptionExport(napi_env env,napi_value exports)1836 napi_value NAPIMessageOptionExport(napi_env env, napi_value exports)
1837 {
1838     const std::string className = "MessageOption";
1839     napi_value tfSync = nullptr;
1840     napi_create_int32(env, MessageOption::TF_SYNC, &tfSync);
1841     napi_value tfAsync = nullptr;
1842     napi_create_int32(env, MessageOption::TF_ASYNC, &tfAsync);
1843     napi_value tfFds = nullptr;
1844     napi_create_int32(env, MessageOption::TF_ACCEPT_FDS, &tfFds);
1845     napi_value tfWaitTime = nullptr;
1846     napi_create_int32(env, MessageOption::TF_WAIT_TIME, &tfWaitTime);
1847     napi_property_descriptor properties[] = {
1848         DECLARE_NAPI_FUNCTION("getFlags", NapiOhosRpcMessageOptionGetFlags),
1849         DECLARE_NAPI_FUNCTION("setFlags", NapiOhosRpcMessageOptionSetFlags),
1850         DECLARE_NAPI_FUNCTION("getWaitTime", NapiOhosRpcMessageOptionGetWaittime),
1851         DECLARE_NAPI_FUNCTION("setWaitTime", NapiOhosRpcMessageOptionSetWaittime),
1852         DECLARE_NAPI_STATIC_PROPERTY("TF_SYNC", tfSync),
1853         DECLARE_NAPI_STATIC_PROPERTY("TF_ASYNC", tfAsync),
1854         DECLARE_NAPI_STATIC_PROPERTY("TF_ACCEPT_FDS", tfFds),
1855         DECLARE_NAPI_STATIC_PROPERTY("TF_WAIT_TIME", tfWaitTime),
1856     };
1857     napi_value constructor = nullptr;
1858     napi_define_class(env, className.c_str(), className.length(), NAPIMessageOption_JS_Constructor, nullptr,
1859         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
1860     NAPI_ASSERT(env, constructor != nullptr, "define js class MessageOption failed");
1861     napi_status status = napi_set_named_property(env, exports, "MessageOption", constructor);
1862     NAPI_ASSERT(env, status == napi_ok, "set property MessageOption to exports failed");
1863     napi_value global = nullptr;
1864     status = napi_get_global(env, &global);
1865     NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
1866     status = napi_set_named_property(env, global, "IPCOptionConstructor_", constructor);
1867     NAPI_ASSERT(env, status == napi_ok, "set message option constructor failed");
1868     return exports;
1869 }
1870 EXTERN_C_END
1871 } // namespace OHOS