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 "work_scheduler_ffi.h"
17 #include "workscheduler_srv_client.h"
18 #include "work_sched_errors.h"
19 #include "work_scheduler_log.h"
20 #include "want_params_wrapper.h"
21 #include "bool_wrapper.h"
22 #include "double_wrapper.h"
23 #include "int_wrapper.h"
24 #include "string_wrapper.h"
25
26 namespace OHOS {
27 namespace WorkScheduler {
28
29 template <class T, class IT, class NativeT>
InnerWrapWantParamsT(const sptr<AAFwk::IInterface> iIt,CParameters * p)30 int32_t InnerWrapWantParamsT(const sptr<AAFwk::IInterface> iIt, CParameters *p)
31 {
32 NativeT natValue = T::Unbox(IT::Query(iIt));
33 NativeT *ptr = static_cast<NativeT *>(malloc(sizeof(NativeT)));
34 if (ptr == nullptr) {
35 LOGE("natValue ptr is nullptr, no memory.");
36 return ERR_NO_MEMORY;
37 }
38 *ptr = natValue;
39 p->value = static_cast<void*>(ptr);
40 p->size = sizeof(NativeT);
41 return 0;
42 }
43
GetWorkInfoV2(RetWorkInfoV2 cwork,WorkInfo & workInfo)44 int32_t GetWorkInfoV2(RetWorkInfoV2 cwork, WorkInfo& workInfo)
45 {
46 auto ret = GetWorkInfo(cwork.v1, workInfo);
47 if (ret != 0) {
48 return ret;
49 }
50 return GetExtrasInfo(cwork, workInfo);
51 }
52
ParseWorkInfoV2(std::shared_ptr<WorkInfo> workInfo,RetWorkInfoV2 & cwork)53 void ParseWorkInfoV2(std::shared_ptr<WorkInfo> workInfo, RetWorkInfoV2& cwork)
54 {
55 ParseWorkInfo(workInfo, cwork.v1);
56 ParseExtrasInfo(workInfo, cwork.parameters);
57 }
58
59 extern "C" {
60 const int32_t BATTERY_LEVEL_MIN = 0;
61 const int32_t BATTERY_LEVEL_MAX = 100;
62
63 const int8_t INT_TYPE = 0;
64 const int8_t F64_TYPE = 1;
65 const int8_t STRING_TYPE = 2;
66 const int8_t BOOL_TYPE = 3;
67 // need to be same as WantParams
68 enum {
69 VALUE_TYPE_NULL = -1,
70 VALUE_TYPE_BOOLEAN = 1,
71 VALUE_TYPE_INT = 5,
72 VALUE_TYPE_DOUBLE = 8,
73 VALUE_TYPE_STRING = 9,
74 };
75
CJ_StartWork(RetWorkInfo work)76 int32_t CJ_StartWork(RetWorkInfo work)
77 {
78 WorkInfo workInfo = WorkInfo();
79 auto paraCode = GetWorkInfo(work, workInfo);
80 if (paraCode != SUCCESS_CODE) {
81 LOGE("WorkScheduler: CJ_StartWork parse parameter failed %{public}d", paraCode);
82 return paraCode;
83 }
84 ErrCode errCode = WorkSchedulerSrvClient::GetInstance().StartWork(workInfo);
85 return errCode;
86 }
87
CJ_StopWork(RetWorkInfo work,bool needCancel)88 int32_t CJ_StopWork(RetWorkInfo work, bool needCancel)
89 {
90 WorkInfo workInfo = WorkInfo();
91 ErrCode errCode;
92 auto paraCode = GetWorkInfo(work, workInfo);
93 if (paraCode != SUCCESS_CODE) {
94 LOGE("WorkScheduler: CJ_StopWork parse parameter failed %{public}d", paraCode);
95 return paraCode;
96 }
97 if (needCancel) {
98 errCode = WorkSchedulerSrvClient::GetInstance().StopAndCancelWork(workInfo);
99 } else {
100 errCode = WorkSchedulerSrvClient::GetInstance().StopWork(workInfo);
101 }
102 return errCode;
103 }
104
CJ_GetWorkStatus(int32_t workId,RetWorkInfo & result)105 int32_t CJ_GetWorkStatus(int32_t workId, RetWorkInfo& result)
106 {
107 std::shared_ptr<WorkInfo> workInfo {nullptr};
108 ErrCode errCode = WorkSchedulerSrvClient::GetInstance().GetWorkStatus(workId, workInfo);
109 if (errCode != ERR_OK) {
110 LOGE("WorkScheduler: CJ_GetWorkStatus failed %{public}d", errCode);
111 return errCode;
112 }
113 ParseWorkInfo(workInfo, result);
114 LOGI("WorkScheduler: CJ_GetWorkStatus success");
115 return errCode;
116 }
117
CJ_ObtainAllWorks()118 RetArrRetWorkInfo CJ_ObtainAllWorks()
119 {
120 std::list<std::shared_ptr<WorkInfo>> workInfoList;
121 ErrCode errCode = WorkSchedulerSrvClient::GetInstance().ObtainAllWorks(workInfoList);
122 RetArrRetWorkInfo ret = { .code = errCode, .size = 0, .data = nullptr};
123 if (errCode != ERR_OK) {
124 LOGE("WorkScheduler: CJ_ObtainAllWorks failed ");
125 return ret;
126 }
127 int64_t listSize = static_cast<int64_t>(workInfoList.size());
128 if (listSize < 0 || listSize > UINT_MAX) {
129 LOGE("Illegal listSize parameter");
130 return ret;
131 }
132 auto data = static_cast<RetWorkInfo*>(malloc(sizeof(RetWorkInfo) * listSize));
133 if (data == nullptr) {
134 return ret;
135 }
136 ret.size = listSize;
137 int index = 0;
138 for (auto workInfo: workInfoList) {
139 ParseWorkInfo(workInfo, data[index]);
140 index++;
141 }
142 ret.data = data;
143 return ret;
144 }
145
CJ_IsLastWorkTimeOut(int32_t workId,bool & result)146 int32_t CJ_IsLastWorkTimeOut(int32_t workId, bool& result)
147 {
148 return WorkSchedulerSrvClient::GetInstance().IsLastWorkTimeout(workId, result);
149 }
150
CJ_StopAndClearWorks()151 int32_t CJ_StopAndClearWorks()
152 {
153 return WorkSchedulerSrvClient::GetInstance().StopAndClearWorks();
154 }
155
CJ_StartWorkV2(RetWorkInfoV2 work)156 int32_t CJ_StartWorkV2(RetWorkInfoV2 work)
157 {
158 WorkInfo workInfo = WorkInfo();
159 auto paraCode = GetWorkInfoV2(work, workInfo);
160 if (paraCode != SUCCESS_CODE) {
161 LOGE("WorkScheduler: CJ_StartWork parse parameter failed %{public}d", paraCode);
162 return paraCode;
163 }
164 ErrCode errCode = WorkSchedulerSrvClient::GetInstance().StartWork(workInfo);
165 return errCode;
166 }
167
CJ_StopWorkV2(RetWorkInfoV2 work,bool needCancel)168 int32_t CJ_StopWorkV2(RetWorkInfoV2 work, bool needCancel)
169 {
170 WorkInfo workInfo = WorkInfo();
171 ErrCode errCode;
172 auto paraCode = GetWorkInfoV2(work, workInfo);
173 if (paraCode != SUCCESS_CODE) {
174 LOGE("WorkScheduler: CJ_StopWork parse parameter failed %{public}d", paraCode);
175 return paraCode;
176 }
177 if (needCancel) {
178 errCode = WorkSchedulerSrvClient::GetInstance().StopAndCancelWork(workInfo);
179 } else {
180 errCode = WorkSchedulerSrvClient::GetInstance().StopWork(workInfo);
181 }
182 return errCode;
183 }
184
CJ_GetWorkStatusV2(int32_t workId,RetWorkInfoV2 & result)185 int32_t CJ_GetWorkStatusV2(int32_t workId, RetWorkInfoV2& result)
186 {
187 std::shared_ptr<WorkInfo> workInfo {nullptr};
188 ErrCode errCode = WorkSchedulerSrvClient::GetInstance().GetWorkStatus(workId, workInfo);
189 if (errCode != ERR_OK) {
190 LOGE("WorkScheduler: CJ_GetWorkStatus failed %{public}d", errCode);
191 return errCode;
192 }
193 ParseWorkInfoV2(workInfo, result);
194 LOGI("WorkScheduler: CJ_GetWorkStatus success");
195 return errCode;
196 }
197
CJ_ObtainAllWorksV2()198 RetArrRetWorkInfoV2 CJ_ObtainAllWorksV2()
199 {
200 std::list<std::shared_ptr<WorkInfo>> workInfoList;
201 ErrCode errCode = WorkSchedulerSrvClient::GetInstance().ObtainAllWorks(workInfoList);
202 RetArrRetWorkInfoV2 ret = { .code = errCode, .size = 0, .data = nullptr};
203 if (errCode != ERR_OK) {
204 LOGE("WorkScheduler: CJ_ObtainAllWorks failed ");
205 return ret;
206 }
207 int64_t listSize = static_cast<int64_t>(workInfoList.size());
208 if (listSize < 0 || listSize > UINT_MAX) {
209 LOGE("Illegal listSize parameter");
210 return ret;
211 }
212 auto data = static_cast<RetWorkInfoV2*>(malloc(sizeof(RetWorkInfoV2) * listSize));
213 if (data == nullptr) {
214 return ret;
215 }
216 ret.size = listSize;
217 int index = 0;
218 for (auto workInfo: workInfoList) {
219 ParseWorkInfoV2(workInfo, data[index]);
220 index++;
221 }
222 ret.data = data;
223 return ret;
224 }
225
226 // extra is not set
GetWorkInfo(RetWorkInfo cwork,WorkInfo & workInfo)227 int32_t GetWorkInfo(RetWorkInfo cwork, WorkInfo& workInfo)
228 {
229 workInfo.SetWorkId(cwork.workId);
230 workInfo.SetElement(std::string(cwork.bundleName), std::string(cwork.abilityName));
231 workInfo.RequestPersisted(cwork.isPersisted);
232 bool hasConditions = false;
233 int32_t ret = GetNetWorkInfo(cwork, workInfo, hasConditions);
234 if (ret != 0) {
235 return ret;
236 }
237 ret = GetChargeInfo(cwork, workInfo, hasConditions);
238 if (ret != 0) {
239 return ret;
240 }
241 ret = GetBatteryInfo(cwork, workInfo, hasConditions);
242 if (ret != 0) {
243 return ret;
244 }
245 ret = GetStorageInfo(cwork, workInfo, hasConditions);
246 if (ret != 0) {
247 return ret;
248 }
249 ret = GetRepeatInfo(cwork, workInfo, hasConditions);
250 if (ret != 0) {
251 return ret;
252 }
253
254 if (!hasConditions) {
255 LOGE("Set none conditions, so fail to init WorkInfo.");
256 return E_CONDITION_EMPTY;
257 }
258 return 0;
259 }
260
GetExtrasInfo(RetWorkInfoV2 cwork,OHOS::WorkScheduler::WorkInfo & workInfo)261 int32_t GetExtrasInfo(RetWorkInfoV2 cwork, OHOS::WorkScheduler::WorkInfo& workInfo)
262 {
263 int32_t code = 0;
264 CArrParameters cArrP = cwork.parameters;
265 AAFwk::WantParams wants;
266 if (cArrP.size == 0) {
267 return code;
268 }
269 for (auto i = 0; i < cArrP.size; ++i) {
270 std::string key = std::string(cArrP.head[i].key);
271 switch (cArrP.head[i].valueType) {
272 case INT_TYPE: {
273 int32_t *intVal = static_cast<int32_t *>(cArrP.head[i].value);
274 wants.SetParam(key, AAFwk::Integer::Box(*intVal));
275 break;
276 }
277 case F64_TYPE: {
278 double *doubleVal = static_cast<double *>(cArrP.head[i].value);
279 wants.SetParam(key, AAFwk::Double::Box(*doubleVal));
280 break;
281 }
282 case STRING_TYPE: {
283 std::string strVal(static_cast<char *>(cArrP.head[i].value));
284 wants.SetParam(key, AAFwk::String::Box(strVal));
285 break;
286 }
287 case BOOL_TYPE: {
288 bool *boolVal = static_cast<bool *>(cArrP.head[i].value);
289 wants.SetParam(key, AAFwk::Boolean::Box(*boolVal));
290 break;
291 }
292 default: {
293 LOGE("parameters type error.");
294 code = E_PARAMETERS_TYPE_ERR;
295 return code;
296 }
297 }
298 }
299 workInfo.RequestExtras(wants);
300 return code;
301 }
302
GetNetWorkInfo(RetWorkInfo cwork,WorkInfo & workInfo,bool & hasCondition)303 int32_t GetNetWorkInfo(RetWorkInfo cwork, WorkInfo& workInfo, bool& hasCondition)
304 {
305 int32_t code = 0;
306 if (cwork.netWorkType == UNSET_INT_PARAM) {
307 LOGI("Unset networkType.");
308 } else if (cwork.netWorkType >= WorkCondition::Network::NETWORK_TYPE_ANY &&
309 cwork.netWorkType <= WorkCondition::Network::NETWORK_TYPE_ETHERNET) {
310 workInfo.RequestNetworkType(WorkCondition::Network(cwork.netWorkType));
311 hasCondition = true;
312 } else {
313 LOGE("NetworkType set is invalid, just ignore set.");
314 code = E_NETWORK_TYPE_ERR;
315 }
316 return code;
317 }
318
GetChargeInfo(RetWorkInfo cwork,WorkInfo & workInfo,bool & hasCondition)319 int32_t GetChargeInfo(RetWorkInfo cwork, WorkInfo& workInfo, bool& hasCondition)
320 {
321 if (!cwork.isCharging) {
322 workInfo.RequestChargerType(false, WorkCondition::Charger::CHARGING_UNPLUGGED);
323 } else {
324 if (cwork.chargerType == UNSET_INT_PARAM) {
325 workInfo.RequestChargerType(true, WorkCondition::Charger::CHARGING_PLUGGED_ANY);
326 } else if (cwork.chargerType >= WorkCondition::Charger::CHARGING_PLUGGED_ANY &&
327 cwork.chargerType <= WorkCondition::Charger::CHARGING_PLUGGED_WIRELESS) {
328 workInfo.RequestChargerType(true, WorkCondition::Charger(cwork.chargerType));
329 hasCondition = true;
330 } else {
331 workInfo.RequestChargerType(true, WorkCondition::Charger::CHARGING_PLUGGED_ANY);
332 LOGE("ChargeType info is invalid, just ignore set.");
333 return E_CHARGER_TYPE_ERR;
334 }
335 }
336 return 0;
337 }
338
GetBatteryInfo(RetWorkInfo cwork,WorkInfo & workInfo,bool & hasCondition)339 int32_t GetBatteryInfo(RetWorkInfo cwork, WorkInfo& workInfo, bool& hasCondition)
340 {
341 if (cwork.batteryLevel == UNSET_INT_PARAM) {
342 LOGI("Unset batteryLevel.");
343 } else if (cwork.batteryLevel >= BATTERY_LEVEL_MIN && cwork.batteryLevel <= BATTERY_LEVEL_MAX) {
344 workInfo.RequestBatteryLevel(cwork.batteryLevel);
345 } else {
346 LOGE("BatteryLevel set is invalid, just ignore set.");
347 return E_BATTERY_LEVEL_ERR;
348 }
349
350 if (cwork.batteryStatus == UNSET_INT_PARAM) {
351 LOGI("Unset batteryStatus.");
352 } else if (cwork.batteryStatus >= WorkCondition::BatteryStatus::BATTERY_STATUS_LOW &&
353 cwork.batteryStatus <= WorkCondition::BatteryStatus::BATTERY_STATUS_LOW_OR_OKAY) {
354 workInfo.RequestBatteryStatus(WorkCondition::BatteryStatus(cwork.batteryStatus));
355 hasCondition = true;
356 } else {
357 LOGE("BatteryStatus set is invalid, just ignore set.");
358 return E_BATTERY_STATUS_ERR;
359 }
360 return 0;
361 }
362
GetStorageInfo(RetWorkInfo cwork,WorkInfo & workInfo,bool & hasCondition)363 int32_t GetStorageInfo(RetWorkInfo cwork, WorkInfo& workInfo, bool& hasCondition)
364 {
365 if (cwork.storageRequest == UNSET_INT_PARAM) {
366 LOGI("Unset StorageRequest.");
367 } else if (cwork.storageRequest >= WorkCondition::Storage::STORAGE_LEVEL_LOW &&
368 cwork.storageRequest <= WorkCondition::Storage::STORAGE_LEVEL_LOW_OR_OKAY) {
369 workInfo.RequestStorageLevel(WorkCondition::Storage(cwork.storageRequest));
370 hasCondition = true;
371 } else {
372 LOGE("StorageRequest set is invalid, just ignore set.");
373 return E_STORAGE_REQUEST_ERR;
374 }
375 return 0;
376 }
377
GetRepeatInfo(RetWorkInfo cwork,WorkInfo & workInfo,bool & hasCondition)378 int32_t GetRepeatInfo(RetWorkInfo cwork, WorkInfo& workInfo, bool& hasCondition)
379 {
380 if (cwork.repeatCycleTime == UNSET_INT_PARAM) {
381 LOGI("RepeatCycleTime not set, just ignore other repeat set.");
382 return 0;
383 }
384
385 if (!cwork.isRepeat && cwork.repeatCount == UNSET_INT_PARAM) {
386 LOGI("Not set isRepeat or repeatCount, ignore.");
387 return 0;
388 }
389 if (cwork.isRepeat) {
390 if (cwork.repeatCount > 0) {
391 LOGI("RepeatCount has been set , ignore isRepeat.");
392 workInfo.RequestRepeatCycle(cwork.repeatCycleTime, cwork.repeatCount);
393 } else {
394 workInfo.RequestRepeatCycle(cwork.repeatCycleTime);
395 }
396 hasCondition = true;
397 return 0;
398 } else {
399 if (cwork.repeatCount < 0) {
400 LOGE("RepeatCount is invalid, ignore.");
401 return E_REPEAT_COUNT_ERR;
402 }
403 workInfo.RequestRepeatCycle(cwork.repeatCycleTime, cwork.repeatCount);
404 hasCondition = true;
405 return 0;
406 }
407 }
408
ParseWorkInfo(std::shared_ptr<WorkInfo> workInfo,RetWorkInfo & cwork)409 void ParseWorkInfo(std::shared_ptr<WorkInfo> workInfo, RetWorkInfo& cwork)
410 {
411 cwork.workId = workInfo->GetWorkId();
412 cwork.bundleName = MallocCString(workInfo->GetBundleName());
413 cwork.abilityName = MallocCString(workInfo->GetAbilityName());
414 cwork.isPersisted = workInfo->IsPersisted();
415 cwork.netWorkType = workInfo->GetNetworkType();
416 auto chargerType = workInfo->GetChargerType();
417 if (chargerType >= WorkCondition::Charger::CHARGING_UNPLUGGED) {
418 cwork.isCharging = false;
419 cwork.chargerType = -1;
420 } else {
421 cwork.isCharging = true;
422 cwork.chargerType = chargerType;
423 }
424 cwork.batteryLevel = workInfo->GetBatteryLevel();
425 cwork.batteryStatus = workInfo->GetBatteryStatus();
426 cwork.storageRequest = workInfo->GetStorageLevel();
427 cwork.isRepeat = workInfo->IsRepeat();
428 cwork.repeatCycleTime = static_cast<int32_t>(workInfo->GetTimeInterval());
429 cwork.repeatCount = workInfo->GetCycleCount();
430 cwork.isDeepIdle = -1;
431 cwork.idleWaitTime = -1;
432 }
433
ConvertToCArrParameters(std::map<std::string,sptr<AAFwk::IInterface>> & extrasMap,CArrParameters & arrParam)434 void ConvertToCArrParameters(std::map<std::string, sptr<AAFwk::IInterface>>& extrasMap, CArrParameters& arrParam)
435 {
436 int typeId = VALUE_TYPE_NULL;
437 int i = 0;
438 int32_t mallocSize = static_cast<int32_t>(sizeof(CParameters) * arrParam.size);
439 arrParam.head = static_cast<CParameters *>(malloc(mallocSize));
440 if (!arrParam.head) {
441 arrParam.size = 0;
442 return;
443 }
444 for (auto it : extrasMap) {
445 typeId = AAFwk::WantParams::GetDataType(it.second);
446 arrParam.head[i].key = MallocCString(it.first);
447 switch (typeId) {
448 case VALUE_TYPE_INT: {
449 arrParam.head[i].valueType = INT_TYPE;
450 InnerWrapWantParamsT<AAFwk::Integer, AAFwk::IInteger, int>(it.second, &arrParam.head[i]);
451 break;
452 }
453 case VALUE_TYPE_DOUBLE: {
454 arrParam.head[i].valueType = F64_TYPE;
455 InnerWrapWantParamsT<AAFwk::Double, AAFwk::IDouble, double>(it.second, &arrParam.head[i]);
456 break;
457 }
458 case VALUE_TYPE_BOOLEAN: {
459 arrParam.head[i].valueType = BOOL_TYPE;
460 InnerWrapWantParamsT<AAFwk::Boolean, AAFwk::IBoolean, bool>(it.second, &arrParam.head[i]);
461 break;
462 }
463 case VALUE_TYPE_STRING: {
464 arrParam.head[i].valueType = STRING_TYPE;
465 InnerWrapWantParamsT<AAFwk::String, AAFwk::IString, std::string>(it.second, &arrParam.head[i]);
466 break;
467 }
468 default: {
469 LOGE("parameters type not supported.");
470 break;
471 }
472 }
473 ++i;
474 }
475 }
476
ParseExtrasInfo(std::shared_ptr<WorkInfo> workInfo,CArrParameters & arrParam)477 void ParseExtrasInfo(std::shared_ptr<WorkInfo> workInfo, CArrParameters &arrParam)
478 {
479 // init arrParam
480 arrParam.size = 0;
481 arrParam.head = nullptr;
482 std::shared_ptr<AAFwk::WantParams> extras = workInfo->GetExtras();
483 if (extras.get() == nullptr) {
484 LOGI("extras map is not initialized.");
485 return;
486 }
487 auto extrasMap = extras->GetParams();
488 arrParam.size = static_cast<int64_t>(extrasMap.size());
489 if (extrasMap.size() == 0) {
490 LOGI("extras parameters is 0.");
491 return;
492 }
493 ConvertToCArrParameters(extrasMap, arrParam);
494 }
495
MallocCString(const std::string & origin)496 char* MallocCString(const std::string& origin)
497 {
498 if (origin.empty()) {
499 return nullptr;
500 }
501 auto len = origin.length() + 1;
502 char* res = static_cast<char*>(malloc(sizeof(char) * len));
503 if (res == nullptr) {
504 return nullptr;
505 }
506 return std::char_traits<char>::copy(res, origin.c_str(), len);
507 }
508 }
509 } // WorkScheduler
510 } // OHOS