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 <gtest/gtest.h>
19 #include <iservice_registry.h>
20 #include <surface.h>
21 #include "accesstoken_kit.h"
22 #include "iconsumer_surface.h"
23 #include "nativetoken_kit.h"
24 #include "token_setproc.h"
25 #include "sync_fence.h"
26 #include "external_window.h"
27 #include "native_window.h"
28 #include "iostream"
29 using namespace testing;
30 using namespace testing::ext;
31
32 namespace OHOS::Rosen {
33 class SurfaceIPCWithPTSTest : public testing::Test, public IBufferConsumerListenerClazz {
34 public:
35 static void SetUpTestCase();
36 void OnBufferAvailable() override;
37 OHOS::GSError SetData(sptr<SurfaceBuffer> &buffer, sptr<Surface> &pSurface);
38 bool GetData(sptr<SurfaceBuffer> &buffer);
39 pid_t ChildProcessMain();
40 sptr<OHOS::Surface> CreateSurface();
41
42 static inline sptr<IConsumerSurface> cSurface = nullptr;
43 static inline int32_t pipeFd[2] = {};
44 static inline int32_t ipcSystemAbilityID = 34156;
45 static inline BufferRequestConfig requestConfig = {};
46 static inline BufferFlushConfig flushConfig = {};
47 static inline int64_t desiredPresentTimestamp = 0;
48 static constexpr const int32_t WAIT_SYSTEM_ABILITY_GET_PRODUCER_TIMES = 1000;
49 };
50
SetUpTestCase()51 void SurfaceIPCWithPTSTest::SetUpTestCase()
52 {
53 GTEST_LOG_(INFO) << getpid();
54 requestConfig = {
55 .width = 0x100, // small
56 .height = 0x100, // small
57 .strideAlignment = 0x8,
58 .format = GRAPHIC_PIXEL_FMT_RGBA_8888,
59 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
60 .timeout = 0,
61 };
62 desiredPresentTimestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
63 std::chrono::steady_clock::now().time_since_epoch()).count();
64 flushConfig = {
65 .damage = {
66 .w = 0x100,
67 .h = 0x100,
68 },
69 .desiredPresentTimestamp = desiredPresentTimestamp,
70 };
71 }
72
OnBufferAvailable()73 void SurfaceIPCWithPTSTest::OnBufferAvailable()
74 {
75 }
76
OnBufferRelease(sptr<SurfaceBuffer> &buffer)77 static inline GSError OnBufferRelease(sptr<SurfaceBuffer> &buffer)
78 {
79 return GSERROR_OK;
80 }
81
SetData(sptr<SurfaceBuffer> &buffer, sptr<Surface> &pSurface)82 OHOS::GSError SurfaceIPCWithPTSTest::SetData(sptr<SurfaceBuffer> &buffer, sptr<Surface> &pSurface)
83 {
84 buffer->GetExtraData()->ExtraSet("123", 0x123);
85 buffer->GetExtraData()->ExtraSet("345", (int64_t)0x345);
86 buffer->GetExtraData()->ExtraSet("567", "567");
87
88 uint32_t reserveInts = 1;
89 GraphicExtDataHandle *handle = AllocExtDataHandle(reserveInts);
90 handle->reserve[0] = 1;
91 OHOS::GSError ret = pSurface->SetTunnelHandle(handle);
92 FreeExtDataHandle(handle);
93 handle = nullptr;
94 return ret;
95 }
96
GetData(sptr<SurfaceBuffer> &buffer)97 bool SurfaceIPCWithPTSTest::GetData(sptr<SurfaceBuffer> &buffer)
98 {
99 int32_t int32;
100 int64_t int64;
101 std::string str;
102 buffer->GetExtraData()->ExtraGet("123", int32);
103 buffer->GetExtraData()->ExtraGet("345", int64);
104 buffer->GetExtraData()->ExtraGet("567", str);
105 if ((int32 != 0x123) || (int64 != 0x345) || (str != "567")) {
106 return false;
107 }
108
109 sptr<SurfaceTunnelHandle> handleGet = nullptr;
110 handleGet = cSurface->GetTunnelHandle();
111 if ((handleGet == nullptr) || (handleGet->GetHandle()->fd != -1) ||
112 (handleGet->GetHandle()->reserveInts != 1) || (handleGet->GetHandle()->reserve[0] != 1)) {
113 return false;
114 }
115
116 GraphicPresentTimestamp timestamp = {GRAPHIC_DISPLAY_PTS_DELAY, 1}; // mock data for test
117 auto sRet = cSurface->SetPresentTimestamp(buffer->GetSeqNum(), timestamp);
118 return (sRet == OHOS::GSERROR_OK);
119 }
120
CreateSurface()121 sptr<OHOS::Surface> SurfaceIPCWithPTSTest::CreateSurface()
122 {
123 sptr<IRemoteObject> robj = nullptr;
124 int i = 0;
125 while (i++ < WAIT_SYSTEM_ABILITY_GET_PRODUCER_TIMES) {
126 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
127 robj = sam->GetSystemAbility(ipcSystemAbilityID);
128 if (robj != nullptr) {
129 break;
130 }
131 usleep(1);
132 }
133
134 auto producer = iface_cast<IBufferProducer>(robj);
135 return Surface::CreateSurfaceAsProducer(producer);
136 }
137
ChildProcessMain()138 pid_t SurfaceIPCWithPTSTest::ChildProcessMain()
139 {
140 pipe(pipeFd);
141 pid_t pid = fork();
142 if (pid != 0) {
143 return pid;
144 }
145
146 int64_t data;
147 int64_t bufferNum;
148 read(pipeFd[0], &bufferNum, sizeof(bufferNum));
149
150 auto pSurface = CreateSurface();
151 auto nativeWindow = OH_NativeWindow_CreateNativeWindow(&pSurface);
152 int32_t code = SET_BUFFER_GEOMETRY;
153 int32_t height = 0x100;
154 int32_t weight = 0x100;
155 OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, height, weight);
156 code = SET_FORMAT;
157 int32_t format = GRAPHIC_PIXEL_FMT_RGBA_8888;
158 OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, format);
159 pSurface->RegisterReleaseListener(OnBufferRelease);
160 sptr<SurfaceBuffer> buffer;
161
162 struct NativeWindowBuffer *nativeWindowBuffer = nullptr;
163 int32_t sRet;
164 int fenceFd = -1;
165 for (int i = 0; i < bufferNum; i++) {
166 buffer = nullptr;
167 auto code = SET_UI_TIMESTAMP;
168 OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, static_cast<uint64_t>(desiredPresentTimestamp));
169 sRet = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &nativeWindowBuffer, &fenceFd);
170 if (sRet != OHOS::GSERROR_OK) {
171 data = sRet;
172 write(pipeFd[1], &data, sizeof(data));
173 exit(0);
174 }
175 if (i == 1) {
176 code = SET_DESIRED_PRESENT_TIMESTAMP;
177 OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, desiredPresentTimestamp);
178 sRet = SetData(nativeWindowBuffer->sfbuffer, pSurface);
179 if (sRet != OHOS::GSERROR_OK) {
180 data = sRet;
181 write(pipeFd[1], &data, sizeof(data));
182 exit(0);
183 }
184 }
185 struct Region *region = new Region();
186 struct Region::Rect *rect = new Region::Rect();
187 rect->w = 0x100;
188 rect->h = 0x100;
189 region->rects = rect;
190 region->rectNumber = 1;
191 sRet = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, nativeWindowBuffer, -1, *region);
192 if (sRet != OHOS::GSERROR_OK) {
193 data = sRet;
194 write(pipeFd[1], &data, sizeof(data));
195 exit(0);
196 }
197 }
198
199 data = sRet;
200 write(pipeFd[1], &data, sizeof(data));
201 usleep(1000); // sleep 1000 microseconds (equals 1 milliseconds)
202 read(pipeFd[0], &data, sizeof(data));
203 usleep(1000); // sleep 1000 microseconds (equals 1 milliseconds)
204 GraphicPresentTimestampType type = GraphicPresentTimestampType::GRAPHIC_DISPLAY_PTS_DELAY;
205 int64_t time = 0;
206 sRet = pSurface->GetPresentTimestamp(buffer->GetSeqNum(), type, time);
207 if (sRet != OHOS::GSERROR_OK || time != 1) {
208 data = sRet;
209 write(pipeFd[1], &data, sizeof(data));
210 exit(0);
211 }
212 pSurface->UnRegisterReleaseListener();
213 close(pipeFd[0]);
214 close(pipeFd[1]);
215 exit(0);
216 return 0;
217 }
218
219 /*
220 * Function: produce and consumer surface by IPC
221 * Type: Function
222 * Rank: Important(2)
223 * EnvConditions: N/A
224 * CaseDescription: 1. produce surface, fill buffer
225 * 2. consume surface and check buffer
226 * 3. call RequestBuffer in this process, check sRet and buffer
227 * @tc.require: issueI5I57K issueI5GMZN issueI5IWHW
228 */
HWTEST_F(SurfaceIPCWithPTSTest, BufferIPC001, Function | MediumTest | Level2)229 HWTEST_F(SurfaceIPCWithPTSTest, BufferIPC001, Function | MediumTest | Level2)
230 {
231 //生产者生产buffer
232 auto pid = ChildProcessMain();
233 ASSERT_GE(pid, 0);
234
235 uint64_t tokenId;
236 const char *perms[2];
237 perms[0] = "ohos.permission.DISTRIBUTED_DATASYNC";
238 perms[1] = "ohos.permission.CAMERA";
239 NativeTokenInfoParams infoInstance = {
240 .dcapsNum = 0,
241 .permsNum = 2,
242 .aclsNum = 0,
243 .dcaps = NULL,
244 .perms = perms,
245 .acls = NULL,
246 .processName = "dcamera_client_demo",
247 .aplStr = "system_basic",
248 };
249 tokenId = GetAccessTokenId(&infoInstance);
250 SetSelfTokenID(tokenId);
251 int32_t rett = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo();
252 ASSERT_EQ(rett, Security::AccessToken::RET_SUCCESS);
253 cSurface = IConsumerSurface::Create("test");
254 cSurface->RegisterConsumerListener(this);
255 auto producer = cSurface->GetProducer();
256 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
257 sam->AddSystemAbility(ipcSystemAbilityID, producer->AsObject());
258
259 int64_t data = 2;
260 write(pipeFd[1], &data, sizeof(data));
261 usleep(1000); // sleep 1000 microseconds (equals 1 milliseconds)
262 read(pipeFd[0], &data, sizeof(data));
263 EXPECT_EQ(data, OHOS::GSERROR_OK);
264
265 //消费者消费buffer
266 IConsumerSurface::AcquireBufferReturnValue returnValue = {
267 .buffer =nullptr,
268 .fence = new SyncFence(-1),
269 };
270 //Branch1 - No buffer ready
271 auto sRet = cSurface->AcquireBuffer(returnValue, desiredPresentTimestamp - 1, false);
272 EXPECT_EQ(sRet, GSERROR_NO_BUFFER_READY);
273
274 //Branch2 - Drop one buffer and acquire one buffer
275 sRet = cSurface->AcquireBuffer(returnValue, desiredPresentTimestamp, false);
276 EXPECT_EQ(sRet, OHOS::GSERROR_OK);
277 EXPECT_NE(returnValue.buffer, nullptr);
278 EXPECT_EQ(GetData(returnValue.buffer), true);
279
280 //Release buffer
281 sRet = cSurface->ReleaseBuffer(returnValue.buffer, -1);
282 EXPECT_EQ(sRet, OHOS::GSERROR_OK);
283
284 //Branch3 - No buffer
285 sRet = cSurface->AcquireBuffer(returnValue, desiredPresentTimestamp, false);
286 EXPECT_EQ(sRet, GSERROR_NO_BUFFER);
287
288 //close resource
289 write(pipeFd[1], &data, sizeof(data));
290 close(pipeFd[0]);
291 close(pipeFd[1]);
292 sam->RemoveSystemAbility(ipcSystemAbilityID);
293 int32_t ret = 0;
294 do {
295 waitpid(pid, nullptr, 0);
296 } while (ret == -1 && errno == EINTR);
297 }
298 }
299