1 /*
2 * Copyright (c) 2023 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 "device_timed_collect.h"
17
18 #include <algorithm>
19
20 #ifdef PREFERENCES_ENABLE
21 #include "preferences_errno.h"
22 #include "preferences_helper.h"
23 #include "preferences_value.h"
24 #endif
25 #include "sam_log.h"
26 #include "sa_profiles.h"
27 #include "system_ability_manager.h"
28 #include "samgr_time_handler.h"
29 #include <cinttypes>
30
31 using namespace std;
32
33 namespace OHOS {
34 namespace {
35 constexpr const char* LOOP_EVENT = "loopevent";
36 constexpr const char* AWAKE_LOOP_EVENT = "awakeloopevent";
37 constexpr const char* ORDER_TIMED_EVENT = "timedevent";
38 constexpr int32_t MIN_INTERVAL = 30;
39 constexpr int32_t MIN_AWAKE_INTERVAL = 3600;
40 }
41
DeviceTimedCollect(const sptr<IReport> & report)42 DeviceTimedCollect::DeviceTimedCollect(const sptr<IReport>& report)
43 : ICollectPlugin(report)
44 {
45 }
46
Init(const std::list<SaProfile> & saProfiles)47 void DeviceTimedCollect::Init(const std::list<SaProfile>& saProfiles)
48 {
49 for (auto& saProfile : saProfiles) {
50 for (auto& onDemandEvent : saProfile.startOnDemand.onDemandEvents) {
51 SaveTimedEvent(onDemandEvent);
52 }
53 for (auto& onDemandEvent : saProfile.stopOnDemand.onDemandEvents) {
54 SaveTimedEvent(onDemandEvent);
55 }
56 }
57 HILOGD("DeviceTimedCollect timedSet count: %{public}zu", nonPersitenceLoopEventSet_.size());
58 }
59
ProcessPersistenceTasks()60 void DeviceTimedCollect::ProcessPersistenceTasks()
61 {
62 #ifdef PREFERENCES_ENABLE
63 preferencesUtil_ = PreferencesUtil::GetInstance();
64 std::map<std::string, NativePreferences::PreferencesValue> allData = preferencesUtil_->ObtainAll();
65 int64_t currentTime = TimeUtils::GetTimestamp();
66 for (const auto& [strInterval, triggerTime] : allData) {
67 if (strInterval.find("_") != std::string::npos) {
68 continue;
69 }
70 int64_t disTime = static_cast<int64_t>(triggerTime) - currentTime;
71 if (strInterval.find(':') != string::npos) {
72 ProcessPersistenceTimedTask(disTime, strInterval);
73 return;
74 }
75 ProcessPersistenceLoopTask(disTime, static_cast<int64_t>(triggerTime), strInterval);
76 }
77 #endif
78 }
79
ProcessPersistenceTimedTask(int64_t disTime,std::string timeString)80 void DeviceTimedCollect::ProcessPersistenceTimedTask(int64_t disTime, std::string timeString)
81 {
82 #ifdef PREFERENCES_ENABLE
83 if (disTime <= 0) {
84 OnDemandEvent event = { TIMED_EVENT, ORDER_TIMED_EVENT, timeString, -1, true };
85 ReportEvent(event);
86 preferencesUtil_->Remove(timeString);
87 return;
88 }
89 auto timedTask = [this, timeString] () {
90 OnDemandEvent event = { TIMED_EVENT, ORDER_TIMED_EVENT, timeString, -1, true };
91 ReportEvent(event);
92 preferencesUtil_->Remove(timeString);
93 };
94 if (!SamgrTimeHandler::GetInstance()->PostTask(timedTask, disTime)) {
95 PostDelayTask(timedTask, disTime);
96 }
97 #endif
98 }
99
ProcessPersistenceLoopTask(int64_t disTime,int64_t triggerTime,std::string strInterval)100 void DeviceTimedCollect::ProcessPersistenceLoopTask(int64_t disTime, int64_t triggerTime, std::string strInterval)
101 {
102 int64_t interval = atoi(strInterval.c_str());
103 {
104 lock_guard<samgr::mutex> autoLock(persitenceLoopEventSetLock_);
105 if (persitenceLoopTasks_.count(interval) > 0) {
106 return;
107 }
108 }
109 #ifdef PREFERENCES_ENABLE
110 int64_t currentTime = TimeUtils::GetTimestamp();
111 if (static_cast<int64_t>(triggerTime) - interval > currentTime) {
112 HILOGW("currentTime is not true");
113 return;
114 }
115 #endif
116 if (interval < MIN_INTERVAL) {
117 HILOGW("interval is not true");
118 return;
119 }
120 auto task = [this, interval] () {
121 lock_guard<samgr::mutex> autoLock(persitenceLoopEventSetLock_);
122 if (persitenceLoopTasks_.find(interval) != persitenceLoopTasks_.end()) {
123 HILOGI("DeviceTimedCollect Persistence ReportEvent interval: %{public}" PRId64, interval);
124 ReportEventByTimeInfo(interval, true);
125 PostPersistenceDelayTask(persitenceLoopTasks_[interval], interval, interval);
126 } else {
127 HILOGI("DeviceTimedCollect Persistence interval %{public}" PRId64 " has been remove", interval);
128 }
129 };
130 {
131 lock_guard<samgr::mutex> autoLock(persitenceLoopEventSetLock_);
132 persitenceLoopTasks_[interval] = task;
133 }
134 if (disTime <= 0) {
135 ReportEventByTimeInfo(interval, true);
136 // In order to enable the timer to start on time next time and make up for the missing time
137 disTime = interval - abs(disTime) % interval;
138 PostPersistenceDelayTask(task, interval, disTime);
139 } else {
140 PostDelayTaskByTimeInfo(task, interval, disTime);
141 }
142 }
143
ReportEventByTimeInfo(int32_t interval,bool persistence)144 void DeviceTimedCollect::ReportEventByTimeInfo(int32_t interval, bool persistence)
145 {
146 lock_guard<samgr::mutex> autoLock(timeInfosLock_);
147 if (timeInfos_.count(interval) == 0) {
148 return;
149 }
150 if (timeInfos_[interval].normal) {
151 OnDemandEvent event = { TIMED_EVENT, LOOP_EVENT, to_string(interval), -1, persistence };
152 HILOGI("report normal:%{public}d ,persistence:%{public}d", interval, persistence);
153 ReportEvent(event);
154 }
155 if (timeInfos_[interval].awake) {
156 OnDemandEvent event = { TIMED_EVENT, AWAKE_LOOP_EVENT, to_string(interval), -1, persistence };
157 HILOGI("report awake:%{public}d ,persistence:%{public}d", interval, persistence);
158 ReportEvent(event);
159 }
160 }
161
SaveTimedInfos(const OnDemandEvent & onDemandEvent,int32_t interval)162 void DeviceTimedCollect::SaveTimedInfos(const OnDemandEvent& onDemandEvent, int32_t interval)
163 {
164 lock_guard<samgr::mutex> autoLock(timeInfosLock_);
165 if (timeInfos_.count(interval) == 0) {
166 TimeInfo info;
167 timeInfos_[interval] = info;
168 }
169 if (onDemandEvent.name == LOOP_EVENT) {
170 timeInfos_[interval].normal = true;
171 }
172 if (onDemandEvent.name == AWAKE_LOOP_EVENT) {
173 timeInfos_[interval].awake = true;
174 }
175 HILOGI("SaveTimedInfos : %{public}d : %{public}d , %{public}d", interval,
176 timeInfos_[interval].normal, timeInfos_[interval].awake);
177 }
178
SaveTimedEvent(const OnDemandEvent & onDemandEvent)179 void DeviceTimedCollect::SaveTimedEvent(const OnDemandEvent& onDemandEvent)
180 {
181 if (onDemandEvent.eventId == TIMED_EVENT &&
182 (onDemandEvent.name == LOOP_EVENT || onDemandEvent.name == AWAKE_LOOP_EVENT)) {
183 HILOGI("DeviceTimedCollect save timed task: %{public}s", onDemandEvent.value.c_str());
184 int32_t interval = atoi(onDemandEvent.value.c_str());
185 if (interval < MIN_INTERVAL) {
186 HILOGE("DeviceTimedCollect invalid interval %{public}s", onDemandEvent.value.c_str());
187 return;
188 }
189 if (interval < MIN_AWAKE_INTERVAL && onDemandEvent.name == AWAKE_LOOP_EVENT) {
190 HILOGE("SaveTimedEvent awake clock invalid interval: %{public}d", interval);
191 return;
192 }
193 if (onDemandEvent.persistence) {
194 lock_guard<samgr::mutex> autoLock(persitenceLoopEventSetLock_);
195 persitenceLoopEventSet_.insert(interval);
196 } else {
197 lock_guard<samgr::mutex> autoLock(nonPersitenceLoopEventSetLock_);
198 nonPersitenceLoopEventSet_.insert(interval);
199 }
200 SaveTimedInfos(onDemandEvent, interval);
201 }
202 }
203
PostPersistenceLoopTaskLocked(int32_t interval)204 void DeviceTimedCollect::PostPersistenceLoopTaskLocked(int32_t interval)
205 {
206 if (persitenceLoopTasks_.count(interval) > 0) {
207 return;
208 }
209 persitenceLoopTasks_[interval] = [this, interval] () {
210 lock_guard<samgr::mutex> autoLock(persitenceLoopEventSetLock_);
211 if (persitenceLoopTasks_.find(interval) != persitenceLoopTasks_.end()) {
212 HILOGI("DeviceTimedCollect PostPersistence ReportEvent interval: %{public}d", interval);
213 ReportEventByTimeInfo(interval, true);
214 PostPersistenceDelayTask(persitenceLoopTasks_[interval], interval, interval);
215 } else {
216 HILOGI("DeviceTimedCollect PostPersistence interval %{public}d has been remove", interval);
217 }
218 };
219 PostPersistenceDelayTask(persitenceLoopTasks_[interval], interval, interval);
220 }
221
PostNonPersistenceLoopTaskLocked(int32_t interval)222 void DeviceTimedCollect::PostNonPersistenceLoopTaskLocked(int32_t interval)
223 {
224 if (nonPersitenceLoopTasks_.count(interval) > 0) {
225 HILOGE("DeviceTimedCollect interval has been post");
226 return;
227 }
228 nonPersitenceLoopTasks_[interval] = [this, interval] () {
229 lock_guard<samgr::mutex> autoLock(nonPersitenceLoopEventSetLock_);
230 if (nonPersitenceLoopEventSet_.find(interval) != nonPersitenceLoopEventSet_.end()) {
231 HILOGI("DeviceTimedCollect ReportEvent interval: %{public}d", interval);
232 ReportEventByTimeInfo(interval, false);
233 PostDelayTaskByTimeInfo(nonPersitenceLoopTasks_[interval], interval, interval);
234 } else {
235 HILOGI("DeviceTimedCollect interval %{public}d has been remove", interval);
236 }
237 };
238 PostDelayTaskByTimeInfo(nonPersitenceLoopTasks_[interval], interval, interval);
239 }
240
PostDelayTaskByTimeInfo(std::function<void ()> callback,int32_t interval,int32_t disTime)241 void DeviceTimedCollect::PostDelayTaskByTimeInfo(std::function<void()> callback,
242 int32_t interval, int32_t disTime)
243 {
244 lock_guard<samgr::mutex> autoLock(timeInfosLock_);
245 if (timeInfos_.count(interval) == 0) {
246 return;
247 }
248 if (timeInfos_[interval].awake) {
249 if (!SamgrTimeHandler::GetInstance()->PostTask(callback, disTime)) {
250 PostDelayTask(callback, disTime);
251 }
252 } else {
253 PostDelayTask(callback, disTime);
254 }
255 }
256
PostPersistenceDelayTask(std::function<void ()> postTask,int32_t interval,int32_t disTime)257 void DeviceTimedCollect::PostPersistenceDelayTask(std::function<void()> postTask,
258 int32_t interval, int32_t disTime)
259 {
260 #ifdef PREFERENCES_ENABLE
261 int64_t currentTime = TimeUtils::GetTimestamp();
262 int64_t upgradeTime = currentTime + static_cast<int64_t>(disTime);
263 preferencesUtil_->SaveLong(to_string(interval), upgradeTime);
264 PostDelayTaskByTimeInfo(postTask, interval, disTime);
265 HILOGI("save persistence time %{public}d, interval time %{public}d", static_cast<int32_t>(upgradeTime), interval);
266 #endif
267 }
268
OnStart()269 int32_t DeviceTimedCollect::OnStart()
270 {
271 HILOGI("DeviceTimedCollect OnStart called");
272 ProcessPersistenceTasks();
273 PostNonPersistenceLoopTasks();
274 PostPersistenceLoopTasks();
275 return ERR_OK;
276 }
277
PostNonPersistenceLoopTasks()278 void DeviceTimedCollect::PostNonPersistenceLoopTasks()
279 {
280 lock_guard<samgr::mutex> autoLock(nonPersitenceLoopEventSetLock_);
281 for (auto it = nonPersitenceLoopEventSet_.begin(); it != nonPersitenceLoopEventSet_.end(); ++it) {
282 HILOGI("DeviceTimedCollect send task: %{public}d", *it);
283 PostNonPersistenceLoopTaskLocked(*it);
284 }
285 }
286
PostPersistenceLoopTasks()287 void DeviceTimedCollect::PostPersistenceLoopTasks()
288 {
289 lock_guard<samgr::mutex> autoLock(persitenceLoopEventSetLock_);
290 for (auto it = persitenceLoopEventSet_.begin(); it != persitenceLoopEventSet_.end(); ++it) {
291 HILOGI("DeviceTimedCollect send persitence task: %{public}d", *it);
292 PostPersistenceLoopTaskLocked(*it);
293 }
294 }
295
OnStop()296 int32_t DeviceTimedCollect::OnStop()
297 {
298 HILOGI("DeviceTimedCollect OnStop called");
299 return ERR_OK;
300 }
301
CalculateDelayTime(const std::string & timeString)302 int64_t DeviceTimedCollect::CalculateDelayTime(const std::string& timeString)
303 {
304 std::tm inputTime;
305 strptime(const_cast<char*>(timeString.c_str()), "%Y-%m-%d-%H:%M:%S", &inputTime);
306 std::time_t orderTime = mktime(&inputTime);
307 int64_t timeGap = orderTime - time(nullptr);
308 return timeGap;
309 }
310
PostPersistenceTimedTaskLocked(std::string timeString,int64_t timeGap)311 void DeviceTimedCollect::PostPersistenceTimedTaskLocked(std::string timeString, int64_t timeGap)
312 {
313 #ifdef PREFERENCES_ENABLE
314 if (timeGap <= 0) {
315 HILOGE("PostPersistenceTimedTask invalid timeGap: %{public}" PRId64 "ms", timeGap);
316 return;
317 }
318 auto timedTask = [this, timeString] () {
319 OnDemandEvent event = { TIMED_EVENT, ORDER_TIMED_EVENT, timeString, -1, true };
320 ReportEvent(event);
321 preferencesUtil_->Remove(timeString);
322 };
323 int64_t currentTime = TimeUtils::GetTimestamp();
324 int64_t upgradeTime = currentTime + timeGap;
325 preferencesUtil_->SaveLong(timeString, upgradeTime);
326 if (!SamgrTimeHandler::GetInstance()->PostTask(timedTask, timeGap)) {
327 PostDelayTask(timedTask, timeGap);
328 }
329 #endif
330 }
331
PostNonPersistenceTimedTaskLocked(std::string timeString,int64_t timeGap)332 void DeviceTimedCollect::PostNonPersistenceTimedTaskLocked(std::string timeString, int64_t timeGap)
333 {
334 auto timedTask = [this, timeString] () {
335 OnDemandEvent event = { TIMED_EVENT, ORDER_TIMED_EVENT, timeString };
336 ReportEvent(event);
337 };
338 if (timeGap <= 0) {
339 HILOGE("PostNonPersistenceTimedTask invalid timeGap: %{public}" PRId64 "ms", timeGap);
340 return;
341 }
342 if (!SamgrTimeHandler::GetInstance()->PostTask(timedTask, timeGap)) {
343 PostDelayTask(timedTask, timeGap);
344 }
345 }
346
AddCollectEvent(const std::vector<OnDemandEvent> & events)347 int32_t DeviceTimedCollect::AddCollectEvent(const std::vector<OnDemandEvent>& events)
348 {
349 for (auto& event : events) {
350 if (event.name != LOOP_EVENT && event.name != ORDER_TIMED_EVENT && event.name != AWAKE_LOOP_EVENT) {
351 HILOGE("DeviceTimedCollect invalid event name: %{public}s", event.name.c_str());
352 return ERR_INVALID_VALUE;
353 }
354 if (event.name == ORDER_TIMED_EVENT) {
355 int64_t timeGap = CalculateDelayTime(event.value);
356 #ifdef PREFERENCES_ENABLE
357 if (event.persistence) {
358 std::lock_guard<samgr::mutex> autoLock(persitenceTimedEventSetLock_);
359 PostPersistenceTimedTaskLocked(event.value, timeGap);
360 continue;
361 }
362 #endif
363 std::lock_guard<samgr::mutex> autoLock(nonPersitenceTimedEventSetLock);
364 PostNonPersistenceTimedTaskLocked(event.value, timeGap);
365 continue;
366 }
367 if (event.persistence) {
368 HILOGE("invalid event persistence, loopevent is not support persistence");
369 return ERR_INVALID_VALUE;
370 }
371 int32_t interval = atoi(event.value.c_str());
372 if (interval < MIN_INTERVAL) {
373 HILOGE("DeviceTimedCollect invalid interval: %{public}d", interval);
374 return ERR_INVALID_VALUE;
375 }
376 if (interval < MIN_AWAKE_INTERVAL && event.name == AWAKE_LOOP_EVENT) {
377 HILOGE("DeviceTimedCollect awake clock invalid interval: %{public}d", interval);
378 return ERR_INVALID_VALUE;
379 }
380 SaveTimedInfos(event, interval);
381 std::lock_guard<samgr::mutex> autoLock(nonPersitenceLoopEventSetLock_);
382 auto iter = nonPersitenceLoopEventSet_.find(interval);
383 if (iter != nonPersitenceLoopEventSet_.end()) {
384 continue;
385 }
386 HILOGI("DeviceTimedCollect add collect events: %{public}d", interval);
387 nonPersitenceLoopEventSet_.insert(interval);
388 PostNonPersistenceLoopTaskLocked(interval);
389 }
390 return ERR_OK;
391 }
392
RemoveUnusedEvent(const OnDemandEvent & event)393 int32_t DeviceTimedCollect::RemoveUnusedEvent(const OnDemandEvent& event)
394 {
395 if (event.name != LOOP_EVENT && event.name != AWAKE_LOOP_EVENT) {
396 HILOGE("DeviceTimedCollect invalid event name: %{public}s", event.name.c_str());
397 return ERR_INVALID_VALUE;
398 }
399 int32_t interval = atoi(event.value.c_str());
400 if (event.persistence) {
401 RemovePersistenceLoopTask(interval);
402 } else {
403 RemoveNonPersistenceLoopTask(interval);
404 }
405 RemoveTimesInfo(event, interval);
406 return ERR_OK;
407 }
408
RemoveTimesInfo(const OnDemandEvent & onDemandEvent,int32_t interval)409 void DeviceTimedCollect::RemoveTimesInfo(const OnDemandEvent& onDemandEvent, int32_t interval)
410 {
411 lock_guard<samgr::mutex> autoLock(timeInfosLock_);
412 if (timeInfos_.count(interval) == 0) {
413 return;
414 }
415 if (onDemandEvent.name == LOOP_EVENT) {
416 timeInfos_[interval].normal = false;
417 }
418 if (onDemandEvent.name == AWAKE_LOOP_EVENT) {
419 timeInfos_[interval].awake = false;
420 }
421 HILOGI("RemoveTimesInfo : %{public}d : %{public}d , %{public}d", interval,
422 timeInfos_[interval].normal, timeInfos_[interval].awake);
423 if (!timeInfos_[interval].normal && !timeInfos_[interval].awake) {
424 timeInfos_.erase(interval);
425 }
426 }
427
RemoveNonPersistenceLoopTask(int32_t interval)428 void DeviceTimedCollect::RemoveNonPersistenceLoopTask(int32_t interval)
429 {
430 std::lock_guard<samgr::mutex> autoLock(nonPersitenceLoopEventSetLock_);
431 auto iter = nonPersitenceLoopEventSet_.find(interval);
432 if (iter != nonPersitenceLoopEventSet_.end()) {
433 nonPersitenceLoopEventSet_.erase(iter);
434 nonPersitenceLoopTasks_.erase(interval);
435 }
436 }
437
RemovePersistenceLoopTask(int32_t interval)438 void DeviceTimedCollect::RemovePersistenceLoopTask(int32_t interval)
439 {
440 std::lock_guard<samgr::mutex> autoLock(persitenceLoopEventSetLock_);
441 auto iter = persitenceLoopEventSet_.find(interval);
442 if (iter != persitenceLoopEventSet_.end()) {
443 persitenceLoopEventSet_.erase(iter);
444 persitenceLoopTasks_.erase(interval);
445 }
446 }
447 }
448