1 /*
2 * Copyright (c) 2021 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
26 using namespace testing;
27 using namespace testing::ext;
28
29 namespace OHOS::Rosen {
30 class SurfaceIPCTest : public testing::Test, public IBufferConsumerListenerClazz {
31 public:
32 static void SetUpTestCase();
33 void OnBufferAvailable() override;
34 OHOS::GSError SetData(sptr<SurfaceBuffer> &buffer, sptr<Surface> &pSurface);
35 bool GetData(sptr<SurfaceBuffer> &buffer);
36 pid_t ChildProcessMain();
37 sptr<OHOS::Surface> CreateSurface();
38
39 static inline sptr<IConsumerSurface> cSurface = nullptr;
40 static inline int32_t pipeMain[2] = {};
41 static inline int32_t pipeChild[2] = {};
42 static inline int32_t ipcSystemAbilityID = 34156;
43 static inline BufferRequestConfig requestConfig = {};
44 static inline BufferFlushConfig flushConfig = {};
45 };
46
SetUpTestCase()47 void SurfaceIPCTest::SetUpTestCase()
48 {
49 GTEST_LOG_(INFO) << getpid();
50 requestConfig = {
51 .width = 0x100, // small
52 .height = 0x100, // small
53 .strideAlignment = 0x8,
54 .format = GRAPHIC_PIXEL_FMT_RGBA_8888,
55 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
56 .timeout = 0,
57 };
58 flushConfig = { .damage = {
59 .w = 0x100,
60 .h = 0x100,
61 } };
62 }
63
OnBufferAvailable()64 void SurfaceIPCTest::OnBufferAvailable()
65 {
66 }
67
OnBufferRelease(sptr<SurfaceBuffer> & buffer)68 static inline GSError OnBufferRelease(sptr<SurfaceBuffer> &buffer)
69 {
70 return GSERROR_OK;
71 }
72
SetData(sptr<SurfaceBuffer> & buffer,sptr<Surface> & pSurface)73 OHOS::GSError SurfaceIPCTest::SetData(sptr<SurfaceBuffer> &buffer, sptr<Surface> &pSurface)
74 {
75 buffer->GetExtraData()->ExtraSet("123", 0x123);
76 buffer->GetExtraData()->ExtraSet("345", (int64_t)0x345);
77 buffer->GetExtraData()->ExtraSet("567", "567");
78
79 uint32_t reserveInts = 1;
80 GraphicExtDataHandle *handle = AllocExtDataHandle(reserveInts);
81 handle->reserve[0] = 1;
82 OHOS::GSError ret = pSurface->SetTunnelHandle(handle);
83 FreeExtDataHandle(handle);
84 handle = nullptr;
85 return ret;
86 }
87
GetData(sptr<SurfaceBuffer> & buffer)88 bool SurfaceIPCTest::GetData(sptr<SurfaceBuffer> &buffer)
89 {
90 int32_t int32;
91 int64_t int64;
92 std::string str;
93 buffer->GetExtraData()->ExtraGet("123", int32);
94 buffer->GetExtraData()->ExtraGet("345", int64);
95 buffer->GetExtraData()->ExtraGet("567", str);
96 if ((int32 != 0x123) || (int64 != 0x345) || (str != "567")) {
97 return false;
98 }
99
100 sptr<SurfaceTunnelHandle> handleGet = nullptr;
101 handleGet = cSurface->GetTunnelHandle();
102 if ((handleGet == nullptr) || (handleGet->GetHandle()->fd != -1) ||
103 (handleGet->GetHandle()->reserveInts != 1) || (handleGet->GetHandle()->reserve[0] != 1)) {
104 return false;
105 }
106
107 GraphicPresentTimestamp timestamp = {GRAPHIC_DISPLAY_PTS_DELAY, 1}; // mock data for test
108 auto sRet = cSurface->SetPresentTimestamp(buffer->GetSeqNum(), timestamp);
109 return (sRet == OHOS::GSERROR_OK);
110 }
111
CreateSurface()112 sptr<OHOS::Surface> SurfaceIPCTest::CreateSurface()
113 {
114 sptr<IRemoteObject> robj = nullptr;
115 while (true) {
116 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
117 robj = sam->GetSystemAbility(ipcSystemAbilityID);
118 if (robj != nullptr) {
119 break;
120 }
121 sleep(0);
122 }
123
124 auto producer = iface_cast<IBufferProducer>(robj);
125 return Surface::CreateSurfaceAsProducer(producer);
126 }
127
ChildProcessMain()128 pid_t SurfaceIPCTest::ChildProcessMain()
129 {
130 pipe(pipeMain);
131 pipe(pipeChild);
132 pid_t pid = fork();
133 if (pid != 0) {
134 return pid;
135 }
136
137 int64_t data;
138 read(pipeMain[0], &data, sizeof(data));
139
140 auto pSurface = CreateSurface();
141 pSurface->RegisterReleaseListener(OnBufferRelease);
142 sptr<SurfaceBuffer> buffer = nullptr;
143 int releaseFence = -1;
144 auto sRet = pSurface->RequestBuffer(buffer, releaseFence, requestConfig);
145 if (sRet != OHOS::GSERROR_OK) {
146 data = sRet;
147 write(pipeChild[1], &data, sizeof(data));
148 exit(0);
149 }
150 sRet = SetData(buffer, pSurface);
151 if (sRet != OHOS::GSERROR_OK) {
152 data = sRet;
153 write(pipeChild[1], &data, sizeof(data));
154 exit(0);
155 }
156
157 sRet = pSurface->FlushBuffer(buffer, -1, flushConfig);
158 data = sRet;
159 write(pipeChild[1], &data, sizeof(data));
160 usleep(1000); // sleep 1000 microseconds (equals 1 milliseconds)
161 read(pipeMain[0], &data, sizeof(data));
162 usleep(1000); // sleep 1000 microseconds (equals 1 milliseconds)
163 GraphicPresentTimestampType type = GraphicPresentTimestampType::GRAPHIC_DISPLAY_PTS_DELAY;
164 int64_t time = 0;
165 sRet = pSurface->GetPresentTimestamp(buffer->GetSeqNum(), type, time);
166 if (sRet != OHOS::GSERROR_OK || time != 1) {
167 data = sRet;
168 write(pipeChild[1], &data, sizeof(data));
169 exit(0);
170 }
171 pSurface->UnRegisterReleaseListener();
172 close(pipeMain[0]);
173 close(pipeMain[1]);
174 close(pipeChild[0]);
175 close(pipeChild[1]);
176 exit(0);
177 return 0;
178 }
179
180 /*
181 * Function: produce and consumer surface by IPC
182 * Type: Function
183 * Rank: Important(2)
184 * EnvConditions: N/A
185 * CaseDescription: 1. produce surface, fill buffer
186 * 2. consume surface and check buffer
187 * 3. call RequestBuffer in this process, check sRet and buffer
188 * @tc.require: issueI5I57K issueI5GMZN issueI5IWHW
189 */
190 HWTEST_F(SurfaceIPCTest, BufferIPC001, TestSize.Level0)
191 {
192 auto pid = ChildProcessMain();
193 ASSERT_GE(pid, 0);
194
195 uint64_t tokenId;
196 const char *perms[2];
197 perms[0] = "ohos.permission.DISTRIBUTED_DATASYNC";
198 perms[1] = "ohos.permission.CAMERA";
199 NativeTokenInfoParams infoInstance = {
200 .dcapsNum = 0,
201 .permsNum = 2,
202 .aclsNum = 0,
203 .dcaps = NULL,
204 .perms = perms,
205 .acls = NULL,
206 .processName = "dcamera_client_demo",
207 .aplStr = "system_basic",
208 };
209 tokenId = GetAccessTokenId(&infoInstance);
210 SetSelfTokenID(tokenId);
211 int32_t rett = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo();
212 ASSERT_EQ(rett, Security::AccessToken::RET_SUCCESS);
213 cSurface = IConsumerSurface::Create("test");
214 cSurface->RegisterConsumerListener(this);
215 auto producer = cSurface->GetProducer();
216 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
217 sam->AddSystemAbility(ipcSystemAbilityID, producer->AsObject());
218
219 int64_t data = 0;
220 write(pipeMain[1], &data, sizeof(data));
221 usleep(1000); // sleep 1000 microseconds (equals 1 milliseconds)
222 read(pipeChild[0], &data, sizeof(data));
223 EXPECT_EQ(data, OHOS::GSERROR_OK);
224
225 sptr<SurfaceBuffer> buffer = nullptr;
226 int32_t fence = -1;
227 int64_t timestamp;
228 Rect damage;
229 auto sRet = cSurface->AcquireBuffer(buffer, fence, timestamp, damage);
230 EXPECT_EQ(sRet, OHOS::GSERROR_OK);
231 EXPECT_NE(buffer, nullptr);
232 EXPECT_EQ(GetData(buffer), true);
233
234 sRet = cSurface->ReleaseBuffer(buffer, -1);
235 EXPECT_EQ(sRet, OHOS::GSERROR_OK);
236
237 // RequestBuffer cannot be called in two processes
238 auto pSurfaceSecond = Surface::CreateSurfaceAsProducer(producer);
239 sptr<SurfaceBuffer> bufferSecond = nullptr;
240 int releaseFence = -1;
241 sRet = pSurfaceSecond->RequestBuffer(bufferSecond, releaseFence, requestConfig);
242 ASSERT_EQ(sRet, GSERROR_CONSUMER_IS_CONNECTED);
243 ASSERT_EQ(bufferSecond, nullptr);
244
245 //close resource
246 write(pipeMain[1], &data, sizeof(data));
247 close(pipeMain[0]);
248 close(pipeMain[1]);
249 close(pipeChild[0]);
250 close(pipeChild[1]);
251 sam->RemoveSystemAbility(ipcSystemAbilityID);
252 int32_t ret = 0;
253 do {
254 waitpid(pid, nullptr, 0);
255 } while (ret == -1 && errno == EINTR);
256 }
257
258 /*
259 * Function: disconnect
260 * Type: Function
261 * Rank: Important(1)
262 * EnvConditions: N/A
263 * CaseDescription: 1. call Disconnect in other process, check sRet
264 */
265 HWTEST_F(SurfaceIPCTest, Disconnect001, TestSize.Level0)
266 {
267 cSurface->RegisterConsumerListener(this);
268 auto producer = cSurface->GetProducer();
269 auto pSurface = Surface::CreateSurfaceAsProducer(producer);
270 auto sRet = pSurface->Disconnect();
271 ASSERT_EQ(sRet, GSERROR_CONSUMER_DISCONNECTED); // Disconnect cannot be called in two processes
272 }
273 }