1 /*
2 * Copyright (c) 2022 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_wrapper.h"
19 #include "transaction/rs_interfaces.h"
20
21 namespace OHOS {
22 namespace AppExecFwk {
23 namespace {
24 constexpr int64_t PERIOD = 16666666; // ns
25 constexpr int64_t MS_PER_NS = 1000000;
26 constexpr int32_t TRY_COUNT_MAX = 6;
27 constexpr int32_t DEVIATION_MIN = 1000; // ns
28 }
29
IdleTime(const std::shared_ptr<EventHandler> & eventHandler,IdleTimeCallback idleTimeCallback)30 IdleTime::IdleTime(const std::shared_ptr<EventHandler> &eventHandler, IdleTimeCallback idleTimeCallback)
31 {
32 eventHandler_ = eventHandler;
33 callback_ = idleTimeCallback;
34 }
35
GetSysTimeNs()36 int64_t IdleTime::GetSysTimeNs()
37 {
38 auto now = std::chrono::steady_clock::now().time_since_epoch();
39 return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
40 }
41
OnVSync(int64_t timestamp,void * client)42 void IdleTime::OnVSync(int64_t timestamp, void* client)
43 {
44 // only use for 60HZ
45 if (continueFailCount_ > TRY_COUNT_MAX) {
46 HILOG_ERROR("Only support 60HZ.");
47 return;
48 }
49 int64_t period = timestamp - firstVSyncTime_;
50 int64_t lastPeriod = period_ == 0 ? PERIOD : period_;
51 int64_t deviation = (period - lastPeriod) > 0 ? period - lastPeriod : lastPeriod - period;
52 if (deviation > MS_PER_NS) { // deviation greater than 1ms
53 RequestVSync();
54 continueFailCount_++;
55 HILOG_DEBUG("fail count is %{public}d, timestamp is %{public}" PRId64 ", period is %{public}" PRId64,
56 continueFailCount_, timestamp, period);
57 } else {
58 if (eventHandler_ == nullptr) {
59 HILOG_ERROR("eventHandler_ is nullptr.");
60 return;
61 }
62 deviation = deviation < DEVIATION_MIN ? DEVIATION_MIN : deviation;
63 int64_t timeOut = lastPeriod / deviation; // up to 16666ms : MS_PER_NS / deviation * lastPeriod / MS_PER_NS
64 std::weak_ptr<IdleTime> weak(shared_from_this());
65 auto task = [weak]() {
66 auto idleTime = weak.lock();
67 if (idleTime == nullptr) {
68 HILOG_ERROR("idleTime is nullptr.");
69 return;
70 }
71 idleTime->RequestVSync();
72 };
73 eventHandler_->PostTask(task, timeOut);
74 if (successCount_ > TRY_COUNT_MAX) {
75 period_ = (period & lastPeriod) + ((period ^ lastPeriod) >> 1); // average
76 } else {
77 period_ = PERIOD;
78 successCount_++;
79 HILOG_DEBUG("fail count is %{public}d, timestamp is %{public}" PRId64 ", period is %{public}" PRId64,
80 continueFailCount_, timestamp, period);
81 }
82 continueFailCount_ = 0;
83 }
84
85 firstVSyncTime_ = timestamp;
86 }
87
RequestVSync()88 void IdleTime::RequestVSync()
89 {
90 if (needStop_) {
91 return;
92 }
93
94 if (receiver_ == nullptr) {
95 auto& rsClient = Rosen::RSInterfaces::GetInstance();
96 receiver_ = rsClient.CreateVSyncReceiver("ABILITY", eventHandler_);
97 if (receiver_ == nullptr) {
98 HILOG_ERROR("Create VSync receiver failed.");
99 return;
100 }
101 receiver_->Init();
102 }
103 std::weak_ptr<IdleTime> weak(shared_from_this());
104 auto task = [weak](int64_t timestamp, void* data) {
105 auto idleTime = weak.lock();
106 if (idleTime == nullptr) {
107 HILOG_ERROR("idleTime is nullptr.");
108 return;
109 }
110 idleTime->OnVSync(timestamp, data);
111 };
112 Rosen::VSyncReceiver::FrameCallback frameCallback = {
113 .userData_ = this,
114 .callback_ = task,
115 };
116 receiver_->RequestNextVSync(frameCallback);
117 }
118
EventTask()119 void IdleTime::EventTask()
120 {
121 if (firstVSyncTime_ == 0 || period_ == 0) {
122 PostTask();
123 HILOG_ERROR("no VSync occur.");
124 return;
125 }
126 int64_t period = period_;
127
128 int64_t occurTimestamp = GetSysTimeNs();
129 int64_t numPeriod = (occurTimestamp - firstVSyncTime_) / period;
130 int64_t lastVSyncTime = numPeriod * period + firstVSyncTime_;
131 int64_t elapsedTime = occurTimestamp - lastVSyncTime;
132 int64_t idleTime = period - elapsedTime;
133 if (callback_ != nullptr) {
134 callback_(idleTime / MS_PER_NS);
135 PostTask();
136 }
137 }
138
PostTask()139 void IdleTime::PostTask()
140 {
141 if (needStop_) {
142 return;
143 }
144
145 if (continueFailCount_ > TRY_COUNT_MAX) {
146 HILOG_ERROR("Only support 60HZ.");
147 return;
148 }
149
150 if (eventHandler_ == nullptr) {
151 HILOG_ERROR("eventHandler_ is nullptr.");
152 return;
153 }
154 std::weak_ptr<IdleTime> weak(shared_from_this());
155 auto task = [weak]() {
156 auto idleTime = weak.lock();
157 if (idleTime == nullptr) {
158 HILOG_ERROR("idleTime is nullptr.");
159 return;
160 }
161 idleTime->EventTask();
162 };
163 eventHandler_->PostTask(task, EventQueue::Priority::IDLE);
164 }
165
Start()166 void IdleTime::Start()
167 {
168 RequestVSync();
169 PostTask();
170 }
171
SetNeedStop(bool needStop)172 void IdleTime::SetNeedStop(bool needStop)
173 {
174 needStop_ = needStop;
175 }
176
GetNeedStop()177 bool IdleTime::GetNeedStop()
178 {
179 return needStop_;
180 }
181
GetIdleNotifyFunc()182 IdleNotifyStatusCallback IdleTime::GetIdleNotifyFunc()
183 {
184 IdleNotifyStatusCallback cb = [this](bool needStop) {
185 if (this->GetNeedStop() == needStop) {
186 return;
187 }
188
189 this->SetNeedStop(needStop);
190 if (needStop == false) {
191 this->Start();
192 }
193 };
194 return cb;
195 }
196 } // AppExecFwk
197 } // namespace OHOS