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 {
39 namespace {
40 constexpr int32_t MAX_SIZE = 128;
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 VSync120To60Test : 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 VSync120To60Test::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 VSync120To60Test::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, "appTest");
150 rsDistributor = new VSyncDistributor(rsController, "rsTest");
151 sptr<VSyncConnection> connServerApp = new VSyncConnection(appDistributor, "appTest", nullptr, 1); // id:1
152 sptr<VSyncConnection> connServerRs = new VSyncConnection(rsDistributor, "rsTest", 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 int changeRefreshRate;
168 std::vector<std::pair<uint64_t, uint32_t>> refreshRates;
169 VSyncGenerator::ListenerRefreshRateData listenerRefreshRates;
170 VSyncGenerator::ListenerPhaseOffsetData listenerPhaseOffset;
171 int64_t rsVsyncCount;
172 uint32_t generatorRefreshRate;
173 int64_t appTimestampPrev;
174 int64_t appTimestampCur;
175 int64_t rsTimestampPrev;
176 int64_t rsTimestampCur;
177 int64_t appPeriod;
178 int64_t rsPeriod;
179 int32_t appRefreshRate;
180 int32_t rsRefreshRate;
181
182 int testTimes = 3; // test 3 times
183 while (testTimes--) {
184 // change refresh rate to 120hz
185 changeRefreshRate = 0;
186 read(pipeFd[0], &changeRefreshRate, sizeof(changeRefreshRate));
187 refreshRates = {{1, 120}}; // 120hz
188 listenerRefreshRates = {
189 .cb = appController,
190 .refreshRates = refreshRates
191 };
192 listenerPhaseOffset = {
193 .cb = appController,
194 .phaseByPulseNum = 0
195 };
196 generatorRefreshRate = 120; // 120hz
197 vsyncGenerator->ChangeGeneratorRefreshRateModel(
198 listenerRefreshRates, listenerPhaseOffset, generatorRefreshRate, rsVsyncCount);
199 // checkout 120hz
200 read(pipeFd[0], &timeStamps, sizeof(timeStamps));
201 appTimestampPrev = timeStamps.appTimestamps[(timeStamps.appIndex - 2) % MAX_SIZE]; // prev should minus 2
202 appTimestampCur = timeStamps.appTimestamps[(timeStamps.appIndex - 1) % MAX_SIZE]; // cur should minus 1
203 rsTimestampPrev = timeStamps.rsTimestamps[(timeStamps.rsIndex - 2) % MAX_SIZE]; // prev should minus 2
204 rsTimestampCur = timeStamps.rsTimestamps[(timeStamps.rsIndex - 1) % MAX_SIZE]; // cur should minus 1
205 appPeriod = appTimestampCur - appTimestampPrev;
206 rsPeriod = rsTimestampCur - rsTimestampPrev;
207 appRefreshRate = JudgeRefreshRate(appPeriod);
208 rsRefreshRate = JudgeRefreshRate(rsPeriod);
209 EXPECT_EQ(appRefreshRate, 120); // 120hz
210 EXPECT_EQ(rsRefreshRate, 120); // 120hz
211 if (appRefreshRate != 120) { // 120hz
212 std::string appTimestamps = "appTimestamps:[";
213 for (int i = 0; i < 15; i++) { // check last 15 samples
214 appTimestamps += std::to_string(g_timeStamps.appTimestamps[i]) + ",";
215 }
216 appTimestamps += "]";
217 std::cout << appTimestamps << std::endl;
218 }
219 if (rsRefreshRate != 120) { // 120hz
220 std::string rsTimestamps = "rsTimestamps:[";
221 for (int i = 0; i < 15; i++) { // check last 15 samples
222 rsTimestamps += std::to_string(g_timeStamps.rsTimestamps[i]) + ",";
223 }
224 rsTimestamps += "]";
225 std::cout << rsTimestamps << std::endl;
226 }
227 std::cout << "appPeriod:" << appPeriod <<
228 ", appRefreshRate:" << appRefreshRate <<
229 ", rsPeriod:" << rsPeriod <<
230 ", rsRefreshRate:" << rsRefreshRate << std::endl;
231
232 // change refresh rate to 60hz
233 changeRefreshRate = 0;
234 read(pipeFd[0], &changeRefreshRate, sizeof(changeRefreshRate));
235 refreshRates = {{1, 60}}; // 60hz
236 listenerRefreshRates = {
237 .cb = appController,
238 .refreshRates = refreshRates
239 };
240 listenerPhaseOffset = {
241 .cb = appController,
242 .phaseByPulseNum = 3 // phase is 3 pulse
243 };
244 generatorRefreshRate = 60; // 60hz
245 vsyncGenerator->ChangeGeneratorRefreshRateModel(
246 listenerRefreshRates, listenerPhaseOffset, generatorRefreshRate, rsVsyncCount);
247 // checkout 60hz
248 read(pipeFd[0], &timeStamps, sizeof(timeStamps));
249 appTimestampPrev = timeStamps.appTimestamps[(timeStamps.appIndex - 2) % MAX_SIZE]; // prev should minus 2
250 appTimestampCur = timeStamps.appTimestamps[(timeStamps.appIndex - 1) % MAX_SIZE]; // cur should minus 1
251 rsTimestampPrev = timeStamps.rsTimestamps[(timeStamps.rsIndex - 2) % MAX_SIZE]; // prev should minus 2
252 rsTimestampCur = timeStamps.rsTimestamps[(timeStamps.rsIndex - 1) % MAX_SIZE]; // cur should minus 1
253 appPeriod = appTimestampCur - appTimestampPrev;
254 rsPeriod = rsTimestampCur - rsTimestampPrev;
255 appRefreshRate = JudgeRefreshRate(appPeriod);
256 rsRefreshRate = JudgeRefreshRate(rsPeriod);
257 EXPECT_EQ(appRefreshRate, 60); // 60hz
258 EXPECT_EQ(rsRefreshRate, 60); // 60hz
259 if (appRefreshRate != 60) { // 60hz
260 std::string appTimestamps = "appTimestamps:[";
261 for (int i = 0; i < 15; i++) { // check last 15 samples
262 appTimestamps += std::to_string(g_timeStamps.appTimestamps[i]) + ",";
263 }
264 appTimestamps += "]";
265 std::cout << appTimestamps << std::endl;
266 }
267 if (rsRefreshRate != 60) { // 60hz
268 std::string rsTimestamps = "rsTimestamps:[";
269 for (int i = 0; i < 15; i++) { // check last 15 samples
270 rsTimestamps += std::to_string(g_timeStamps.rsTimestamps[i]) + ",";
271 }
272 rsTimestamps += "]";
273 std::cout << rsTimestamps << std::endl;
274 }
275 std::cout << "appPeriod:" << appPeriod <<
276 ", appRefreshRate:" << appRefreshRate <<
277 ", rsPeriod:" << rsPeriod <<
278 ", rsRefreshRate:" << rsRefreshRate << std::endl;
279 }
280
281 read(pipeFd[0], buf, sizeof(buf));
282 sam->RemoveSystemAbility(ipcSystemAbilityIDApp);
283 sam->RemoveSystemAbility(ipcSystemAbilityIDRs);
284 close(pipeFd[0]);
285 close(pipe1Fd[1]);
286 exit(0);
287 #endif
288 }
289
Process2()290 void VSync120To60Test::Process2()
291 {
292 close(pipeFd[0]);
293 close(pipe1Fd[1]);
294 char buf[10];
295 read(pipe1Fd[0], buf, sizeof(buf));
296 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
297 auto robjApp = sam->GetSystemAbility(ipcSystemAbilityIDApp);
298 auto robjRs = sam->GetSystemAbility(ipcSystemAbilityIDRs);
299 std::cout << "(robjApp == nullptr):" << (robjApp == nullptr) << std::endl;
300 std::cout << "(robjRs == nullptr):" << (robjRs == nullptr) << std::endl;
301 auto connApp = iface_cast<IVSyncConnection>(robjApp);
302 auto connRs = iface_cast<IVSyncConnection>(robjRs);
303 receiverApp = new VSyncReceiver(connApp);
304 receiverRs = new VSyncReceiver(connRs);
305 receiverApp->Init();
306 receiverRs->Init();
307 VSyncReceiver::FrameCallback fcbApp = {
308 .userData_ = nullptr,
309 .callback_ = OnVSyncApp,
310 };
311 VSyncReceiver::FrameCallback fcbRs = {
312 .userData_ = nullptr,
313 .callback_ = OnVSyncRs,
314 };
315
316 int testTimes = 3; // test 3 times
317 while (testTimes--) {
318 // change refresh rate to 60hz
319 int changeRefreshRate = 0;
320 write(pipeFd[1], &changeRefreshRate, sizeof(changeRefreshRate));
321 int appNum = 3; // RequestNextVSync 3 times
322 int rsNum = 4; // RequestNextVSync 4 times
323 while (appNum > 0 || rsNum > 0) {
324 if (appNum > 0) {
325 receiverApp->RequestNextVSync(fcbApp);
326 }
327 if (rsNum > 0) {
328 receiverRs->RequestNextVSync(fcbRs);
329 }
330 while (g_appVSyncFlag == 0 && g_rsVSyncFlag == 0) {
331 usleep(100); // 100us
332 }
333 if (g_appVSyncFlag) {
334 appNum--;
335 g_appVSyncFlag = 0;
336 }
337 if (g_rsVSyncFlag) {
338 rsNum--;
339 g_rsVSyncFlag = 0;
340 }
341 }
342 write(pipeFd[1], &g_timeStamps, sizeof(g_timeStamps));
343
344 // change refresh rate to 60hz
345 changeRefreshRate = 0;
346 write(pipeFd[1], &changeRefreshRate, sizeof(changeRefreshRate));
347 appNum = 3; // RequestNextVSync 3 times
348 rsNum = 3; // RequestNextVSync 4 times
349 while (appNum > 0 || rsNum > 0) {
350 if (appNum > 0) {
351 receiverApp->RequestNextVSync(fcbApp);
352 }
353 if (rsNum > 0) {
354 receiverRs->RequestNextVSync(fcbRs);
355 }
356 while (g_appVSyncFlag == 0 && g_rsVSyncFlag == 0) {
357 usleep(100); // 100us
358 }
359 if (g_appVSyncFlag) {
360 appNum--;
361 g_appVSyncFlag = 0;
362 }
363 if (g_rsVSyncFlag) {
364 rsNum--;
365 g_rsVSyncFlag = 0;
366 }
367 }
368 write(pipeFd[1], &g_timeStamps, sizeof(g_timeStamps));
369 }
370 }
371
372 HWTEST_F(VSync120To60Test, ChangeRefreshRateTest, Function | MediumTest | Level2)
373 {
374 if (pipe(pipeFd) < 0) {
375 exit(1);
376 }
377 if (pipe(pipe1Fd) < 0) {
378 exit(0);
379 }
380 pid = fork();
381 if (pid < 0) {
382 exit(1);
383 }
384 if (pid != 0) {
385 Process1();
386 } else {
387 Process2();
388 }
389 }
390 }
391