1 /*
2 * Copyright (c) 2022-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 #include <string>
16 #include <set>
17
18 #include "event_handler.h"
19 #include "hilog_tag_wrapper.h"
20 #include "js_context_utils.h"
21 #include "js_data_struct_converter.h"
22 #include "js_error_utils.h"
23 #include "js_runtime.h"
24 #include "js_runtime_utils.h"
25 #include "napi_common_want.h"
26 #include "napi_remote_object.h"
27 #include "ability_runtime/js_caller_complex.h"
28
29 namespace OHOS {
30 namespace AbilityRuntime {
31 namespace { // nameless
32 static std::map<NativeValueType, std::string> logcast = {
33 { NATIVE_UNDEFINED, std::string("NATIVE_UNDEFINED") },
34 { NATIVE_NULL, std::string("NATIVE_NULL") },
35 { NATIVE_BOOLEAN, std::string("NATIVE_BOOLEAN") },
36 { NATIVE_NUMBER, std::string("NATIVE_NUMBER") },
37 { NATIVE_STRING, std::string("NATIVE_STRING") },
38 { NATIVE_SYMBOL, std::string("NATIVE_SYMBOL") },
39 { NATIVE_OBJECT, std::string("NATIVE_OBJECT") },
40 { NATIVE_FUNCTION, std::string("NATIVE_FUNCTION") },
41 { NATIVE_EXTERNAL, std::string("NATIVE_EXTERNAL") },
42 { NATIVE_BIGINT, std::string("NATIVE_BIGINT") },
43 };
44
45 class JsCallerComplex {
46 public:
47 enum class OBJSTATE {
48 OBJ_NORMAL,
49 OBJ_EXECUTION,
50 OBJ_RELEASE
51 };
52
JsCallerComplex(napi_env env,ReleaseCallFunc releaseCallFunc,sptr<IRemoteObject> callee,std::shared_ptr<CallerCallBack> callerCallBack)53 explicit JsCallerComplex(
54 napi_env env, ReleaseCallFunc releaseCallFunc, sptr<IRemoteObject> callee,
55 std::shared_ptr<CallerCallBack> callerCallBack) : releaseCallFunc_(releaseCallFunc),
56 callee_(callee), releaseCallBackEngine_(env), remoteStateChanegdEngine_(env),
57 callerCallBackObj_(callerCallBack), jsReleaseCallBackObj_(nullptr), jsRemoteStateChangedObj_(nullptr)
58 {
59 AddJsCallerComplex(this);
60 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
61 currentState_ = OBJSTATE::OBJ_NORMAL;
62 };
~JsCallerComplex()63 virtual~JsCallerComplex()
64 {
65 RemoveJsCallerComplex(this);
66 };
67
ReleaseObject(JsCallerComplex * data)68 static bool ReleaseObject(JsCallerComplex* data)
69 {
70 TAG_LOGD(AAFwkTag::DEFAULT, "called");
71 if (data == nullptr) {
72 TAG_LOGE(AAFwkTag::DEFAULT, "null data");
73 return false;
74 }
75
76 if (!data->ChangeCurrentState(OBJSTATE::OBJ_RELEASE)) {
77 auto handler = data->GetEventHandler();
78 if (handler == nullptr) {
79 TAG_LOGE(AAFwkTag::DEFAULT, "null handler");
80 return false;
81 }
82 auto releaseObjTask = [pdata = data] () {
83 if (!FindJsCallerComplex(pdata)) {
84 TAG_LOGE(AAFwkTag::DEFAULT, "argc not found");
85 return;
86 }
87 ReleaseObject(pdata);
88 };
89
90 handler->PostTask(releaseObjTask, "FinalizerRelease");
91 return false;
92 } else {
93 // when the object is about to be destroyed, does not reset state
94 std::unique_ptr<JsCallerComplex> delObj(data);
95 }
96 TAG_LOGD(AAFwkTag::DEFAULT, "end");
97 return true;
98 }
99
Finalizer(napi_env env,void * data,void * hint)100 static void Finalizer(napi_env env, void* data, void* hint)
101 {
102 TAG_LOGD(AAFwkTag::DEFAULT, "called");
103 if (data == nullptr) {
104 TAG_LOGE(AAFwkTag::DEFAULT, "null data");
105 return;
106 }
107
108 auto ptr = static_cast<JsCallerComplex*>(data);
109 if (!FindJsCallerComplex(ptr)) {
110 TAG_LOGE(AAFwkTag::DEFAULT, "argc not found");
111 return;
112 }
113
114 ReleaseObject(ptr);
115 TAG_LOGD(AAFwkTag::DEFAULT, "end");
116 }
117
JsReleaseCall(napi_env env,napi_callback_info info)118 static napi_value JsReleaseCall(napi_env env, napi_callback_info info)
119 {
120 if (env == nullptr || info == nullptr) {
121 TAG_LOGE(AAFwkTag::DEFAULT, "null %{public}s", ((env == nullptr) ? "env" : "info"));
122 return nullptr;
123 }
124 GET_NAPI_INFO_AND_CALL(env, info, JsCallerComplex, ReleaseCallInner);
125 }
126
JsSetOnReleaseCallBack(napi_env env,napi_callback_info info)127 static napi_value JsSetOnReleaseCallBack(napi_env env, napi_callback_info info)
128 {
129 if (env == nullptr || info == nullptr) {
130 TAG_LOGE(AAFwkTag::DEFAULT, "null %{public}s", ((env == nullptr) ? "env" : "info"));
131 return nullptr;
132 }
133 GET_NAPI_INFO_AND_CALL(env, info, JsCallerComplex, SetOnReleaseCallBackInner);
134 }
135
JsSetOnRemoteStateChanged(napi_env env,napi_callback_info info)136 static napi_value JsSetOnRemoteStateChanged(napi_env env, napi_callback_info info)
137 {
138 if (env == nullptr || info == nullptr) {
139 TAG_LOGE(AAFwkTag::DEFAULT, "null %{public}s", ((env == nullptr) ? "env" : "info"));
140 return nullptr;
141 }
142 GET_NAPI_INFO_AND_CALL(env, info, JsCallerComplex, SetOnRemoteStateChangedInner);
143 }
144
AddJsCallerComplex(JsCallerComplex * ptr)145 static bool AddJsCallerComplex(JsCallerComplex* ptr)
146 {
147 if (ptr == nullptr) {
148 TAG_LOGE(AAFwkTag::DEFAULT, "null ptr");
149 return false;
150 }
151
152 std::lock_guard<std::mutex> lck (jsCallerComplexMutex);
153 auto iter = jsCallerComplexManagerList.find(ptr);
154 if (iter != jsCallerComplexManagerList.end()) {
155 TAG_LOGE(AAFwkTag::DEFAULT, "address exist");
156 return false;
157 }
158
159 auto iterRet = jsCallerComplexManagerList.emplace(ptr);
160 TAG_LOGD(AAFwkTag::DEFAULT, "retval: %{public}s", iterRet.second ? "true" : "false");
161 return iterRet.second;
162 }
163
RemoveJsCallerComplex(JsCallerComplex * ptr)164 static bool RemoveJsCallerComplex(JsCallerComplex* ptr)
165 {
166 if (ptr == nullptr) {
167 TAG_LOGE(AAFwkTag::DEFAULT, "null ptr");
168 return false;
169 }
170
171 std::lock_guard<std::mutex> lck (jsCallerComplexMutex);
172 auto iter = jsCallerComplexManagerList.find(ptr);
173 if (iter == jsCallerComplexManagerList.end()) {
174 TAG_LOGE(AAFwkTag::DEFAULT, "argc not found");
175 return false;
176 }
177
178 jsCallerComplexManagerList.erase(ptr);
179 TAG_LOGD(AAFwkTag::DEFAULT, "end");
180 return true;
181 }
182
FindJsCallerComplex(JsCallerComplex * ptr)183 static bool FindJsCallerComplex(JsCallerComplex* ptr)
184 {
185 if (ptr == nullptr) {
186 TAG_LOGE(AAFwkTag::DEFAULT, "null ptr");
187 return false;
188 }
189 auto ret = true;
190 std::lock_guard<std::mutex> lck (jsCallerComplexMutex);
191 auto iter = jsCallerComplexManagerList.find(ptr);
192 if (iter == jsCallerComplexManagerList.end()) {
193 ret = false;
194 }
195 TAG_LOGD(AAFwkTag::DEFAULT, "retval %{public}s", ret ? "true" : "false");
196 return ret;
197 }
198
FindJsCallerComplexAndChangeState(JsCallerComplex * ptr,OBJSTATE state)199 static bool FindJsCallerComplexAndChangeState(JsCallerComplex* ptr, OBJSTATE state)
200 {
201 if (ptr == nullptr) {
202 TAG_LOGE(AAFwkTag::DEFAULT, "null ptr");
203 return false;
204 }
205
206 std::lock_guard<std::mutex> lck (jsCallerComplexMutex);
207 auto iter = jsCallerComplexManagerList.find(ptr);
208 if (iter == jsCallerComplexManagerList.end()) {
209 TAG_LOGE(AAFwkTag::DEFAULT, "argc not found");
210 return false;
211 }
212
213 auto ret = ptr->ChangeCurrentState(state);
214 TAG_LOGD(AAFwkTag::DEFAULT, "ChangeCurrentState ret:%{public}s", ret ? "true" : "false");
215
216 return ret;
217 }
218
GetRemoteObject()219 sptr<IRemoteObject> GetRemoteObject()
220 {
221 return callee_;
222 }
223
GetEventHandler()224 std::shared_ptr<AppExecFwk::EventHandler> GetEventHandler()
225 {
226 return handler_;
227 }
228
ChangeCurrentState(OBJSTATE state)229 bool ChangeCurrentState(OBJSTATE state)
230 {
231 auto ret = false;
232 if (stateMechanismMutex_.try_lock() == false) {
233 TAG_LOGE(AAFwkTag::DEFAULT, "mutex try_lock false");
234 return ret;
235 }
236
237 if (currentState_ == OBJSTATE::OBJ_NORMAL) {
238 currentState_ = state;
239 ret = true;
240 TAG_LOGD(AAFwkTag::DEFAULT, "currentState_:OBJ_NORMAL");
241 } else if (currentState_ == state) {
242 ret = true;
243 TAG_LOGD(AAFwkTag::DEFAULT, "currentState_:state");
244 } else {
245 ret = false;
246 TAG_LOGD(AAFwkTag::DEFAULT, "ret: false");
247 }
248
249 stateMechanismMutex_.unlock();
250 return ret;
251 }
252
GetCurrentState()253 OBJSTATE GetCurrentState()
254 {
255 return currentState_;
256 }
257
StateReset()258 void StateReset()
259 {
260 currentState_ = OBJSTATE::OBJ_NORMAL;
261 }
262
SetJsRemoteObj(napi_env env,napi_value value)263 void SetJsRemoteObj(napi_env env, napi_value value)
264 {
265 if (env == nullptr || value == nullptr) {
266 TAG_LOGE(AAFwkTag::DEFAULT, "parameter error");
267 return;
268 }
269 napi_ref ref = nullptr;
270 napi_create_reference(env, value, 1, &ref);
271 jsRemoteObj_.reset(reinterpret_cast<NativeReference*>(ref));
272 jsRemoteObjEnv_ = env;
273 }
274
ReleaseJsRemoteObj()275 void ReleaseJsRemoteObj()
276 {
277 if (jsRemoteObjEnv_ == nullptr || jsRemoteObj_ == nullptr) {
278 return;
279 }
280 TAG_LOGI(AAFwkTag::DEFAULT, "before release call");
281 napi_value value = jsRemoteObj_->GetNapiValue();
282 NAPI_ohos_rpc_ClearNativeRemoteProxy(jsRemoteObjEnv_, value);
283 jsRemoteObj_.reset();
284 jsRemoteObjEnv_ = nullptr;
285 }
286
287 private:
288
OnReleaseNotify(const std::string & str)289 void OnReleaseNotify(const std::string &str)
290 {
291 TAG_LOGD(AAFwkTag::DEFAULT, "begin");
292 if (handler_ == nullptr) {
293 TAG_LOGE(AAFwkTag::DEFAULT, "null handler");
294 return;
295 }
296
297 auto task = [notify = this, &str] () {
298 if (!FindJsCallerComplex(notify)) {
299 TAG_LOGE(AAFwkTag::DEFAULT, "address error");
300 return;
301 }
302 notify->OnReleaseNotifyTask(str);
303 };
304 handler_->PostSyncTask(task, "OnReleaseNotify");
305 TAG_LOGD(AAFwkTag::DEFAULT, "end");
306 }
307
OnReleaseNotifyTask(const std::string & str)308 void OnReleaseNotifyTask(const std::string &str)
309 {
310 TAG_LOGD(AAFwkTag::DEFAULT, "begin");
311 if (jsReleaseCallBackObj_ == nullptr) {
312 TAG_LOGE(AAFwkTag::DEFAULT, "null jsreleaseObj");
313 return;
314 }
315
316 napi_value value = jsReleaseCallBackObj_->GetNapiValue();
317 napi_value callback = jsReleaseCallBackObj_->GetNapiValue();
318 napi_value args[] = { CreateJsValue(releaseCallBackEngine_, str) };
319 napi_call_function(releaseCallBackEngine_, value, callback, 1, args, nullptr);
320 callee_ = nullptr;
321 StateReset();
322 }
323
OnRemoteStateChangedNotify(const std::string & str)324 void OnRemoteStateChangedNotify(const std::string &str)
325 {
326 TAG_LOGD(AAFwkTag::DEFAULT, "begin");
327 if (handler_ == nullptr) {
328 TAG_LOGE(AAFwkTag::DEFAULT, "null handler");
329 return;
330 }
331
332 auto task = [notify = this, &str] () {
333 if (!FindJsCallerComplex(notify)) {
334 TAG_LOGE(AAFwkTag::DEFAULT, "ptr not found");
335 return;
336 }
337 notify->OnRemoteStateChangedNotifyTask(str);
338 };
339 handler_->PostSyncTask(task, "OnRemoteStateChangedNotify");
340 TAG_LOGD(AAFwkTag::DEFAULT, "end");
341 }
342
OnRemoteStateChangedNotifyTask(const std::string & str)343 void OnRemoteStateChangedNotifyTask(const std::string &str)
344 {
345 TAG_LOGD(AAFwkTag::DEFAULT, "begin");
346 if (jsRemoteStateChangedObj_ == nullptr) {
347 TAG_LOGE(AAFwkTag::DEFAULT, "null jsRemoteStateChangedObj");
348 return;
349 }
350
351 napi_value value = jsRemoteStateChangedObj_->GetNapiValue();
352 napi_value callback = jsRemoteStateChangedObj_->GetNapiValue();
353 napi_value args[] = { CreateJsValue(remoteStateChanegdEngine_, str) };
354 napi_call_function(remoteStateChanegdEngine_, value, callback, 1, args, nullptr);
355 StateReset();
356 TAG_LOGD(AAFwkTag::DEFAULT, "end");
357 }
358
ReleaseCallInner(napi_env env,NapiCallbackInfo & info)359 napi_value ReleaseCallInner(napi_env env, NapiCallbackInfo& info)
360 {
361 TAG_LOGD(AAFwkTag::DEFAULT, "called");
362 if (callerCallBackObj_ == nullptr) {
363 TAG_LOGE(AAFwkTag::DEFAULT, "null CallBacker");
364 ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
365 }
366
367 if (!releaseCallFunc_) {
368 TAG_LOGE(AAFwkTag::DEFAULT, "null releaseFunc");
369 ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
370 }
371 callee_ = nullptr;
372 callerCallBackObj_->SetCallBack(nullptr);
373 ReleaseJsRemoteObj();
374 int32_t innerErrorCode = releaseCallFunc_(callerCallBackObj_);
375 if (innerErrorCode != ERR_OK) {
376 TAG_LOGE(AAFwkTag::DEFAULT, "ReleaseAbility failed %{public}d", static_cast<int>(innerErrorCode));
377 ThrowError(env, innerErrorCode);
378 }
379
380 return CreateJsUndefined(env);
381 }
382
SetOnReleaseCallBackInner(napi_env env,NapiCallbackInfo & info)383 napi_value SetOnReleaseCallBackInner(napi_env env, NapiCallbackInfo& info)
384 {
385 TAG_LOGD(AAFwkTag::DEFAULT, "start");
386 constexpr size_t argcOne = 1;
387 if (info.argc < argcOne) {
388 TAG_LOGE(AAFwkTag::DEFAULT, "Invalid argc");
389 ThrowTooFewParametersError(env);
390 }
391 bool isCallable = false;
392 napi_is_callable(env, info.argv[0], &isCallable);
393 if (!isCallable) {
394 TAG_LOGE(AAFwkTag::DEFAULT, "IsCallable %{public}s", isCallable ? "true" : "false");
395 ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
396 }
397
398 if (callerCallBackObj_ == nullptr) {
399 TAG_LOGE(AAFwkTag::DEFAULT, "null CallBacker");
400 ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
401 }
402
403 auto param1 = info.argv[0];
404 if (param1 == nullptr) {
405 TAG_LOGE(AAFwkTag::DEFAULT, "null param1");
406 ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
407 }
408
409 napi_ref ref = nullptr;
410 napi_create_reference(releaseCallBackEngine_, param1, 1, &ref);
411 jsReleaseCallBackObj_.reset(reinterpret_cast<NativeReference*>(ref));
412 auto task = [notify = this] (const std::string &str) {
413 if (!FindJsCallerComplexAndChangeState(notify, OBJSTATE::OBJ_EXECUTION)) {
414 TAG_LOGE(AAFwkTag::DEFAULT, "address error");
415 return;
416 }
417 notify->OnReleaseNotify(str);
418 };
419 callerCallBackObj_->SetOnRelease(task);
420 return CreateJsUndefined(env);
421 }
422
SetOnRemoteStateChangedInner(napi_env env,NapiCallbackInfo & info)423 napi_value SetOnRemoteStateChangedInner(napi_env env, NapiCallbackInfo& info)
424 {
425 TAG_LOGD(AAFwkTag::DEFAULT, "begin");
426 constexpr size_t argcOne = 1;
427 if (info.argc < argcOne) {
428 TAG_LOGE(AAFwkTag::DEFAULT, "Invalid argc");
429 ThrowTooFewParametersError(env);
430 }
431 bool isCallable = false;
432 napi_is_callable(env, info.argv[0], &isCallable);
433 if (!isCallable) {
434 TAG_LOGE(AAFwkTag::DEFAULT, "IsCallable %{public}s", isCallable ? "true" : "false");
435 ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
436 }
437
438 if (callerCallBackObj_ == nullptr) {
439 TAG_LOGE(AAFwkTag::DEFAULT, "CallBacker null");
440 ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
441 }
442
443 auto param1 = info.argv[0];
444 if (param1 == nullptr) {
445 TAG_LOGE(AAFwkTag::DEFAULT, "param1 null");
446 ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
447 }
448
449 napi_ref ref = nullptr;
450 napi_create_reference(remoteStateChanegdEngine_, param1, 1, &ref);
451 jsRemoteStateChangedObj_.reset(reinterpret_cast<NativeReference*>(ref));
452 auto task = [notify = this] (const std::string &str) {
453 TAG_LOGI(AAFwkTag::DEFAULT, "state changed");
454 if (!FindJsCallerComplexAndChangeState(notify, OBJSTATE::OBJ_EXECUTION)) {
455 TAG_LOGE(AAFwkTag::DEFAULT, "address error");
456 return;
457 }
458 notify->OnRemoteStateChangedNotify(str);
459 };
460 callerCallBackObj_->SetOnRemoteStateChanged(task);
461 TAG_LOGD(AAFwkTag::DEFAULT, "end");
462 return CreateJsUndefined(env);
463 }
464
465 private:
466 ReleaseCallFunc releaseCallFunc_;
467 sptr<IRemoteObject> callee_;
468 napi_env releaseCallBackEngine_;
469 napi_env remoteStateChanegdEngine_;
470 napi_env jsRemoteObjEnv_ = nullptr;
471 std::shared_ptr<CallerCallBack> callerCallBackObj_;
472 std::unique_ptr<NativeReference> jsReleaseCallBackObj_;
473 std::unique_ptr<NativeReference> jsRemoteStateChangedObj_;
474 std::unique_ptr<NativeReference> jsRemoteObj_;
475 std::shared_ptr<AppExecFwk::EventHandler> handler_;
476 std::mutex stateMechanismMutex_;
477 OBJSTATE currentState_;
478
479 static std::set<JsCallerComplex*> jsCallerComplexManagerList;
480 static std::mutex jsCallerComplexMutex;
481 };
482
483 std::set<JsCallerComplex*> JsCallerComplex::jsCallerComplexManagerList;
484 std::mutex JsCallerComplex::jsCallerComplexMutex;
485 } // nameless
486
CreateJsCallerComplex(napi_env env,ReleaseCallFunc releaseCallFunc,sptr<IRemoteObject> callee,std::shared_ptr<CallerCallBack> callerCallBack)487 napi_value CreateJsCallerComplex(
488 napi_env env, ReleaseCallFunc releaseCallFunc, sptr<IRemoteObject> callee,
489 std::shared_ptr<CallerCallBack> callerCallBack)
490 {
491 TAG_LOGD(AAFwkTag::DEFAULT, "begin");
492 if (callee == nullptr || callerCallBack == nullptr || releaseCallFunc == nullptr) {
493 TAG_LOGE(AAFwkTag::DEFAULT, "%{public}s null",
494 (callee == nullptr) ? ("callee") :
495 ((releaseCallFunc == nullptr) ? ("releaseCallFunc") : ("callerCallBack")));
496 return CreateJsUndefined(env);
497 }
498
499 napi_value object = nullptr;
500 napi_create_object(env, &object);
501 auto jsCaller = std::make_unique<JsCallerComplex>(env, releaseCallFunc, callee, callerCallBack);
502 auto remoteObj = jsCaller->GetRemoteObject();
503 if (remoteObj == nullptr) {
504 TAG_LOGE(AAFwkTag::DEFAULT, "remoteObj null");
505 return CreateJsUndefined(env);
506 }
507
508 auto jsRemoteObj = CreateJsCalleeRemoteObject(env, remoteObj);
509 jsCaller->SetJsRemoteObj(env, jsRemoteObj);
510 napi_wrap(env, object, jsCaller.release(), JsCallerComplex::Finalizer, nullptr, nullptr);
511 napi_set_named_property(env, object, "callee", jsRemoteObj);
512 const char *moduleName = "JsCallerComplex";
513 BindNativeFunction(env, object, "release", moduleName, JsCallerComplex::JsReleaseCall);
514 BindNativeFunction(env, object, "onRelease", moduleName, JsCallerComplex::JsSetOnReleaseCallBack);
515 BindNativeFunction(env, object, "onRemoteStateChange", moduleName, JsCallerComplex::JsSetOnRemoteStateChanged);
516
517 TAG_LOGD(AAFwkTag::DEFAULT, "end");
518 return object;
519 }
520
CreateJsCalleeRemoteObject(napi_env env,sptr<IRemoteObject> callee)521 napi_value CreateJsCalleeRemoteObject(napi_env env, sptr<IRemoteObject> callee)
522 {
523 if (callee == nullptr) {
524 TAG_LOGE(AAFwkTag::DEFAULT, "null data");
525 return CreateJsUndefined(env);
526 }
527 napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(env, callee);
528 if (napiRemoteObject == nullptr) {
529 TAG_LOGE(AAFwkTag::DEFAULT, "remoteObj null");
530 }
531 return napiRemoteObject;
532 }
533 } // AbilityRuntime
534 } // OHOS
535