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