• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18 
19 #include "layers_extensions.h"
20 
21 #include <alloca.h>
22 #include <dirent.h>
23 #include <dlfcn.h>
24 #include <string.h>
25 #include <sys/prctl.h>
26 
27 #include <mutex>
28 #include <string>
29 #include <vector>
30 
31 #include <android/dlext.h>
32 #include <android-base/strings.h>
33 #include <cutils/properties.h>
34 #include <graphicsenv/GraphicsEnv.h>
35 #include <log/log.h>
36 #include <nativebridge/native_bridge.h>
37 #include <nativeloader/native_loader.h>
38 #include <utils/Trace.h>
39 #include <ziparchive/zip_archive.h>
40 
41 // TODO(b/143296676): This file currently builds up global data structures as it
42 // loads, and never cleans them up. This means we're doing heap allocations
43 // without going through an app-provided allocator, but worse, we'll leak those
44 // allocations if the loader is unloaded.
45 //
46 // We should allocate "enough" BSS space, and suballocate from there. Will
47 // probably want to intern strings, etc., and will need some custom/manual data
48 // structures.
49 
50 namespace vulkan {
51 namespace api {
52 
53 struct Layer {
54     VkLayerProperties properties;
55     size_t library_idx;
56 
57     // true if the layer intercepts vkCreateDevice and device commands
58     bool is_global;
59 
60     std::vector<VkExtensionProperties> instance_extensions;
61     std::vector<VkExtensionProperties> device_extensions;
62 };
63 
64 namespace {
65 
66 const char kSystemLayerLibraryDir[] = "/data/local/debug/vulkan";
67 
68 class LayerLibrary {
69    public:
LayerLibrary(const std::string & path,const std::string & filename)70     explicit LayerLibrary(const std::string& path,
71                           const std::string& filename)
72         : path_(path),
73           filename_(filename),
74           dlhandle_(nullptr),
75           native_bridge_(false),
76           refcount_(0) {}
77 
LayerLibrary(LayerLibrary && other)78     LayerLibrary(LayerLibrary&& other) noexcept
79         : path_(std::move(other.path_)),
80           filename_(std::move(other.filename_)),
81           dlhandle_(other.dlhandle_),
82           native_bridge_(other.native_bridge_),
83           refcount_(other.refcount_) {
84         other.dlhandle_ = nullptr;
85         other.refcount_ = 0;
86     }
87 
88     LayerLibrary(const LayerLibrary&) = delete;
89     LayerLibrary& operator=(const LayerLibrary&) = delete;
90 
91     // these are thread-safe
92     bool Open();
93     void Close();
94 
95     bool EnumerateLayers(size_t library_idx,
96                          std::vector<Layer>& instance_layers) const;
97 
98     void* GetGPA(const Layer& layer, const std::string_view gpa_name) const;
99 
GetFilename()100     const std::string GetFilename() { return filename_; }
101 
102    private:
103     // TODO(b/79940628): remove that adapter when we could use NativeBridgeGetTrampoline
104     // for native libraries.
105     template<typename Func = void*>
GetTrampoline(const char * name) const106     Func GetTrampoline(const char* name) const {
107         if (native_bridge_) {
108             return reinterpret_cast<Func>(android::NativeBridgeGetTrampoline(
109                 dlhandle_, name, nullptr, 0));
110         }
111         return reinterpret_cast<Func>(dlsym(dlhandle_, name));
112     }
113 
114     const std::string path_;
115 
116     // Track the filename alone so we can detect duplicates
117     const std::string filename_;
118 
119     std::mutex mutex_;
120     void* dlhandle_;
121     bool native_bridge_;
122     size_t refcount_;
123 };
124 
Open()125 bool LayerLibrary::Open() {
126     std::lock_guard<std::mutex> lock(mutex_);
127     if (refcount_++ == 0) {
128         ALOGV("opening layer library '%s'", path_.c_str());
129         // Libraries in the system layer library dir can't be loaded into
130         // the application namespace. That causes compatibility problems, since
131         // any symbol dependencies will be resolved by system libraries. They
132         // can't safely use libc++_shared, for example. Which is one reason
133         // (among several) we only allow them in non-user builds.
134         auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
135         if (app_namespace &&
136             !android::base::StartsWith(path_, kSystemLayerLibraryDir)) {
137             char* error_msg = nullptr;
138             dlhandle_ = OpenNativeLibraryInNamespace(
139                 app_namespace, path_.c_str(), &native_bridge_, &error_msg);
140             if (!dlhandle_) {
141                 ALOGE("failed to load layer library '%s': %s", path_.c_str(), error_msg);
142                 android::NativeLoaderFreeErrorMessage(error_msg);
143                 refcount_ = 0;
144                 return false;
145             }
146         } else {
147           dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
148             if (!dlhandle_) {
149                 ALOGE("failed to load layer library '%s': %s", path_.c_str(),
150                       dlerror());
151                 refcount_ = 0;
152                 return false;
153             }
154         }
155     }
156     return true;
157 }
158 
Close()159 void LayerLibrary::Close() {
160     std::lock_guard<std::mutex> lock(mutex_);
161     if (--refcount_ == 0) {
162         ALOGV("closing layer library '%s'", path_.c_str());
163         char* error_msg = nullptr;
164         if (!android::CloseNativeLibrary(dlhandle_, native_bridge_, &error_msg)) {
165             ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg);
166             android::NativeLoaderFreeErrorMessage(error_msg);
167             refcount_++;
168         } else {
169            dlhandle_ = nullptr;
170         }
171     }
172 }
173 
EnumerateLayers(size_t library_idx,std::vector<Layer> & instance_layers) const174 bool LayerLibrary::EnumerateLayers(size_t library_idx,
175                                    std::vector<Layer>& instance_layers) const {
176     PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers =
177         GetTrampoline<PFN_vkEnumerateInstanceLayerProperties>(
178             "vkEnumerateInstanceLayerProperties");
179     PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions =
180         GetTrampoline<PFN_vkEnumerateInstanceExtensionProperties>(
181             "vkEnumerateInstanceExtensionProperties");
182     if (!enumerate_instance_layers || !enumerate_instance_extensions) {
183         ALOGE("layer library '%s' missing some instance enumeration functions",
184               path_.c_str());
185         return false;
186     }
187 
188     // device functions are optional
189     PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
190         GetTrampoline<PFN_vkEnumerateDeviceLayerProperties>(
191             "vkEnumerateDeviceLayerProperties");
192     PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
193         GetTrampoline<PFN_vkEnumerateDeviceExtensionProperties>(
194             "vkEnumerateDeviceExtensionProperties");
195 
196     // get layer counts
197     uint32_t num_instance_layers = 0;
198     uint32_t num_device_layers = 0;
199     VkResult result = enumerate_instance_layers(&num_instance_layers, nullptr);
200     if (result != VK_SUCCESS || !num_instance_layers) {
201         if (result != VK_SUCCESS) {
202             ALOGE(
203                 "vkEnumerateInstanceLayerProperties failed for library '%s': "
204                 "%d",
205                 path_.c_str(), result);
206         }
207         return false;
208     }
209     if (enumerate_device_layers) {
210         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
211                                          nullptr);
212         if (result != VK_SUCCESS) {
213             ALOGE(
214                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
215                 path_.c_str(), result);
216             return false;
217         }
218     }
219 
220     // get layer properties
221     std::vector<VkLayerProperties> properties(num_instance_layers + num_device_layers);
222     result = enumerate_instance_layers(&num_instance_layers, properties.data());
223     if (result != VK_SUCCESS) {
224         ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
225               path_.c_str(), result);
226         return false;
227     }
228     if (num_device_layers > 0) {
229         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
230                                          &properties[num_instance_layers]);
231         if (result != VK_SUCCESS) {
232             ALOGE(
233                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
234                 path_.c_str(), result);
235             return false;
236         }
237     }
238 
239     // append layers to instance_layers
240     size_t prev_num_instance_layers = instance_layers.size();
241     instance_layers.reserve(prev_num_instance_layers + num_instance_layers);
242     for (size_t i = 0; i < num_instance_layers; i++) {
243         const VkLayerProperties& props = properties[i];
244 
245         Layer layer;
246         layer.properties = props;
247         layer.library_idx = library_idx;
248         layer.is_global = false;
249 
250         uint32_t count = 0;
251         result =
252             enumerate_instance_extensions(props.layerName, &count, nullptr);
253         if (result != VK_SUCCESS) {
254             ALOGE(
255                 "vkEnumerateInstanceExtensionProperties(\"%s\") failed for "
256                 "library '%s': %d",
257                 props.layerName, path_.c_str(), result);
258             instance_layers.resize(prev_num_instance_layers);
259             return false;
260         }
261         layer.instance_extensions.resize(count);
262         result = enumerate_instance_extensions(
263             props.layerName, &count, layer.instance_extensions.data());
264         if (result != VK_SUCCESS) {
265             ALOGE(
266                 "vkEnumerateInstanceExtensionProperties(\"%s\") failed for "
267                 "library '%s': %d",
268                 props.layerName, path_.c_str(), result);
269             instance_layers.resize(prev_num_instance_layers);
270             return false;
271         }
272 
273         for (size_t j = 0; j < num_device_layers; j++) {
274             const auto& dev_props = properties[num_instance_layers + j];
275             if (memcmp(&props, &dev_props, sizeof(props)) == 0) {
276                 layer.is_global = true;
277                 break;
278             }
279         }
280 
281         if (layer.is_global && enumerate_device_extensions) {
282             result = enumerate_device_extensions(
283                 VK_NULL_HANDLE, props.layerName, &count, nullptr);
284             if (result != VK_SUCCESS) {
285                 ALOGE(
286                     "vkEnumerateDeviceExtensionProperties(\"%s\") failed for "
287                     "library '%s': %d",
288                     props.layerName, path_.c_str(), result);
289                 instance_layers.resize(prev_num_instance_layers);
290                 return false;
291             }
292             layer.device_extensions.resize(count);
293             result = enumerate_device_extensions(
294                 VK_NULL_HANDLE, props.layerName, &count,
295                 layer.device_extensions.data());
296             if (result != VK_SUCCESS) {
297                 ALOGE(
298                     "vkEnumerateDeviceExtensionProperties(\"%s\") failed for "
299                     "library '%s': %d",
300                     props.layerName, path_.c_str(), result);
301                 instance_layers.resize(prev_num_instance_layers);
302                 return false;
303             }
304         }
305 
306         instance_layers.push_back(layer);
307         ALOGD("added %s layer '%s' from library '%s'",
308               (layer.is_global) ? "global" : "instance", props.layerName,
309               path_.c_str());
310     }
311 
312     return true;
313 }
314 
GetGPA(const Layer & layer,const std::string_view gpa_name) const315 void* LayerLibrary::GetGPA(const Layer& layer, const std::string_view gpa_name) const {
316     std::string layer_name { layer.properties.layerName };
317     if (void* gpa = GetTrampoline((layer_name.append(gpa_name).c_str())))
318         return gpa;
319     return GetTrampoline((std::string {"vk"}.append(gpa_name)).c_str());
320 }
321 
322 // ----------------------------------------------------------------------------
323 
324 std::vector<LayerLibrary> g_layer_libraries;
325 std::vector<Layer> g_instance_layers;
326 
AddLayerLibrary(const std::string & path,const std::string & filename)327 void AddLayerLibrary(const std::string& path, const std::string& filename) {
328     LayerLibrary library(path + "/" + filename, filename);
329     if (!library.Open())
330         return;
331 
332     if (!library.EnumerateLayers(g_layer_libraries.size(), g_instance_layers)) {
333         library.Close();
334         return;
335     }
336 
337     library.Close();
338 
339     g_layer_libraries.emplace_back(std::move(library));
340 }
341 
342 template <typename Functor>
ForEachFileInDir(const std::string & dirname,Functor functor)343 void ForEachFileInDir(const std::string& dirname, Functor functor) {
344     auto dir_deleter = [](DIR* handle) { closedir(handle); };
345     std::unique_ptr<DIR, decltype(dir_deleter)> dir(opendir(dirname.c_str()),
346                                                     dir_deleter);
347     if (!dir) {
348         // It's normal for some search directories to not exist, especially
349         // /data/local/debug/vulkan.
350         int err = errno;
351         ALOGW_IF(err != ENOENT, "failed to open layer directory '%s': %s",
352                  dirname.c_str(), strerror(err));
353         return;
354     }
355     ALOGD("searching for layers in '%s'", dirname.c_str());
356     dirent* entry;
357     while ((entry = readdir(dir.get())) != nullptr)
358         functor(entry->d_name);
359 }
360 
361 template <typename Functor>
ForEachFileInZip(const std::string & zipname,const std::string & dir_in_zip,Functor functor)362 void ForEachFileInZip(const std::string& zipname,
363                       const std::string& dir_in_zip,
364                       Functor functor) {
365     int32_t err;
366     ZipArchiveHandle zip = nullptr;
367     if ((err = OpenArchive(zipname.c_str(), &zip)) != 0) {
368         ALOGE("failed to open apk '%s': %d", zipname.c_str(), err);
369         return;
370     }
371     std::string prefix(dir_in_zip + "/");
372     void* iter_cookie = nullptr;
373     if ((err = StartIteration(zip, &iter_cookie, prefix, "")) != 0) {
374         ALOGE("failed to iterate entries in apk '%s': %d", zipname.c_str(),
375               err);
376         CloseArchive(zip);
377         return;
378     }
379     ALOGD("searching for layers in '%s!/%s'", zipname.c_str(),
380           dir_in_zip.c_str());
381     ZipEntry entry;
382     std::string name;
383     while (Next(iter_cookie, &entry, &name) == 0) {
384         std::string filename(name.substr(prefix.length()));
385         // only enumerate direct entries of the directory, not subdirectories
386         if (filename.find('/') != filename.npos)
387             continue;
388         // Check whether it *may* be possible to load the library directly from
389         // the APK. Loading still may fail for other reasons, but this at least
390         // lets us avoid failed-to-load log messages in the typical case of
391         // compressed and/or unaligned libraries.
392         if (entry.method != kCompressStored || entry.offset % PAGE_SIZE != 0)
393             continue;
394         functor(filename);
395     }
396     EndIteration(iter_cookie);
397     CloseArchive(zip);
398 }
399 
400 template <typename Functor>
ForEachFileInPath(const std::string & path,Functor functor)401 void ForEachFileInPath(const std::string& path, Functor functor) {
402     size_t zip_pos = path.find("!/");
403     if (zip_pos == std::string::npos) {
404         ForEachFileInDir(path, functor);
405     } else {
406         ForEachFileInZip(path.substr(0, zip_pos), path.substr(zip_pos + 2),
407                          functor);
408     }
409 }
410 
DiscoverLayersInPathList(const std::string & pathstr)411 void DiscoverLayersInPathList(const std::string& pathstr) {
412     ATRACE_CALL();
413 
414     std::vector<std::string> paths = android::base::Split(pathstr, ":");
415     for (const auto& path : paths) {
416         ForEachFileInPath(path, [&](const std::string& filename) {
417             if (android::base::StartsWith(filename, "libVkLayer") &&
418                 android::base::EndsWith(filename, ".so")) {
419 
420                 // Check to ensure we haven't seen this layer already
421                 // Let the first instance of the shared object be enumerated
422                 // We're searching for layers in following order:
423                 // 1. system path
424                 // 2. libraryPermittedPath (if enabled)
425                 // 3. libraryPath
426 
427                 bool duplicate = false;
428                 for (auto& layer : g_layer_libraries) {
429                     if (layer.GetFilename() == filename) {
430                         ALOGV("Skipping duplicate layer %s in %s",
431                               filename.c_str(), path.c_str());
432                         duplicate = true;
433                     }
434                 }
435 
436                 if (!duplicate)
437                     AddLayerLibrary(path, filename);
438             }
439         });
440     }
441 }
442 
FindExtension(const std::vector<VkExtensionProperties> & extensions,const char * name)443 const VkExtensionProperties* FindExtension(
444     const std::vector<VkExtensionProperties>& extensions,
445     const char* name) {
446     auto it = std::find_if(extensions.cbegin(), extensions.cend(),
447                            [=](const VkExtensionProperties& ext) {
448                                return (strcmp(ext.extensionName, name) == 0);
449                            });
450     return (it != extensions.cend()) ? &*it : nullptr;
451 }
452 
GetLayerGetProcAddr(const Layer & layer,const std::string_view gpa_name)453 void* GetLayerGetProcAddr(const Layer& layer,
454                           const std::string_view gpa_name) {
455     const LayerLibrary& library = g_layer_libraries[layer.library_idx];
456     return library.GetGPA(layer, gpa_name);
457 }
458 
459 }  // anonymous namespace
460 
DiscoverLayers()461 void DiscoverLayers() {
462     ATRACE_CALL();
463 
464     if (android::GraphicsEnv::getInstance().isDebuggable()) {
465         DiscoverLayersInPathList(kSystemLayerLibraryDir);
466     }
467     if (!android::GraphicsEnv::getInstance().getLayerPaths().empty())
468         DiscoverLayersInPathList(android::GraphicsEnv::getInstance().getLayerPaths());
469 }
470 
GetLayerCount()471 uint32_t GetLayerCount() {
472     return static_cast<uint32_t>(g_instance_layers.size());
473 }
474 
GetLayer(uint32_t index)475 const Layer& GetLayer(uint32_t index) {
476     return g_instance_layers[index];
477 }
478 
FindLayer(const char * name)479 const Layer* FindLayer(const char* name) {
480     auto layer =
481         std::find_if(g_instance_layers.cbegin(), g_instance_layers.cend(),
482                      [=](const Layer& entry) {
483                          return strcmp(entry.properties.layerName, name) == 0;
484                      });
485     return (layer != g_instance_layers.cend()) ? &*layer : nullptr;
486 }
487 
GetLayerProperties(const Layer & layer)488 const VkLayerProperties& GetLayerProperties(const Layer& layer) {
489     return layer.properties;
490 }
491 
IsLayerGlobal(const Layer & layer)492 bool IsLayerGlobal(const Layer& layer) {
493     return layer.is_global;
494 }
495 
GetLayerInstanceExtensions(const Layer & layer,uint32_t & count)496 const VkExtensionProperties* GetLayerInstanceExtensions(const Layer& layer,
497                                                         uint32_t& count) {
498     count = static_cast<uint32_t>(layer.instance_extensions.size());
499     return layer.instance_extensions.data();
500 }
501 
GetLayerDeviceExtensions(const Layer & layer,uint32_t & count)502 const VkExtensionProperties* GetLayerDeviceExtensions(const Layer& layer,
503                                                       uint32_t& count) {
504     count = static_cast<uint32_t>(layer.device_extensions.size());
505     return layer.device_extensions.data();
506 }
507 
FindLayerInstanceExtension(const Layer & layer,const char * name)508 const VkExtensionProperties* FindLayerInstanceExtension(const Layer& layer,
509                                                         const char* name) {
510     return FindExtension(layer.instance_extensions, name);
511 }
512 
FindLayerDeviceExtension(const Layer & layer,const char * name)513 const VkExtensionProperties* FindLayerDeviceExtension(const Layer& layer,
514                                                       const char* name) {
515     return FindExtension(layer.device_extensions, name);
516 }
517 
GetLayerRef(const Layer & layer)518 LayerRef GetLayerRef(const Layer& layer) {
519     LayerLibrary& library = g_layer_libraries[layer.library_idx];
520     return LayerRef((library.Open()) ? &layer : nullptr);
521 }
522 
LayerRef(const Layer * layer)523 LayerRef::LayerRef(const Layer* layer) : layer_(layer) {}
524 
~LayerRef()525 LayerRef::~LayerRef() {
526     if (layer_) {
527         LayerLibrary& library = g_layer_libraries[layer_->library_idx];
528         library.Close();
529     }
530 }
531 
LayerRef(LayerRef && other)532 LayerRef::LayerRef(LayerRef&& other) noexcept : layer_(other.layer_) {
533     other.layer_ = nullptr;
534 }
535 
GetGetInstanceProcAddr() const536 PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
537     return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
538                         GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr"))
539                   : nullptr;
540 }
541 
GetGetDeviceProcAddr() const542 PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
543     return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
544                         GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr"))
545                   : nullptr;
546 }
547 
548 }  // namespace api
549 }  // namespace vulkan
550