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
16 #include "wl_shm_buffer_factory.h"
17
18 #include <cerrno>
19 #include <fcntl.h>
20 #include <map>
21 #include <securec.h>
22 #include <sys/mman.h>
23 #include <unistd.h>
24
25 #include "window_manager_hilog.h"
26 #include "wl_display.h"
27 #include "wl_shm_buffer.h"
28
29 namespace OHOS {
30 namespace {
31 constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0, "WMWlSHMBufferFactory" };
32 constexpr int32_t STRIDE_NUM = 4;
33 }
34
GetInstance()35 sptr<WlSHMBufferFactory> WlSHMBufferFactory::GetInstance()
36 {
37 if (instance == nullptr) {
38 static std::mutex mutex;
39 std::lock_guard<std::mutex> lock(mutex);
40 if (instance == nullptr) {
41 instance = new WlSHMBufferFactory();
42 }
43 }
44 return instance;
45 }
46
Init()47 void WlSHMBufferFactory::Init()
48 {
49 delegator.Dep<WaylandService>()->OnAppear(&WlSHMBufferFactory::OnAppear);
50 }
51
Deinit()52 void WlSHMBufferFactory::Deinit()
53 {
54 if (shmbuf != nullptr) {
55 wl_shm_destroy(shmbuf);
56 shmbuf = nullptr;
57 }
58 }
59
OnAppear(const GetServiceFunc get,const std::string & iname,uint32_t ver)60 void WlSHMBufferFactory::OnAppear(const GetServiceFunc get, const std::string &iname, uint32_t ver)
61 {
62 if (iname == "wl_shm") {
63 constexpr uint32_t wlShmVersion = 1;
64 auto ret = get(&wl_shm_interface, wlShmVersion);
65 shmbuf = static_cast<struct wl_shm *>(ret);
66 }
67 }
68
69 namespace {
CreateShmFile(int32_t size)70 int32_t CreateShmFile(int32_t size)
71 {
72 static const char tempPath[] = "/weston-shared-XXXXXX";
73 static const char path[] = "/data/weston";
74 size_t len = sizeof(path) + sizeof(tempPath) + 1;
75 std::unique_ptr<char[]> name = std::make_unique<char[]>(len);
76 auto ret = strcpy_s(name.get(), len, path);
77 if (ret) {
78 WMLOGFE("strcpy_s: %{public}s, name: %{public}s, len: %{public}zu, path: %{public}s",
79 strerror(errno), name.get() ? "Yes" : "No", len, path);
80 return -1;
81 }
82
83 ret = strcat_s(name.get(), len, tempPath);
84 if (ret) {
85 WMLOGFE("strcpy_s: %{public}s, name: %{public}s, len: %{public}zu, tempPath: %{public}s",
86 strerror(errno), name.get() ? "Yes" : "No", len, tempPath);
87 return -1;
88 }
89
90 int32_t fd = mkstemp(name.get());
91 if (fd < 0) {
92 WMLOGFE("mktemp failed with %{public}d, name: %{public}s", fd, name.get());
93 return -1;
94 }
95
96 ret = fcntl(fd, F_GETFD);
97 if (ret == -1) {
98 WMLOGFE("fcntl F_GETFD return -1, errno: %{public}s", strerror(errno));
99 close(fd);
100 return -1;
101 }
102
103 uint32_t flags = ret;
104 ret = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
105 if (ret == -1) {
106 WMLOGFE("fctn F_SETFD return -1, errno: %{public}s", strerror(errno));
107 close(fd);
108 return -1;
109 }
110
111 ret = unlink(name.get());
112 if (ret == -1) {
113 WMLOGFE("unlink return -1, errno: %{public}s", strerror(errno));
114 close(fd);
115 return -1;
116 }
117
118 ret = ftruncate(fd, size);
119 if (ret < 0) {
120 WMLOGFE("ftruncate: %{public}s", strerror(errno));
121 close(fd);
122 return -1;
123 }
124
125 return fd;
126 }
127 } // namespace
128
CreatePool(uint32_t mmapSize,int32_t & fd,void * & mmapPtr)129 wl_shm_pool *WlSHMBufferFactory::CreatePool(uint32_t mmapSize, int32_t &fd, void *&mmapPtr)
130 {
131 if (mmapSize == 0) {
132 WMLOGFE("shared memory size is zero");
133 return nullptr;
134 }
135
136 if (shmbuf == nullptr) {
137 WMLOGFE("shmbuf is nullptr");
138 return nullptr;
139 }
140
141 fd = CreateShmFile(mmapSize);
142 if (fd < 0) {
143 WMLOGFE("CreateShmFile failed, size: %{public}d", mmapSize);
144 return nullptr;
145 }
146
147 mmapPtr = mmap(nullptr, mmapSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
148 if (mmapPtr == nullptr) {
149 WMLOGFE("mmap failed, size: %{public}d, fd: %{public}d", mmapSize, fd);
150 close(fd);
151 return nullptr;
152 }
153
154 auto pool = wl_shm_create_pool(shmbuf, fd, mmapSize);
155 if (pool == nullptr) {
156 WMLOGFE("wl_shm_create_pool failed, size: %{public}d, fd: %{public}d", mmapSize, fd);
157 munmap(mmapPtr, mmapSize);
158 close(fd);
159 }
160 return pool;
161 }
162
Create(uint32_t w,uint32_t h,int32_t format)163 sptr<WlBuffer> WlSHMBufferFactory::Create(uint32_t w, uint32_t h, int32_t format)
164 {
165 uint32_t stride = w * STRIDE_NUM;
166 uint32_t mmapSize = stride * h;
167 int32_t fd = -1;
168 void *mmapPtr = nullptr;
169 auto pool = CreatePool(mmapSize, fd, mmapPtr);
170 if (pool == nullptr) {
171 return nullptr;
172 }
173
174 auto display = delegator.Dep<WlDisplay>();
175 auto buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format);
176 if (buffer == nullptr) {
177 WMLOGFE("%{public}s failed, %{public}dx%{public}d, stride: %{public}d, format: %{public}d",
178 "wl_shm_pool_create_buffer", w, h, stride, format);
179 munmap(mmapPtr, mmapSize);
180 close(fd);
181 wl_shm_pool_destroy(pool);
182 return nullptr;
183 }
184
185 display->Sync();
186 if (display->GetError() != 0) {
187 WMLOGFE("%{public}s failed with %{public}d, %{public}dx%{public}d, stride: %{public}d, format: %{public}d",
188 "wl_shm_pool_create_buffer", display->GetError(), w, h, stride, format);
189 wl_buffer_destroy(buffer);
190 munmap(mmapPtr, mmapSize);
191 close(fd);
192 wl_shm_pool_destroy(pool);
193 return nullptr;
194 }
195
196 sptr<WlSHMBuffer> ret = new WlSHMBuffer(buffer);
197 if (ret == nullptr) {
198 WMLOGFE("new WlSHMBuffer failed");
199 wl_buffer_destroy(buffer);
200 munmap(mmapPtr, mmapSize);
201 close(fd);
202 wl_shm_pool_destroy(pool);
203 return nullptr;
204 }
205 ret->SetMmap(mmapPtr, mmapSize);
206
207 wl_shm_pool_destroy(pool);
208 close(fd);
209 return ret;
210 }
211 } // namespace OHOS
212