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