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