1 /*
2 * Copyright (c) 2022-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 "idle_time.h"
17
18 #include "hilog_tag_wrapper.h"
19 #ifdef SUPPORT_SCREEN
20 #include "transaction/rs_interfaces.h"
21 #endif // SUPPORT_SCREEN
22 namespace OHOS {
23 namespace AppExecFwk {
24 namespace {
25 constexpr int64_t MS_PER_NS = 1000000;
26 constexpr int32_t MAX_PERIOD_COUNT = 10;
27
GetSysTimeNs()28 int64_t GetSysTimeNs()
29 {
30 auto now = std::chrono::steady_clock::now().time_since_epoch();
31 return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
32 }
33 } // namespace
34
IdleTime(const std::shared_ptr<EventHandler> &eventHandler, IdleTimeCallback idleTimeCallback)35 IdleTime::IdleTime(const std::shared_ptr<EventHandler> &eventHandler, IdleTimeCallback idleTimeCallback)
36 {
37 eventHandler_ = eventHandler;
38 callback_ = idleTimeCallback;
39 }
40
InitVSyncReceiver()41 void IdleTime::InitVSyncReceiver()
42 {
43 if (needStop_) {
44 return;
45 }
46 #ifdef SUPPORT_SCREEN
47 if (receiver_ == nullptr) {
48 auto& rsClient = Rosen::RSInterfaces::GetInstance();
49 receiver_ = rsClient.CreateVSyncReceiver("ABILITY", eventHandler_);
50 if (receiver_ == nullptr) {
51 TAG_LOGE(AAFwkTag::APPKIT, "Create VSync receiver failed");
52 return;
53 }
54 receiver_->Init();
55 }
56 #endif // SUPPORT_SCREEN
57 }
58
EventTask()59 void IdleTime::EventTask()
60 {
61 if (receiver_ == nullptr) {
62 TAG_LOGE(AAFwkTag::APPKIT, "no VSyncReceiver");
63 return;
64 }
65
66 if (callback_ == nullptr) {
67 TAG_LOGE(AAFwkTag::APPKIT, "no callback_");
68 return;
69 }
70
71 int64_t period = 0;
72 int64_t lastVSyncTime = 0;
73 #ifdef SUPPORT_SCREEN
74 VsyncError err = receiver_->GetVSyncPeriodAndLastTimeStamp(period, lastVSyncTime, true);
75 #endif // SUPPORT_SCREEN
76 TAG_LOGD(AAFwkTag::APPKIT, "EventTask period %{public}" PRId64 ", lastVSyncTime is %{public}" PRId64, period,
77 lastVSyncTime);
78 int64_t occurTimestamp = GetSysTimeNs();
79 #ifdef SUPPORT_SCREEN
80 if (GSERROR_OK == err && period > 0 && lastVSyncTime > 0 && occurTimestamp > lastVSyncTime) {
81 int64_t elapsedTime = occurTimestamp - lastVSyncTime;
82 int64_t idleTime = period - (elapsedTime % period) ;
83 int64_t cycle = elapsedTime / period ;
84 TAG_LOGD(
85 AAFwkTag::APPKIT, "EventTask idleTime %{public}" PRId64 ", cycle is %{public}" PRId64, idleTime, cycle);
86 if (idleTime > 0 && cycle < MAX_PERIOD_COUNT) {
87 TAG_LOGD(AAFwkTag::APPKIT, "callback_");
88 callback_(idleTime / MS_PER_NS);
89 }
90 }
91 #endif // SUPPORT_SCREEN
92 PostTask();
93 }
94
PostTask()95 void IdleTime::PostTask()
96 {
97 if (needStop_) {
98 return;
99 }
100
101 if (eventHandler_ == nullptr) {
102 TAG_LOGE(AAFwkTag::APPKIT, "eventHandler_ is nullptr");
103 return;
104 }
105 std::weak_ptr<IdleTime> weak(shared_from_this());
106 auto task = [weak]() {
107 auto idleTime = weak.lock();
108 if (idleTime == nullptr) {
109 TAG_LOGE(AAFwkTag::APPKIT, "idleTime is nullptr");
110 return;
111 }
112 idleTime->EventTask();
113 };
114 eventHandler_->PostTask(task, "IdleTime:PostTask", 0, EventQueue::Priority::IDLE);
115 }
116
Start()117 void IdleTime::Start()
118 {
119 InitVSyncReceiver();
120 PostTask();
121 }
122
SetNeedStop(bool needStop)123 void IdleTime::SetNeedStop(bool needStop)
124 {
125 needStop_ = needStop;
126 }
127
GetNeedStop()128 bool IdleTime::GetNeedStop()
129 {
130 return needStop_;
131 }
132
GetIdleNotifyFunc()133 IdleNotifyStatusCallback IdleTime::GetIdleNotifyFunc()
134 {
135 IdleNotifyStatusCallback cb = [this](bool needStop) {
136 if (this->GetNeedStop() == needStop) {
137 return;
138 }
139
140 this->SetNeedStop(needStop);
141 if (needStop == false) {
142 this->Start();
143 }
144 };
145 return cb;
146 }
147 } // AppExecFwk
148 } // namespace OHOS