• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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