androidopengl-esnative-activityqualcommgoogle-pixel

glCreateShader() crashes on Android 11 / Pixel 5


I have a NativeActivity program which works fine on a OnePlus 3T running Android 9. It crashes on startup in Android 11 running on a Pixel 5. I'm using Visual Studio 2019 and SDK Build-tools 29.0.2 and Platform-Tools 30.0.4. The AndroidManifest.xml requires GLES version 3.1, and targets SDK 25 (allowing down to 21.)

    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="25"/>
    <uses-feature android:glEsVersion="0x00030001" android:required="true" />

The code starts out with the standard EGL setup to get a window, create a surface, create a context, and so on (verbatim from the NativeActivity sample,) and then runs into an initialization function:

void graphics_init(float width, float height) {
    // Initialize GL state.
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glDisable(GL_CULL_FACE);
    glShadeModel(GL_SMOOTH);
    glDisable(GL_DEPTH_TEST);

    GLenum err = glGetError();
    GLuint fs = 0;
    GLuint vs = graphics_load_shader_text(guiVShader, GL_VERTEX_SHADER);

It gets through this part. It crashes inside graphics_load_shader_text():

GLuint graphics_load_shader_text(char const* text, GLenum shaderType) {
    LOGI("Creating shader type 0x%x", shaderType);
    GLuint shader = glCreateShader(shaderType);
    LOGI("Shader id is %d, source is length %ld", shader, (long)strlen(text));
    glShaderSource(shader, 1, (GLchar const**)&text, nullptr);

Specifically, the call to glCreateShader() ends up generating a null pointer seg-v.

The logcat at the time looks like this:

11-01 11:49:50.005 14655 14681 V threaded_app: APP_CMD_INIT_WINDOW
11-01 11:49:50.005 14655 14681 I AdrenoGLES-0: QUALCOMM build                   : 973378a, Ie73904e3bd
11-01 11:49:50.005 14655 14681 I AdrenoGLES-0: Build Date                       : 06/24/20
11-01 11:49:50.005 14655 14681 I AdrenoGLES-0: OpenGL ES Shader Compiler Version: EV031.31.04.00
11-01 11:49:50.005 14655 14681 I AdrenoGLES-0: Local Branch                     : gfx-adreno.lnx.2.0
11-01 11:49:50.005 14655 14681 I AdrenoGLES-0: Remote Branch                    : quic/gfx-adreno.lnx.2.0
11-01 11:49:50.005 14655 14681 I AdrenoGLES-0: Remote Branch                    : NONE
11-01 11:49:50.005 14655 14681 I AdrenoGLES-0: Reconstruct Branch               : NOTHING
11-01 11:49:50.005 14655 14681 I AdrenoGLES-0: Build Config                     : S P 10.0.4 AArch64
11-01 11:49:50.005 14655 14681 I AdrenoGLES-0: Driver Path                      : /vendor/lib64/egl/libGLESv2_adreno.so
11-01 11:49:50.009 14655 14681 I AdrenoGLES-0: PFP: 0x016dd089, ME: 0x00000000
11-01 11:49:50.010   536   536 E SELinux : avc:  denied  { find } for interface=vendor.qti.qspmhal::IQspmhal sid=u:r:untrusted_app_25:s0:c512,c768 pid=14655 scontext=u:r:untrusted_app_25:s0:c512,c768 tcontext=u:object_r:hal_qspmhal_hwservice:s0 tclass=hwservice_manager permissive=0
11-01 11:49:50.011 14655 14681 E Adreno-AppProfiles: Could not find QSPM HAL service
11-01 11:49:50.013 14655 14681 W AdrenoUtils: <ReadGpuID_from_sysfs:197>: Failed to open /sys/class/kgsl/kgsl-3d0/gpu_model
11-01 11:49:50.013 14655 14681 W AdrenoUtils: <ReadGpuID:221>: Failed to read chip ID from gpu_model. Fallback to use the GSL path
11-01 11:49:50.017  1421  1521 D ArtManagerInternalImpl: /data/misc/iorapd/com.enchantedage.XMCRemote3/1/android.app.NativeActivity/compiled_traces/compiled_trace.pb doesn't exist
11-01 11:49:50.017  1421  1521 I ActivityTaskManager: Displayed com.enchantedage.XMCRemote3/android.app.NativeActivity: +175ms
11-01 11:49:50.022   861   866 E statsd  : Predicate 5980654721335871649 dropping data for dimension key (10)0x2010101->10388[I] (10)0x30000->*launch*[S]
11-01 11:49:50.022  1421  1516 D EventSequenceValidator: Transition from ACTIVITY_LAUNCHED to ACTIVITY_FINISHED
11-01 11:49:50.025 14655 14681 I XMCRemote3.NativeActivity: Creating shader type 0x8b31
11-01 11:49:50.025 14655 14681 F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 14681 (dage.XMCRemote3), pid 14655 (dage.XMCRemote3)

Looking at this, the one thing that looks suspicious to me is the SELinux failure:

11-01 11:49:50.010   536   536 E SELinux : avc:  denied  { find } for interface=vendor.qti.qspmhal::IQspmhal sid=u:r:untrusted_app_25:s0:c512,c768 pid=14655 scontext=u:r:untrusted_app_25:s0:c512,c768 tcontext=u:object_r:hal_qspmhal_hwservice:s0 tclass=hwservice_manager permissive=0

Is this the proximate cause of this failure? The "untrusted_app_25" bit seems like it might come from the "Debug Signing" used for USB development deployment; is that correct? If so, how do I work around it for development? And how can I ensure the app is not untrusted when finally deploying it for real?

I've Googled around a bit, and "Just write some SELinux manifests and install them" doesn't seem like a good idea, because I don't think an APK can (or should!) do this in general, and doing so obviously depends on the specific device hardware and drivers used, so that can't be the intended way for this to work.

So, what am I missing?


Solution

  • It turns out that the standard NativeActivity setup is lacking a few bits to make sure GLES 3 always works. It happened to work on OnePlus-with-Android-9, and happened to not work on Pixel-with-Android-11.

    The setup requires adding EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, to the attribs for eglChooseConfig() and to get that define, I also need to #include <EGL/eglext.h> in the file. Additionally, I had to add EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE for contextAttributes for eglCreateContext() which, by default, does not pass any attributes. The updated setup function looks like this (hopefully this helps someone else in that situation):

    static int engine_init_display(struct engine* engine) {
        EGLint const static attribs[] = {
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_BLUE_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_RED_SIZE, 8,
            EGL_NATIVE_RENDERABLE, EGL_TRUE,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, // new requirement
            EGL_NONE
        };
        EGLint w, h, format;
        EGLint numConfigs;
        EGLConfig config;
        EGLSurface surface;
        EGLContext context;
    
        EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        eglInitialize(display, 0, 0);
        eglChooseConfig(display, attribs, &config, 1, &numConfigs);
        eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
        ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
        surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
        EGLint const static contextAttribs[] = {
            EGL_CONTEXT_CLIENT_VERSION, 3, // new requirement
            EGL_NONE
        };
        context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
        if (context == EGL_NO_CONTEXT) {
            xmc_error("Could not create graphics context");
            return -1;
        }
        if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
            xmc_error("Graphics init failed: Unable to eglMakeCurrent");
            return -1;
        }
        ...
    

    xmc_error() is my own function -- feel free to substitute whatever you want there. The original sample wasn't very verbose about what went wrong.