• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "js_driver_extension.h"
17 
18 #include "ability_info.h"
19 #include "hitrace_meter.h"
20 #include "hilog_wrapper.h"
21 #include "js_extension_common.h"
22 #include "js_extension_context.h"
23 #include "js_runtime.h"
24 #include "js_runtime_utils.h"
25 #include "js_driver_extension_context.h"
26 #include "napi/native_api.h"
27 #include "napi/native_node_api.h"
28 #include "napi_common_configuration.h"
29 #include "napi_common_want.h"
30 #include "napi_remote_object.h"
31 
32 namespace OHOS {
33 namespace AbilityRuntime {
34 namespace {
35 constexpr size_t ARGC_ONE = 1;
36 }
37 
38 namespace {
PromiseCallback(NativeEngine * engine,NativeCallbackInfo * info)39 NativeValue *PromiseCallback(NativeEngine *engine, NativeCallbackInfo *info)
40 {
41     if (info == nullptr || info->functionInfo == nullptr || info->functionInfo->data == nullptr) {
42         HILOG_ERROR("PromiseCallback, Invalid input info.");
43         return nullptr;
44     }
45     void *data = info->functionInfo->data;
46     auto *callbackInfo = static_cast<AppExecFwk::AbilityTransactionCallbackInfo<> *>(data);
47     callbackInfo->Call();
48     AppExecFwk::AbilityTransactionCallbackInfo<>::Destroy(callbackInfo);
49     info->functionInfo->data = nullptr;
50     return nullptr;
51 }
52 
OnConnectPromiseCallback(NativeEngine * engine,NativeCallbackInfo * info)53 NativeValue *OnConnectPromiseCallback(NativeEngine *engine, NativeCallbackInfo *info)
54 {
55     if (info == nullptr || info->functionInfo == nullptr || info->functionInfo->data == nullptr) {
56         HILOG_ERROR("PromiseCallback, Invalid input info.");
57         return nullptr;
58     }
59     void *data = info->functionInfo->data;
60     auto *callbackInfo = static_cast<AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> *>(data);
61     sptr<IRemoteObject> service = nullptr;
62     if (info->argc > 0) {
63         service = NAPI_ohos_rpc_getNativeRemoteObject(reinterpret_cast<napi_env>(engine),
64             reinterpret_cast<napi_value>(info->argv[0]));
65     }
66     callbackInfo->Call(service);
67     AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>>::Destroy(callbackInfo);
68     info->functionInfo->data = nullptr;
69     return nullptr;
70 }
71 }
72 
73 using namespace OHOS::AppExecFwk;
74 
AttachDriverExtensionContext(NativeEngine * engine,void * value,void *)75 NativeValue *AttachDriverExtensionContext(NativeEngine *engine, void *value, void *)
76 {
77     HILOG_INFO("AttachDriverExtensionContext");
78     if (value == nullptr) {
79         HILOG_WARN("invalid parameter.");
80         return nullptr;
81     }
82     auto ptr = reinterpret_cast<std::weak_ptr<DriverExtensionContext> *>(value)->lock();
83     if (ptr == nullptr) {
84         HILOG_WARN("invalid context.");
85         return nullptr;
86     }
87     NativeValue *object = CreateJsDriverExtensionContext(*engine, ptr);
88     auto contextObj = JsRuntime::LoadSystemModuleByEngine(engine,
89         "application.DriverExtensionContext", &object, 1)->Get();
90     NativeObject *nObject = ConvertNativeValueTo<NativeObject>(contextObj);
91     nObject->ConvertToNativeBindingObject(engine, DetachCallbackFunc, AttachDriverExtensionContext,
92         value, nullptr);
93     auto workContext = new (std::nothrow) std::weak_ptr<DriverExtensionContext>(ptr);
94     nObject->SetNativePointer(workContext,
95         [](NativeEngine *, void *data, void *) {
96             HILOG_INFO("Finalizer for weak_ptr driver extension context is called");
97             delete static_cast<std::weak_ptr<DriverExtensionContext> *>(data);
98         }, nullptr);
99     return contextObj;
100 }
101 
Create(const std::unique_ptr<Runtime> & runtime)102 JsDriverExtension* JsDriverExtension::Create(const std::unique_ptr<Runtime>& runtime)
103 {
104     return new JsDriverExtension(static_cast<JsRuntime&>(*runtime));
105 }
106 
JsDriverExtension(JsRuntime & jsRuntime)107 JsDriverExtension::JsDriverExtension(JsRuntime& jsRuntime) : jsRuntime_(jsRuntime) {}
108 JsDriverExtension::~JsDriverExtension() = default;
109 
Init(const std::shared_ptr<AbilityLocalRecord> & record,const std::shared_ptr<OHOSApplication> & application,std::shared_ptr<AbilityHandler> & handler,const sptr<IRemoteObject> & token)110 void JsDriverExtension::Init(const std::shared_ptr<AbilityLocalRecord> &record,
111     const std::shared_ptr<OHOSApplication> &application, std::shared_ptr<AbilityHandler> &handler,
112     const sptr<IRemoteObject> &token)
113 {
114     DriverExtension::Init(record, application, handler, token);
115     std::string srcPath = "";
116     GetSrcPath(srcPath);
117     if (srcPath.empty()) {
118         HILOG_ERROR("Failed to get srcPath");
119         return;
120     }
121 
122     std::string moduleName(Extension::abilityInfo_->moduleName);
123     moduleName.append("::").append(abilityInfo_->name);
124     HILOG_DEBUG("JsStaticSubscriberExtension::Init moduleName:%{public}s,srcPath:%{public}s.",
125         moduleName.c_str(), srcPath.c_str());
126     HandleScope handleScope(jsRuntime_);
127     auto& engine = jsRuntime_.GetNativeEngine();
128 
129     jsObj_ = jsRuntime_.LoadModule(
130         moduleName, srcPath, abilityInfo_->hapPath, abilityInfo_->compileMode == CompileMode::ES_MODULE);
131     if (jsObj_ == nullptr) {
132         HILOG_ERROR("Failed to get jsObj_");
133         return;
134     }
135 
136     HILOG_INFO("JsDriverExtension::Init ConvertNativeValueTo.");
137     NativeObject* obj = ConvertNativeValueTo<NativeObject>(jsObj_->Get());
138     if (obj == nullptr) {
139         HILOG_ERROR("Failed to get JsDriverExtension object");
140         return;
141     }
142 
143     BindContext(engine, obj);
144 
145     SetExtensionCommon(JsExtensionCommon::Create(jsRuntime_, static_cast<NativeReference&>(*jsObj_), shellContextRef_));
146 }
147 
BindContext(NativeEngine & engine,NativeObject * obj)148 void JsDriverExtension::BindContext(NativeEngine& engine, NativeObject* obj)
149 {
150     auto context = GetContext();
151     if (context == nullptr) {
152         HILOG_ERROR("Failed to get context");
153         return;
154     }
155     HILOG_INFO("JsDriverExtension::Init CreateJsDriverExtensionContext.");
156     NativeValue* contextObj = CreateJsDriverExtensionContext(engine, context);
157     shellContextRef_ = JsRuntime::LoadSystemModuleByEngine(&engine, "application.DriverExtensionContext",
158         &contextObj, ARGC_ONE);
159     contextObj = shellContextRef_->Get();
160     NativeObject *nativeObj = ConvertNativeValueTo<NativeObject>(contextObj);
161     if (nativeObj == nullptr) {
162         HILOG_ERROR("Failed to get context native object");
163         return;
164     }
165     auto workContext = new (std::nothrow) std::weak_ptr<DriverExtensionContext>(context);
166     nativeObj->ConvertToNativeBindingObject(&engine, DetachCallbackFunc, AttachDriverExtensionContext,
167         workContext, nullptr);
168     HILOG_INFO("JsDriverExtension::Init Bind.");
169     context->Bind(jsRuntime_, shellContextRef_.get());
170     HILOG_INFO("JsDriverExtension::SetProperty.");
171     obj->SetProperty("context", contextObj);
172     HILOG_INFO("Set driver extension context");
173 
174     nativeObj->SetNativePointer(workContext,
175         [](NativeEngine*, void* data, void*) {
176             HILOG_INFO("Finalizer for weak_ptr driver extension context is called");
177             delete static_cast<std::weak_ptr<DriverExtensionContext>*>(data);
178         }, nullptr);
179 
180     HILOG_INFO("JsDriverExtension::Init end.");
181 }
182 
OnStart(const AAFwk::Want & want)183 void JsDriverExtension::OnStart(const AAFwk::Want &want)
184 {
185     Extension::OnStart(want);
186     HILOG_INFO("JsDriverExtension OnStart begin..");
187     HandleScope handleScope(jsRuntime_);
188     NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
189     napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
190     NativeValue* nativeWant = reinterpret_cast<NativeValue*>(napiWant);
191     NativeValue* argv[] = {nativeWant};
192     CallObjectMethod("onInit", argv, ARGC_ONE);
193     HILOG_INFO("%{public}s end.", __func__);
194 }
195 
OnStop()196 void JsDriverExtension::OnStop()
197 {
198     DriverExtension::OnStop();
199     HILOG_INFO("JsDriverExtension OnStop begin.");
200     CallObjectMethod("onRelease");
201     bool ret = ConnectionManager::GetInstance().DisconnectCaller(GetContext()->GetToken());
202     if (ret) {
203         ConnectionManager::GetInstance().ReportConnectionLeakEvent(getpid(), gettid());
204         HILOG_INFO("The driver extension connection is not disconnected.");
205     }
206     HILOG_INFO("%{public}s end.", __func__);
207 }
208 
OnConnect(const AAFwk::Want & want)209 sptr<IRemoteObject> JsDriverExtension::OnConnect(const AAFwk::Want &want)
210 {
211     HandleScope handleScope(jsRuntime_);
212     NativeValue *result = CallOnConnect(want);
213     NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
214     auto remoteObj = NAPI_ohos_rpc_getNativeRemoteObject(
215         reinterpret_cast<napi_env>(nativeEngine), reinterpret_cast<napi_value>(result));
216     if (remoteObj == nullptr) {
217         HILOG_ERROR("remoteObj nullptr.");
218     }
219     return remoteObj;
220 }
221 
OnConnect(const AAFwk::Want & want,AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> * callbackInfo,bool & isAsyncCallback)222 sptr<IRemoteObject> JsDriverExtension::OnConnect(const AAFwk::Want &want,
223     AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> *callbackInfo, bool &isAsyncCallback)
224 {
225     HandleScope handleScope(jsRuntime_);
226     NativeEngine *nativeEngine = &jsRuntime_.GetNativeEngine();
227     NativeValue *result = CallOnConnect(want);
228     bool isPromise = CheckPromise(result);
229     if (!isPromise) {
230         isAsyncCallback = false;
231         sptr<IRemoteObject> remoteObj = NAPI_ohos_rpc_getNativeRemoteObject(reinterpret_cast<napi_env>(nativeEngine),
232             reinterpret_cast<napi_value>(result));
233         if (remoteObj == nullptr) {
234             HILOG_ERROR("remoteObj nullptr.");
235         }
236         return remoteObj;
237     }
238 
239     bool callResult = false;
240     do {
241         auto *retObj = ConvertNativeValueTo<NativeObject>(result);
242         if (retObj == nullptr) {
243             HILOG_ERROR("CallPromise, Failed to convert native value to NativeObject.");
244             break;
245         }
246         NativeValue *then = retObj->GetProperty("then");
247         if (then == nullptr) {
248             HILOG_ERROR("CallPromise, Failed to get property: then.");
249             break;
250         }
251         if (!then->IsCallable()) {
252             HILOG_ERROR("CallPromise, property then is not callable.");
253             break;
254         }
255         auto promiseCallback = nativeEngine->CreateFunction("promiseCallback", strlen("promiseCallback"),
256             OnConnectPromiseCallback, callbackInfo);
257         NativeValue *argv[1] = { promiseCallback };
258         nativeEngine->CallFunction(result, then, argv, 1);
259         callResult = true;
260     } while (false);
261 
262     if (!callResult) {
263         HILOG_ERROR("Failed to call promise.");
264         isAsyncCallback = false;
265     } else {
266         isAsyncCallback = true;
267     }
268     return nullptr;
269 }
270 
OnDisconnect(const AAFwk::Want & want)271 void JsDriverExtension::OnDisconnect(const AAFwk::Want &want)
272 {
273     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
274     Extension::OnDisconnect(want);
275     HILOG_DEBUG("%{public}s begin.", __func__);
276     CallOnDisconnect(want, false);
277     HILOG_DEBUG("%{public}s end.", __func__);
278 }
279 
OnDisconnect(const AAFwk::Want & want,AppExecFwk::AbilityTransactionCallbackInfo<> * callbackInfo,bool & isAsyncCallback)280 void JsDriverExtension::OnDisconnect(const AAFwk::Want &want,
281     AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback)
282 {
283     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
284     Extension::OnDisconnect(want);
285     HILOG_DEBUG("%{public}s begin.", __func__);
286     NativeValue *result = CallOnDisconnect(want, true);
287     bool isPromise = CheckPromise(result);
288     if (!isPromise) {
289         isAsyncCallback = false;
290         return;
291     }
292     bool callResult = CallPromise(result, callbackInfo);
293     if (!callResult) {
294         HILOG_ERROR("Failed to call promise.");
295         isAsyncCallback = false;
296     } else {
297         isAsyncCallback = true;
298     }
299 
300     HILOG_DEBUG("%{public}s end.", __func__);
301 }
302 
CallObjectMethod(const char * name,NativeValue * const * argv,size_t argc)303 NativeValue* JsDriverExtension::CallObjectMethod(const char* name, NativeValue* const *argv, size_t argc)
304 {
305     HILOG_INFO("JsDriverExtension::CallObjectMethod(%{public}s), begin", name);
306 
307     if (!jsObj_) {
308         HILOG_WARN("Not found DriverExtension.js");
309         return nullptr;
310     }
311 
312     HandleScope handleScope(jsRuntime_);
313     auto& nativeEngine = jsRuntime_.GetNativeEngine();
314 
315     NativeValue* value = jsObj_->Get();
316     NativeObject* obj = ConvertNativeValueTo<NativeObject>(value);
317     if (obj == nullptr) {
318         HILOG_ERROR("Failed to get DriverExtension object");
319         return nullptr;
320     }
321 
322     NativeValue* method = obj->GetProperty(name);
323     if (method == nullptr || method->TypeOf() != NATIVE_FUNCTION) {
324         HILOG_ERROR("Failed to get '%{public}s' from DriverExtension object", name);
325         return nullptr;
326     }
327     HILOG_INFO("JsDriverExtension::CallFunction(%{public}s), success", name);
328     return nativeEngine.CallFunction(value, method, argv, argc);
329 }
330 
GetSrcPath(std::string & srcPath)331 void JsDriverExtension::GetSrcPath(std::string &srcPath)
332 {
333     if (!Extension::abilityInfo_->isModuleJson) {
334         /* temporary compatibility api8 + config.json */
335         srcPath.append(Extension::abilityInfo_->package);
336         srcPath.append("/assets/js/");
337         if (!Extension::abilityInfo_->srcPath.empty()) {
338             srcPath.append(Extension::abilityInfo_->srcPath);
339         }
340         srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
341         return;
342     }
343 
344     if (!Extension::abilityInfo_->srcEntrance.empty()) {
345         srcPath.append(Extension::abilityInfo_->moduleName + "/");
346         srcPath.append(Extension::abilityInfo_->srcEntrance);
347         srcPath.erase(srcPath.rfind('.'));
348         srcPath.append(".abc");
349     }
350 }
351 
CallOnConnect(const AAFwk::Want & want)352 NativeValue *JsDriverExtension::CallOnConnect(const AAFwk::Want &want)
353 {
354     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
355     Extension::OnConnect(want);
356     HILOG_DEBUG("%{public}s begin.", __func__);
357     NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
358     napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
359     auto* nativeWant = reinterpret_cast<NativeValue*>(napiWant);
360     NativeValue* argv[] = {nativeWant};
361     if (!jsObj_) {
362         HILOG_WARN("Not found DriverExtension.js");
363         return nullptr;
364     }
365 
366     NativeValue* value = jsObj_->Get();
367     auto* obj = ConvertNativeValueTo<NativeObject>(value);
368     if (obj == nullptr) {
369         HILOG_ERROR("Failed to get DriverExtension object");
370         return nullptr;
371     }
372 
373     NativeValue* method = obj->GetProperty("onConnect");
374     if (method == nullptr) {
375         HILOG_ERROR("Failed to get onConnect from DriverExtension object");
376         return nullptr;
377     }
378     HILOG_INFO("JsDriverExtension::CallFunction onConnect, success");
379     NativeValue* remoteNative = nativeEngine->CallFunction(value, method, argv, ARGC_ONE);
380     if (remoteNative == nullptr) {
381         HILOG_ERROR("remoteNative nullptr.");
382     }
383     HILOG_DEBUG("%{public}s end.", __func__);
384     return remoteNative;
385 }
386 
CallOnDisconnect(const AAFwk::Want & want,bool withResult)387 NativeValue *JsDriverExtension::CallOnDisconnect(const AAFwk::Want &want, bool withResult)
388 {
389     HandleEscape handleEscape(jsRuntime_);
390     NativeEngine *nativeEngine = &jsRuntime_.GetNativeEngine();
391     napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
392     NativeValue *nativeWant = reinterpret_cast<NativeValue *>(napiWant);
393     NativeValue *argv[] = { nativeWant };
394     if (!jsObj_) {
395         HILOG_WARN("Not found DriverExtension.js");
396         return nullptr;
397     }
398 
399     NativeValue *value = jsObj_->Get();
400     NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
401     if (obj == nullptr) {
402         HILOG_ERROR("Failed to get DriverExtension object");
403         return nullptr;
404     }
405 
406     NativeValue *method = obj->GetProperty("onDisconnect");
407     if (method == nullptr) {
408         HILOG_ERROR("Failed to get onDisconnect from DriverExtension object");
409         return nullptr;
410     }
411 
412     if (withResult) {
413         return handleEscape.Escape(nativeEngine->CallFunction(value, method, argv, ARGC_ONE));
414     } else {
415         nativeEngine->CallFunction(value, method, argv, ARGC_ONE);
416         return nullptr;
417     }
418 }
419 
CheckPromise(NativeValue * result)420 bool JsDriverExtension::CheckPromise(NativeValue *result)
421 {
422     if (result == nullptr) {
423         HILOG_DEBUG("CheckPromise, result is null, no need to call promise.");
424         return false;
425     }
426     if (!result->IsPromise()) {
427         HILOG_DEBUG("CheckPromise, result is not promise, no need to call promise.");
428         return false;
429     }
430     return true;
431 }
432 
CallPromise(NativeValue * result,AppExecFwk::AbilityTransactionCallbackInfo<> * callbackInfo)433 bool JsDriverExtension::CallPromise(NativeValue *result, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo)
434 {
435     auto *retObj = ConvertNativeValueTo<NativeObject>(result);
436     if (retObj == nullptr) {
437         HILOG_ERROR("CallPromise, Failed to convert native value to NativeObject.");
438         return false;
439     }
440     NativeValue *then = retObj->GetProperty("then");
441     if (then == nullptr) {
442         HILOG_ERROR("CallPromise, Failed to get property: then.");
443         return false;
444     }
445     if (!then->IsCallable()) {
446         HILOG_ERROR("CallPromise, property then is not callable.");
447         return false;
448     }
449     HandleScope handleScope(jsRuntime_);
450     auto &nativeEngine = jsRuntime_.GetNativeEngine();
451     auto promiseCallback = nativeEngine.CreateFunction("promiseCallback", strlen("promiseCallback"), PromiseCallback,
452         callbackInfo);
453     NativeValue *argv[1] = { promiseCallback };
454     nativeEngine.CallFunction(result, then, argv, 1);
455     return true;
456 }
457 
Dump(const std::vector<std::string> & params,std::vector<std::string> & info)458 void JsDriverExtension::Dump(const std::vector<std::string> &params, std::vector<std::string> &info)
459 {
460     Extension::Dump(params, info);
461     HILOG_INFO("%{public}s called.", __func__);
462     HandleScope handleScope(jsRuntime_);
463     auto& nativeEngine = jsRuntime_.GetNativeEngine();
464     // create js array object of params
465     NativeValue* arrayValue = nativeEngine.CreateArray(params.size());
466     NativeArray* array = ConvertNativeValueTo<NativeArray>(arrayValue);
467     uint32_t index = 0;
468     for (const auto &param : params) {
469         array->SetElement(index++, CreateJsValue(nativeEngine, param));
470     }
471 
472     NativeValue* argv[] = { arrayValue };
473     NativeValue* dumpInfo = CallObjectMethod("onDump", argv, ARGC_ONE);
474     if (dumpInfo == nullptr) {
475         HILOG_ERROR("dumpInfo nullptr.");
476         return;
477     }
478     NativeArray* dumpInfoNative = ConvertNativeValueTo<NativeArray>(dumpInfo);
479     if (dumpInfoNative == nullptr) {
480         HILOG_ERROR("dumpInfoNative nullptr.");
481         return;
482     }
483     for (uint32_t i = 0; i < dumpInfoNative->GetLength(); i++) {
484         std::string dumpInfoStr;
485         if (!ConvertFromJsValue(nativeEngine, dumpInfoNative->GetElement(i), dumpInfoStr)) {
486             HILOG_ERROR("Parse dumpInfoStr failed");
487             return;
488         }
489         info.push_back(dumpInfoStr);
490     }
491     HILOG_DEBUG("Dump info size: %{public}zu", info.size());
492 }
493 }
494 }
495