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