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