1 /*
2 * Copyright 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "layers_extensions.h"
18
19 #include "base/System.h"
20 #include "base/PathUtils.h"
21
22 #include <alloca.h>
23 #include <dirent.h>
24 #include <dlfcn.h>
25 #include <string.h>
26
27 #include <algorithm>
28 #include <memory>
29 #include <mutex>
30 #include <string>
31 #include <vector>
32
33 #include <android/dlext.h>
34 #include <cutils/properties.h>
35 #include <log/log.h>
36
37 using android::base::pj;
38
39 // TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
40 // not a good long-term solution. Having a hard-coded enum of extensions is
41 // bad, of course. Representing sets of extensions (requested, supported, etc.)
42 // as a bitset isn't necessarily bad, if the mapping from extension to bit were
43 // dynamic. Need to rethink this completely when there's a little more time.
44
45 // TODO(jessehall): This file currently builds up global data structures as it
46 // loads, and never cleans them up. This means we're doing heap allocations
47 // without going through an app-provided allocator, but worse, we'll leak those
48 // allocations if the loader is unloaded.
49 //
50 // We should allocate "enough" BSS space, and suballocate from there. Will
51 // probably want to intern strings, etc., and will need some custom/manual data
52 // structures.
53
54 namespace vulkan {
55 namespace api {
56
57 struct Layer {
58 VkLayerProperties properties;
59 size_t library_idx;
60
61 // true if the layer intercepts vkCreateDevice and device commands
62 bool is_global;
63
64 std::vector<VkExtensionProperties> instance_extensions;
65 std::vector<VkExtensionProperties> device_extensions;
66 };
67
68 namespace {
69
70 const char kSystemLayerLibraryDir[] = "/data/local/debug/vulkan";
71
72 class LayerLibrary {
73 public:
LayerLibrary(const std::string & path,const std::string & filename)74 explicit LayerLibrary(const std::string& path,
75 const std::string& filename)
76 : path_(path),
77 filename_(filename),
78 dlhandle_(nullptr),
79 native_bridge_(false),
80 refcount_(0) {}
81
LayerLibrary(LayerLibrary && other)82 LayerLibrary(LayerLibrary&& other) noexcept
83 : path_(std::move(other.path_)),
84 filename_(std::move(other.filename_)),
85 dlhandle_(other.dlhandle_),
86 native_bridge_(other.native_bridge_),
87 refcount_(other.refcount_) {
88 other.dlhandle_ = nullptr;
89 other.refcount_ = 0;
90 }
91
92 LayerLibrary(const LayerLibrary&) = delete;
93 LayerLibrary& operator=(const LayerLibrary&) = delete;
94
95 // these are thread-safe
96 bool Open();
97 void Close();
98
99 bool EnumerateLayers(size_t library_idx,
100 std::vector<Layer>& instance_layers) const;
101
102 void* GetGPA(const Layer& layer,
103 const char* gpa_name,
104 size_t gpa_name_len) const;
105
GetFilename()106 const std::string GetFilename() { return filename_; }
107
108 private:
109 // TODO(b/79940628): remove that adapter when we could use NativeBridgeGetTrampoline
110 // for native libraries.
111 template<typename Func = void*>
GetTrampoline(const char * name) const112 Func GetTrampoline(const char* name) const {
113 return reinterpret_cast<Func>(dlsym(dlhandle_, name));
114 }
115
116 const std::string path_;
117
118 // Track the filename alone so we can detect duplicates
119 const std::string filename_;
120
121 std::mutex mutex_;
122 void* dlhandle_;
123 bool native_bridge_;
124 size_t refcount_;
125 };
126
Open()127 bool LayerLibrary::Open() {
128 std::lock_guard<std::mutex> lock(mutex_);
129 if (refcount_++ == 0) {
130 ALOGV("opening layer library '%s'", path_.c_str());
131 dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
132 if (!dlhandle_) {
133 ALOGE("failed to load layer library '%s': %s", path_.c_str(),
134 dlerror());
135 refcount_ = 0;
136 return false;
137 }
138 }
139 return true;
140 }
141
Close()142 void LayerLibrary::Close() {
143 std::lock_guard<std::mutex> lock(mutex_);
144 if (--refcount_ == 0) {
145 ALOGV("closing layer library '%s'", path_.c_str());
146 std::string error_msg;
147 dlclose(dlhandle_);
148 dlhandle_ = nullptr;
149 }
150 }
151
EnumerateLayers(size_t library_idx,std::vector<Layer> & instance_layers) const152 bool LayerLibrary::EnumerateLayers(size_t library_idx,
153 std::vector<Layer>& instance_layers) const {
154 PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers =
155 GetTrampoline<PFN_vkEnumerateInstanceLayerProperties>(
156 "vkEnumerateInstanceLayerProperties");
157 PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions =
158 GetTrampoline<PFN_vkEnumerateInstanceExtensionProperties>(
159 "vkEnumerateInstanceExtensionProperties");
160 if (!enumerate_instance_layers || !enumerate_instance_extensions) {
161 ALOGE("layer library '%s' missing some instance enumeration functions",
162 path_.c_str());
163 return false;
164 }
165
166 // device functions are optional
167 PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
168 GetTrampoline<PFN_vkEnumerateDeviceLayerProperties>(
169 "vkEnumerateDeviceLayerProperties");
170 PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
171 GetTrampoline<PFN_vkEnumerateDeviceExtensionProperties>(
172 "vkEnumerateDeviceExtensionProperties");
173
174 // get layer counts
175 uint32_t num_instance_layers = 0;
176 uint32_t num_device_layers = 0;
177 VkResult result = enumerate_instance_layers(&num_instance_layers, nullptr);
178 if (result != VK_SUCCESS || !num_instance_layers) {
179 if (result != VK_SUCCESS) {
180 ALOGE(
181 "vkEnumerateInstanceLayerProperties failed for library '%s': "
182 "%d",
183 path_.c_str(), result);
184 }
185 return false;
186 }
187 if (enumerate_device_layers) {
188 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
189 nullptr);
190 if (result != VK_SUCCESS) {
191 ALOGE(
192 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
193 path_.c_str(), result);
194 return false;
195 }
196 }
197
198 // get layer properties
199 VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca(
200 (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
201 result = enumerate_instance_layers(&num_instance_layers, properties);
202 if (result != VK_SUCCESS) {
203 ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
204 path_.c_str(), result);
205 return false;
206 }
207 if (num_device_layers > 0) {
208 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
209 properties + num_instance_layers);
210 if (result != VK_SUCCESS) {
211 ALOGE(
212 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
213 path_.c_str(), result);
214 return false;
215 }
216 }
217
218 // append layers to instance_layers
219 size_t prev_num_instance_layers = instance_layers.size();
220 instance_layers.reserve(prev_num_instance_layers + num_instance_layers);
221 for (size_t i = 0; i < num_instance_layers; i++) {
222 const VkLayerProperties& props = properties[i];
223
224 Layer layer;
225 layer.properties = props;
226 layer.library_idx = library_idx;
227 layer.is_global = false;
228
229 uint32_t count = 0;
230 result =
231 enumerate_instance_extensions(props.layerName, &count, nullptr);
232 if (result != VK_SUCCESS) {
233 ALOGE(
234 "vkEnumerateInstanceExtensionProperties(\"%s\") failed for "
235 "library '%s': %d",
236 props.layerName, path_.c_str(), result);
237 instance_layers.resize(prev_num_instance_layers);
238 return false;
239 }
240 layer.instance_extensions.resize(count);
241 result = enumerate_instance_extensions(
242 props.layerName, &count, layer.instance_extensions.data());
243 if (result != VK_SUCCESS) {
244 ALOGE(
245 "vkEnumerateInstanceExtensionProperties(\"%s\") failed for "
246 "library '%s': %d",
247 props.layerName, path_.c_str(), result);
248 instance_layers.resize(prev_num_instance_layers);
249 return false;
250 }
251
252 for (size_t j = 0; j < num_device_layers; j++) {
253 const auto& dev_props = properties[num_instance_layers + j];
254 if (memcmp(&props, &dev_props, sizeof(props)) == 0) {
255 layer.is_global = true;
256 break;
257 }
258 }
259
260 if (layer.is_global && enumerate_device_extensions) {
261 result = enumerate_device_extensions(
262 VK_NULL_HANDLE, props.layerName, &count, nullptr);
263 if (result != VK_SUCCESS) {
264 ALOGE(
265 "vkEnumerateDeviceExtensionProperties(\"%s\") failed for "
266 "library '%s': %d",
267 props.layerName, path_.c_str(), result);
268 instance_layers.resize(prev_num_instance_layers);
269 return false;
270 }
271 layer.device_extensions.resize(count);
272 result = enumerate_device_extensions(
273 VK_NULL_HANDLE, props.layerName, &count,
274 layer.device_extensions.data());
275 if (result != VK_SUCCESS) {
276 ALOGE(
277 "vkEnumerateDeviceExtensionProperties(\"%s\") failed for "
278 "library '%s': %d",
279 props.layerName, path_.c_str(), result);
280 instance_layers.resize(prev_num_instance_layers);
281 return false;
282 }
283 }
284
285 instance_layers.push_back(layer);
286 ALOGD("added %s layer '%s' from library '%s'",
287 (layer.is_global) ? "global" : "instance", props.layerName,
288 path_.c_str());
289 }
290
291 return true;
292 }
293
GetGPA(const Layer & layer,const char * gpa_name,size_t gpa_name_len) const294 void* LayerLibrary::GetGPA(const Layer& layer,
295 const char* gpa_name,
296 size_t gpa_name_len) const {
297 void* gpa;
298 size_t layer_name_len =
299 std::max(size_t{2}, strlen(layer.properties.layerName));
300 char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
301 strcpy(name, layer.properties.layerName);
302 strcpy(name + layer_name_len, gpa_name);
303 if (!(gpa = GetTrampoline(name))) {
304 strcpy(name, "vk");
305 strcpy(name + 2, gpa_name);
306 gpa = GetTrampoline(name);
307 }
308 return gpa;
309 }
310
311 // ----------------------------------------------------------------------------
312
313 std::vector<LayerLibrary> g_layer_libraries;
314 std::vector<Layer> g_instance_layers;
315
AddLayerLibrary(const std::string & path,const std::string & filename)316 void AddLayerLibrary(const std::string& path, const std::string& filename) {
317 LayerLibrary library(path + "/" + filename, filename);
318 if (!library.Open())
319 return;
320
321 if (!library.EnumerateLayers(g_layer_libraries.size(), g_instance_layers)) {
322 library.Close();
323 return;
324 }
325
326 library.Close();
327
328 g_layer_libraries.emplace_back(std::move(library));
329 }
330
331 template <typename Functor>
ForEachFileInDir(const std::string & dirname,Functor functor)332 void ForEachFileInDir(const std::string& dirname, Functor functor) {
333 auto dir_deleter = [](DIR* handle) { closedir(handle); };
334 std::unique_ptr<DIR, decltype(dir_deleter)> dir(opendir(dirname.c_str()),
335 dir_deleter);
336 if (!dir) {
337 // It's normal for some search directories to not exist, especially
338 // /data/local/debug/vulkan.
339 int err = errno;
340 ALOGW_IF(err != ENOENT, "failed to open layer directory '%s': %s",
341 dirname.c_str(), strerror(err));
342 return;
343 }
344 ALOGD("searching for layers in '%s'", dirname.c_str());
345 dirent* entry;
346 while ((entry = readdir(dir.get())) != nullptr)
347 functor(entry->d_name);
348 }
349
350 template <typename Functor>
ForEachFileInPath(const std::string & path,Functor functor)351 void ForEachFileInPath(const std::string& path, Functor functor) {
352 size_t zip_pos = path.find("!/");
353 if (zip_pos == std::string::npos) {
354 ForEachFileInDir(path, functor);
355 }
356 }
357
DiscoverLayersInPathList(const std::string & path)358 void DiscoverLayersInPathList(const std::string& path) {
359 ForEachFileInPath(path, [&](const std::string& filename) {
360 if (filename.find("libVkLayer") == 0) {
361 // Check to ensure we haven't seen this layer already
362 // Let the first instance of the shared object be enumerated
363 // We're searching for layers in following order:
364 // 1. system path
365 // 2. libraryPermittedPath (if enabled)
366 // 3. libraryPath
367
368 bool duplicate = false;
369 for (auto& layer : g_layer_libraries) {
370 if (layer.GetFilename() == filename) {
371 ALOGV("Skipping duplicate layer %s in %s", filename.c_str(),
372 path.c_str());
373 duplicate = true;
374 }
375 }
376
377 if (!duplicate)
378 AddLayerLibrary(path, filename);
379 }
380 });
381 }
382
FindExtension(const std::vector<VkExtensionProperties> & extensions,const char * name)383 const VkExtensionProperties* FindExtension(
384 const std::vector<VkExtensionProperties>& extensions,
385 const char* name) {
386 auto it = std::find_if(extensions.cbegin(), extensions.cend(),
387 [=](const VkExtensionProperties& ext) {
388 return (strcmp(ext.extensionName, name) == 0);
389 });
390 return (it != extensions.cend()) ? &*it : nullptr;
391 }
392
GetLayerGetProcAddr(const Layer & layer,const char * gpa_name,size_t gpa_name_len)393 void* GetLayerGetProcAddr(const Layer& layer,
394 const char* gpa_name,
395 size_t gpa_name_len) {
396 const LayerLibrary& library = g_layer_libraries[layer.library_idx];
397 return library.GetGPA(layer, gpa_name, gpa_name_len);
398 }
399
400 } // anonymous namespace
401
DiscoverLayers()402 void DiscoverLayers() {
403 auto layerDiscoveryPath =
404 pj({android::base::getProgramDirectory(), "lib64"});
405 DiscoverLayersInPathList(layerDiscoveryPath);
406 std::string vkSdkPath = android::base::getEnvironmentVariable("VULKAN_SDK");
407 if (vkSdkPath != "") {
408 DiscoverLayersInPathList(vkSdkPath);
409 }
410 }
411
GetLayerCount()412 uint32_t GetLayerCount() {
413 return static_cast<uint32_t>(g_instance_layers.size());
414 }
415
GetLayer(uint32_t index)416 const Layer& GetLayer(uint32_t index) {
417 return g_instance_layers[index];
418 }
419
FindLayer(const char * name)420 const Layer* FindLayer(const char* name) {
421 auto layer =
422 std::find_if(g_instance_layers.cbegin(), g_instance_layers.cend(),
423 [=](const Layer& entry) {
424 return strcmp(entry.properties.layerName, name) == 0;
425 });
426 return (layer != g_instance_layers.cend()) ? &*layer : nullptr;
427 }
428
GetLayerProperties(const Layer & layer)429 const VkLayerProperties& GetLayerProperties(const Layer& layer) {
430 return layer.properties;
431 }
432
IsLayerGlobal(const Layer & layer)433 bool IsLayerGlobal(const Layer& layer) {
434 return layer.is_global;
435 }
436
GetLayerInstanceExtensions(const Layer & layer,uint32_t & count)437 const VkExtensionProperties* GetLayerInstanceExtensions(const Layer& layer,
438 uint32_t& count) {
439 count = static_cast<uint32_t>(layer.instance_extensions.size());
440 return layer.instance_extensions.data();
441 }
442
GetLayerDeviceExtensions(const Layer & layer,uint32_t & count)443 const VkExtensionProperties* GetLayerDeviceExtensions(const Layer& layer,
444 uint32_t& count) {
445 count = static_cast<uint32_t>(layer.device_extensions.size());
446 return layer.device_extensions.data();
447 }
448
FindLayerInstanceExtension(const Layer & layer,const char * name)449 const VkExtensionProperties* FindLayerInstanceExtension(const Layer& layer,
450 const char* name) {
451 return FindExtension(layer.instance_extensions, name);
452 }
453
FindLayerDeviceExtension(const Layer & layer,const char * name)454 const VkExtensionProperties* FindLayerDeviceExtension(const Layer& layer,
455 const char* name) {
456 return FindExtension(layer.device_extensions, name);
457 }
458
GetLayerRef(const Layer & layer)459 LayerRef GetLayerRef(const Layer& layer) {
460 LayerLibrary& library = g_layer_libraries[layer.library_idx];
461 return LayerRef((library.Open()) ? &layer : nullptr);
462 }
463
LayerRef(const Layer * layer)464 LayerRef::LayerRef(const Layer* layer) : layer_(layer) {}
465
~LayerRef()466 LayerRef::~LayerRef() {
467 if (layer_) {
468 LayerLibrary& library = g_layer_libraries[layer_->library_idx];
469 library.Close();
470 }
471 }
472
LayerRef(LayerRef && other)473 LayerRef::LayerRef(LayerRef&& other) noexcept : layer_(other.layer_) {
474 other.layer_ = nullptr;
475 }
476
GetGetInstanceProcAddr() const477 PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
478 return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
479 GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19))
480 : nullptr;
481 }
482
GetGetDeviceProcAddr() const483 PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
484 return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
485 GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17))
486 : nullptr;
487 }
488
489 } // namespace api
490 } // namespace vulkan
491