1 /*
2 * Copyright (c) 2025 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 "remote_object_impl.h"
17
18 #include <cinttypes>
19 #include <hitrace_meter.h>
20 #include <string_ex.h>
21
22 #include "cj_lambda.h"
23 #include "ipc_utils_ffi.h"
24 #include "iremote_invoker.h"
25 #include "remote_object_internal_impl.h"
26 #include "remote_proxy_holder_impl.h"
27
28 using namespace OHOS::FFI;
29
30 namespace OHOS {
31 static const uint64_t HITRACE_TAG_RPC = (1ULL << 46); // RPC and IPC tag.
32
33 static std::atomic<int32_t> bytraceId = 1000;
34
RemoteObjectImpl(std::thread::id jsThreadId,const std::u16string & descriptor)35 RemoteObjectImpl::RemoteObjectImpl(std::thread::id jsThreadId, const std::u16string& descriptor)
36 : IPCObjectStub(descriptor)
37 {
38 jsThreadId_ = jsThreadId;
39 }
40
CjRemoteObjectImpl(RemoteObjectHolderImpl * holder)41 CjRemoteObjectImpl::CjRemoteObjectImpl(RemoteObjectHolderImpl* holder)
42 {
43 holder_ = holder;
44 }
45
~CjRemoteObjectImpl()46 CjRemoteObjectImpl::~CjRemoteObjectImpl()
47 {
48 if (holder_ == nullptr) {
49 ZLOGW(LOG_LABEL, "~CjRemoteObjectImpl null holder");
50 return;
51 }
52 holder_->Lock();
53 int32_t curAttachCount = holder_->DecAttachCount();
54 holder_->Unlock();
55 ZLOGD(LOG_LABEL, "~CjRemoteObjectImpl, curAttachCount:%{public}d", curAttachCount);
56 if (curAttachCount == 0) {
57 delete holder_;
58 }
59 }
60
GetDescriptor(int32_t * errCode)61 char* CjRemoteObjectImpl::GetDescriptor(int32_t* errCode)
62 {
63 if (holder_ == nullptr) {
64 ZLOGE(LOG_LABEL, "failed to get napi remote object holder");
65 *errCode = errorDesc::PROXY_OR_REMOTE_OBJECT_INVALID_ERROR;
66 return nullptr;
67 }
68 sptr<IRemoteObject> nativeObject = holder_->Get();
69 if (nativeObject == nullptr) {
70 ZLOGE(LOG_LABEL, "native stub object is nullptr");
71 *errCode = errorDesc::PROXY_OR_REMOTE_OBJECT_INVALID_ERROR;
72 return nullptr;
73 }
74 std::u16string descriptor = nativeObject->GetObjectDescriptor();
75 std::string str = Str16ToStr8(descriptor);
76 return MallocCString(str);
77 }
78
ModifyLocalInterface(char * stringValue)79 int32_t CjRemoteObjectImpl::ModifyLocalInterface(char* stringValue)
80 {
81 size_t maxLen = 40960;
82 if (strlen(stringValue) >= maxLen) {
83 ZLOGE(LOG_LABEL, "string length too large");
84 return errorDesc::CHECK_PARAM_ERROR;
85 }
86 if (holder_ == nullptr) {
87 ZLOGE(LOG_LABEL, "failed to get napi remote object holder");
88 return errorDesc::PROXY_OR_REMOTE_OBJECT_INVALID_ERROR;
89 }
90 std::string descriptor = stringValue;
91 holder_->attachLocalInterface(descriptor);
92 return 0;
93 }
94
StubExecuteSendRequest(CJSendRequestParam * param)95 void StubExecuteSendRequest(CJSendRequestParam* param)
96 {
97 if (param == nullptr) {
98 ZLOGE(LOG_LABEL, "param is null");
99 return;
100 }
101 param->errCode =
102 param->target->SendRequest(param->code, *(param->data.get()), *(param->reply.get()), param->option);
103 uint64_t curTime = static_cast<uint64_t>(
104 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch())
105 .count());
106 ZLOGI(LOG_LABEL, "sendRequest done, errCode:%{public}d time:%{public}" PRIu64, param->errCode, curTime);
107 if (param->traceId != 0) {
108 FinishAsyncTrace(HITRACE_TAG_RPC, (param->traceValue).c_str(), param->traceId);
109 }
110 auto callback = CJLambda::Create(reinterpret_cast<void (*)(RequestResult)>(param->callback));
111 if (callback) {
112 ZLOGI(LOG_LABEL, "callback started");
113 RequestResult result = RequestResult {
114 .errCode = param->errCode, .code = param->code, .data = param->cjDataRef, .reply = param->cjReplyRef
115 };
116 callback(result);
117 }
118 delete param;
119 }
120
SendMessageRequest(uint32_t code,int64_t dataId,int64_t replyId,MessageOption option,int64_t funcId)121 int32_t CjRemoteObjectImpl::SendMessageRequest(
122 uint32_t code, int64_t dataId, int64_t replyId, MessageOption option, int64_t funcId)
123 {
124 auto data = FFIData::GetData<MessageSequenceImpl>(dataId);
125 if (!data) {
126 ZLOGE(LOG_LABEL, "[RPC] failed to get data message parcel");
127 return errorDesc::CHECK_PARAM_ERROR;
128 }
129 auto reply = FFIData::GetData<MessageSequenceImpl>(replyId);
130 if (!reply) {
131 ZLOGE(LOG_LABEL, "[RPC] failed to get reply message parcel");
132 return errorDesc::CHECK_PARAM_ERROR;
133 }
134 if (holder_ == nullptr) {
135 ZLOGE(LOG_LABEL, "failed to get napi remote object holder");
136 return errorDesc::PROXY_OR_REMOTE_OBJECT_INVALID_ERROR;
137 }
138 sptr<IRemoteObject> target = holder_->Get();
139 if (target == nullptr) {
140 ZLOGE(LOG_LABEL, "native stub object is nullptr");
141 return errorDesc::PROXY_OR_REMOTE_OBJECT_INVALID_ERROR;
142 }
143 CJSendRequestParam* sendRequestParam = new (std::nothrow) CJSendRequestParam {
144 .target = target,
145 .code = code,
146 .data = data->GetMessageParcel(),
147 .reply = reply->GetMessageParcel(),
148 .option = option,
149 .errCode = -1,
150 .cjDataRef = dataId,
151 .cjReplyRef = replyId,
152 .callback = funcId,
153 .traceId = 0,
154 };
155 if (sendRequestParam == nullptr) {
156 ZLOGE(LOG_LABEL, "new SendRequestParam failed");
157 return errorDesc::PROXY_OR_REMOTE_OBJECT_INVALID_ERROR;
158 }
159 std::string remoteDescriptor = Str16ToStr8(target->GetObjectDescriptor());
160 if (!remoteDescriptor.empty()) {
161 std::string traceValue = remoteDescriptor + std::to_string(code);
162 int32_t traceId = bytraceId.fetch_add(1, std::memory_order_seq_cst);
163 StartAsyncTrace(HITRACE_TAG_RPC, traceValue.c_str(), traceId);
164 }
165 std::thread t(StubExecuteSendRequest, sendRequestParam);
166 t.detach();
167 return 0;
168 }
169
GetHolder()170 RemoteObjectHolderImpl* CjRemoteObjectImpl::GetHolder()
171 {
172 return holder_;
173 }
174
IsProxyObject()175 bool CjRemoteObjectImpl::IsProxyObject()
176 {
177 if (holder_ == nullptr) {
178 ZLOGE(LOG_LABEL, "failed to get napi remote object holder");
179 return false;
180 }
181 sptr<IRemoteObject> target = holder_->Get();
182 if (target == nullptr) {
183 ZLOGE(LOG_LABEL, "native stub object is nullptr");
184 return false;
185 }
186 return target->IsProxyObject();
187 }
188
GetRemoteObject()189 sptr<IRemoteObject> CjRemoteObjectImpl::GetRemoteObject()
190 {
191 if (holder_ == nullptr) {
192 ZLOGE(LOG_LABEL, "failed to get napi remote object holder");
193 return nullptr;
194 }
195 return holder_->Get();
196 }
197
CreateStubRemoteObject(const sptr<IRemoteObject> target)198 int64_t CreateStubRemoteObject(const sptr<IRemoteObject> target)
199 {
200 std::u16string descriptor = target->GetObjectDescriptor();
201 RemoteObjectHolderImpl* holder = new (std::nothrow) RemoteObjectHolderImpl(descriptor);
202 if (holder == nullptr) {
203 return 0;
204 }
205 holder->Set(target);
206 auto remotrObject = FFIData::Create<CjRemoteObjectImpl>(holder);
207 if (!remotrObject) {
208 delete holder;
209 return 0;
210 }
211 return remotrObject->GetID();
212 }
213
CreateProxyRemoteObject(const sptr<IRemoteObject> target)214 int64_t CreateProxyRemoteObject(const sptr<IRemoteObject> target)
215 {
216 auto proxyHolder = FFIData::Create<RemoteProxyHolderImpl>();
217 if (proxyHolder == nullptr) {
218 return 0;
219 }
220 proxyHolder->object_ = target;
221 proxyHolder->list_ = new (std::nothrow) CJDeathRecipientList();
222 if (proxyHolder->list_ == nullptr) {
223 ZLOGE(LOG_LABEL, "new NAPIDeathRecipientList failed");
224 FFIData::Release(proxyHolder->GetID());
225 return 0;
226 }
227 return proxyHolder->GetID();
228 }
229
CJ_rpc_CreateRemoteObject(const sptr<IRemoteObject> target)230 int64_t CJ_rpc_CreateRemoteObject(const sptr<IRemoteObject> target)
231 {
232 if (target == nullptr) {
233 uint64_t curTime = static_cast<uint64_t>(
234 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch())
235 .count());
236 ZLOGE(LOG_LABEL, "RemoteObject is null time:%{public}" PRIu64, curTime);
237 return 0;
238 }
239 if (!target->IsProxyObject()) {
240 IPCObjectStub* tmp = static_cast<IPCObjectStub*>(target.GetRefPtr());
241 uint32_t objectType = static_cast<uint32_t>(tmp->GetObjectType());
242 ZLOGD(LOG_LABEL, "create js object, type:%{public}d", objectType);
243 if (objectType == IPCObjectStub::OBJECT_TYPE_JAVASCRIPT || objectType == IPCObjectStub::OBJECT_TYPE_NATIVE) {
244 return CreateStubRemoteObject(target);
245 }
246 }
247
248 return CreateProxyRemoteObject(target);
249 }
250
CJ_rpc_getNativeRemoteObject(int64_t object)251 sptr<IRemoteObject> CJ_rpc_getNativeRemoteObject(int64_t object)
252 {
253 auto remoteObject = FFIData::GetData<CjIRemoteObjectImpl>(object);
254 if (!remoteObject) {
255 ZLOGE(LOG_LABEL, "get stub constructor failed");
256 return nullptr;
257 }
258 return remoteObject->GetRemoteObject();
259 }
260
261 extern "C" {
OHOS_CallCreateRemoteObject(void * param)262 FFI_EXPORT int64_t OHOS_CallCreateRemoteObject(void* param)
263 {
264 auto remoteObject = reinterpret_cast<sptr<IRemoteObject>*>(param);
265 if (remoteObject == nullptr) {
266 return 0;
267 }
268 return CJ_rpc_CreateRemoteObject(*remoteObject);
269 }
270
OHOS_CallGetNativeRemoteObject(int64_t object,void * param)271 FFI_EXPORT void OHOS_CallGetNativeRemoteObject(int64_t object, void* param)
272 {
273 if (param == nullptr) {
274 return;
275 }
276 auto ret = CJ_rpc_getNativeRemoteObject(object);
277 auto remoteObject = reinterpret_cast<sptr<IRemoteObject>*>(param);
278 *remoteObject = ret;
279 return;
280 }
281 }
282 } // namespace OHOS