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