Loader.cpp revision 1508ae60cc02d0ed84f216f3ddd43a932c2ede42
1/* 2 ** Copyright 2007, 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 LOG_NDEBUG 0 18#define ATRACE_TAG ATRACE_TAG_GRAPHICS 19 20#include <array> 21#include <ctype.h> 22#include <dirent.h> 23#include <dlfcn.h> 24#include <errno.h> 25#include <limits.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29 30#include <android/dlext.h> 31#include <cutils/properties.h> 32#include <log/log.h> 33#include <utils/Trace.h> 34 35#include <EGL/egl.h> 36 37#include "egldefs.h" 38#include "Loader.h" 39 40// ---------------------------------------------------------------------------- 41namespace android { 42// ---------------------------------------------------------------------------- 43 44 45/* 46 * EGL userspace drivers must be provided either: 47 * - as a single library: 48 * /vendor/lib/egl/libGLES.so 49 * 50 * - as separate libraries: 51 * /vendor/lib/egl/libEGL.so 52 * /vendor/lib/egl/libGLESv1_CM.so 53 * /vendor/lib/egl/libGLESv2.so 54 * 55 * The software renderer for the emulator must be provided as a single 56 * library at: 57 * 58 * /system/lib/egl/libGLES_android.so 59 * 60 * 61 * For backward compatibility and to facilitate the transition to 62 * this new naming scheme, the loader will additionally look for: 63 * 64 * /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so 65 * 66 */ 67 68ANDROID_SINGLETON_STATIC_INSTANCE( Loader ) 69 70/* This function is called to check whether we run inside the emulator, 71 * and if this is the case whether GLES GPU emulation is supported. 72 * 73 * Returned values are: 74 * -1 -> not running inside the emulator 75 * 0 -> running inside the emulator, but GPU emulation not supported 76 * 1 -> running inside the emulator, GPU emulation is supported 77 * through the "emulation" host-side OpenGL ES implementation. 78 * 2 -> running inside the emulator, GPU emulation is supported 79 * through a guest-side vendor driver's OpenGL ES implementation. 80 */ 81static int 82checkGlesEmulationStatus(void) 83{ 84 /* We're going to check for the following kernel parameters: 85 * 86 * qemu=1 -> tells us that we run inside the emulator 87 * android.qemu.gles=<number> -> tells us the GLES GPU emulation status 88 * 89 * Note that we will return <number> if we find it. This let us support 90 * more additionnal emulation modes in the future. 91 */ 92 char prop[PROPERTY_VALUE_MAX]; 93 int result = -1; 94 95 /* First, check for qemu=1 */ 96 property_get("ro.kernel.qemu",prop,"0"); 97 if (atoi(prop) != 1) 98 return -1; 99 100 /* We are in the emulator, get GPU status value */ 101 property_get("qemu.gles",prop,"0"); 102 return atoi(prop); 103} 104 105// ---------------------------------------------------------------------------- 106 107static char const * getProcessCmdline() { 108 long pid = getpid(); 109 char procPath[128]; 110 snprintf(procPath, 128, "/proc/%ld/cmdline", pid); 111 FILE * file = fopen(procPath, "r"); 112 if (file) { 113 static char cmdline[256]; 114 char *str = fgets(cmdline, sizeof(cmdline) - 1, file); 115 fclose(file); 116 if (str) { 117 return cmdline; 118 } 119 } 120 return NULL; 121} 122 123static void* do_dlopen(const char* path, int mode) { 124 ATRACE_CALL(); 125 return dlopen(path, mode); 126} 127 128// ---------------------------------------------------------------------------- 129 130Loader::driver_t::driver_t(void* gles) 131{ 132 dso[0] = gles; 133 for (size_t i=1 ; i<NELEM(dso) ; i++) 134 dso[i] = 0; 135} 136 137Loader::driver_t::~driver_t() 138{ 139 for (size_t i=0 ; i<NELEM(dso) ; i++) { 140 if (dso[i]) { 141 dlclose(dso[i]); 142 dso[i] = 0; 143 } 144 } 145} 146 147status_t Loader::driver_t::set(void* hnd, int32_t api) 148{ 149 switch (api) { 150 case EGL: 151 dso[0] = hnd; 152 break; 153 case GLESv1_CM: 154 dso[1] = hnd; 155 break; 156 case GLESv2: 157 dso[2] = hnd; 158 break; 159 default: 160 return BAD_INDEX; 161 } 162 return NO_ERROR; 163} 164 165// ---------------------------------------------------------------------------- 166 167Loader::Loader() 168 : getProcAddress(NULL), 169 mLibGui(nullptr), 170 mGetDriverNamespace(nullptr) 171{ 172 // FIXME: See note in GraphicsEnv.h about android_getDriverNamespace(). 173 // libgui should already be loaded in any process that uses libEGL, but 174 // if for some reason it isn't, then we're not going to get a driver 175 // namespace anyway, so don't force it to be loaded. 176 mLibGui = dlopen("libgui.so", RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY); 177 if (!mLibGui) { 178 ALOGD("failed to load libgui: %s", dlerror()); 179 return; 180 } 181 mGetDriverNamespace = reinterpret_cast<decltype(mGetDriverNamespace)>( 182 dlsym(mLibGui, "android_getDriverNamespace")); 183} 184 185Loader::~Loader() { 186 if (mLibGui) 187 dlclose(mLibGui); 188} 189 190static void* load_wrapper(const char* path) { 191 void* so = do_dlopen(path, RTLD_NOW | RTLD_LOCAL); 192 ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror()); 193 return so; 194} 195 196#ifndef EGL_WRAPPER_DIR 197#if defined(__LP64__) 198#define EGL_WRAPPER_DIR "/system/lib64" 199#else 200#define EGL_WRAPPER_DIR "/system/lib" 201#endif 202#endif 203 204static void setEmulatorGlesValue(void) { 205 char prop[PROPERTY_VALUE_MAX]; 206 property_get("ro.kernel.qemu", prop, "0"); 207 if (atoi(prop) != 1) return; 208 209 property_get("ro.kernel.qemu.gles",prop,"0"); 210 if (atoi(prop) == 1) { 211 ALOGD("Emulator has host GPU support, qemu.gles is set to 1."); 212 property_set("qemu.gles", "1"); 213 return; 214 } 215 216 // for now, checking the following 217 // directory is good enough for emulator system images 218 const char* vendor_lib_path = 219#if defined(__LP64__) 220 "/vendor/lib64/egl"; 221#else 222 "/vendor/lib/egl"; 223#endif 224 225 const bool has_vendor_lib = (access(vendor_lib_path, R_OK) == 0); 226 if (has_vendor_lib) { 227 ALOGD("Emulator has vendor provided software renderer, qemu.gles is set to 2."); 228 property_set("qemu.gles", "2"); 229 } else { 230 ALOGD("Emulator without GPU support detected. " 231 "Fallback to legacy software renderer, qemu.gles is set to 0."); 232 property_set("qemu.gles", "0"); 233 } 234} 235 236void* Loader::open(egl_connection_t* cnx) 237{ 238 ATRACE_CALL(); 239 240 void* dso; 241 driver_t* hnd = 0; 242 243 setEmulatorGlesValue(); 244 245 dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2); 246 if (dso) { 247 hnd = new driver_t(dso); 248 } else { 249 // Always load EGL first 250 dso = load_driver("EGL", cnx, EGL); 251 if (dso) { 252 hnd = new driver_t(dso); 253 hnd->set( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM ); 254 hnd->set( load_driver("GLESv2", cnx, GLESv2), GLESv2 ); 255 } 256 } 257 258 LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation"); 259 260 cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so"); 261 cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so"); 262 cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so"); 263 264 LOG_ALWAYS_FATAL_IF(!cnx->libEgl, 265 "couldn't load system EGL wrapper libraries"); 266 267 LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1, 268 "couldn't load system OpenGL ES wrapper libraries"); 269 270 return (void*)hnd; 271} 272 273status_t Loader::close(void* driver) 274{ 275 driver_t* hnd = (driver_t*)driver; 276 delete hnd; 277 return NO_ERROR; 278} 279 280void Loader::init_api(void* dso, 281 char const * const * api, 282 __eglMustCastToProperFunctionPointerType* curr, 283 getProcAddressType getProcAddress) 284{ 285 ATRACE_CALL(); 286 287 const ssize_t SIZE = 256; 288 char scrap[SIZE]; 289 while (*api) { 290 char const * name = *api; 291 __eglMustCastToProperFunctionPointerType f = 292 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name); 293 if (f == NULL) { 294 // couldn't find the entry-point, use eglGetProcAddress() 295 f = getProcAddress(name); 296 } 297 if (f == NULL) { 298 // Try without the OES postfix 299 ssize_t index = ssize_t(strlen(name)) - 3; 300 if ((index>0 && (index<SIZE-1)) && (!strcmp(name+index, "OES"))) { 301 strncpy(scrap, name, index); 302 scrap[index] = 0; 303 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap); 304 //ALOGD_IF(f, "found <%s> instead", scrap); 305 } 306 } 307 if (f == NULL) { 308 // Try with the OES postfix 309 ssize_t index = ssize_t(strlen(name)) - 3; 310 if (index>0 && strcmp(name+index, "OES")) { 311 snprintf(scrap, SIZE, "%sOES", name); 312 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap); 313 //ALOGD_IF(f, "found <%s> instead", scrap); 314 } 315 } 316 if (f == NULL) { 317 //ALOGD("%s", name); 318 f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented; 319 320 /* 321 * GL_EXT_debug_label is special, we always report it as 322 * supported, it's handled by GLES_trace. If GLES_trace is not 323 * enabled, then these are no-ops. 324 */ 325 if (!strcmp(name, "glInsertEventMarkerEXT")) { 326 f = (__eglMustCastToProperFunctionPointerType)gl_noop; 327 } else if (!strcmp(name, "glPushGroupMarkerEXT")) { 328 f = (__eglMustCastToProperFunctionPointerType)gl_noop; 329 } else if (!strcmp(name, "glPopGroupMarkerEXT")) { 330 f = (__eglMustCastToProperFunctionPointerType)gl_noop; 331 } 332 } 333 *curr++ = f; 334 api++; 335 } 336} 337 338static void* load_system_driver(const char* kind) { 339 ATRACE_CALL(); 340 class MatchFile { 341 public: 342 static String8 find(const char* kind) { 343 String8 result; 344 int emulationStatus = checkGlesEmulationStatus(); 345 switch (emulationStatus) { 346 case 0: 347#if defined(__LP64__) 348 result.setTo("/system/lib64/egl/libGLES_android.so"); 349#else 350 result.setTo("/system/lib/egl/libGLES_android.so"); 351#endif 352 return result; 353 case 1: 354 // Use host-side OpenGL through the "emulation" library 355#if defined(__LP64__) 356 result.appendFormat("/system/lib64/egl/lib%s_emulation.so", kind); 357#else 358 result.appendFormat("/system/lib/egl/lib%s_emulation.so", kind); 359#endif 360 return result; 361 default: 362 // Not in emulator, or use other guest-side implementation 363 break; 364 } 365 366 String8 pattern; 367 pattern.appendFormat("lib%s", kind); 368 const char* const searchPaths[] = { 369#if defined(__LP64__) 370 "/vendor/lib64/egl", 371 "/system/lib64/egl" 372#else 373 "/vendor/lib/egl", 374 "/system/lib/egl" 375#endif 376 }; 377 378 // first, we search for the exact name of the GLES userspace 379 // driver in both locations. 380 // i.e.: 381 // libGLES.so, or: 382 // libEGL.so, libGLESv1_CM.so, libGLESv2.so 383 384 for (size_t i=0 ; i<NELEM(searchPaths) ; i++) { 385 if (find(result, pattern, searchPaths[i], true)) { 386 return result; 387 } 388 } 389 390 // for compatibility with the old "egl.cfg" naming convention 391 // we look for files that match: 392 // libGLES_*.so, or: 393 // libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so 394 395 pattern.append("_"); 396 for (size_t i=0 ; i<NELEM(searchPaths) ; i++) { 397 if (find(result, pattern, searchPaths[i], false)) { 398 return result; 399 } 400 } 401 402 // we didn't find the driver. gah. 403 result.clear(); 404 return result; 405 } 406 407 private: 408 static bool find(String8& result, 409 const String8& pattern, const char* const search, bool exact) { 410 if (exact) { 411 String8 absolutePath; 412 absolutePath.appendFormat("%s/%s.so", search, pattern.string()); 413 if (!access(absolutePath.string(), R_OK)) { 414 result = absolutePath; 415 return true; 416 } 417 return false; 418 } 419 420 DIR* d = opendir(search); 421 if (d != NULL) { 422 struct dirent cur; 423 struct dirent* e; 424 while (readdir_r(d, &cur, &e) == 0 && e) { 425 if (e->d_type == DT_DIR) { 426 continue; 427 } 428 if (!strcmp(e->d_name, "libGLES_android.so")) { 429 // always skip the software renderer 430 continue; 431 } 432 if (strstr(e->d_name, pattern.string()) == e->d_name) { 433 if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) { 434 result.clear(); 435 result.appendFormat("%s/%s", search, e->d_name); 436 closedir(d); 437 return true; 438 } 439 } 440 } 441 closedir(d); 442 } 443 return false; 444 } 445 }; 446 447 448 String8 absolutePath = MatchFile::find(kind); 449 if (absolutePath.isEmpty()) { 450 // this happens often, we don't want to log an error 451 return 0; 452 } 453 const char* const driver_absolute_path = absolutePath.string(); 454 455 void* dso = do_dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL); 456 if (dso == 0) { 457 const char* err = dlerror(); 458 ALOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown"); 459 return 0; 460 } 461 462 ALOGD("loaded %s", driver_absolute_path); 463 464 return dso; 465} 466 467static void* do_android_dlopen_ext(const char* path, int mode, const android_dlextinfo* info) { 468 ATRACE_CALL(); 469 return android_dlopen_ext(path, mode, info); 470} 471 472static const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{ 473 "ro.hardware.egl", 474 "ro.board.platform", 475}}; 476 477static void* load_updated_driver(const char* kind, android_namespace_t* ns) { 478 ATRACE_CALL(); 479 const android_dlextinfo dlextinfo = { 480 .flags = ANDROID_DLEXT_USE_NAMESPACE, 481 .library_namespace = ns, 482 }; 483 void* so = nullptr; 484 char prop[PROPERTY_VALUE_MAX + 1]; 485 for (auto key : HAL_SUBNAME_KEY_PROPERTIES) { 486 if (property_get(key, prop, nullptr) > 0) { 487 String8 name; 488 name.appendFormat("lib%s_%s.so", kind, prop); 489 so = do_android_dlopen_ext(name.string(), RTLD_LOCAL | RTLD_NOW, 490 &dlextinfo); 491 if (so) 492 return so; 493 } 494 } 495 return nullptr; 496} 497 498void *Loader::load_driver(const char* kind, 499 egl_connection_t* cnx, uint32_t mask) 500{ 501 ATRACE_CALL(); 502 503 void* dso = nullptr; 504 if (mGetDriverNamespace) { 505 android_namespace_t* ns = mGetDriverNamespace(); 506 if (ns) { 507 dso = load_updated_driver(kind, ns); 508 } 509 } 510 if (!dso) { 511 dso = load_system_driver(kind); 512 if (!dso) 513 return NULL; 514 } 515 516 if (mask & EGL) { 517 getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress"); 518 519 ALOGE_IF(!getProcAddress, 520 "can't find eglGetProcAddress() in EGL driver library"); 521 522 egl_t* egl = &cnx->egl; 523 __eglMustCastToProperFunctionPointerType* curr = 524 (__eglMustCastToProperFunctionPointerType*)egl; 525 char const * const * api = egl_names; 526 while (*api) { 527 char const * name = *api; 528 __eglMustCastToProperFunctionPointerType f = 529 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name); 530 if (f == NULL) { 531 // couldn't find the entry-point, use eglGetProcAddress() 532 f = getProcAddress(name); 533 if (f == NULL) { 534 f = (__eglMustCastToProperFunctionPointerType)0; 535 } 536 } 537 *curr++ = f; 538 api++; 539 } 540 } 541 542 if (mask & GLESv1_CM) { 543 init_api(dso, gl_names, 544 (__eglMustCastToProperFunctionPointerType*) 545 &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl, 546 getProcAddress); 547 } 548 549 if (mask & GLESv2) { 550 init_api(dso, gl_names, 551 (__eglMustCastToProperFunctionPointerType*) 552 &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl, 553 getProcAddress); 554 } 555 556 return dso; 557} 558 559// ---------------------------------------------------------------------------- 560}; // namespace android 561// ---------------------------------------------------------------------------- 562