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 if (persitenceLoopTasks_.count(interval) > 0) {
104 return;
105 }
106 #ifdef PREFERENCES_ENABLE
107 int64_t currentTime = TimeUtils::GetTimestamp();
108 if (static_cast<int64_t>(triggerTime) - interval > currentTime) {
109 HILOGW("currentTime is not true");
110 return;
111 }
112 #endif
113 if (interval < MIN_INTERVAL) {
114 HILOGW("interval is not true");
115 return;
116 }
117 persitenceLoopTasks_[interval] = [this, interval] () {
118 ReportEventByTimeInfo(interval, true);
119 PostPersistenceDelayTask(persitenceLoopTasks_[interval], interval, interval);
120 };
121 if (disTime <= 0) {
122 ReportEventByTimeInfo(interval, true);
123 // In order to enable the timer to start on time next time and make up for the missing time
124 disTime = interval - abs(disTime) % interval;
125 PostPersistenceDelayTask(persitenceLoopTasks_[interval], interval, disTime);
126 } else {
127 PostDelayTaskByTimeInfo(persitenceLoopTasks_[interval], interval, disTime);
128 }
129 }
130
ReportEventByTimeInfo(int32_t interval,bool persistence)131 void DeviceTimedCollect::ReportEventByTimeInfo(int32_t interval, bool persistence)
132 {
133 lock_guard<mutex> autoLock(timeInfosLock_);
134 if (timeInfos_.count(interval) == 0) {
135 return;
136 }
137 if (timeInfos_[interval].normal) {
138 OnDemandEvent event = { TIMED_EVENT, LOOP_EVENT, to_string(interval), -1, persistence };
139 HILOGI("report normal:%{public}d ,persistence:%{public}d", interval, persistence);
140 ReportEvent(event);
141 }
142 if (timeInfos_[interval].awake) {
143 OnDemandEvent event = { TIMED_EVENT, AWAKE_LOOP_EVENT, to_string(interval), -1, persistence };
144 HILOGI("report awake:%{public}d ,persistence:%{public}d", interval, persistence);
145 ReportEvent(event);
146 }
147 }
148
SaveTimedInfos(const OnDemandEvent & onDemandEvent,int32_t interval)149 void DeviceTimedCollect::SaveTimedInfos(const OnDemandEvent& onDemandEvent, int32_t interval)
150 {
151 lock_guard<mutex> autoLock(timeInfosLock_);
152 if (timeInfos_.count(interval) == 0) {
153 TimeInfo info;
154 timeInfos_[interval] = info;
155 }
156 if (onDemandEvent.name == LOOP_EVENT) {
157 timeInfos_[interval].normal = true;
158 }
159 if (onDemandEvent.name == AWAKE_LOOP_EVENT) {
160 timeInfos_[interval].awake = true;
161 }
162 HILOGI("SaveTimedInfos : %{public}d : %{public}d , %{public}d", interval,
163 timeInfos_[interval].normal, timeInfos_[interval].awake);
164 }
165
SaveTimedEvent(const OnDemandEvent & onDemandEvent)166 void DeviceTimedCollect::SaveTimedEvent(const OnDemandEvent& onDemandEvent)
167 {
168 if (onDemandEvent.eventId == TIMED_EVENT &&
169 (onDemandEvent.name == LOOP_EVENT || onDemandEvent.name == AWAKE_LOOP_EVENT)) {
170 HILOGI("DeviceTimedCollect save timed task: %{public}s", onDemandEvent.value.c_str());
171 int32_t interval = atoi(onDemandEvent.value.c_str());
172 if (interval < MIN_INTERVAL) {
173 HILOGE("DeviceTimedCollect invalid interval %{public}s", onDemandEvent.value.c_str());
174 return;
175 }
176 if (interval < MIN_AWAKE_INTERVAL && onDemandEvent.name == AWAKE_LOOP_EVENT) {
177 HILOGE("SaveTimedEvent awake clock invalid interval: %{public}d", interval);
178 return;
179 }
180 if (onDemandEvent.persistence) {
181 lock_guard<mutex> autoLock(persitenceLoopEventSetLock_);
182 persitenceLoopEventSet_.insert(interval);
183 } else {
184 lock_guard<mutex> autoLock(nonPersitenceLoopEventSetLock_);
185 nonPersitenceLoopEventSet_.insert(interval);
186 }
187 SaveTimedInfos(onDemandEvent, interval);
188 }
189 }
190
PostPersistenceLoopTaskLocked(int32_t interval)191 void DeviceTimedCollect::PostPersistenceLoopTaskLocked(int32_t interval)
192 {
193 if (persitenceLoopTasks_.count(interval) > 0) {
194 return;
195 }
196 persitenceLoopTasks_[interval] = [this, interval] () {
197 ReportEventByTimeInfo(interval, true);
198 PostPersistenceDelayTask(persitenceLoopTasks_[interval], interval, interval);
199 };
200 PostPersistenceDelayTask(persitenceLoopTasks_[interval], interval, interval);
201 }
202
PostNonPersistenceLoopTaskLocked(int32_t interval)203 void DeviceTimedCollect::PostNonPersistenceLoopTaskLocked(int32_t interval)
204 {
205 if (nonPersitenceLoopTasks_.count(interval) > 0) {
206 HILOGE("DeviceTimedCollect interval has been post");
207 return;
208 }
209 nonPersitenceLoopTasks_[interval] = [this, interval] () {
210 lock_guard<mutex> autoLock(nonPersitenceLoopEventSetLock_);
211 if (nonPersitenceLoopEventSet_.find(interval) != nonPersitenceLoopEventSet_.end()) {
212 HILOGI("DeviceTimedCollect ReportEvent interval: %{public}d", interval);
213 ReportEventByTimeInfo(interval, false);
214 PostDelayTaskByTimeInfo(nonPersitenceLoopTasks_[interval], interval, interval);
215 } else {
216 HILOGI("DeviceTimedCollect interval %{public}d has been remove", interval);
217 }
218 };
219 PostDelayTaskByTimeInfo(nonPersitenceLoopTasks_[interval], interval, interval);
220 }
221
PostDelayTaskByTimeInfo(std::function<void ()> callback,int32_t interval,int32_t disTime)222 void DeviceTimedCollect::PostDelayTaskByTimeInfo(std::function<void()> callback,
223 int32_t interval, int32_t disTime)
224 {
225 lock_guard<mutex> autoLock(timeInfosLock_);
226 if (timeInfos_.count(interval) == 0) {
227 return;
228 }
229 if (timeInfos_[interval].awake) {
230 if (!SamgrTimeHandler::GetInstance()->PostTask(callback, disTime)) {
231 PostDelayTask(callback, disTime);
232 }
233 } else {
234 PostDelayTask(callback, disTime);
235 }
236 }
237
PostPersistenceDelayTask(std::function<void ()> postTask,int32_t interval,int32_t disTime)238 void DeviceTimedCollect::PostPersistenceDelayTask(std::function<void()> postTask,
239 int32_t interval, int32_t disTime)
240 {
241 #ifdef PREFERENCES_ENABLE
242 int64_t currentTime = TimeUtils::GetTimestamp();
243 int64_t upgradeTime = currentTime + static_cast<int64_t>(disTime);
244 preferencesUtil_->SaveLong(to_string(interval), upgradeTime);
245 PostDelayTaskByTimeInfo(postTask, interval, disTime);
246 HILOGI("save persistence time %{public}d, interval time %{public}d", static_cast<int32_t>(upgradeTime), interval);
247 #endif
248 }
249
OnStart()250 int32_t DeviceTimedCollect::OnStart()
251 {
252 HILOGI("DeviceTimedCollect OnStart called");
253 ProcessPersistenceTasks();
254 PostNonPersistenceLoopTasks();
255 PostPersistenceLoopTasks();
256 return ERR_OK;
257 }
258
PostNonPersistenceLoopTasks()259 void DeviceTimedCollect::PostNonPersistenceLoopTasks()
260 {
261 lock_guard<mutex> autoLock(nonPersitenceLoopEventSetLock_);
262 for (auto it = nonPersitenceLoopEventSet_.begin(); it != nonPersitenceLoopEventSet_.end(); ++it) {
263 HILOGI("DeviceTimedCollect send task: %{public}d", *it);
264 PostNonPersistenceLoopTaskLocked(*it);
265 }
266 }
267
PostPersistenceLoopTasks()268 void DeviceTimedCollect::PostPersistenceLoopTasks()
269 {
270 lock_guard<mutex> autoLock(persitenceLoopEventSetLock_);
271 for (auto it = persitenceLoopEventSet_.begin(); it != persitenceLoopEventSet_.end(); ++it) {
272 HILOGI("DeviceTimedCollect send persitence task: %{public}d", *it);
273 PostPersistenceLoopTaskLocked(*it);
274 }
275 }
276
OnStop()277 int32_t DeviceTimedCollect::OnStop()
278 {
279 HILOGI("DeviceTimedCollect OnStop called");
280 return ERR_OK;
281 }
282
CalculateDelayTime(const std::string & timeString)283 int64_t DeviceTimedCollect::CalculateDelayTime(const std::string& timeString)
284 {
285 std::tm inputTime;
286 strptime(const_cast<char*>(timeString.c_str()), "%Y-%m-%d-%H:%M:%S", &inputTime);
287 std::time_t orderTime = mktime(&inputTime);
288 int64_t timeGap = orderTime - time(nullptr);
289 return timeGap;
290 }
291
PostPersistenceTimedTaskLocked(std::string timeString,int64_t timeGap)292 void DeviceTimedCollect::PostPersistenceTimedTaskLocked(std::string timeString, int64_t timeGap)
293 {
294 #ifdef PREFERENCES_ENABLE
295 if (timeGap <= 0) {
296 HILOGE("PostPersistenceTimedTask invalid timeGap: %{public}" PRId64 "ms", timeGap);
297 return;
298 }
299 auto timedTask = [this, timeString] () {
300 OnDemandEvent event = { TIMED_EVENT, ORDER_TIMED_EVENT, timeString, -1, true };
301 ReportEvent(event);
302 preferencesUtil_->Remove(timeString);
303 };
304 int64_t currentTime = TimeUtils::GetTimestamp();
305 int64_t upgradeTime = currentTime + timeGap;
306 preferencesUtil_->SaveLong(timeString, upgradeTime);
307 if (!SamgrTimeHandler::GetInstance()->PostTask(timedTask, timeGap)) {
308 PostDelayTask(timedTask, timeGap);
309 }
310 #endif
311 }
312
PostNonPersistenceTimedTaskLocked(std::string timeString,int64_t timeGap)313 void DeviceTimedCollect::PostNonPersistenceTimedTaskLocked(std::string timeString, int64_t timeGap)
314 {
315 auto timedTask = [this, timeString] () {
316 OnDemandEvent event = { TIMED_EVENT, ORDER_TIMED_EVENT, timeString };
317 ReportEvent(event);
318 };
319 if (timeGap <= 0) {
320 HILOGE("PostNonPersistenceTimedTask invalid timeGap: %{public}" PRId64 "ms", timeGap);
321 return;
322 }
323 if (!SamgrTimeHandler::GetInstance()->PostTask(timedTask, timeGap)) {
324 PostDelayTask(timedTask, timeGap);
325 }
326 }
327
AddCollectEvent(const OnDemandEvent & event)328 int32_t DeviceTimedCollect::AddCollectEvent(const OnDemandEvent& event)
329 {
330 if (event.name != LOOP_EVENT && event.name != ORDER_TIMED_EVENT && event.name != AWAKE_LOOP_EVENT) {
331 HILOGE("DeviceTimedCollect invalid event name: %{public}s", event.name.c_str());
332 return ERR_INVALID_VALUE;
333 }
334 if (event.name == ORDER_TIMED_EVENT) {
335 int64_t timeGap = CalculateDelayTime(event.value);
336 #ifdef PREFERENCES_ENABLE
337 if (event.persistence) {
338 std::lock_guard<std::mutex> autoLock(persitenceTimedEventSetLock_);
339 PostPersistenceTimedTaskLocked(event.value, timeGap);
340 return ERR_OK;
341 }
342 #endif
343 std::lock_guard<std::mutex> autoLock(nonPersitenceTimedEventSetLock);
344 PostNonPersistenceTimedTaskLocked(event.value, timeGap);
345 return ERR_OK;
346 }
347 if (event.persistence) {
348 HILOGE("invalid event persistence, loopevent is not support persistence");
349 return ERR_INVALID_VALUE;
350 }
351 int32_t interval = atoi(event.value.c_str());
352 if (interval < MIN_INTERVAL) {
353 HILOGE("DeviceTimedCollect invalid interval: %{public}d", interval);
354 return ERR_INVALID_VALUE;
355 }
356 if (interval < MIN_AWAKE_INTERVAL && event.name == AWAKE_LOOP_EVENT) {
357 HILOGE("DeviceTimedCollect awake clock invalid interval: %{public}d", interval);
358 return ERR_INVALID_VALUE;
359 }
360 SaveTimedInfos(event, interval);
361 std::lock_guard<std::mutex> autoLock(nonPersitenceLoopEventSetLock_);
362 auto iter = nonPersitenceLoopEventSet_.find(interval);
363 if (iter != nonPersitenceLoopEventSet_.end()) {
364 return ERR_OK;
365 }
366 HILOGI("DeviceTimedCollect add collect events: %{public}d", interval);
367 nonPersitenceLoopEventSet_.insert(interval);
368 PostNonPersistenceLoopTaskLocked(interval);
369 return ERR_OK;
370 }
371
RemoveUnusedEvent(const OnDemandEvent & event)372 int32_t DeviceTimedCollect::RemoveUnusedEvent(const OnDemandEvent& event)
373 {
374 if (event.name != LOOP_EVENT && event.name != AWAKE_LOOP_EVENT) {
375 HILOGE("DeviceTimedCollect invalid event name: %{public}s", event.name.c_str());
376 return ERR_INVALID_VALUE;
377 }
378 int32_t interval = atoi(event.value.c_str());
379 if (event.persistence) {
380 RemovePersistenceLoopTask(interval);
381 } else {
382 RemoveNonPersistenceLoopTask(interval);
383 }
384 RemoveTimesInfo(event, interval);
385 return ERR_OK;
386 }
387
RemoveTimesInfo(const OnDemandEvent & onDemandEvent,int32_t interval)388 void DeviceTimedCollect::RemoveTimesInfo(const OnDemandEvent& onDemandEvent, int32_t interval)
389 {
390 lock_guard<mutex> autoLock(timeInfosLock_);
391 if (timeInfos_.count(interval) == 0) {
392 return;
393 }
394 if (onDemandEvent.name == LOOP_EVENT) {
395 timeInfos_[interval].normal = false;
396 }
397 if (onDemandEvent.name == AWAKE_LOOP_EVENT) {
398 timeInfos_[interval].awake = false;
399 }
400 HILOGI("RemoveTimesInfo : %{public}d : %{public}d , %{public}d", interval,
401 timeInfos_[interval].normal, timeInfos_[interval].awake);
402 if (!timeInfos_[interval].normal && !timeInfos_[interval].awake) {
403 timeInfos_.erase(interval);
404 }
405 }
406
RemoveNonPersistenceLoopTask(int32_t interval)407 void DeviceTimedCollect::RemoveNonPersistenceLoopTask(int32_t interval)
408 {
409 std::lock_guard<std::mutex> autoLock(nonPersitenceLoopEventSetLock_);
410 auto iter = nonPersitenceLoopEventSet_.find(interval);
411 if (iter != nonPersitenceLoopEventSet_.end()) {
412 nonPersitenceLoopEventSet_.erase(iter);
413 nonPersitenceLoopTasks_.erase(interval);
414 }
415 }
416
RemovePersistenceLoopTask(int32_t interval)417 void DeviceTimedCollect::RemovePersistenceLoopTask(int32_t interval)
418 {
419 std::lock_guard<std::mutex> autoLock(persitenceLoopEventSetLock_);
420 auto iter = persitenceLoopEventSet_.find(interval);
421 if (iter != persitenceLoopEventSet_.end()) {
422 persitenceLoopEventSet_.erase(iter);
423 persitenceLoopTasks_.erase(interval);
424 }
425 }
426 }
427