1 /*
2  * Copyright (c) 2021 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 "ability_info.h"
17 #include "hilog_wrapper.h"
18 #include "hitrace_meter.h"
19 #include "js_runtime.h"
20 #include "js_runtime_utils.h"
21 #include "js_wallpaper_extension_ability.h"
22 #include "js_wallpaper_extension_context.h"
23 #include "napi/native_api.h"
24 #include "napi/native_node_api.h"
25 #include "napi_common_util.h"
26 #include "napi_common_want.h"
27 #include "napi_remote_object.h"
28 #include "uv_queue.h"
29 #include "wallpaper_extension_ability_stub.h"
30 #include "wallpaper_manager.h"
31 
32 namespace OHOS {
33 namespace AbilityRuntime {
34 namespace {
35 constexpr size_t ARGC_ONE = 1;
36 } // namespace
37 
38 JsWallpaperExtensionAbility *JsWallpaperExtensionAbility::jsWallpaperExtensionAbility = NULL;
39 std::mutex JsWallpaperExtensionAbility::mtx;
40 using namespace OHOS::AppExecFwk;
41 using namespace OHOS::MiscServices;
Create(const std::unique_ptr<Runtime> & runtime)42 JsWallpaperExtensionAbility *JsWallpaperExtensionAbility::Create(const std::unique_ptr<Runtime> &runtime)
43 {
44     HILOG_INFO("jws JsWallpaperExtensionAbility begin Create.");
45     std::lock_guard<std::mutex> lock(mtx);
46     jsWallpaperExtensionAbility = new JsWallpaperExtensionAbility(static_cast<JsRuntime &>(*runtime));
47     return jsWallpaperExtensionAbility;
48 }
49 
JsWallpaperExtensionAbility(JsRuntime & jsRuntime)50 JsWallpaperExtensionAbility::JsWallpaperExtensionAbility(JsRuntime &jsRuntime) : jsRuntime_(jsRuntime)
51 {
52 }
~JsWallpaperExtensionAbility()53 JsWallpaperExtensionAbility::~JsWallpaperExtensionAbility()
54 {
55     jsRuntime_.FreeNativeReference(std::move(jsObj_));
56     std::lock_guard<std::mutex> lock(mtx);
57     jsWallpaperExtensionAbility = nullptr;
58 }
59 
Init(const std::shared_ptr<AbilityLocalRecord> & record,const std::shared_ptr<OHOSApplication> & application,std::shared_ptr<AbilityHandler> & handler,const sptr<IRemoteObject> & token)60 void JsWallpaperExtensionAbility::Init(const std::shared_ptr<AbilityLocalRecord> &record,
61     const std::shared_ptr<OHOSApplication> &application, std::shared_ptr<AbilityHandler> &handler,
62     const sptr<IRemoteObject> &token)
63 {
64     HILOG_INFO("jws JsWallpaperExtensionAbility begin Init.");
65     WallpaperExtensionAbility::Init(record, application, handler, token);
66     std::string srcPath = "";
67     GetSrcPath(srcPath);
68     if (srcPath.empty()) {
69         HILOG_ERROR("Failed to get srcPath!");
70         return;
71     }
72     return InitMoudle(srcPath);
73 }
74 
InitMoudle(std::string srcPath)75 void JsWallpaperExtensionAbility::InitMoudle(std::string srcPath)
76 {
77     std::string moduleName(Extension::abilityInfo_->moduleName);
78     moduleName.append("::").append(abilityInfo_->name);
79     HandleScope handleScope(jsRuntime_);
80     napi_env env = jsRuntime_.GetNapiEnv();
81     jsObj_ = jsRuntime_.LoadModule(
82         moduleName, srcPath, abilityInfo_->hapPath, Extension::abilityInfo_->compileMode == CompileMode::ES_MODULE);
83     if (jsObj_ == nullptr) {
84         HILOG_ERROR("Failed to get jsObj_ !");
85         return;
86     }
87     napi_value obj = jsObj_->GetNapiValue();
88     if (obj == nullptr) {
89         HILOG_ERROR("Failed to get JsWallpaperExtensionAbility object!");
90         return;
91     }
92     auto context = GetContext();
93     if (context == nullptr) {
94         HILOG_ERROR("Failed to get context!");
95         return;
96     }
97     napi_value contextObj = CreateJsWallpaperExtensionContext(env, context);
98     auto shellContextRef = jsRuntime_.LoadSystemModule("WallpaperExtensionContext", &contextObj, ARGC_ONE);
99     if (shellContextRef == nullptr) {
100         HILOG_ERROR("Failed to load system module!");
101         return;
102     }
103     contextObj = shellContextRef->GetNapiValue();
104     context->Bind(jsRuntime_, shellContextRef.release());
105     napi_set_named_property(env, obj, "context", contextObj);
106     if (contextObj == nullptr) {
107         HILOG_ERROR("Failed to get wallpaper extension native object!");
108         return;
109     }
110     auto workContext = new (std::nothrow) WallpaperExtensionContext();
111     if (workContext == nullptr) {
112         HILOG_ERROR("Failed to new workContext!");
113         return;
114     }
115     auto ret = napi_wrap(
116         env, contextObj, workContext,
117         [](napi_env, void *data, void *) { delete static_cast<AbilityRuntime::Context *>(data); }, nullptr, nullptr);
118     if (ret != napi_ok) {
119         delete workContext;
120     }
121 }
122 
OnStart(const AAFwk::Want & want)123 void JsWallpaperExtensionAbility::OnStart(const AAFwk::Want &want)
124 {
125     StartAsyncTrace(HITRACE_TAG_MISC, "OnStart", static_cast<int32_t>(TraceTaskId::ONSTART_EXTENSION));
126     StartAsyncTrace(
127         HITRACE_TAG_MISC, "Extension::OnStart", static_cast<int32_t>(TraceTaskId::ONSTART_MIDDLE_EXTENSION));
128     Extension::OnStart(want);
129     FinishAsyncTrace(
130         HITRACE_TAG_MISC, "Extension::OnStart", static_cast<int32_t>(TraceTaskId::ONSTART_MIDDLE_EXTENSION));
131     HILOG_INFO("jws JsWallpaperExtensionAbility OnStart begin.");
132     HandleScope handleScope(jsRuntime_);
133     napi_env env = jsRuntime_.GetNapiEnv();
134     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
135     napi_value argv[] = { napiWant };
136     StartAsyncTrace(HITRACE_TAG_MISC, "onCreate", static_cast<int32_t>(TraceTaskId::ONCREATE_EXTENSION));
137     CallObjectMethod("onCreate", argv, ARGC_ONE);
138     FinishAsyncTrace(HITRACE_TAG_MISC, "onCreate", static_cast<int32_t>(TraceTaskId::ONCREATE_EXTENSION));
139     CallObjectMethod("createWallpaperWin");
140     RegisterWallpaperCallback();
141     HILOG_INFO("%{public}s end.", __func__);
142     FinishAsyncTrace(HITRACE_TAG_MISC, "onCreate", static_cast<int32_t>(TraceTaskId::ONSTART_EXTENSION));
143 }
144 
OnStop()145 void JsWallpaperExtensionAbility::OnStop()
146 {
147     WallpaperExtensionAbility::OnStop();
148     HILOG_INFO("jws JsWallpaperExtensionAbility OnStop begin.");
149     CallObjectMethod("onDestroy");
150     bool ret = ConnectionManager::GetInstance().DisconnectCaller(GetContext()->GetToken());
151     if (ret) {
152         HILOG_INFO("The wallpaper extension connection is not disconnected.");
153     }
154 }
155 
OnConnect(const AAFwk::Want & want)156 sptr<IRemoteObject> JsWallpaperExtensionAbility::OnConnect(const AAFwk::Want &want)
157 {
158     HILOG_INFO("jws JsWallpaperExtensionAbility OnConnect begin.");
159     Extension::OnConnect(want);
160     auto remoteObj = new (std::nothrow) WallpaperMgrService::WallpaperExtensionAbilityStub();
161     if (remoteObj == nullptr) {
162         HILOG_ERROR("failed to create IWallpaperExtensionAbility");
163         return nullptr;
164     }
165     return remoteObj;
166 }
167 
OnDisconnect(const AAFwk::Want & want)168 void JsWallpaperExtensionAbility::OnDisconnect(const AAFwk::Want &want)
169 {
170     HILOG_INFO("jws JsWallpaperExtensionAbility OnDisconnect begin.");
171     Extension::OnDisconnect(want);
172 }
173 
OnCommand(const AAFwk::Want & want,bool restart,int32_t startId)174 void JsWallpaperExtensionAbility::OnCommand(const AAFwk::Want &want, bool restart, int32_t startId)
175 {
176     HILOG_INFO("jws JsWallpaperExtensionAbility OnCommand begin.");
177     Extension::OnCommand(want, restart, startId);
178     HILOG_INFO(
179         "%{public}s begin restart=%{public}s,startId=%{public}d.", __func__, restart ? "true" : "false", startId);
180 }
181 
CallObjectMethod(const std::string & name,napi_value const * argv,size_t argc)182 napi_value JsWallpaperExtensionAbility::CallObjectMethod(const std::string &name, napi_value const *argv, size_t argc)
183 {
184     HILOG_INFO("jws JsWallpaperExtensionAbility::CallObjectMethod(%{public}s), begin", name.c_str());
185 
186     if (!jsObj_) {
187         HILOG_WARN("Not found WallpaperExtensionAbility.js .");
188         return nullptr;
189     }
190 
191     HandleScope handleScope(jsRuntime_);
192     napi_env env = jsRuntime_.GetNapiEnv();
193     napi_value obj = jsObj_->GetNapiValue();
194     if (obj == nullptr) {
195         HILOG_ERROR("Failed to get WallpaperExtensionAbility object!");
196         return nullptr;
197     }
198 
199     napi_value method = nullptr;
200     napi_get_named_property(env, obj, name.c_str(), &method);
201     if (method == nullptr) {
202         HILOG_ERROR("Failed to get '%{public}s' from WallpaperExtensionAbility object", name.c_str());
203         return nullptr;
204     }
205 
206     HILOG_INFO("JsWallpaperExtensionAbility::CallFunction(%{public}s) success.", name.c_str());
207     napi_value remoteNapi = nullptr;
208     napi_status status = napi_call_function(env, obj, method, argc, argv, &remoteNapi);
209     if (status != napi_ok) {
210         HILOG_ERROR("JsWallpaperExtensionAbility::CallFunction(%{public}s) failed!", name.c_str());
211         return nullptr;
212     }
213     return remoteNapi;
214 }
215 
GetSrcPath(std::string & srcPath)216 void JsWallpaperExtensionAbility::GetSrcPath(std::string &srcPath)
217 {
218     HILOG_INFO("jws JsWallpaperExtensionAbility GetSrcPath begin.");
219     if (!Extension::abilityInfo_->isModuleJson) {
220         /* temporary compatibility api8 + config.json */
221         srcPath.append(Extension::abilityInfo_->package);
222         srcPath.append("/assets/js/");
223         if (!Extension::abilityInfo_->srcPath.empty()) {
224             srcPath.append(Extension::abilityInfo_->srcPath);
225         }
226         srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
227         return;
228     }
229 
230     if (!Extension::abilityInfo_->srcEntrance.empty()) {
231         srcPath.append(Extension::abilityInfo_->moduleName + "/");
232         srcPath.append(Extension::abilityInfo_->srcEntrance);
233         srcPath.erase(srcPath.rfind('.'));
234         srcPath.append(".abc");
235     }
236 }
237 
RegisterWallpaperCallback()238 void JsWallpaperExtensionAbility::RegisterWallpaperCallback()
239 {
240     WallpaperMgrService::WallpaperManager::GetInstance().RegisterWallpaperCallback([](int32_t wallpaperType) -> bool {
241         HILOG_INFO("jsWallpaperExtensionAbility->CallObjectMethod.");
242         std::lock_guard<std::mutex> lock(mtx);
243         if (JsWallpaperExtensionAbility::jsWallpaperExtensionAbility == nullptr) {
244             return false;
245         }
246         napi_env napiEnv = (JsWallpaperExtensionAbility::jsWallpaperExtensionAbility->jsRuntime_).GetNapiEnv();
247         WorkData *workData = new (std::nothrow) WorkData(napiEnv, nullptr, wallpaperType);
248         if (workData == nullptr) {
249             return false;
250         }
251         uv_after_work_cb afterCallback = [](uv_work_t *work, int32_t status) {
252             WorkData *workData = reinterpret_cast<WorkData *>(work->data);
253             if (workData == nullptr) {
254                 delete work;
255                 return;
256             }
257             napi_handle_scope scope = nullptr;
258             napi_open_handle_scope(workData->env_, &scope);
259             if (scope == nullptr) {
260                 delete workData;
261                 delete work;
262                 return;
263             }
264             napi_value type = OHOS::AppExecFwk::WrapInt32ToJS(workData->env_, workData->wallpaperType);
265 
266             napi_value arg[] = { type };
267             std::lock_guard<std::mutex> lock(mtx);
268             if (JsWallpaperExtensionAbility::jsWallpaperExtensionAbility != nullptr) {
269                 JsWallpaperExtensionAbility::jsWallpaperExtensionAbility->CallObjectMethod(
270                     "onWallpaperChange", arg, ARGC_ONE);
271             }
272             napi_close_handle_scope(workData->env_, scope);
273             delete workData;
274             delete work;
275         };
276         UvQueue::Call(napiEnv, workData, afterCallback);
277         return true;
278     });
279 }
280 
281 } // namespace AbilityRuntime
282 } // namespace OHOS
283