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