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