• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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