1 /*
2 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
3 * Not a Contribution.
4 *
5 * Copyright 2015 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #include "EGLImageWrapper.h"
21 #include <cutils/native_handle.h>
22 #include <gralloc_priv.h>
23 #include <ui/GraphicBuffer.h>
24 #include <fcntl.h>
25 #include <string>
26 #include <map>
27 #include <utility>
28
29 using std::string;
30 using std::map;
31 using std::pair;
32
33 static string pidString = std::to_string(getpid());
34
35 #ifndef TARGET_ION_ABI_VERSION
36 //-----------------------------------------------------------------------------
free_ion_cookie(int ion_fd,int cookie)37 static void free_ion_cookie(int ion_fd, int cookie)
38 //-----------------------------------------------------------------------------
39 {
40 if (ion_fd && !ioctl(ion_fd, ION_IOC_FREE, &cookie)) {
41 } else {
42 ALOGE("ION_IOC_FREE failed: ion_fd = %d, cookie = %d", ion_fd, cookie);
43 }
44 }
45
46 //-----------------------------------------------------------------------------
get_ion_cookie(int ion_fd,int fd)47 static int get_ion_cookie(int ion_fd, int fd)
48 //-----------------------------------------------------------------------------
49 {
50 int cookie = fd;
51
52 struct ion_fd_data fdData;
53 memset(&fdData, 0, sizeof(fdData));
54 fdData.fd = fd;
55
56 if (ion_fd && !ioctl(ion_fd, ION_IOC_IMPORT, &fdData)) {
57 cookie = fdData.handle;
58 } else {
59 ALOGE("ION_IOC_IMPORT failed: ion_fd = %d, fd = %d", ion_fd, fd);
60 }
61
62 return cookie;
63 }
64 #else
65 //-----------------------------------------------------------------------------
get_ion_buff_str(int buff_fd)66 static string get_ion_buff_str(int buff_fd)
67 //-----------------------------------------------------------------------------
68 {
69 string retStr = {};
70 if (buff_fd >= 0) {
71 string fdString = std::to_string(buff_fd);
72 string symlinkPath = "/proc/"+pidString+"/fd/"+fdString;
73 char buffer[1024] = {};
74 ssize_t ret = ::readlink(symlinkPath.c_str(), buffer, sizeof(buffer) - 1);
75 if (ret != -1) {
76 buffer[ret] = '\0';
77 retStr = buffer;
78 }
79 }
80
81 return retStr;
82 }
83 #endif
84
85 //-----------------------------------------------------------------------------
operator ()(int & buffInt,EGLImageBuffer * & eglImage)86 void EGLImageWrapper::DeleteEGLImageCallback::operator()(int& buffInt, EGLImageBuffer*& eglImage)
87 //-----------------------------------------------------------------------------
88 {
89 if (eglImage != 0) {
90 delete eglImage;
91 }
92
93 #ifndef TARGET_ION_ABI_VERSION
94 free_ion_cookie(ion_fd, buffInt /* cookie */);
95 #else
96 if (!mapClearPending) {
97 for (auto it = buffStrbuffIntMapPtr->begin(); it != buffStrbuffIntMapPtr->end(); it++) {
98 if (it->second == buffInt /* counter */) {
99 buffStrbuffIntMapPtr->erase(it);
100 return;
101 }
102 }
103 }
104 #endif
105 }
106
107 //-----------------------------------------------------------------------------
EGLImageWrapper()108 EGLImageWrapper::EGLImageWrapper()
109 //-----------------------------------------------------------------------------
110 {
111 eglImageBufferCache = new android::LruCache<int, EGLImageBuffer*>(32);
112 callback = new DeleteEGLImageCallback(&buffStrbuffIntMap);
113 eglImageBufferCache->setOnEntryRemovedListener(callback);
114
115 #ifndef TARGET_ION_ABI_VERSION
116 ion_fd = open("/dev/ion", O_RDONLY);
117 callback->ion_fd = ion_fd;
118 #endif
119 }
120
121 //-----------------------------------------------------------------------------
~EGLImageWrapper()122 EGLImageWrapper::~EGLImageWrapper()
123 //-----------------------------------------------------------------------------
124 {
125 if (eglImageBufferCache != 0) {
126 if (callback != 0) {
127 callback->mapClearPending = true;
128 }
129 eglImageBufferCache->clear();
130 delete eglImageBufferCache;
131 eglImageBufferCache = 0;
132 buffStrbuffIntMap.clear();
133 }
134
135 if (callback != 0) {
136 delete callback;
137 callback = 0;
138 }
139
140 #ifndef TARGET_ION_ABI_VERSION
141 if (ion_fd > 0) {
142 close(ion_fd);
143 ion_fd = -1;
144 }
145 #endif
146 }
147
148 //-----------------------------------------------------------------------------
L_wrap(const private_handle_t * src)149 static EGLImageBuffer* L_wrap(const private_handle_t *src)
150 //-----------------------------------------------------------------------------
151 {
152 EGLImageBuffer* result = 0;
153
154 native_handle_t *native_handle = const_cast<private_handle_t *>(src);
155
156 int flags = android::GraphicBuffer::USAGE_HW_TEXTURE |
157 android::GraphicBuffer::USAGE_SW_READ_NEVER |
158 android::GraphicBuffer::USAGE_SW_WRITE_NEVER;
159
160 if (src->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
161 flags |= android::GraphicBuffer::USAGE_PROTECTED;
162 }
163
164 android::sp<android::GraphicBuffer> graphicBuffer =
165 new android::GraphicBuffer(src->unaligned_width, src->unaligned_height, src->format,
166 #ifndef __NOUGAT__
167 1, // Layer count
168 #endif
169 flags, src->width /*src->stride*/,
170 native_handle, false);
171
172 result = new EGLImageBuffer(graphicBuffer);
173
174 return result;
175 }
176
177 //-----------------------------------------------------------------------------
wrap(const void * pvt_handle)178 EGLImageBuffer *EGLImageWrapper::wrap(const void *pvt_handle)
179 //-----------------------------------------------------------------------------
180 {
181 const private_handle_t *src = static_cast<const private_handle_t *>(pvt_handle);
182
183 #ifndef TARGET_ION_ABI_VERSION
184 int ion_cookie = get_ion_cookie(ion_fd, src->fd);
185 EGLImageBuffer* eglImage = nullptr;
186 eglImage = eglImageBufferCache->get(ion_cookie);
187 if (eglImage == 0) {
188 eglImage = L_wrap(src);
189 eglImageBufferCache->put(ion_cookie, eglImage);
190 } else {
191 free_ion_cookie(ion_fd, ion_cookie);
192 }
193 #else
194 string buffStr = get_ion_buff_str(src->fd);
195 EGLImageBuffer* eglImage = nullptr;
196 if (!buffStr.empty()) {
197 auto it = buffStrbuffIntMap.find(buffStr);
198 if (it != buffStrbuffIntMap.end()) {
199 eglImage = eglImageBufferCache->get(it->second);
200 } else {
201 eglImage = L_wrap(src);
202 buffStrbuffIntMap.insert(pair<string, int>(buffStr, buffInt));
203 eglImageBufferCache->put(buffInt, eglImage);
204 buffInt++;
205 }
206 } else {
207 ALOGE("Could not provide an eglImage for fd = %d, EGLImageWrapper = %p", src->fd, this);
208 }
209 #endif
210
211 return eglImage;
212 }
213