• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 VSync120To30Test : 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 VSync120To30Test::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 VSync120To30Test::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 30hz
233         changeRefreshRate = 0;
234         read(pipeFd[0], &changeRefreshRate, sizeof(changeRefreshRate));
235         refreshRates = {{1, 30}}; // 30hz
236         listenerRefreshRates = {
237             .cb = appController,
238             .refreshRates = refreshRates
239         };
240         listenerPhaseOffset = {
241             .cb = appController,
242             .phaseByPulseNum = 9 // phase is 9 pulse
243         };
244         generatorRefreshRate = 30; // 30hz
245         vsyncGenerator->ChangeGeneratorRefreshRateModel(
246             listenerRefreshRates, listenerPhaseOffset, generatorRefreshRate, rsVsyncCount);
247         // checkout 30hz
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, 30); // 30hz
258         EXPECT_EQ(rsRefreshRate, 30); // 30hz
259         if (appRefreshRate != 30) { // 30hz
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 != 30) { // 30hz
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 VSync120To30Test::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 30hz
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(VSync120To30Test, 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