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