• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_fence_extension.h"
17 #include "js_fence_extension_context.h"
18 #include "fence_extension_stub_impl.h"
19 
20 #include "ability_handler.h"
21 #include "ability_info.h"
22 #include "hilog_wrapper.h"
23 #include "js_extension_common.h"
24 #include "js_extension_context.h"
25 #include "runtime.h"
26 #include "js_runtime.h"
27 #include "js_runtime_utils.h"
28 #include "display_manager.h"
29 #include "napi/native_api.h"
30 #include "napi/native_node_api.h"
31 #include "napi_common_configuration.h"
32 #include "napi_common_want.h"
33 #include "napi_remote_object.h"
34 #include "location_log.h"
35 #include "geofence_definition.h"
36 #include <thread>
37 #include "napi/native_api.h"
38 #include "uv.h"
39 
40 using namespace OHOS::AbilityRuntime;
41 namespace OHOS {
42 namespace Location {
43 const size_t ARGC_ONE = 1;
44 const size_t ARGC_TWO = 2;
45 const size_t LOAD_SYSTEM_MODULE_ARGC = 1;
46 const std::string CONTEXT_MODULE_PATH = "app.ability.FenceExtensionContext";
47 using namespace OHOS::AppExecFwk;
48 
AttachFenceExtensionContext(napi_env env,void * value,void *)49 napi_value AttachFenceExtensionContext(napi_env env, void *value, void *)
50 {
51     LBSLOGI(FENCE_EXTENSION, "AttachFenceExtensionContext");
52     if (value == nullptr) {
53         LBSLOGE(FENCE_EXTENSION, "invalid parameter");
54         return nullptr;
55     }
56 
57     auto ptr = reinterpret_cast<std::weak_ptr<FenceExtensionContext> *>(value)->lock();
58     if (ptr == nullptr) {
59         LBSLOGE(FENCE_EXTENSION, "invalid context");
60         return nullptr;
61     }
62 
63     napi_value object = JsFenceExtensionContext::CreateJsFenceExtensionContext(env, ptr);
64     auto napiContextObj =
65         AbilityRuntime::JsRuntime::LoadSystemModuleByEngine(env, CONTEXT_MODULE_PATH, &object, LOAD_SYSTEM_MODULE_ARGC)
66             ->GetNapiValue();
67 
68     napi_coerce_to_native_binding_object(
69         env, napiContextObj, AbilityRuntime::DetachCallbackFunc, AttachFenceExtensionContext, value, nullptr);
70     auto workContext = new (std::nothrow) std::weak_ptr<FenceExtensionContext>(ptr);
71     if (workContext == nullptr) {
72         LBSLOGE(FENCE_EXTENSION, "invalid extension context");
73         return nullptr;
74     }
75     auto retStatus = ::napi_wrap(
76         env,
77         napiContextObj,
78         workContext,
79         [](napi_env, void *data, void *) {
80             LBSLOGI(FENCE_EXTENSION, "Finalizer for weak_ptr extension context is called");
81             delete static_cast<std::weak_ptr<FenceExtensionContext> *>(data);
82         },
83         nullptr,
84         nullptr);
85     if (retStatus != ::napi_status::napi_ok) {
86         LBSLOGE(FENCE_EXTENSION, "Napi wrap context error");
87         return nullptr;
88     }
89     LBSLOGI(FENCE_EXTENSION, "AttachFenceExtensionContext end");
90     return napiContextObj;
91 }
92 
Create(const std::unique_ptr<AbilityRuntime::Runtime> & runtime)93 JsFenceExtension *JsFenceExtension::Create(const std::unique_ptr<AbilityRuntime::Runtime> &runtime)
94 {
95     return new (std::nothrow) JsFenceExtension(static_cast<AbilityRuntime::JsRuntime &>(*runtime));
96 }
97 
JsFenceExtension(AbilityRuntime::JsRuntime & jsRuntime)98 JsFenceExtension::JsFenceExtension(AbilityRuntime::JsRuntime &jsRuntime) : jsRuntime_(jsRuntime)
99 {}
100 
~JsFenceExtension()101 JsFenceExtension::~JsFenceExtension()
102 {
103     LBSLOGD(FENCE_EXTENSION, "Js extension destructor");
104     auto context = GetContext();
105     if (context) {
106         context->Unbind();
107     }
108     jsRuntime_.FreeNativeReference(std::move(jsObj_));
109     jsRuntime_.FreeNativeReference(std::move(shellContextRef_));
110 }
111 
Init(const std::shared_ptr<AppExecFwk::AbilityLocalRecord> & record,const std::shared_ptr<AppExecFwk::OHOSApplication> & application,std::shared_ptr<AppExecFwk::AbilityHandler> & handler,const sptr<IRemoteObject> & token)112 void JsFenceExtension::Init(const std::shared_ptr<AppExecFwk::AbilityLocalRecord> &record,
113     const std::shared_ptr<AppExecFwk::OHOSApplication> &application,
114     std::shared_ptr<AppExecFwk::AbilityHandler> &handler, const sptr<IRemoteObject> &token)
115 {
116     FenceExtension::Init(record, application, handler, token);
117     if (Extension::abilityInfo_->srcEntrance.empty()) {
118         LBSLOGE(FENCE_EXTENSION, "srcEntrance of abilityInfo is empty");
119         return;
120     }
121     std::string srcPath = "";
122     GetSrcPath(srcPath);
123     if (srcPath.empty()) {
124         LBSLOGE(FENCE_EXTENSION, "Failed to get srcPath");
125         return;
126     }
127 
128     std::string moduleName(Extension::abilityInfo_->moduleName);
129     moduleName.append("::").append(abilityInfo_->name);
130     LBSLOGW(FENCE_EXTENSION,
131         "JsFenceExtension::Init module:%{public}s,srcPath:%{public}s",
132         moduleName.c_str(),
133         srcPath.c_str());
134     AbilityRuntime::HandleScope handleScope(jsRuntime_);
135 
136     jsObj_ = jsRuntime_.LoadModule(moduleName,
137         srcPath,
138         abilityInfo_->hapPath,
139         abilityInfo_->compileMode == CompileMode::ES_MODULE,
140         false,
141         abilityInfo_->srcEntrance);
142     if (jsObj_ == nullptr) {
143         LBSLOGE(FENCE_EXTENSION, "Failed to load ability module");
144         return;
145     }
146     napi_value obj = jsObj_->GetNapiValue();
147     if (obj == nullptr) {
148         LBSLOGE(FENCE_EXTENSION, "Failed to get extension object");
149         return;
150     }
151     napi_env env = jsRuntime_.GetNapiEnv();
152 
153     LBSLOGI(FENCE_EXTENSION, "Init end");
154     BindContext(env, obj);
155 }
156 
BindContext(const::napi_env & env,const::napi_value & obj)157 void JsFenceExtension::BindContext(const ::napi_env &env, const ::napi_value &obj)
158 {
159     LBSLOGI(FENCE_EXTENSION, "BindContext start");
160     auto context = GetContext();
161     if (context == nullptr) {
162         LBSLOGE(FENCE_EXTENSION, "Failed to get context");
163         return;
164     }
165     napi_value contextObj = JsFenceExtensionContext::CreateJsFenceExtensionContext(env, context);
166     auto shellContextRef_ =
167         AbilityRuntime::JsRuntime::LoadSystemModuleByEngine(env, CONTEXT_MODULE_PATH, &contextObj, ARGC_ONE);
168     if (shellContextRef_ == nullptr) {
169         LBSLOGE(FENCE_EXTENSION, "Failed to get shell context from system module");
170         return;
171     }
172     napi_value nativeObj = shellContextRef_->GetNapiValue();
173     if (nativeObj == nullptr) {
174         LBSLOGE(FENCE_EXTENSION, "Failed to load context module");
175         return;
176     }
177 
178     auto workContext = new (std::nothrow) std::weak_ptr<FenceExtensionContext>(context);
179     if (workContext == nullptr) {
180         LBSLOGE(FENCE_EXTENSION, "invalid extension context");
181         return;
182     }
183     napi_coerce_to_native_binding_object(
184         env, nativeObj, AbilityRuntime::DetachCallbackFunc, AttachFenceExtensionContext, workContext, nullptr);
185     context->Bind(jsRuntime_, shellContextRef_.release());
186     napi_set_named_property(env, obj, "context", nativeObj);
187 
188     napi_wrap(
189         env,
190         nativeObj,
191         workContext,
192         [](napi_env, void *data, void *) {
193             LBSLOGI(FENCE_EXTENSION, "Finalizer for weak_ptr extension context is called");
194             delete static_cast<std::weak_ptr<FenceExtensionContext> *>(data);
195         },
196         nullptr,
197         nullptr);
198     LBSLOGI(FENCE_EXTENSION, "BindContext end");
199 }
OnStart(const AAFwk::Want & want)200 void JsFenceExtension::OnStart(const AAFwk::Want &want)
201 {
202     AbilityRuntime::Extension::OnStart(want);
203 }
204 
OnStop()205 void JsFenceExtension::OnStop()
206 {
207     LBSLOGI(FENCE_EXTENSION, "OnStop called");
208     AbilityRuntime::HandleScope handleScope(jsRuntime_);
209     if (jsObj_ == nullptr) {
210         LBSLOGE(FENCE_EXTENSION, "js fence extension obj is null");
211         return;
212     }
213     ::napi_value method = GetMethod(jsRuntime_, jsObj_, "onDestroy");
214     if (method == nullptr) {
215         LBSLOGE(FENCE_EXTENSION, "Call function method is null");
216         return;
217     }
218     napi_value argv[0];
219     ::napi_value undefined;
220     ::napi_env env = jsRuntime_.GetNapiEnv();
221     ::napi_value value = jsObj_->GetNapiValue();
222     ::napi_status retStatus = ::napi_call_function(env, value, method, 0, argv, &undefined);
223     if (retStatus != ::napi_status::napi_ok) {
224         LBSLOGE(FENCE_EXTENSION, "Call function error");
225     }
226     LBSLOGI(FENCE_EXTENSION, "Call onDestroy end");
227     AbilityRuntime::Extension::OnStop();
228 }
229 
OnConnect(const AAFwk::Want & want)230 sptr<IRemoteObject> JsFenceExtension::OnConnect(const AAFwk::Want &want)
231 {
232     LBSLOGI(FENCE_EXTENSION, "OnConnect");
233     AbilityRuntime::Extension::OnConnect(want);
234     sptr<FenceExtensionStubImpl> remoteObject =
235         new (std::nothrow) FenceExtensionStubImpl(std::static_pointer_cast<JsFenceExtension>(shared_from_this()));
236     if (remoteObject == nullptr) {
237         LBSLOGE(FENCE_EXTENSION, "failed to create FenceExtensionStubImpl");
238         return nullptr;
239     }
240     return remoteObject->AsObject();
241 }
242 
OnDisconnect(const AAFwk::Want & want)243 void JsFenceExtension::OnDisconnect(const AAFwk::Want &want)
244 {
245     LBSLOGI(FENCE_EXTENSION, "OnDisconnect");
246     Extension::OnDisconnect(want);
247 }
248 
OnFenceStatusChange(std::map<std::string,std::string> extraData)249 FenceExtensionErrCode JsFenceExtension::OnFenceStatusChange(std::map<std::string, std::string> extraData)
250 {
251     LBSLOGI(FENCE_EXTENSION, "js fence extension:OnFenceStatusChange");
252     if (jsObj_ == nullptr) {
253         LBSLOGE(FENCE_EXTENSION, "js fence extension obj is null");
254         return FenceExtensionErrCode::EXTENSION_JS_OBJ_IS_NULL;
255     }
256 
257     auto task = [=]() {
258         LBSLOGI(FENCE_EXTENSION, "call js function start");
259         JsFenceExtension::CallToUiThread(extraData);
260     };
261     if (handler_ == nullptr) {
262         LBSLOGE(FENCE_EXTENSION, "PostTask call js function start");
263         return FenceExtensionErrCode::EXTENSION_JS_CALL_FAILED;
264     }
265     handler_->PostTask(task, "FenceExtension OnFenceStatusChange Task");
266     LBSLOGI(FENCE_EXTENSION, "PostTask call js function start");
267     return FenceExtensionErrCode::EXTENSION_SUCCESS;
268 }
269 
GetSrcPath(std::string & srcPath)270 void JsFenceExtension::GetSrcPath(std::string &srcPath)
271 {
272     if (!Extension::abilityInfo_->srcEntrance.empty()) {
273         srcPath.append(Extension::abilityInfo_->moduleName);
274         srcPath.append("/");
275         srcPath.append(Extension::abilityInfo_->srcEntrance);
276         srcPath.erase(srcPath.rfind('.'));
277         srcPath.append(".abc");
278     }
279 }
280 
CallToUiThread(std::map<std::string,std::string> extraData)281 FenceExtensionErrCode JsFenceExtension::CallToUiThread(std::map<std::string, std::string> extraData)
282 {
283     LBSLOGI(FENCE_EXTENSION, "js fence extension:OnFenceStatusChange");
284     if (jsObj_ == nullptr) {
285         return FenceExtensionErrCode::EXTENSION_JS_OBJ_IS_NULL;
286     }
287     AbilityRuntime::HandleScope handleScope(jsRuntime_);
288     ::napi_value method = GetMethod(jsRuntime_, jsObj_, "onFenceStatusChange");
289     if (method == nullptr) {
290         return FenceExtensionErrCode::EXTENSION_JS_NOT_FOUND_METHOD;
291     }
292     auto fenceId = std::atoi(GetAndDeleteFromMap(extraData, EXTENSION_PARAM_KEY_FENCE_ID).c_str());
293     auto fenceEvent = std::atoi(GetAndDeleteFromMap(extraData, EXTENSION_PARAM_KEY_FENCE_EVENT).c_str());
294     ::napi_value transitionObj;
295     ::napi_env env = jsRuntime_.GetNapiEnv();
296     napi_status retTransition = ::napi_create_object(env, &transitionObj);
297     if (retTransition != napi_ok) {
298         return FenceExtensionErrCode::EXTENSION_JS_CREATE_PARAM_ERROR;
299     }
300     SetValueInt32(env, "geofenceId", fenceId, transitionObj);
301     SetValueInt32(env, "transitionEvent", static_cast<int>(fenceEvent), transitionObj);
302     ::napi_value addtionsRecord;
303     if (extraData.size() > 0) {
304         ::napi_status status = napi_create_object(env, &addtionsRecord);
305         for (const auto &pair : extraData) {
306             napi_value key, value;
307             status = napi_create_string_utf8(env, pair.first.c_str(), NAPI_AUTO_LENGTH, &key);
308             if (status != napi_ok) {
309                 break;
310             }
311             status = napi_create_string_utf8(env, pair.second.c_str(), NAPI_AUTO_LENGTH, &value);
312             if (status != napi_ok) {
313                 break;
314             }
315             status = napi_set_property(env, addtionsRecord, key, value);
316             if (status != napi_ok) {
317                 break;
318             }
319         }
320     } else {
321         ::napi_status status = napi_get_undefined(env, &addtionsRecord);
322     }
323     ::napi_value argv[PARAM2];
324     argv[PARAM0] = transitionObj;
325     argv[PARAM1] = addtionsRecord;
326     ::napi_value abilityObj = jsObj_->GetNapiValue();
327     ::napi_value undefined;
328     ::napi_status callStatus = ::napi_call_function(env, abilityObj, method, ARGC_TWO, argv, &undefined);
329     return FenceExtensionErrCode::EXTENSION_SUCCESS;
330 }
331 
SetValueUtf8String(const napi_env & env,const char * fieldStr,const char * str,napi_value & result)332 napi_status JsFenceExtension::SetValueUtf8String(
333     const napi_env &env, const char *fieldStr, const char *str, napi_value &result)
334 {
335     napi_value value = nullptr;
336     NAPI_CALL_BASE(env, napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value), napi_generic_failure);
337     NAPI_CALL_BASE(env, napi_set_named_property(env, result, fieldStr, value), napi_generic_failure);
338     return napi_ok;
339 }
SetValueInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)340 napi_status JsFenceExtension::SetValueInt32(
341     const napi_env &env, const char *fieldStr, const int intValue, napi_value &result)
342 {
343     napi_value value = nullptr;
344     NAPI_CALL_BASE(env, napi_create_int32(env, intValue, &value), napi_generic_failure);
345     NAPI_CALL_BASE(env, napi_set_named_property(env, result, fieldStr, value), napi_generic_failure);
346     return napi_ok;
347 }
GetAndDeleteFromMap(std::map<std::string,std::string> & param,std::string key)348 std::string JsFenceExtension::GetAndDeleteFromMap(std::map<std::string, std::string> &param, std::string key)
349 {
350     auto mapItr = param.find(key);
351     std::string value;
352     if (mapItr != param.end()) {
353         value = mapItr->second;
354         param.erase(key);
355     }
356     return value;
357 }
358 
GetMethod(AbilityRuntime::JsRuntime & jsRuntime,const std::unique_ptr<NativeReference> & jsObj,const std::string & name)359 ::napi_value JsFenceExtension::GetMethod(
360     AbilityRuntime::JsRuntime &jsRuntime, const std::unique_ptr<NativeReference> &jsObj, const std::string &name)
361 {
362     if (!jsObj) {
363         LBSLOGE(FENCE_EXTENSION, "Not found Extension.js");
364         return nullptr;
365     }
366 
367     ::napi_value obj = jsObj->GetNapiValue();
368     if (obj == nullptr) {
369         LBSLOGE(FENCE_EXTENSION, "Failed to get Extension object");
370         return nullptr;
371     }
372 
373     ::napi_env env = jsRuntime.GetNapiEnv();
374     ::napi_value method;
375     ::napi_status ret = ::napi_get_named_property(env, obj, name.c_str(), &method);
376     if (ret != ::napi_status::napi_ok) {
377         LBSLOGE(FENCE_EXTENSION, "napi get name fail(%{public}d)", ret);
378         return nullptr;
379     }
380     ::napi_valuetype type = ::napi_valuetype::napi_undefined;
381     ::napi_valuetype functionType = ::napi_valuetype::napi_function;
382     ::napi_status retType = ::napi_typeof(env, method, &functionType);
383     if (retType != ::napi_status::napi_ok) {
384         LBSLOGE(FENCE_EXTENSION, "Parse napi object type fail(%{public}d)", retType);
385         return nullptr;
386     }
387     return method;
388 }
389 }  // namespace Location
390 }  // namespace OHOS