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 #include "hitrace_meter.h"
27 #include "work_sched_constants.h"
28
29 namespace OHOS {
30 namespace WorkScheduler {
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
DetachCallbackFunc(napi_env env,void * value,void *)49 inline void *DetachCallbackFunc(napi_env env, void *value, void *)
50 {
51 return value;
52 }
53
AttachWorkSchedulerExtensionContext(napi_env env,void * value,void *)54 napi_value AttachWorkSchedulerExtensionContext(napi_env env, void *value, void *)
55 {
56 WS_HILOGI("AttachWorkSchedulerExtensionContext");
57 if (value == nullptr) {
58 WS_HILOGE("invalid parameter.");
59 return nullptr;
60 }
61 auto ptr = reinterpret_cast<std::weak_ptr<WorkSchedulerExtensionContext> *>(value)->lock();
62 if (ptr == nullptr) {
63 WS_HILOGE("invalid context.");
64 return nullptr;
65 }
66 napi_value object = CreateJsWorkSchedulerExtensionContext(env, ptr);
67 auto loadObject = AbilityRuntime::JsRuntime::LoadSystemModuleByEngine(env,
68 "application.WorkSchedulerExtensionContext", &object, 1);
69 if (loadObject == nullptr) {
70 return nullptr;
71 }
72 napi_value contextObj = loadObject->GetNapiValue();
73 napi_coerce_to_native_binding_object(env, contextObj, DetachCallbackFunc,
74 AttachWorkSchedulerExtensionContext, value, nullptr);
75 auto workContext = new (std::nothrow) std::weak_ptr<WorkSchedulerExtensionContext>(ptr);
76 if (workContext == nullptr) {
77 WS_HILOGE("init WorkSchedulerExtensionContext failed.");
78 return nullptr;
79 }
80 napi_status status = napi_wrap(env, contextObj, workContext,
81 [](napi_env env, void *data, void *) {
82 WS_HILOGI("Finalizer for weak_ptr WorkSchedulerExtensionContext is called");
83 delete static_cast<std::weak_ptr<WorkSchedulerExtensionContext> *>(data);
84 }, nullptr, nullptr);
85 if (status != napi_ok) {
86 WS_HILOGE("WorkSchedulerExtension failed to wrap the context");
87 delete workContext;
88 workContext = nullptr;
89 return nullptr;
90 }
91
92 return contextObj;
93 }
94
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)95 void JsWorkSchedulerExtension::Init(const std::shared_ptr<AppExecFwk::AbilityLocalRecord>& record,
96 const std::shared_ptr<AppExecFwk::OHOSApplication>& application,
97 std::shared_ptr<AppExecFwk::AbilityHandler>& handler,
98 const sptr<IRemoteObject>& token)
99 {
100 WS_HILOGD("enter");
101 WorkSchedulerExtension::Init(record, application, handler, token);
102 std::string srcPath = "";
103 GetSrcPath(srcPath);
104 if (srcPath.empty()) {
105 WS_HILOGE("JsWorkSchedulerExtension Failed to get srcPath");
106 return;
107 }
108
109 std::string moduleName(Extension::abilityInfo_->moduleName);
110 moduleName.append("::").append(abilityInfo_->name);
111 WS_HILOGD("moduleName:%{public}s, srcPath:%{private}s.", moduleName.c_str(), srcPath.c_str());
112 AbilityRuntime::HandleScope handleScope(jsRuntime_);
113 napi_env env = jsRuntime_.GetNapiEnv();
114
115 jsObj_ = jsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath,
116 abilityInfo_->compileMode == AbilityRuntime::CompileMode::ES_MODULE, false, abilityInfo_->srcEntrance);
117 if (jsObj_ == nullptr) {
118 WS_HILOGE("WorkSchedulerExtension Failed to get jsObj_");
119 return;
120 }
121 napi_value obj = jsObj_->GetNapiValue();
122 if (obj == nullptr) {
123 WS_HILOGE("WorkSchedulerExtension Failed to get JsWorkSchedulerExtension object");
124 return;
125 }
126 BindContext(env, obj);
127
128 WS_HILOGD("end.");
129 }
130
BindContext(napi_env env,napi_value obj)131 void JsWorkSchedulerExtension::BindContext(napi_env env, napi_value obj)
132 {
133 auto context = GetContext();
134 if (context == nullptr) {
135 WS_HILOGE("WorkSchedulerExtension Failed to get context");
136 return;
137 }
138 napi_value contextObj = CreateJsWorkSchedulerExtensionContext(env, context);
139 shellContextRef_ = jsRuntime_.LoadSystemModule("application.WorkSchedulerExtensionContext",
140 &contextObj, 1);
141 if (shellContextRef_ == nullptr) {
142 WS_HILOGE("WorkSchedulerExtension Failed to get shellContextRef_");
143 return;
144 }
145 contextObj = shellContextRef_->GetNapiValue();
146
147 auto workContext = new (std::nothrow) std::weak_ptr<WorkSchedulerExtensionContext>(context);
148 if (workContext == nullptr) {
149 WS_HILOGE("init WorkSchedulerExtensionContext failed.");
150 return;
151 }
152 napi_coerce_to_native_binding_object(env, contextObj, DetachCallbackFunc,
153 AttachWorkSchedulerExtensionContext, workContext, nullptr);
154 WS_HILOGI("JsWorkSchedulerExtension init bind and set property.");
155 context->Bind(jsRuntime_, shellContextRef_.get());
156 napi_set_named_property(env, obj, "context", contextObj);
157 WS_HILOGI("Set JsWorkSchedulerExtension context pointer is nullptr or not:%{public}d",
158 context.get() == nullptr);
159
160 napi_status status = napi_wrap(env, contextObj, workContext,
161 [](napi_env env, void* data, void*) {
162 WS_HILOGI("Finalizer for weak_ptr WorkSchedulerExtensionContext is called");
163 delete static_cast<std::weak_ptr<WorkSchedulerExtensionContext> *>(data);
164 }, nullptr, nullptr);
165 if (status != napi_ok) {
166 WS_HILOGE("WorkSchedulerExtension failed to wrap the context");
167 delete workContext;
168 workContext = nullptr;
169 }
170 }
171
OnStart(const AAFwk::Want & want)172 void JsWorkSchedulerExtension::OnStart(const AAFwk::Want& want)
173 {
174 WS_HILOGD("begin");
175 AbilityRuntime::Extension::OnStart(want);
176 }
177
OnStop()178 void JsWorkSchedulerExtension::OnStop()
179 {
180 AbilityRuntime::Extension::OnStop();
181 WS_HILOGD("end.");
182 }
183
OnConnect(const AAFwk::Want & want)184 __attribute__((no_sanitize("cfi"))) sptr<IRemoteObject> JsWorkSchedulerExtension::OnConnect(const AAFwk::Want& want)
185 {
186 AbilityRuntime::Extension::OnConnect(want);
187 WS_HILOGD("begin.");
188 sptr<WorkSchedulerStubImp> remoteObject = new (std::nothrow) WorkSchedulerStubImp(
189 std::static_pointer_cast<JsWorkSchedulerExtension>(shared_from_this()));
190 if (remoteObject == nullptr) {
191 WS_HILOGE("OnConnect get null");
192 return remoteObject;
193 }
194 WS_HILOGD("end.");
195 return remoteObject->AsObject();
196 }
197
OnDisconnect(const AAFwk::Want & want)198 void JsWorkSchedulerExtension::OnDisconnect(const AAFwk::Want& want)
199 {
200 WS_HILOGD("begin.");
201 AbilityRuntime::Extension::OnDisconnect(want);
202 }
203
SetCommonInfo(napi_env env,napi_value workInfoData,int32_t workId,const std::string & bundleName,const std::string & abilityName)204 void SetCommonInfo(napi_env env, napi_value workInfoData, int32_t workId,
205 const std::string& bundleName, const std::string& abilityName)
206 {
207 napi_value workIdValue;
208 napi_create_int32(env, workId, &workIdValue);
209 napi_set_named_property(env, workInfoData, "workId", workIdValue);
210
211 napi_value bundleNameValue;
212 napi_create_string_utf8(env, bundleName.c_str(), bundleName.size(), &bundleNameValue);
213 napi_set_named_property(env, workInfoData, "bundleName", bundleNameValue);
214
215 napi_value abilityNameValue;
216 napi_create_string_utf8(env, abilityName.c_str(), abilityName.size(), &abilityNameValue);
217 napi_set_named_property(env, workInfoData, "abilityName", abilityNameValue);
218 }
219
SetPersistedInfo(napi_env env,napi_value workInfoData,bool isPersisted)220 void SetPersistedInfo(napi_env env, napi_value workInfoData, bool isPersisted)
221 {
222 napi_value isPersistedValue;
223 napi_get_boolean(env, isPersisted, &isPersistedValue);
224 napi_set_named_property(env, workInfoData, "isPersisted", isPersistedValue);
225 }
226
SetExtrasInfo(napi_env env,napi_value workInfoData,bool getExtrasRet,const std::string & extrasStr)227 void SetExtrasInfo(napi_env env, napi_value workInfoData, bool getExtrasRet, const std::string& extrasStr)
228 {
229 if (getExtrasRet) {
230 napi_value parametersValue;
231 napi_create_string_utf8(env, extrasStr.c_str(), extrasStr.size(), ¶metersValue);
232 napi_set_named_property(env, workInfoData, "parameters", parametersValue);
233 }
234 }
235
SetNetWorkInfo(napi_env env,napi_value workInfoData,WorkCondition::Network networkType)236 void SetNetWorkInfo(napi_env env, napi_value workInfoData, WorkCondition::Network networkType)
237 {
238 if (networkType != WorkCondition::Network::NETWORK_UNKNOWN) {
239 napi_value networkTypeValue;
240 napi_create_int32(env, networkType, &networkTypeValue);
241 napi_set_named_property(env, workInfoData, "networkType", networkTypeValue);
242 }
243 }
244
SetChargerTypeInfo(napi_env env,napi_value workInfoData,WorkCondition::Charger charger)245 void SetChargerTypeInfo(napi_env env, napi_value workInfoData, WorkCondition::Charger charger)
246 {
247 if (charger != WorkCondition::Charger::CHARGING_UNKNOWN) {
248 if (charger == WorkCondition::Charger::CHARGING_UNPLUGGED) {
249 napi_value isChargingValue;
250 napi_get_boolean(env, false, &isChargingValue);
251 napi_set_named_property(env, workInfoData, "isCharging", isChargingValue);
252 } else {
253 napi_value isChargingValue;
254 napi_get_boolean(env, true, &isChargingValue);
255 napi_set_named_property(env, workInfoData, "isCharging", isChargingValue);
256
257 napi_value chargerTypeValue;
258 napi_create_int32(env, charger, &chargerTypeValue);
259 napi_set_named_property(env, workInfoData, "chargerType", chargerTypeValue);
260 }
261 }
262 }
263
SetBatteryInfo(napi_env env,napi_value workInfoData,int32_t batteryLevel,WorkCondition::BatteryStatus batteryStatus)264 void SetBatteryInfo(napi_env env, napi_value workInfoData, int32_t batteryLevel,
265 WorkCondition::BatteryStatus batteryStatus)
266 {
267 if (batteryLevel != INVALID_VALUE) {
268 napi_value batteryLevelValue;
269 napi_create_int32(env, batteryLevel, &batteryLevelValue);
270 napi_set_named_property(env, workInfoData, "batteryLevel", batteryLevelValue);
271 }
272 if (batteryStatus != WorkCondition::BatteryStatus::BATTERY_UNKNOWN) {
273 napi_value batteryStatusValue;
274 napi_create_int32(env, batteryStatus, &batteryStatusValue);
275 napi_set_named_property(env, workInfoData, "batteryStatus", batteryStatusValue);
276 }
277 }
278
SetStorageInfo(napi_env env,napi_value workInfoData,WorkCondition::Storage storageLevel)279 void SetStorageInfo(napi_env env, napi_value workInfoData, WorkCondition::Storage storageLevel)
280 {
281 if (storageLevel != WorkCondition::Storage::STORAGE_UNKNOWN) {
282 napi_value storageLevelValue;
283 napi_create_int32(env, storageLevel, &storageLevelValue);
284 napi_set_named_property(env, workInfoData, "storageRequest", storageLevelValue);
285 }
286 }
287
SetRepeatInfo(napi_env env,napi_value workInfoData,bool isRepeat,uint32_t timeInterval,int32_t cycleCount)288 void SetRepeatInfo(napi_env env, napi_value workInfoData, bool isRepeat,
289 uint32_t timeInterval, int32_t cycleCount)
290 {
291 if (isRepeat) {
292 napi_value isRepeatValue;
293 napi_get_boolean(env, true, &isRepeatValue);
294 napi_set_named_property(env, workInfoData, "isRepeat", isRepeatValue);
295
296 napi_value repeatCycleTimeValue;
297 napi_create_uint32(env, timeInterval, &repeatCycleTimeValue);
298 napi_set_named_property(env, workInfoData, "repeatCycleTime", repeatCycleTimeValue);
299 } else {
300 napi_value repeatCycleTimeValue;
301 napi_create_uint32(env, timeInterval, &repeatCycleTimeValue);
302 napi_set_named_property(env, workInfoData, "repeatCycleTime", repeatCycleTimeValue);
303
304 napi_value repeatCountValue;
305 napi_create_int32(env, cycleCount, &repeatCountValue);
306 napi_set_named_property(env, workInfoData, "repeatCount", repeatCountValue);
307 }
308 }
309
SetDeepIdleInfo(napi_env env,napi_value workInfoData,WorkCondition::DeepIdle value)310 void SetDeepIdleInfo(napi_env env, napi_value workInfoData, WorkCondition::DeepIdle value)
311 {
312 if (value == WorkCondition::DeepIdle::DEEP_IDLE_UNKNOWN) {
313 return;
314 }
315 napi_value isDeepIdle;
316 napi_get_boolean(env, (value == WorkCondition::DeepIdle::DEEP_IDLE_IN), &isDeepIdle);
317 napi_set_named_property(env, workInfoData, "isDeepIdle", isDeepIdle);
318 }
319
CallFuncation(napi_env env,napi_value workInfoData,std::unique_ptr<NativeReference> & jsObj_,const char * functionName)320 bool CallFuncation(napi_env env, napi_value workInfoData,
321 std::unique_ptr<NativeReference> &jsObj_, const char* functionName)
322 {
323 napi_value argv[] = {workInfoData};
324 if (!jsObj_) {
325 WS_HILOGE("WorkSchedulerExtension Not found js");
326 return false;
327 }
328
329 napi_value value = jsObj_->GetNapiValue();
330 if (value == nullptr) {
331 WS_HILOGE("WorkSchedulerExtension Failed to get WorkSchedulerExtension object");
332 return false;
333 }
334
335 napi_value method;
336 napi_get_named_property(env, value, functionName, &method);
337 if (method == nullptr) {
338 WS_HILOGE("WorkSchedulerExtension call function %{public}s error, method name is nullptr", functionName);
339 return false;
340 }
341
342 napi_value callFunctionResult;
343 if (napi_call_function(env, value, method, 1, argv, &callFunctionResult) != napi_ok) {
344 WS_HILOGE("WorkSchedulerExtension call function %{public}s error", functionName);
345 return false;
346 }
347
348 return true;
349 }
350
OnWorkStart(WorkInfo & workInfo)351 void JsWorkSchedulerExtension::OnWorkStart(WorkInfo& workInfo)
352 {
353 if (handler_ == nullptr) {
354 return;
355 }
356 WS_HILOGD("begin.");
357 int32_t workId = workInfo.GetWorkId();
358 std::string bundleName = workInfo.GetBundleName();
359 std::string abilityName = workInfo.GetAbilityName();
360 bool isPersisted = workInfo.IsPersisted();
361 WorkCondition::Network networkType = workInfo.GetNetworkType();
362 WorkCondition::Charger charger = workInfo.GetChargerType();
363 int32_t batteryLevel = workInfo.GetBatteryLevel();
364 WorkCondition::BatteryStatus batteryStatus = workInfo.GetBatteryStatus();
365 WorkCondition::Storage storageLevel = workInfo.GetStorageLevel();
366 uint32_t timeInterval = workInfo.GetTimeInterval();
367 bool isRepeat = workInfo.IsRepeat();
368 int32_t cycleCount = workInfo.GetCycleCount();
369 WorkCondition::DeepIdle deepIdleValue = workInfo.GetDeepIdle();
370 std::string extrasStr;
371 bool getExtrasRet = GetExtrasJsonStr(workInfo, extrasStr);
372 WorkSchedulerExtension::OnWorkStart(workInfo);
373 auto task = [=]() {
374 AbilityRuntime::HandleScope handleScope(jsRuntime_);
375 napi_env env = jsRuntime_.GetNapiEnv();
376
377 napi_value workInfoData;
378 if (napi_create_object(env, &workInfoData) != napi_ok) {
379 WS_HILOGE("WorkSchedulerExtension failed to create workInfoData OnWorkStart");
380 return;
381 }
382
383 SetCommonInfo(env, workInfoData, workId, bundleName, abilityName);
384 SetExtrasInfo(env, workInfoData, getExtrasRet, extrasStr);
385 SetPersistedInfo(env, workInfoData, isPersisted);
386 SetNetWorkInfo(env, workInfoData, networkType);
387 SetChargerTypeInfo(env, workInfoData, charger);
388 SetBatteryInfo(env, workInfoData, batteryLevel, batteryStatus);
389 SetStorageInfo(env, workInfoData, storageLevel);
390 SetDeepIdleInfo(env, workInfoData, deepIdleValue);
391
392 if (timeInterval > 0) {
393 SetRepeatInfo(env, workInfoData, isRepeat, timeInterval, cycleCount);
394 }
395
396 HitraceScoped traceScoped(HITRACE_TAG_OHOS, "JsWorkSchedulerExtension::onWorkStart");
397 if (!CallFuncation(env, workInfoData, jsObj_, "onWorkStart")) {
398 return;
399 }
400 };
401 handler_->PostTask(task);
402 }
403
OnWorkStop(WorkInfo & workInfo)404 void JsWorkSchedulerExtension::OnWorkStop(WorkInfo& workInfo)
405 {
406 if (handler_ == nullptr) {
407 return;
408 }
409 WS_HILOGD("begin.");
410 int32_t workId = workInfo.GetWorkId();
411 std::string bundleName = workInfo.GetBundleName();
412 std::string abilityName = workInfo.GetAbilityName();
413 bool isPersisted = workInfo.IsPersisted();
414 WorkCondition::Network networkType = workInfo.GetNetworkType();
415 WorkCondition::Charger charger = workInfo.GetChargerType();
416 int32_t batteryLevel = workInfo.GetBatteryLevel();
417 WorkCondition::BatteryStatus batteryStatus = workInfo.GetBatteryStatus();
418 WorkCondition::Storage storageLevel = workInfo.GetStorageLevel();
419 uint32_t timeInterval = workInfo.GetTimeInterval();
420 bool isRepeat = workInfo.IsRepeat();
421 int32_t cycleCount = workInfo.GetCycleCount();
422 WorkCondition::DeepIdle deepIdleValue = workInfo.GetDeepIdle();
423 std::string extrasStr;
424 bool getExtrasRet = GetExtrasJsonStr(workInfo, extrasStr);
425 WorkSchedulerExtension::OnWorkStop(workInfo);
426 auto task = [=]() {
427 AbilityRuntime::HandleScope handleScope(jsRuntime_);
428 napi_env env = jsRuntime_.GetNapiEnv();
429
430 napi_value workInfoData;
431 if (napi_create_object(env, &workInfoData) != napi_ok) {
432 WS_HILOGE("WorkSchedulerExtension failed to create workInfoData OnWorkStop");
433 return;
434 }
435
436 SetCommonInfo(env, workInfoData, workId, bundleName, abilityName);
437 SetExtrasInfo(env, workInfoData, getExtrasRet, extrasStr);
438 SetPersistedInfo(env, workInfoData, isPersisted);
439 SetNetWorkInfo(env, workInfoData, networkType);
440 SetChargerTypeInfo(env, workInfoData, charger);
441 SetBatteryInfo(env, workInfoData, batteryLevel, batteryStatus);
442 SetStorageInfo(env, workInfoData, storageLevel);
443 SetDeepIdleInfo(env, workInfoData, deepIdleValue);
444
445 if (timeInterval > 0) {
446 SetRepeatInfo(env, workInfoData, isRepeat, timeInterval, cycleCount);
447 }
448
449 HitraceScoped traceScoped(HITRACE_TAG_OHOS, "JsWorkSchedulerExtension::onWorkStop");
450 if (!CallFuncation(env, workInfoData, jsObj_, "onWorkStop")) {
451 return;
452 }
453 };
454 handler_->PostTask(task);
455 }
456
GetSrcPath(std::string & srcPath)457 void JsWorkSchedulerExtension::GetSrcPath(std::string &srcPath)
458 {
459 if (!Extension::abilityInfo_->isStageBasedModel) {
460 /* temporary compatibility api8 + config.json */
461 srcPath.append(Extension::abilityInfo_->package);
462 srcPath.append("/assets/js/");
463 if (!Extension::abilityInfo_->srcPath.empty()) {
464 srcPath.append(Extension::abilityInfo_->srcPath);
465 }
466 srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
467 return;
468 }
469
470 if (!Extension::abilityInfo_->srcEntrance.empty()) {
471 srcPath.append(Extension::abilityInfo_->moduleName + "/");
472 srcPath.append(Extension::abilityInfo_->srcEntrance);
473 srcPath.erase(srcPath.rfind('.'));
474 srcPath.append(".abc");
475 }
476 }
477
GetExtrasJsonStr(const WorkInfo & workInfo,std::string & extrasStr)478 bool JsWorkSchedulerExtension::GetExtrasJsonStr(const WorkInfo& workInfo, std::string& extrasStr)
479 {
480 std::shared_ptr<AAFwk::WantParams> extras = workInfo.GetExtras();
481 nlohmann::json extrasJson;
482 if (!extras) {
483 WS_HILOGD("parameter is null.");
484 return false;
485 }
486 auto extrasMap = extras->GetParams();
487 int typeId = INVALID_VALUE;
488 for (auto it : extrasMap) {
489 typeId = AAFwk::WantParams::GetDataType(it.second);
490 if (typeId != INVALID_VALUE) {
491 std::string value = AAFwk::WantParams::GetStringByType(it.second, typeId);
492 extrasJson[it.first] = value;
493 } else {
494 WS_HILOGE("parameters type not supported.");
495 }
496 }
497 extrasStr = extrasJson.dump(JSON_INDENT_WIDTH);
498 return true;
499 }
500 } // namespace WorkScheduler
501 } // namespace OHOS
502