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