1 /*
2 * Copyright (c) 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 #include <chrono>
16 #include <thread>
17 #include <unistd.h>
18 #include <condition_variable>
19 #include <gtest/gtest.h>
20 #include <iservice_registry.h>
21 #include "vsync_receiver.h"
22 #include "vsync_controller.h"
23 #include "vsync_sampler.h"
24 #include "vsync_generator.h"
25 #include "vsync_distributor.h"
26 #include "accesstoken_kit.h"
27 #ifdef SUPPORT_ACCESS_TOKEN
28 #include "nativetoken_kit.h"
29 #include "token_setproc.h"
30 #endif
31 #include "vsync_type.h"
32
33 #include <iostream>
34
35 using namespace testing;
36 using namespace testing::ext;
37
38 namespace OHOS::Rosen {
SystemTime()39 static int64_t SystemTime()
40 {
41 timespec t = {};
42 clock_gettime(CLOCK_MONOTONIC, &t);
43 return int64_t(t.tv_sec) * 1000000000LL + t.tv_nsec; // 1000000000ns == 1s
44 }
45
46 namespace {
47 constexpr int32_t MAX_SIZE = 128;
48 typedef struct VSyncTimeStamps {
49 int64_t appTimestamps[MAX_SIZE] = {0};
50 int32_t appIndex = 0;
51 int64_t rsTimestamps[MAX_SIZE] = {0};
52 int32_t rsIndex = 0;
53 } VSyncTimeStamps;
54 VSyncTimeStamps g_timeStamps = {};
55 int32_t g_appVSyncFlag = 0;
56 int32_t g_rsVSyncFlag = 0;
57 constexpr int32_t SAMPLER_NUMBER = 6;
OnVSyncApp(int64_t time,void * data)58 static void OnVSyncApp(int64_t time, void *data)
59 {
60 g_appVSyncFlag = 1;
61 g_timeStamps.appTimestamps[g_timeStamps.appIndex++] = time;
62 g_timeStamps.appIndex %= MAX_SIZE;
63 }
OnVSyncRs(int64_t time,void * data)64 static void OnVSyncRs(int64_t time, void *data)
65 {
66 g_rsVSyncFlag = 1;
67 g_timeStamps.rsTimestamps[g_timeStamps.rsIndex++] = time;
68 g_timeStamps.rsIndex %= MAX_SIZE;
69 }
70 }
71 class VSync30To60Test : public testing::Test {
72 public:
73 int32_t JudgeRefreshRate(int64_t period);
74 void Process1();
75 void Process2();
76
77 sptr<VSyncSampler> vsyncSampler = nullptr;
78 sptr<VSyncController> appController = nullptr;
79 sptr<VSyncController> rsController = nullptr;
80 sptr<VSyncDistributor> appDistributor = nullptr;
81 sptr<VSyncDistributor> rsDistributor = nullptr;
82 sptr<VSyncGenerator> vsyncGenerator = nullptr;
83 sptr<VSyncReceiver> receiverApp = nullptr;
84 sptr<VSyncReceiver> receiverRs = nullptr;
85
86 static inline pid_t pid = 0;
87 static inline int pipeFd[2] = {};
88 static inline int pipe1Fd[2] = {};
89 static inline int32_t ipcSystemAbilityIDApp = 34156;
90 static inline int32_t ipcSystemAbilityIDRs = 34157;
91 };
92
InitNativeTokenInfo()93 static void InitNativeTokenInfo()
94 {
95 #ifdef SUPPORT_ACCESS_TOKEN
96 uint64_t tokenId;
97 const char *perms[2];
98 perms[0] = "ohos.permission.DISTRIBUTED_DATASYNC";
99 perms[1] = "ohos.permission.CAMERA";
100 NativeTokenInfoParams infoInstance = {
101 .dcapsNum = 0,
102 .permsNum = 2,
103 .aclsNum = 0,
104 .dcaps = NULL,
105 .perms = perms,
106 .acls = NULL,
107 .processName = "dcamera_client_demo",
108 .aplStr = "system_basic",
109 };
110 tokenId = GetAccessTokenId(&infoInstance);
111 SetSelfTokenID(tokenId);
112 int32_t ret = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo();
113 ASSERT_EQ(ret, Security::AccessToken::RET_SUCCESS);
114 std::this_thread::sleep_for(std::chrono::milliseconds(50)); // wait 50ms
115 #endif
116 }
117
JudgeRefreshRate(int64_t period)118 int32_t VSync30To60Test::JudgeRefreshRate(int64_t period)
119 {
120 if (period <= 0) {
121 return 0;
122 }
123 int32_t actualRefreshRate = round(1.0 / (static_cast<double>(period) / 1000000000.0)); // 1.0s == 1000000000.0ns
124 int32_t refreshRate = actualRefreshRate;
125 int32_t diff = 0;
126 while ((abs(refreshRate - actualRefreshRate) < 5) && // ±5Hz
127 (CreateVSyncGenerator()->GetVSyncMaxRefreshRate() % refreshRate != 0)) {
128 if (diff < 0) {
129 diff = -diff;
130 } else {
131 diff = -diff - 1;
132 }
133 refreshRate = actualRefreshRate + diff;
134 }
135 return refreshRate;
136 }
137
Process1()138 void VSync30To60Test::Process1()
139 {
140 #ifdef SUPPORT_ACCESS_TOKEN
141 InitNativeTokenInfo();
142 vsyncGenerator = CreateVSyncGenerator();
143 vsyncSampler = CreateVSyncSampler();
144 int32_t count = 0;
145 int64_t timestamp = 16666667; // 16666667ns
146 while (count <= SAMPLER_NUMBER) {
147 vsyncSampler->AddSample(timestamp);
148 usleep(1000); // 1000us
149 timestamp += 16666667; // 16666667ns
150 count++;
151 }
152 vsyncGenerator->SetVSyncMode(VSYNC_MODE_LTPO);
153 std::cout << "pulse:" << vsyncGenerator->GetVSyncPulse() << std::endl;
154 appController = new VSyncController(vsyncGenerator, 0);
155 rsController = new VSyncController(vsyncGenerator, 0);
156 appDistributor = new VSyncDistributor(appController, "appTest");
157 rsDistributor = new VSyncDistributor(rsController, "rsTest");
158 sptr<VSyncConnection> connServerApp = new VSyncConnection(appDistributor, "appTest", nullptr, 1); // id:1
159 sptr<VSyncConnection> connServerRs = new VSyncConnection(rsDistributor, "rsTest", nullptr, 2); // id:2
160 appDistributor->AddConnection(connServerApp);
161 rsDistributor->AddConnection(connServerRs);
162 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
163 sam->AddSystemAbility(ipcSystemAbilityIDApp, connServerApp->AsObject());
164 sam->AddSystemAbility(ipcSystemAbilityIDRs, connServerRs->AsObject());
165 VSyncTimeStamps timeStamps = {};
166 vsyncGenerator->SetRSDistributor(rsDistributor);
167 vsyncGenerator->SetAppDistributor(appDistributor);
168
169 close(pipeFd[1]);
170 close(pipe1Fd[0]);
171 char buf[10] = "start";
172 write(pipe1Fd[1], buf, sizeof(buf));
173
174 int changeRefreshRate;
175 std::vector<std::pair<uint64_t, uint32_t>> refreshRates;
176 VSyncGenerator::ListenerRefreshRateData listenerRefreshRates;
177 VSyncGenerator::ListenerPhaseOffsetData listenerPhaseOffset;
178 int64_t rsVsyncCount;
179 uint32_t generatorRefreshRate;
180 int64_t appTimestampPrev;
181 int64_t appTimestampCur;
182 int64_t rsTimestampPrev;
183 int64_t rsTimestampCur;
184 int64_t appPeriod;
185 int64_t rsPeriod;
186 int32_t appRefreshRate;
187 int32_t rsRefreshRate;
188
189 int testTimes = 3; // test 3 times
190 while (testTimes--) {
191 // change refresh rate to 30hz
192 changeRefreshRate = 0;
193 read(pipeFd[0], &changeRefreshRate, sizeof(changeRefreshRate));
194 refreshRates = {{1, 30}}; // 30hz
195 listenerRefreshRates = {
196 .cb = appController,
197 .refreshRates = refreshRates
198 };
199 listenerPhaseOffset = {
200 .cb = appController,
201 .phaseByPulseNum = 9 // phase is 9 pulse
202 };
203 generatorRefreshRate = 30; // 30hz
204 vsyncGenerator->ChangeGeneratorRefreshRateModel(
205 listenerRefreshRates, listenerPhaseOffset, generatorRefreshRate, rsVsyncCount);
206 // checkout 30hz
207 read(pipeFd[0], &timeStamps, sizeof(timeStamps));
208 appTimestampPrev = timeStamps.appTimestamps[(timeStamps.appIndex - 2) % MAX_SIZE]; // prev should minus 2
209 appTimestampCur = timeStamps.appTimestamps[(timeStamps.appIndex - 1) % MAX_SIZE]; // cur should minus 1
210 rsTimestampPrev = timeStamps.rsTimestamps[(timeStamps.rsIndex - 2) % MAX_SIZE]; // prev should minus 2
211 rsTimestampCur = timeStamps.rsTimestamps[(timeStamps.rsIndex - 1) % MAX_SIZE]; // cur should minus 1
212 appPeriod = appTimestampCur - appTimestampPrev;
213 rsPeriod = rsTimestampCur - rsTimestampPrev;
214 appRefreshRate = JudgeRefreshRate(appPeriod);
215 rsRefreshRate = JudgeRefreshRate(rsPeriod);
216 EXPECT_EQ(appRefreshRate, 30); // 30hz
217 EXPECT_EQ(rsRefreshRate, 30); // 30hz
218 if (appRefreshRate != 30) { // 30hz
219 std::string appTimestamps = "appTimestamps:[";
220 for (int i = 0; i < 15; i++) { // check last 15 samples
221 appTimestamps += std::to_string(g_timeStamps.appTimestamps[i]) + ",";
222 }
223 appTimestamps += "]";
224 std::cout << appTimestamps << std::endl;
225 }
226 if (rsRefreshRate != 30) { // 30hz
227 std::string rsTimestamps = "rsTimestamps:[";
228 for (int i = 0; i < 15; i++) { // check last 15 samples
229 rsTimestamps += std::to_string(g_timeStamps.rsTimestamps[i]) + ",";
230 }
231 rsTimestamps += "]";
232 std::cout << rsTimestamps << std::endl;
233 }
234 std::cout << "appPeriod:" << appPeriod <<
235 ", appRefreshRate:" << appRefreshRate <<
236 ", rsPeriod:" << rsPeriod <<
237 ", rsRefreshRate:" << rsRefreshRate << std::endl;
238
239 // change refresh rate to 60hz
240 changeRefreshRate = 0;
241 read(pipeFd[0], &changeRefreshRate, sizeof(changeRefreshRate));
242 refreshRates = {{1, 60}}; // 60hz
243 listenerRefreshRates = {
244 .cb = appController,
245 .refreshRates = refreshRates
246 };
247 listenerPhaseOffset = {
248 .cb = appController,
249 .phaseByPulseNum = 3 // phase is 3 pulse
250 };
251 generatorRefreshRate = 60; // 60hz
252 int64_t systemTime = SystemTime();
253 vsyncGenerator->ChangeGeneratorRefreshRateModel(
254 listenerRefreshRates, listenerPhaseOffset, generatorRefreshRate,
255 rsVsyncCount, systemTime + 3000000); // 3000000==3ms
256 // checkout 60hz
257 read(pipeFd[0], &timeStamps, sizeof(timeStamps));
258 appTimestampPrev = timeStamps.appTimestamps[(timeStamps.appIndex - 2) % MAX_SIZE]; // prev should minus 2
259 appTimestampCur = timeStamps.appTimestamps[(timeStamps.appIndex - 1) % MAX_SIZE]; // cur should minus 1
260 rsTimestampPrev = timeStamps.rsTimestamps[(timeStamps.rsIndex - 2) % MAX_SIZE]; // prev should minus 2
261 rsTimestampCur = timeStamps.rsTimestamps[(timeStamps.rsIndex - 1) % MAX_SIZE]; // cur should minus 1
262 appPeriod = appTimestampCur - appTimestampPrev;
263 rsPeriod = rsTimestampCur - rsTimestampPrev;
264 appRefreshRate = JudgeRefreshRate(appPeriod);
265 rsRefreshRate = JudgeRefreshRate(rsPeriod);
266 EXPECT_EQ(appRefreshRate, 60); // 60hz
267 EXPECT_EQ(rsRefreshRate, 60); // 60hz
268 if (appRefreshRate != 60) { // 60hz
269 std::string appTimestamps = "appTimestamps:[";
270 for (int i = 0; i < 15; i++) { // check last 15 samples
271 appTimestamps += std::to_string(g_timeStamps.appTimestamps[i]) + ",";
272 }
273 appTimestamps += "]";
274 std::cout << appTimestamps << std::endl;
275 }
276 if (rsRefreshRate != 60) { // 60hz
277 std::string rsTimestamps = "rsTimestamps:[";
278 for (int i = 0; i < 15; i++) { // check last 15 samples
279 rsTimestamps += std::to_string(g_timeStamps.rsTimestamps[i]) + ",";
280 }
281 rsTimestamps += "]";
282 std::cout << rsTimestamps << std::endl;
283 }
284 std::cout << "appPeriod:" << appPeriod <<
285 ", appRefreshRate:" << appRefreshRate <<
286 ", rsPeriod:" << rsPeriod <<
287 ", rsRefreshRate:" << rsRefreshRate << std::endl;
288 }
289
290 read(pipeFd[0], buf, sizeof(buf));
291 sam->RemoveSystemAbility(ipcSystemAbilityIDApp);
292 sam->RemoveSystemAbility(ipcSystemAbilityIDRs);
293 close(pipeFd[0]);
294 close(pipe1Fd[1]);
295 exit(0);
296 #endif
297 }
298
Process2()299 void VSync30To60Test::Process2()
300 {
301 close(pipeFd[0]);
302 close(pipe1Fd[1]);
303 char buf[10];
304 read(pipe1Fd[0], buf, sizeof(buf));
305 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
306 auto robjApp = sam->GetSystemAbility(ipcSystemAbilityIDApp);
307 auto robjRs = sam->GetSystemAbility(ipcSystemAbilityIDRs);
308 std::cout << "(robjApp == nullptr):" << (robjApp == nullptr) << std::endl;
309 std::cout << "(robjRs == nullptr):" << (robjRs == nullptr) << std::endl;
310 auto connApp = iface_cast<IVSyncConnection>(robjApp);
311 auto connRs = iface_cast<IVSyncConnection>(robjRs);
312 receiverApp = new VSyncReceiver(connApp);
313 receiverRs = new VSyncReceiver(connRs);
314 receiverApp->Init();
315 receiverRs->Init();
316 VSyncReceiver::FrameCallback fcbApp = {
317 .userData_ = nullptr,
318 .callback_ = OnVSyncApp,
319 };
320 VSyncReceiver::FrameCallback fcbRs = {
321 .userData_ = nullptr,
322 .callback_ = OnVSyncRs,
323 };
324
325 int testTimes = 3; // test 3 times
326 while (testTimes--) {
327 // change refresh rate to 30hz
328 int changeRefreshRate = 0;
329 write(pipeFd[1], &changeRefreshRate, sizeof(changeRefreshRate));
330 int appNum = 3; // RequestNextVSync 3 times
331 int rsNum = 4; // RequestNextVSync 4 times
332 while (appNum > 0 || rsNum > 0) {
333 if (appNum > 0) {
334 receiverApp->RequestNextVSync(fcbApp);
335 }
336 if (rsNum > 0) {
337 receiverRs->RequestNextVSync(fcbRs);
338 }
339 while (g_appVSyncFlag == 0 && g_rsVSyncFlag == 0) {
340 usleep(100); // 100us
341 }
342 if (g_appVSyncFlag) {
343 appNum--;
344 g_appVSyncFlag = 0;
345 }
346 if (g_rsVSyncFlag) {
347 rsNum--;
348 g_rsVSyncFlag = 0;
349 }
350 }
351 write(pipeFd[1], &g_timeStamps, sizeof(g_timeStamps));
352
353 // change refresh rate to 60hz
354 changeRefreshRate = 0;
355 write(pipeFd[1], &changeRefreshRate, sizeof(changeRefreshRate));
356 appNum = 3; // RequestNextVSync 3 times
357 rsNum = 3; // RequestNextVSync 4 times
358 while (appNum > 0 || rsNum > 0) {
359 if (appNum > 0) {
360 receiverApp->RequestNextVSync(fcbApp);
361 }
362 if (rsNum > 0) {
363 receiverRs->RequestNextVSync(fcbRs);
364 }
365 while (g_appVSyncFlag == 0 && g_rsVSyncFlag == 0) {
366 usleep(100); // 100us
367 }
368 if (g_appVSyncFlag) {
369 appNum--;
370 g_appVSyncFlag = 0;
371 }
372 if (g_rsVSyncFlag) {
373 rsNum--;
374 g_rsVSyncFlag = 0;
375 }
376 }
377 write(pipeFd[1], &g_timeStamps, sizeof(g_timeStamps));
378 }
379 }
380
381 HWTEST_F(VSync30To60Test, ChangeRefreshRateTest, Function | MediumTest | Level2)
382 {
383 if (pipe(pipeFd) < 0) {
384 exit(1);
385 }
386 if (pipe(pipe1Fd) < 0) {
387 exit(0);
388 }
389 pid = fork();
390 if (pid < 0) {
391 exit(1);
392 }
393 if (pid != 0) {
394 Process1();
395 } else {
396 Process2();
397 }
398 }
399 }
400