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