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) {}
37 JsWorkSchedulerExtension::~JsWorkSchedulerExtension() = default;
38
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)39 void JsWorkSchedulerExtension::Init(const std::shared_ptr<AppExecFwk::AbilityLocalRecord>& record,
40 const std::shared_ptr<AppExecFwk::OHOSApplication>& application,
41 std::shared_ptr<AppExecFwk::AbilityHandler>& handler,
42 const sptr<IRemoteObject>& token)
43 {
44 WS_HILOGD("enter");
45 WorkSchedulerExtension::Init(record, application, handler, token);
46 std::string srcPath = "";
47 GetSrcPath(srcPath);
48 if (srcPath.empty()) {
49 WS_HILOGE("JsWorkSchedulerExtension Failed to get srcPath");
50 return;
51 }
52
53 std::string moduleName(Extension::abilityInfo_->moduleName);
54 moduleName.append("::").append(abilityInfo_->name);
55 WS_HILOGD("moduleName:%{public}s, srcPath:%{public}s.", moduleName.c_str(), srcPath.c_str());
56 AbilityRuntime::HandleScope handleScope(jsRuntime_);
57 auto& engine = jsRuntime_.GetNativeEngine();
58
59 jsObj_ = jsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath);
60 if (jsObj_ == nullptr) {
61 WS_HILOGE("WorkSchedulerExtension Failed to get jsObj_");
62 return;
63 }
64 NativeObject* obj = AbilityRuntime::ConvertNativeValueTo<NativeObject>(jsObj_->Get());
65 if (obj == nullptr) {
66 WS_HILOGE("WorkSchedulerExtension Failed to get JsWorkSchedulerExtension object");
67 return;
68 }
69
70 auto context = GetContext();
71 if (context == nullptr) {
72 WS_HILOGE("WorkSchedulerExtension Failed to get context");
73 return;
74 }
75 NativeValue* contextObj = CreateJsWorkSchedulerExtensionContext(engine, context);
76 auto shellContextRef = jsRuntime_.LoadSystemModule("WorkSchedulerExtensionContext",
77 &contextObj, 1);
78 contextObj = shellContextRef->Get();
79 context->Bind(jsRuntime_, shellContextRef.release());
80 obj->SetProperty("context", contextObj);
81 WS_HILOGD("end.");
82 }
83
OnStart(const AAFwk::Want & want)84 void JsWorkSchedulerExtension::OnStart(const AAFwk::Want& want)
85 {
86 WS_HILOGD("begin");
87 AbilityRuntime::Extension::OnStart(want);
88 }
89
OnStop()90 void JsWorkSchedulerExtension::OnStop()
91 {
92 AbilityRuntime::Extension::OnStop();
93 WS_HILOGD("end.");
94 }
95
OnConnect(const AAFwk::Want & want)96 sptr<IRemoteObject> JsWorkSchedulerExtension::OnConnect(const AAFwk::Want& want)
97 {
98 AbilityRuntime::Extension::OnConnect(want);
99 WS_HILOGD("begin.");
100 sptr<WorkSchedulerStubImp> remoteObject = new (std::nothrow) WorkSchedulerStubImp(
101 std::static_pointer_cast<JsWorkSchedulerExtension>(shared_from_this()));
102 if (remoteObject == nullptr) {
103 WS_HILOGE("OnConnect get null");
104 return remoteObject;
105 }
106 WS_HILOGD("end.");
107 return remoteObject->AsObject();
108 }
109
OnDisconnect(const AAFwk::Want & want)110 void JsWorkSchedulerExtension::OnDisconnect(const AAFwk::Want& want)
111 {
112 WS_HILOGD("begin.");
113 AbilityRuntime::Extension::OnDisconnect(want);
114 }
115
OnWorkStart(WorkInfo & workInfo)116 void JsWorkSchedulerExtension::OnWorkStart(WorkInfo& workInfo)
117 {
118 if (handler_ == nullptr) {
119 return;
120 }
121 WS_HILOGD("begin.");
122 int32_t workId = workInfo.GetWorkId();
123 std::string bundleName = workInfo.GetBundleName();
124 std::string abilityName = workInfo.GetAbilityName();
125 bool isPersisted = workInfo.IsPersisted();
126 WorkCondition::Network networkType = workInfo.GetNetworkType();
127 WorkCondition::Charger charger = workInfo.GetChargerType();
128 int32_t batteryLevel = workInfo.GetBatteryLevel();
129 WorkCondition::BatteryStatus batteryStatus = workInfo.GetBatteryStatus();
130 WorkCondition::Storage storageLevel = workInfo.GetStorageLevel();
131 uint32_t timeInterval = workInfo.GetTimeInterval();
132 bool isRepeat = workInfo.IsRepeat();
133 int32_t cycleCount = workInfo.GetCycleCount();
134 std::string extrasStr;
135 bool getExtrasRet = GetExtrasJsonStr(workInfo, extrasStr);
136 WorkSchedulerExtension::OnWorkStart(workInfo);
137 auto task = [=]() {
138 AbilityRuntime::HandleScope handleScope(jsRuntime_);
139 NativeEngine& nativeEngine = jsRuntime_.GetNativeEngine();
140
141 NativeValue* jworkInfoData = nativeEngine.CreateObject();
142 NativeObject* workInfoData = AbilityRuntime::ConvertNativeValueTo<NativeObject>(jworkInfoData);
143 workInfoData->SetProperty("workId", nativeEngine.CreateNumber(workId));
144
145 workInfoData->SetProperty("bundleName", nativeEngine.CreateString(bundleName.c_str(), bundleName.size()));
146
147 workInfoData->SetProperty("abilityName", nativeEngine.CreateString(abilityName.c_str(), abilityName.size()));
148
149 if (getExtrasRet) {
150 workInfoData->SetProperty("parameters", nativeEngine.CreateString(extrasStr.c_str(), extrasStr.size()));
151 }
152
153 workInfoData->SetProperty("isPersisted", nativeEngine.CreateBoolean(isPersisted));
154 if (networkType != WorkCondition::Network::NETWORK_UNKNOWN) {
155 workInfoData->SetProperty("networkType", nativeEngine.CreateNumber(networkType));
156 }
157 if (charger != WorkCondition::Charger::CHARGING_UNKNOWN) {
158 if (charger == WorkCondition::Charger::CHARGING_UNPLUGGED) {
159 workInfoData->SetProperty("isCharging", nativeEngine.CreateBoolean(false));
160 } else {
161 workInfoData->SetProperty("isCharging", nativeEngine.CreateBoolean(true));
162 workInfoData->SetProperty("chargerType", nativeEngine.CreateNumber(charger));
163 }
164 }
165 if (batteryLevel != INVALID_VALUE) {
166 workInfoData->SetProperty("batteryLevel", nativeEngine.CreateNumber(batteryLevel));
167 }
168 if (batteryStatus != WorkCondition::BatteryStatus::BATTERY_UNKNOWN) {
169 workInfoData->SetProperty("batteryStatus", nativeEngine.CreateNumber(batteryStatus));
170 }
171 if (storageLevel != WorkCondition::Storage::STORAGE_UNKNOWN) {
172 workInfoData->SetProperty("storageRequest", nativeEngine.CreateNumber(storageLevel));
173 }
174
175 if (timeInterval > 0) {
176 if (isRepeat) {
177 workInfoData->SetProperty("isRepeat", nativeEngine.CreateBoolean(true));
178 workInfoData->SetProperty("repeatCycleTime", nativeEngine.CreateNumber(timeInterval));
179 } else {
180 workInfoData->SetProperty("repeatCycleTime", nativeEngine.CreateNumber(timeInterval));
181 workInfoData->SetProperty("repeatCount", nativeEngine.CreateNumber(cycleCount));
182 }
183 }
184
185 NativeValue* argv[] = {jworkInfoData};
186 if (!jsObj_) {
187 WS_HILOGE("WorkSchedulerExtension Not found js");
188 return;
189 }
190
191 NativeValue* value = jsObj_->Get();
192 NativeObject* obj = AbilityRuntime::ConvertNativeValueTo<NativeObject>(value);
193 if (obj == nullptr) {
194 WS_HILOGE("WorkSchedulerExtension Failed to get WorkSchedulerExtension object");
195 return;
196 }
197
198 NativeValue* method = obj->GetProperty("onWorkStart");
199 if (method == nullptr) {
200 WS_HILOGE("WorkSchedulerExtension Failed to get onWorkStart from WorkSchedulerExtension object");
201 return;
202 }
203 nativeEngine.CallFunction(value, method, argv, 1);
204 };
205 handler_->PostTask(task);
206 }
207
OnWorkStop(WorkInfo & workInfo)208 void JsWorkSchedulerExtension::OnWorkStop(WorkInfo& workInfo)
209 {
210 if (handler_ == nullptr) {
211 return;
212 }
213 WS_HILOGD("begin.");
214 int32_t workId = workInfo.GetWorkId();
215 std::string bundleName = workInfo.GetBundleName();
216 std::string abilityName = workInfo.GetAbilityName();
217 bool isPersisted = workInfo.IsPersisted();
218 WorkCondition::Network networkType = workInfo.GetNetworkType();
219 WorkCondition::Charger charger = workInfo.GetChargerType();
220 int32_t batteryLevel = workInfo.GetBatteryLevel();
221 WorkCondition::BatteryStatus batteryStatus = workInfo.GetBatteryStatus();
222 WorkCondition::Storage storageLevel = workInfo.GetStorageLevel();
223 uint32_t timeInterval = workInfo.GetTimeInterval();
224 bool isRepeat = workInfo.IsRepeat();
225 int32_t cycleCount = workInfo.GetCycleCount();
226 std::string extrasStr;
227 bool getExtrasRet = GetExtrasJsonStr(workInfo, extrasStr);
228 WorkSchedulerExtension::OnWorkStop(workInfo);
229 auto task = [=]() {
230 AbilityRuntime::HandleScope handleScope(jsRuntime_);
231 NativeEngine& nativeEngine = jsRuntime_.GetNativeEngine();
232
233 NativeValue* jworkInfoData = nativeEngine.CreateObject();
234 NativeObject* workInfoData = AbilityRuntime::ConvertNativeValueTo<NativeObject>(jworkInfoData);
235 workInfoData->SetProperty("workId", nativeEngine.CreateNumber(workId));
236
237 workInfoData->SetProperty("bundleName", nativeEngine.CreateString(bundleName.c_str(), bundleName.size()));
238
239 workInfoData->SetProperty("abilityName", nativeEngine.CreateString(abilityName.c_str(), abilityName.size()));
240
241 if (getExtrasRet) {
242 workInfoData->SetProperty("parameters", nativeEngine.CreateString(extrasStr.c_str(), extrasStr.size()));
243 }
244
245 workInfoData->SetProperty("isPersisted", nativeEngine.CreateBoolean(isPersisted));
246 if (networkType != WorkCondition::Network::NETWORK_UNKNOWN) {
247 workInfoData->SetProperty("networkType", nativeEngine.CreateNumber(networkType));
248 }
249 if (charger != WorkCondition::Charger::CHARGING_UNKNOWN) {
250 if (charger == WorkCondition::Charger::CHARGING_UNPLUGGED) {
251 workInfoData->SetProperty("isCharging", nativeEngine.CreateBoolean(false));
252 } else {
253 workInfoData->SetProperty("isCharging", nativeEngine.CreateBoolean(true));
254 workInfoData->SetProperty("chargerType", nativeEngine.CreateNumber(charger));
255 }
256 }
257 if (batteryLevel != INVALID_VALUE) {
258 workInfoData->SetProperty("batteryLevel", nativeEngine.CreateNumber(batteryLevel));
259 }
260 if (batteryStatus != WorkCondition::BatteryStatus::BATTERY_UNKNOWN) {
261 workInfoData->SetProperty("batteryStatus", nativeEngine.CreateNumber(batteryStatus));
262 }
263 if (storageLevel != WorkCondition::Storage::STORAGE_UNKNOWN) {
264 workInfoData->SetProperty("storageRequest", nativeEngine.CreateNumber(storageLevel));
265 }
266
267 if (timeInterval > 0) {
268 if (isRepeat) {
269 workInfoData->SetProperty("isRepeat", nativeEngine.CreateBoolean(true));
270 workInfoData->SetProperty("repeatCycleTime", nativeEngine.CreateNumber(timeInterval));
271 } else {
272 workInfoData->SetProperty("repeatCycleTime", nativeEngine.CreateNumber(timeInterval));
273 workInfoData->SetProperty("repeatCount", nativeEngine.CreateNumber(cycleCount));
274 }
275 }
276
277 NativeValue* argv[] = {jworkInfoData};
278 if (!jsObj_) {
279 WS_HILOGE("WorkSchedulerExtension Not found js");
280 return;
281 }
282
283 NativeValue* value = jsObj_->Get();
284 NativeObject* obj = AbilityRuntime::ConvertNativeValueTo<NativeObject>(value);
285 if (obj == nullptr) {
286 WS_HILOGE("WorkSchedulerExtension Failed to get object");
287 return;
288 }
289
290 NativeValue* method = obj->GetProperty("onWorkStop");
291 if (method == nullptr) {
292 WS_HILOGE("WorkSchedulerExtension Failed to get onWorkStop from object");
293 return;
294 }
295 nativeEngine.CallFunction(value, method, argv, 1);
296 };
297 handler_->PostTask(task);
298 }
299
GetSrcPath(std::string & srcPath)300 void JsWorkSchedulerExtension::GetSrcPath(std::string &srcPath)
301 {
302 if (!Extension::abilityInfo_->isStageBasedModel) {
303 /* temporary compatibility api8 + config.json */
304 srcPath.append(Extension::abilityInfo_->package);
305 srcPath.append("/assets/js/");
306 if (!Extension::abilityInfo_->srcPath.empty()) {
307 srcPath.append(Extension::abilityInfo_->srcPath);
308 }
309 srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
310 return;
311 }
312
313 if (!Extension::abilityInfo_->srcEntrance.empty()) {
314 srcPath.append(Extension::abilityInfo_->moduleName + "/");
315 srcPath.append(Extension::abilityInfo_->srcEntrance);
316 srcPath.erase(srcPath.rfind('.'));
317 srcPath.append(".abc");
318 }
319 }
320
GetExtrasJsonStr(const WorkInfo & workInfo,std::string & extrasStr)321 bool JsWorkSchedulerExtension::GetExtrasJsonStr(const WorkInfo& workInfo, std::string& extrasStr)
322 {
323 std::shared_ptr<AAFwk::WantParams> extras = workInfo.GetExtras();
324 Json::Value extrasJson;
325 if (!extras) {
326 WS_HILOGI("parameter is null.");
327 return false;
328 }
329 auto extrasMap = extras->GetParams();
330 int typeId = INVALID_VALUE;
331 for (auto it : extrasMap) {
332 typeId = AAFwk::WantParams::GetDataType(it.second);
333 if (typeId != INVALID_VALUE) {
334 std::string value = AAFwk::WantParams::GetStringByType(it.second, typeId);
335 extrasJson[it.first] = value;
336 } else {
337 WS_HILOGE("parameters type not supported.");
338 }
339 }
340 Json::StreamWriterBuilder builder;
341 extrasStr = Json::writeString(builder, extrasJson);
342 return true;
343 }
344 } // namespace WorkScheduler
345 } // namespace OHOS
346