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