1 /*
2 * Copyright (c) 2024 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 "js_uiservice_uiext_connection.h"
17
18 #include "ability_business_error.h"
19 #include "hilog_tag_wrapper.h"
20 #include "js_error_utils.h"
21 #include "js_ui_service_proxy.h"
22 #include "napi_common_want.h"
23 #include "ui_extension_servicehost_stub_impl.h"
24
25 namespace OHOS {
26 namespace AbilityRuntime {
27 constexpr size_t ARGC_ONE = 1;
28
29 namespace UIServiceConnection {
30 static std::map<UIExtensionConnectionKey, sptr<JSUIServiceUIExtConnection>, key_compare> gUiServiceExtConnects;
31 static std::recursive_mutex gUiServiceExtConnectsLock;
32 static int64_t gUiServiceExtConnectSn = 0;
33
AddUIServiceExtensionConnection(AAFwk::Want & want,sptr<JSUIServiceUIExtConnection> & connection)34 void AddUIServiceExtensionConnection(AAFwk::Want& want, sptr<JSUIServiceUIExtConnection>& connection)
35 {
36 std::lock_guard<std::recursive_mutex> lock(gUiServiceExtConnectsLock);
37 UIExtensionConnectionKey key;
38 key.id = gUiServiceExtConnectSn;
39 key.want = want;
40 connection->SetConnectionId(key.id);
41 gUiServiceExtConnects.emplace(key, connection);
42 if (gUiServiceExtConnectSn < INT32_MAX) {
43 gUiServiceExtConnectSn++;
44 } else {
45 gUiServiceExtConnectSn = 0;
46 }
47 }
48
RemoveUIServiceExtensionConnection(const int64_t & connectId)49 void RemoveUIServiceExtensionConnection(const int64_t& connectId)
50 {
51 std::lock_guard<std::recursive_mutex> lock(gUiServiceExtConnectsLock);
52 auto item = std::find_if(gUiServiceExtConnects.begin(), gUiServiceExtConnects.end(),
53 [&connectId](const auto &obj) {
54 return connectId == obj.first.id;
55 });
56 if (item != gUiServiceExtConnects.end()) {
57 TAG_LOGI(AAFwkTag::UI_EXT, "found, erase");
58 gUiServiceExtConnects.erase(item);
59 } else {
60 TAG_LOGI(AAFwkTag::UI_EXT, "not found");
61 }
62 TAG_LOGI(AAFwkTag::CONTEXT, "Connects new size:%{public}zu", gUiServiceExtConnects.size());
63 }
64
FindUIServiceExtensionConnection(const int64_t & connectId,AAFwk::Want & want,sptr<JSUIServiceUIExtConnection> & connection)65 void FindUIServiceExtensionConnection(const int64_t& connectId, AAFwk::Want& want,
66 sptr<JSUIServiceUIExtConnection>& connection)
67 {
68 std::lock_guard<std::recursive_mutex> lock(gUiServiceExtConnectsLock);
69 TAG_LOGI(AAFwkTag::UI_EXT, "connection:%{public}d", static_cast<int32_t>(connectId));
70 auto item = std::find_if(gUiServiceExtConnects.begin(), gUiServiceExtConnects.end(),
71 [&connectId](const auto &obj) {
72 return connectId == obj.first.id;
73 });
74 if (item != gUiServiceExtConnects.end()) {
75 want = item->first.want;
76 connection = item->second;
77 TAG_LOGI(AAFwkTag::UI_EXT, "found");
78 } else {
79 TAG_LOGI(AAFwkTag::UI_EXT, "not found");
80 }
81 }
82
FindUIServiceExtensionConnection(napi_env env,AAFwk::Want & want,napi_value callback,sptr<JSUIServiceUIExtConnection> & connection)83 void FindUIServiceExtensionConnection(napi_env env, AAFwk::Want& want, napi_value callback,
84 sptr<JSUIServiceUIExtConnection>& connection)
85 {
86 std::lock_guard<std::recursive_mutex> lock(gUiServiceExtConnectsLock);
87 auto item = std::find_if(gUiServiceExtConnects.begin(), gUiServiceExtConnects.end(),
88 [&want, env, callback](const auto &obj) {
89 bool wantEquals = (obj.first.want.GetElement() == want.GetElement());
90 std::unique_ptr<NativeReference>& tempCallbackPtr = obj.second->GetJsConnectionObject();
91 bool callbackObjectEquals =
92 JSUIServiceUIExtConnection::IsJsCallbackObjectEquals(env, tempCallbackPtr, callback);
93 return wantEquals && callbackObjectEquals;
94 });
95 if (item == gUiServiceExtConnects.end()) {
96 return;
97 }
98 connection = item->second;
99 }
100 }
101
JSUIServiceUIExtConnection(napi_env env)102 JSUIServiceUIExtConnection::JSUIServiceUIExtConnection(napi_env env) : JSUIExtensionConnection(env)
103 {
104 TAG_LOGI(AAFwkTag::UISERVC_EXT, "JSUIServiceUIExtConnection");
105 wptr<JSUIServiceUIExtConnection> weakthis = this;
106 serviceHostStub_ = sptr<UIExtensionServiceHostStubImpl>::MakeSptr(weakthis);
107 }
108
~JSUIServiceUIExtConnection()109 JSUIServiceUIExtConnection::~JSUIServiceUIExtConnection()
110 {
111 TAG_LOGI(AAFwkTag::UISERVC_EXT, "~JSUIServiceUIExtConnection");
112 serviceHostStub_ = nullptr;
113 napiAsyncTask_.reset();
114 ReleaseNativeReference(serviceProxyObject_.release());
115 }
116
HandleOnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)117 void JSUIServiceUIExtConnection::HandleOnAbilityConnectDone(
118 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int resultCode)
119 {
120 if (napiAsyncTask_ != nullptr) {
121 TAG_LOGI(AAFwkTag::UISERVC_EXT, "HandleOnAbilityConnectDone, CreateJsUIServiceProxy");
122 sptr<UIExtensionServiceHostStubImpl> hostStub = GetServiceHostStub();
123 sptr<IRemoteObject> hostProxy = nullptr;
124 if (hostStub != nullptr) {
125 hostProxy = hostStub->AsObject();
126 }
127 napi_value proxy = AAFwk::JsUIServiceProxy::CreateJsUIServiceProxy(env_, remoteObject,
128 connectionId_, hostProxy);
129 SetProxyObject(proxy);
130 napiAsyncTask_->ResolveWithNoError(env_, proxy);
131
132 ResolveDuplicatedPendingTask(env_, proxy);
133 } else {
134 TAG_LOGE(AAFwkTag::UISERVC_EXT, "HandleOnAbilityConnectDone, napiAsyncTask_ null");
135 }
136 napiAsyncTask_.reset();
137 }
138
HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)139 void JSUIServiceUIExtConnection::HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName &element,
140 int resultCode)
141 {
142 if (napiAsyncTask_ != nullptr) {
143 napi_value innerError = CreateJsError(env_, AbilityErrorCode::ERROR_CODE_INNER);
144 napiAsyncTask_->Reject(env_, innerError);
145 RejectDuplicatedPendingTask(env_, innerError);
146 napiAsyncTask_ = nullptr;
147 }
148 CallJsOnDisconnect();
149 SetProxyObject(nullptr);
150 RemoveConnectionObject();
151 duplicatedPendingTaskList_.clear();
152 UIServiceConnection::RemoveUIServiceExtensionConnection(connectionId_);
153 }
154
SetNapiAsyncTask(std::shared_ptr<NapiAsyncTask> & task)155 void JSUIServiceUIExtConnection::SetNapiAsyncTask(std::shared_ptr<NapiAsyncTask>& task)
156 {
157 napiAsyncTask_ = task;
158 }
159
AddDuplicatedPendingTask(std::unique_ptr<NapiAsyncTask> & task)160 void JSUIServiceUIExtConnection::AddDuplicatedPendingTask(std::unique_ptr<NapiAsyncTask>& task)
161 {
162 duplicatedPendingTaskList_.push_back(std::move(task));
163 }
164
ResolveDuplicatedPendingTask(napi_env env,napi_value proxy)165 void JSUIServiceUIExtConnection::ResolveDuplicatedPendingTask(napi_env env, napi_value proxy)
166 {
167 TAG_LOGI(AAFwkTag::UISERVC_EXT, "called, size %{public}zu", duplicatedPendingTaskList_.size());
168 for (auto &task : duplicatedPendingTaskList_) {
169 if (task != nullptr) {
170 task->ResolveWithNoError(env, proxy);
171 }
172 }
173 duplicatedPendingTaskList_.clear();
174 }
175
RejectDuplicatedPendingTask(napi_env env,napi_value error)176 void JSUIServiceUIExtConnection::RejectDuplicatedPendingTask(napi_env env, napi_value error)
177 {
178 TAG_LOGI(AAFwkTag::UISERVC_EXT, "called, size %{public}zu", duplicatedPendingTaskList_.size());
179 for (auto &task : duplicatedPendingTaskList_) {
180 if (task != nullptr) {
181 task->Reject(env, error);
182 }
183 }
184 duplicatedPendingTaskList_.clear();
185 }
186
SetProxyObject(napi_value proxy)187 void JSUIServiceUIExtConnection::SetProxyObject(napi_value proxy)
188 {
189 TAG_LOGI(AAFwkTag::UISERVC_EXT, "SetProxyObject");
190 serviceProxyObject_.reset();
191 if (proxy != nullptr) {
192 napi_ref ref = nullptr;
193 napi_create_reference(env_, proxy, 1, &ref);
194 serviceProxyObject_ = std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref));
195 }
196 }
197
GetProxyObject()198 napi_value JSUIServiceUIExtConnection::GetProxyObject()
199 {
200 if (serviceProxyObject_ == nullptr) {
201 return nullptr;
202 }
203 return serviceProxyObject_->GetNapiValue();
204 }
205
OnSendData(OHOS::AAFwk::WantParams & data)206 int32_t JSUIServiceUIExtConnection::OnSendData(OHOS::AAFwk::WantParams &data)
207 {
208 wptr<JSUIServiceUIExtConnection> connection = this;
209 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>
210 ([connection, wantParams = data](napi_env env, NapiAsyncTask &task, int32_t status) {
211 sptr<JSUIServiceUIExtConnection> connectionSptr = connection.promote();
212 if (!connectionSptr) {
213 TAG_LOGE(AAFwkTag::UISERVC_EXT, "connectionSptr nullptr");
214 return;
215 }
216 connectionSptr->HandleOnSendData(wantParams);
217 });
218
219 napi_ref callback = nullptr;
220 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
221 NapiAsyncTask::Schedule("JSUIServiceUIExtConnection::SendData",
222 env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
223
224 return static_cast<int32_t>(AbilityErrorCode::ERROR_OK);
225 }
226
HandleOnSendData(const OHOS::AAFwk::WantParams & data)227 void JSUIServiceUIExtConnection::HandleOnSendData(const OHOS::AAFwk::WantParams &data)
228 {
229 napi_value argv[] = { AppExecFwk::CreateJsWantParams(env_, data) };
230 CallObjectMethod("onData", argv, ARGC_ONE);
231 }
232
CallJsOnDisconnect()233 void JSUIServiceUIExtConnection::CallJsOnDisconnect()
234 {
235 TAG_LOGI(AAFwkTag::UISERVC_EXT, "called");
236 CallObjectMethod("onDisconnect", nullptr, 0);
237 }
238
IsJsCallbackObjectEquals(napi_env env,std::unique_ptr<NativeReference> & callback,napi_value value)239 bool JSUIServiceUIExtConnection::IsJsCallbackObjectEquals(napi_env env,
240 std::unique_ptr<NativeReference> &callback, napi_value value)
241 {
242 if (value == nullptr || callback == nullptr) {
243 return callback.get() == reinterpret_cast<NativeReference*>(value);
244 }
245 auto object = callback->GetNapiValue();
246 if (object == nullptr) {
247 TAG_LOGE(AAFwkTag::UISERVC_EXT, "Failed to get object.");
248 return false;
249 }
250 bool result = false;
251 if (napi_strict_equals(env, object, value, &result) != napi_ok) {
252 TAG_LOGE(AAFwkTag::UISERVC_EXT, "Object does not match value.");
253 return false;
254 }
255 return result;
256 }
257
258 }
259 }
260