1 /*
2 * Copyright (c) 2025 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 SurfaceIPCWithConnectStrictlyTest : public testing::Test, public IBufferConsumerListenerClazz {
31 public:
32 static void SetUpTestCase();
33 void OnBufferAvailable() override;
34 bool GetData(sptr<SurfaceBuffer> &buffer);
35 pid_t ChildProcessMain();
36 sptr<OHOS::Surface> CreateSurface();
37
38 static inline sptr<IConsumerSurface> cSurface = nullptr;
39 static inline int32_t pipeRead[2] = {};
40 static inline int32_t pipeWrite[2] = {};
41 static inline int32_t ipcSystemAbilityID = 34156;
42 static inline BufferRequestConfig requestConfig = {};
43 static inline BufferFlushConfig flushConfig = {};
44 };
45
SetUpTestCase()46 void SurfaceIPCWithConnectStrictlyTest::SetUpTestCase()
47 {
48 GTEST_LOG_(INFO) << getpid();
49 requestConfig = {
50 .width = 0x100, // small
51 .height = 0x100, // small
52 .strideAlignment = 0x8,
53 .format = GRAPHIC_PIXEL_FMT_RGBA_8888,
54 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
55 .timeout = 0,
56 };
57 flushConfig = { .damage = {
58 .w = 0x100,
59 .h = 0x100,
60 } };
61 }
62
OnBufferAvailable()63 void SurfaceIPCWithConnectStrictlyTest::OnBufferAvailable()
64 {
65 }
66
OnBufferRelease(sptr<SurfaceBuffer> & buffer)67 static inline GSError OnBufferRelease(sptr<SurfaceBuffer> &buffer)
68 {
69 return GSERROR_OK;
70 }
71
CreateSurface()72 sptr<OHOS::Surface> SurfaceIPCWithConnectStrictlyTest::CreateSurface()
73 {
74 sptr<IRemoteObject> robj = nullptr;
75 while (true) {
76 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
77 robj = sam->GetSystemAbility(ipcSystemAbilityID);
78 if (robj != nullptr) {
79 break;
80 }
81 sleep(0);
82 }
83
84 auto producer = iface_cast<IBufferProducer>(robj);
85 return Surface::CreateSurfaceAsProducer(producer);
86 }
87
ChildProcessMain()88 pid_t SurfaceIPCWithConnectStrictlyTest::ChildProcessMain()
89 {
90 pipe(pipeRead);
91 pipe(pipeWrite);
92 pid_t pid = fork();
93 if (pid != 0) {
94 return pid;
95 }
96
97 int64_t data;
98 read(pipeRead[0], &data, sizeof(data));
99
100 auto pSurface = CreateSurface();
101 pSurface->RegisterReleaseListener(OnBufferRelease);
102 int releaseFence = -1;
103
104 // Branch1: producer Surface Request Buffer failed with GSERROR_CONSUMER_DISCONNECTED after disconnect strictly,
105 // but producer Surface Request Buffer success after enable connect strictly.
106 pSurface->DisconnectStrictly();
107 pSurface->Disconnect();
108 sptr<SurfaceBuffer> buffer1 = nullptr;
109 auto sRet = pSurface->RequestBuffer(buffer1, releaseFence, requestConfig);
110 EXPECT_EQ(sRet, OHOS::GSERROR_CONSUMER_DISCONNECTED);
111 pSurface->ConnectStrictly();
112 sRet = pSurface->RequestBuffer(buffer1, releaseFence, requestConfig);
113 EXPECT_EQ(sRet, OHOS::GSERROR_OK);
114 sRet = pSurface->FlushBuffer(buffer1, -1, flushConfig);
115 EXPECT_EQ(sRet, OHOS::GSERROR_OK);
116 data = sRet;
117 write(pipeWrite[1], &data, sizeof(data));
118 read(pipeRead[0], &data, sizeof(data));
119
120 // Branch2: producer request buffer success when ConnectStricyly(), flush buffer failed with
121 // GSERROR_CONSUMER_DISCONNECTED after disconnect strictly, but producer flush buffer success after
122 // connect strictly.
123
124 sptr<SurfaceBuffer> buffer2 = nullptr;
125 pSurface->ConnectStrictly();
126 sRet = pSurface->RequestBuffer(buffer2, releaseFence, requestConfig);
127 EXPECT_EQ(sRet, OHOS::GSERROR_OK);
128 pSurface->DisconnectStrictly();
129 sRet = pSurface->FlushBuffer(buffer2, -1, flushConfig);
130 EXPECT_EQ(sRet, OHOS::GSERROR_CONSUMER_DISCONNECTED);
131 pSurface->ConnectStrictly();
132 sRet = pSurface->FlushBuffer(buffer2, -1, flushConfig);
133 EXPECT_EQ(sRet, OHOS::GSERROR_OK);
134 data = sRet;
135 write(pipeWrite[1], &data, sizeof(data));
136 read(pipeRead[0], &data, sizeof(data));
137
138 write(pipeWrite[1], &data, sizeof(data));
139 usleep(1000); // sleep 1000 microseconds (equals 1 milliseconds)
140 read(pipeRead[0], &data, sizeof(data));
141 usleep(1000); // sleep 1000 microseconds (equals 1 milliseconds)
142 pSurface->UnRegisterReleaseListener();
143 close(pipeRead[0]);
144 close(pipeRead[1]);
145 close(pipeWrite[0]);
146 close(pipeWrite[1]);
147 exit(0);
148 return 0;
149 }
150
151 /*
152 * Function: produce and consumer surface by IPC
153 * Type: Function
154 * Rank: Important(2)
155 * EnvConditions: N/A
156 * Case1Description:
157 * Branch1: 1. PreSet: create producer surface and disconnect strictly
158 * 2. Operation: the producer failed to request buffer with error code GSERROR_CONSUMER_DISCONNECTED,
159 * but succeeded after being connected strictly.
160 * Branch2: 1. PreSet: producer connect strictly on request buffer and disconnect strictly to flush buffer
161 * 2. Operation: the producer failed to flush buffer with error code GSERROR_CONSUMER_DISCONNECTED,
162 * but succeeded after being connected strictly.
163 */
164 HWTEST_F(SurfaceIPCWithConnectStrictlyTest, BufferIPC001, TestSize.Level0)
165 {
166 auto pid = ChildProcessMain();
167 ASSERT_GE(pid, 0);
168
169 uint64_t tokenId;
170 const char *perms[2];
171 perms[0] = "ohos.permission.DISTRIBUTED_DATASYNC";
172 perms[1] = "ohos.permission.CAMERA";
173 NativeTokenInfoParams infoInstance = {
174 .dcapsNum = 0,
175 .permsNum = 2,
176 .aclsNum = 0,
177 .dcaps = NULL,
178 .perms = perms,
179 .acls = NULL,
180 .processName = "dcamera_client_demo",
181 .aplStr = "system_basic",
182 };
183 tokenId = GetAccessTokenId(&infoInstance);
184 SetSelfTokenID(tokenId);
185 int32_t rett = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo();
186 ASSERT_EQ(rett, Security::AccessToken::RET_SUCCESS);
187 cSurface = IConsumerSurface::Create("test");
188 cSurface->RegisterConsumerListener(this);
189 auto producer = cSurface->GetProducer();
190 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
191 sam->AddSystemAbility(ipcSystemAbilityID, producer->AsObject());
192
193 int64_t data = 0;
194 write(pipeRead[1], &data, sizeof(data));
195 read(pipeWrite[0], &data, sizeof(data));
196 EXPECT_EQ(data, OHOS::GSERROR_OK);
197
198 // requested 3 buffer in 3 branch
199 for (int i = 0 ; i < 2 ; i++) {
200 sptr<SurfaceBuffer> buffer = nullptr;
201 int32_t fence = -1;
202 int64_t timestamp;
203 Rect damage;
204 auto sRet = cSurface->AcquireBuffer(buffer, fence, timestamp, damage);
205 EXPECT_EQ(sRet, OHOS::GSERROR_OK);
206 EXPECT_NE(buffer, nullptr);
207 write(pipeRead[1], &data, sizeof(data));
208 read(pipeWrite[0], &data, sizeof(data));
209 EXPECT_EQ(data, OHOS::GSERROR_OK);
210 }
211
212 //close resource
213 write(pipeRead[1], &data, sizeof(data));
214 close(pipeRead[0]);
215 close(pipeRead[1]);
216 close(pipeWrite[0]);
217 close(pipeWrite[1]);
218 sam->RemoveSystemAbility(ipcSystemAbilityID);
219 int32_t ret = 0;
220 do {
221 waitpid(pid, nullptr, 0);
222 } while (ret == -1 && errno == EINTR);
223 }
224 }
225