1 /*
2 * Copyright (c) 2022 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_work_scheduler_extension.h"
17
18 #include <string>
19
20 #include "runtime.h"
21 #include "js_runtime.h"
22 #include "js_runtime_utils.h"
23 #include "work_scheduler_extension.h"
24 #include "js_work_scheduler_extension_context.h"
25 #include "work_scheduler_stub_imp.h"
26
27 namespace OHOS {
28 namespace WorkScheduler {
29 const int32_t INVALID_VALUE = -1;
30
Create(const std::unique_ptr<AbilityRuntime::Runtime> & runtime)31 JsWorkSchedulerExtension* JsWorkSchedulerExtension::Create(const std::unique_ptr<AbilityRuntime::Runtime>& runtime)
32 {
33 return new JsWorkSchedulerExtension(static_cast<AbilityRuntime::JsRuntime&>(*runtime));
34 }
35
JsWorkSchedulerExtension(AbilityRuntime::JsRuntime & jsRuntime)36 JsWorkSchedulerExtension::JsWorkSchedulerExtension(AbilityRuntime::JsRuntime& jsRuntime) : jsRuntime_(jsRuntime) {}
~JsWorkSchedulerExtension()37 JsWorkSchedulerExtension::~JsWorkSchedulerExtension()
38 {
39 WS_HILOGD("Js WorkScheduler extension destructor.");
40 auto context = GetContext();
41 if (context) {
42 context->Unbind();
43 }
44
45 jsRuntime_.FreeNativeReference(std::move(jsObj_));
46 jsRuntime_.FreeNativeReference(std::move(shellContextRef_));
47 }
48
AttachWorkSchedulerExtensionContext(NativeEngine * engine,void * value,void *)49 NativeValue *AttachWorkSchedulerExtensionContext(NativeEngine *engine, void *value, void *)
50 {
51 WS_HILOGI("AttachWorkSchedulerExtensionContext");
52 if (value == nullptr) {
53 WS_HILOGE("invalid parameter.");
54 return nullptr;
55 }
56 auto ptr = reinterpret_cast<std::weak_ptr<WorkSchedulerExtensionContext> *>(value)->lock();
57 if (ptr == nullptr) {
58 WS_HILOGE("invalid context.");
59 return nullptr;
60 }
61 NativeValue *object = CreateJsWorkSchedulerExtensionContext(*engine, ptr);
62 auto contextObj = AbilityRuntime::JsRuntime::LoadSystemModuleByEngine(engine,
63 "application.WorkSchedulerExtensionContext", &object, 1)->Get();
64 NativeObject *nObject = AbilityRuntime::ConvertNativeValueTo<NativeObject>(contextObj);
65 nObject->ConvertToNativeBindingObject(engine, AbilityRuntime::DetachCallbackFunc,
66 AttachWorkSchedulerExtensionContext, value, nullptr);
67 auto workContext = new (std::nothrow) std::weak_ptr<WorkSchedulerExtensionContext>(ptr);
68 nObject->SetNativePointer(workContext,
69 [](NativeEngine *, void *data, void *) {
70 WS_HILOGI("Finalizer for weak_ptr WorkSchedulerExtensionContext is called");
71 delete static_cast<std::weak_ptr<WorkSchedulerExtensionContext> *>(data);
72 }, nullptr);
73 return contextObj;
74 }
75
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)76 void JsWorkSchedulerExtension::Init(const std::shared_ptr<AppExecFwk::AbilityLocalRecord>& record,
77 const std::shared_ptr<AppExecFwk::OHOSApplication>& application,
78 std::shared_ptr<AppExecFwk::AbilityHandler>& handler,
79 const sptr<IRemoteObject>& token)
80 {
81 WS_HILOGD("enter");
82 WorkSchedulerExtension::Init(record, application, handler, token);
83 std::string srcPath = "";
84 GetSrcPath(srcPath);
85 if (srcPath.empty()) {
86 WS_HILOGE("JsWorkSchedulerExtension Failed to get srcPath");
87 return;
88 }
89
90 std::string moduleName(Extension::abilityInfo_->moduleName);
91 moduleName.append("::").append(abilityInfo_->name);
92 WS_HILOGD("moduleName:%{public}s, srcPath:%{public}s.", moduleName.c_str(), srcPath.c_str());
93 AbilityRuntime::HandleScope handleScope(jsRuntime_);
94 auto& engine = jsRuntime_.GetNativeEngine();
95
96 jsObj_ = jsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath,
97 abilityInfo_->compileMode == AbilityRuntime::CompileMode::ES_MODULE);
98 if (jsObj_ == nullptr) {
99 WS_HILOGE("WorkSchedulerExtension Failed to get jsObj_");
100 return;
101 }
102 NativeObject* obj = AbilityRuntime::ConvertNativeValueTo<NativeObject>(jsObj_->Get());
103 if (obj == nullptr) {
104 WS_HILOGE("WorkSchedulerExtension Failed to get JsWorkSchedulerExtension object");
105 return;
106 }
107 BindContext(engine, obj);
108
109 WS_HILOGD("end.");
110 }
111
BindContext(NativeEngine & engine,NativeObject * obj)112 void JsWorkSchedulerExtension::BindContext(NativeEngine& engine, NativeObject* obj)
113 {
114 auto context = GetContext();
115 if (context == nullptr) {
116 WS_HILOGE("WorkSchedulerExtension Failed to get context");
117 return;
118 }
119 NativeValue* contextObj = CreateJsWorkSchedulerExtensionContext(engine, context);
120 shellContextRef_ = jsRuntime_.LoadSystemModule("application.WorkSchedulerExtensionContext",
121 &contextObj, 1);
122 contextObj = shellContextRef_->Get();
123
124 NativeObject* nativeObj = AbilityRuntime::ConvertNativeValueTo<NativeObject>(contextObj);
125 if (nativeObj == nullptr) {
126 WS_HILOGE("Failed to get context native object");
127 return;
128 }
129 auto workContext = new (std::nothrow) std::weak_ptr<WorkSchedulerExtensionContext>(context);
130 nativeObj->ConvertToNativeBindingObject(&engine, AbilityRuntime::DetachCallbackFunc,
131 AttachWorkSchedulerExtensionContext, workContext, nullptr);
132 WS_HILOGI("JsWorkSchedulerExtension init bind and set property.");
133 context->Bind(jsRuntime_, shellContextRef_.get());
134 obj->SetProperty("context", contextObj);
135 WS_HILOGI("Set JsWorkSchedulerExtension context pointer is nullptr or not:%{public}d",
136 context.get() == nullptr);
137 nativeObj->SetNativePointer(workContext,
138 [](NativeEngine*, void* data, void*) {
139 WS_HILOGI("Finalizer for weak_ptr WorkSchedulerExtensionContext is called");
140 delete static_cast<std::weak_ptr<WorkSchedulerExtensionContext> *>(data);
141 }, nullptr);
142 }
143
OnStart(const AAFwk::Want & want)144 void JsWorkSchedulerExtension::OnStart(const AAFwk::Want& want)
145 {
146 WS_HILOGD("begin");
147 AbilityRuntime::Extension::OnStart(want);
148 }
149
OnStop()150 void JsWorkSchedulerExtension::OnStop()
151 {
152 AbilityRuntime::Extension::OnStop();
153 WS_HILOGD("end.");
154 }
155
OnConnect(const AAFwk::Want & want)156 sptr<IRemoteObject> JsWorkSchedulerExtension::OnConnect(const AAFwk::Want& want)
157 {
158 AbilityRuntime::Extension::OnConnect(want);
159 WS_HILOGD("begin.");
160 sptr<WorkSchedulerStubImp> remoteObject = new (std::nothrow) WorkSchedulerStubImp(
161 std::static_pointer_cast<JsWorkSchedulerExtension>(shared_from_this()));
162 if (remoteObject == nullptr) {
163 WS_HILOGE("OnConnect get null");
164 return remoteObject;
165 }
166 WS_HILOGD("end.");
167 return remoteObject->AsObject();
168 }
169
OnDisconnect(const AAFwk::Want & want)170 void JsWorkSchedulerExtension::OnDisconnect(const AAFwk::Want& want)
171 {
172 WS_HILOGD("begin.");
173 AbilityRuntime::Extension::OnDisconnect(want);
174 }
175
OnWorkStart(WorkInfo & workInfo)176 void JsWorkSchedulerExtension::OnWorkStart(WorkInfo& workInfo)
177 {
178 if (handler_ == nullptr) {
179 return;
180 }
181 WS_HILOGD("begin.");
182 int32_t workId = workInfo.GetWorkId();
183 std::string bundleName = workInfo.GetBundleName();
184 std::string abilityName = workInfo.GetAbilityName();
185 bool isPersisted = workInfo.IsPersisted();
186 WorkCondition::Network networkType = workInfo.GetNetworkType();
187 WorkCondition::Charger charger = workInfo.GetChargerType();
188 int32_t batteryLevel = workInfo.GetBatteryLevel();
189 WorkCondition::BatteryStatus batteryStatus = workInfo.GetBatteryStatus();
190 WorkCondition::Storage storageLevel = workInfo.GetStorageLevel();
191 uint32_t timeInterval = workInfo.GetTimeInterval();
192 bool isRepeat = workInfo.IsRepeat();
193 int32_t cycleCount = workInfo.GetCycleCount();
194 std::string extrasStr;
195 bool getExtrasRet = GetExtrasJsonStr(workInfo, extrasStr);
196 WorkSchedulerExtension::OnWorkStart(workInfo);
197 auto task = [=]() {
198 AbilityRuntime::HandleScope handleScope(jsRuntime_);
199 NativeEngine& nativeEngine = jsRuntime_.GetNativeEngine();
200
201 NativeValue* jworkInfoData = nativeEngine.CreateObject();
202 NativeObject* workInfoData = AbilityRuntime::ConvertNativeValueTo<NativeObject>(jworkInfoData);
203 workInfoData->SetProperty("workId", nativeEngine.CreateNumber(workId));
204
205 workInfoData->SetProperty("bundleName", nativeEngine.CreateString(bundleName.c_str(), bundleName.size()));
206
207 workInfoData->SetProperty("abilityName", nativeEngine.CreateString(abilityName.c_str(), abilityName.size()));
208
209 if (getExtrasRet) {
210 workInfoData->SetProperty("parameters", nativeEngine.CreateString(extrasStr.c_str(), extrasStr.size()));
211 }
212
213 workInfoData->SetProperty("isPersisted", nativeEngine.CreateBoolean(isPersisted));
214 if (networkType != WorkCondition::Network::NETWORK_UNKNOWN) {
215 workInfoData->SetProperty("networkType", nativeEngine.CreateNumber(networkType));
216 }
217 if (charger != WorkCondition::Charger::CHARGING_UNKNOWN) {
218 if (charger == WorkCondition::Charger::CHARGING_UNPLUGGED) {
219 workInfoData->SetProperty("isCharging", nativeEngine.CreateBoolean(false));
220 } else {
221 workInfoData->SetProperty("isCharging", nativeEngine.CreateBoolean(true));
222 workInfoData->SetProperty("chargerType", nativeEngine.CreateNumber(charger));
223 }
224 }
225 if (batteryLevel != INVALID_VALUE) {
226 workInfoData->SetProperty("batteryLevel", nativeEngine.CreateNumber(batteryLevel));
227 }
228 if (batteryStatus != WorkCondition::BatteryStatus::BATTERY_UNKNOWN) {
229 workInfoData->SetProperty("batteryStatus", nativeEngine.CreateNumber(batteryStatus));
230 }
231 if (storageLevel != WorkCondition::Storage::STORAGE_UNKNOWN) {
232 workInfoData->SetProperty("storageRequest", nativeEngine.CreateNumber(storageLevel));
233 }
234
235 if (timeInterval > 0) {
236 if (isRepeat) {
237 workInfoData->SetProperty("isRepeat", nativeEngine.CreateBoolean(true));
238 workInfoData->SetProperty("repeatCycleTime", nativeEngine.CreateNumber(timeInterval));
239 } else {
240 workInfoData->SetProperty("repeatCycleTime", nativeEngine.CreateNumber(timeInterval));
241 workInfoData->SetProperty("repeatCount", nativeEngine.CreateNumber(cycleCount));
242 }
243 }
244
245 NativeValue* argv[] = {jworkInfoData};
246 if (!jsObj_) {
247 WS_HILOGE("WorkSchedulerExtension Not found js");
248 return;
249 }
250
251 NativeValue* value = jsObj_->Get();
252 NativeObject* obj = AbilityRuntime::ConvertNativeValueTo<NativeObject>(value);
253 if (obj == nullptr) {
254 WS_HILOGE("WorkSchedulerExtension Failed to get WorkSchedulerExtension object");
255 return;
256 }
257
258 NativeValue* method = obj->GetProperty("onWorkStart");
259 if (method == nullptr) {
260 WS_HILOGE("WorkSchedulerExtension Failed to get onWorkStart from WorkSchedulerExtension object");
261 return;
262 }
263 nativeEngine.CallFunction(value, method, argv, 1);
264 };
265 handler_->PostTask(task);
266 }
267
OnWorkStop(WorkInfo & workInfo)268 void JsWorkSchedulerExtension::OnWorkStop(WorkInfo& workInfo)
269 {
270 if (handler_ == nullptr) {
271 return;
272 }
273 WS_HILOGD("begin.");
274 int32_t workId = workInfo.GetWorkId();
275 std::string bundleName = workInfo.GetBundleName();
276 std::string abilityName = workInfo.GetAbilityName();
277 bool isPersisted = workInfo.IsPersisted();
278 WorkCondition::Network networkType = workInfo.GetNetworkType();
279 WorkCondition::Charger charger = workInfo.GetChargerType();
280 int32_t batteryLevel = workInfo.GetBatteryLevel();
281 WorkCondition::BatteryStatus batteryStatus = workInfo.GetBatteryStatus();
282 WorkCondition::Storage storageLevel = workInfo.GetStorageLevel();
283 uint32_t timeInterval = workInfo.GetTimeInterval();
284 bool isRepeat = workInfo.IsRepeat();
285 int32_t cycleCount = workInfo.GetCycleCount();
286 std::string extrasStr;
287 bool getExtrasRet = GetExtrasJsonStr(workInfo, extrasStr);
288 WorkSchedulerExtension::OnWorkStop(workInfo);
289 auto task = [=]() {
290 AbilityRuntime::HandleScope handleScope(jsRuntime_);
291 NativeEngine& nativeEngine = jsRuntime_.GetNativeEngine();
292
293 NativeValue* jworkInfoData = nativeEngine.CreateObject();
294 NativeObject* workInfoData = AbilityRuntime::ConvertNativeValueTo<NativeObject>(jworkInfoData);
295 workInfoData->SetProperty("workId", nativeEngine.CreateNumber(workId));
296
297 workInfoData->SetProperty("bundleName", nativeEngine.CreateString(bundleName.c_str(), bundleName.size()));
298
299 workInfoData->SetProperty("abilityName", nativeEngine.CreateString(abilityName.c_str(), abilityName.size()));
300
301 if (getExtrasRet) {
302 workInfoData->SetProperty("parameters", nativeEngine.CreateString(extrasStr.c_str(), extrasStr.size()));
303 }
304
305 workInfoData->SetProperty("isPersisted", nativeEngine.CreateBoolean(isPersisted));
306 if (networkType != WorkCondition::Network::NETWORK_UNKNOWN) {
307 workInfoData->SetProperty("networkType", nativeEngine.CreateNumber(networkType));
308 }
309 if (charger != WorkCondition::Charger::CHARGING_UNKNOWN) {
310 if (charger == WorkCondition::Charger::CHARGING_UNPLUGGED) {
311 workInfoData->SetProperty("isCharging", nativeEngine.CreateBoolean(false));
312 } else {
313 workInfoData->SetProperty("isCharging", nativeEngine.CreateBoolean(true));
314 workInfoData->SetProperty("chargerType", nativeEngine.CreateNumber(charger));
315 }
316 }
317 if (batteryLevel != INVALID_VALUE) {
318 workInfoData->SetProperty("batteryLevel", nativeEngine.CreateNumber(batteryLevel));
319 }
320 if (batteryStatus != WorkCondition::BatteryStatus::BATTERY_UNKNOWN) {
321 workInfoData->SetProperty("batteryStatus", nativeEngine.CreateNumber(batteryStatus));
322 }
323 if (storageLevel != WorkCondition::Storage::STORAGE_UNKNOWN) {
324 workInfoData->SetProperty("storageRequest", nativeEngine.CreateNumber(storageLevel));
325 }
326
327 if (timeInterval > 0) {
328 if (isRepeat) {
329 workInfoData->SetProperty("isRepeat", nativeEngine.CreateBoolean(true));
330 workInfoData->SetProperty("repeatCycleTime", nativeEngine.CreateNumber(timeInterval));
331 } else {
332 workInfoData->SetProperty("repeatCycleTime", nativeEngine.CreateNumber(timeInterval));
333 workInfoData->SetProperty("repeatCount", nativeEngine.CreateNumber(cycleCount));
334 }
335 }
336
337 NativeValue* argv[] = {jworkInfoData};
338 if (!jsObj_) {
339 WS_HILOGE("WorkSchedulerExtension Not found js");
340 return;
341 }
342
343 NativeValue* value = jsObj_->Get();
344 NativeObject* obj = AbilityRuntime::ConvertNativeValueTo<NativeObject>(value);
345 if (obj == nullptr) {
346 WS_HILOGE("WorkSchedulerExtension Failed to get object");
347 return;
348 }
349
350 NativeValue* method = obj->GetProperty("onWorkStop");
351 if (method == nullptr) {
352 WS_HILOGE("WorkSchedulerExtension Failed to get onWorkStop from object");
353 return;
354 }
355 nativeEngine.CallFunction(value, method, argv, 1);
356 };
357 handler_->PostTask(task);
358 }
359
GetSrcPath(std::string & srcPath)360 void JsWorkSchedulerExtension::GetSrcPath(std::string &srcPath)
361 {
362 if (!Extension::abilityInfo_->isStageBasedModel) {
363 /* temporary compatibility api8 + config.json */
364 srcPath.append(Extension::abilityInfo_->package);
365 srcPath.append("/assets/js/");
366 if (!Extension::abilityInfo_->srcPath.empty()) {
367 srcPath.append(Extension::abilityInfo_->srcPath);
368 }
369 srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
370 return;
371 }
372
373 if (!Extension::abilityInfo_->srcEntrance.empty()) {
374 srcPath.append(Extension::abilityInfo_->moduleName + "/");
375 srcPath.append(Extension::abilityInfo_->srcEntrance);
376 srcPath.erase(srcPath.rfind('.'));
377 srcPath.append(".abc");
378 }
379 }
380
GetExtrasJsonStr(const WorkInfo & workInfo,std::string & extrasStr)381 bool JsWorkSchedulerExtension::GetExtrasJsonStr(const WorkInfo& workInfo, std::string& extrasStr)
382 {
383 std::shared_ptr<AAFwk::WantParams> extras = workInfo.GetExtras();
384 Json::Value extrasJson;
385 if (!extras) {
386 WS_HILOGI("parameter is null.");
387 return false;
388 }
389 auto extrasMap = extras->GetParams();
390 int typeId = INVALID_VALUE;
391 for (auto it : extrasMap) {
392 typeId = AAFwk::WantParams::GetDataType(it.second);
393 if (typeId != INVALID_VALUE) {
394 std::string value = AAFwk::WantParams::GetStringByType(it.second, typeId);
395 extrasJson[it.first] = value;
396 } else {
397 WS_HILOGE("parameters type not supported.");
398 }
399 }
400 Json::StreamWriterBuilder builder;
401 extrasStr = Json::writeString(builder, extrasJson);
402 return true;
403 }
404 } // namespace WorkScheduler
405 } // namespace OHOS
406