eglCreateWindowSurface: native_window_api_connect failed

Davide Berra picture Davide Berra · Jan 14, 2019 · Viewed 9.3k times · Source

I have a problem that occours only with the latest Samsung Galaxy series when android:hardwareAccelerated is set to false into manifest file

As far as i know (tried by myself) it happens on Galaxy S9, J6 and Note 8 but not on Galaxy S8 for example. Other phones seem not affected at all.

The problem is that i got a GLSurfaceView that shows nothing (black screen) but if i switch between activities, it start to work again, i guess because it renews the View with no errors.

This is the suspect log lines i've found

01-13 14:39:47.813 25013 25080 E libEGL  : eglCreateWindowSurface: native_window_api_connect (win=0xc166b808) failed (0xffffffed) (already connected to another API?)
01-13 14:39:47.813 25013 25080 E libEGL  : eglCreateWindowSurface:679 error 3003 (EGL_BAD_ALLOC)

and these are the crucial part of my code:

GLSurf glsurf;

public void onPause() {
    super.onPause();

    // stop
    if (glsurf != null) {
        glsurf.onPause();
    }
}

@Override
public void onResume() {
    super.onResume();

    if (glsurf != null)
        glsurf.onResume();
}

public class GLSurf extends GLSurfaceView {

    public GLSurf(Context context) {
        super(context);

        /* Create an OpenGL ES 2.0 context. */
        setEGLContextClientVersion(2);
        setEGLConfigChooser(8, 8, 8, 8, 16, 0);

        // Set the Renderer for drawing on the GLSurfaceView
        mRenderer = new GLRenderer(context);
        setRenderer(mRenderer);

        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
    }
}

public class GLRenderer implements Renderer {

    GLRenderer(Context c){
        // does nothing
    }

    @Override
    public void onDrawFrame(GL10 unused) {

        // i've copied it but it's not even reached

        // call jni function updating the single texture filling the screen
        nativeGLRender();

        // Draw the triangles
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length,
                GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {

        // We need to know the current width and height.
        mScreenWidth = width;
        mScreenHeight = height;

        // Redo the Viewport.
        GLES20.glViewport(0, 0, (int)mScreenWidth, (int)mScreenHeight);

    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        // Set the clear color to black
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1);
    }

}

Some info more:

the EGL_BAD_ALLOC occours always after this sequence of events with meaningful (at least i think) logs

onCreate
onResume
onPause

GLSurfaceView: Warning, !readyToDraw() but waiting for draw finished! Early reporting draw finished.

onResume 

libEGL  : eglCreateWindowSurface: native_window_api_connect (win=0xc166b808) failed (0xffffffed) (already connected to another API?)
libEGL  : eglCreateWindowSurface:679 error 3003 (EGL_BAD_ALLOC)

onPause
onStop
onDestroy
onCreate 
onResume
onSurfaceCreated

        : NULL == surf->write_back_color_buffer
        : NULL == surf->write_back_color_buffer
GLThread: eglSwapBuffers failed: EGL_BAD_SURFACE

... black screen ...

Please note that above events occour with no user interaction and in a span of 1-2 seconds. Any idea about what's going on?

For completion of infos, the following is the sequence of a working phone (e.g. my nexus 6)

onCreate
onResume
onSurfaceCreated
... working screen

Edit Jan 16th:

New informations about the issue:

  • When the app starts for the first time, it works
  • Never work on the next tries
  • It works if put in background and restored
  • The error never happen if i put android:hardwareAccelerated to true (but i cannot turn it on for other reasons)

Edit Jan 18th

  • I forgot to mention that the issue occours only if android:hardwareAccelerated is set to false

I ALSO FOUND THE REASON OF THE BUG

Don't know why, but i just changed this part of code

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();

    getWindow().setFormat(PixelFormat.RGB_565);
}

with this

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
}

and everything went ok. A bug in Samsung drivers? Maybe...

I hope this could be useful for somebody

Answer

Jon Goodwin picture Jon Goodwin · Jan 17, 2019

eglCreateWindowSurface: native_window_api_connect failed Any idea about what's going on?

The problem viewed from logcat perspective

The called function from eglApi.cpp is:

/*
 * native_window_api_connect(..., int api)
 * connects an API to this window. only one API can be connected at a time.
 * Returns -EINVAL if for some reason the window cannot be connected, which
 * can happen if it's connected to some other API.
 */
static inline int native_window_api_connect(
        struct ANativeWindow* window, int api)
{
    return window->perform(window, NATIVE_WINDOW_API_CONNECT, api);
}

Here is a comment block from the WindowSurface.recreate() from WindowSurface.java method that says:

/*
 * If the previous EGLSurface isn't fully destroyed, e.g. it's still current on a
 * context somewhere, the create call will fail with complaints from the Surface
 * about already being connected.
*/

Related problem

Opengls eglCreateWindowSurface GL Error EGL_BAD_ALLOC from Jitesh Dalsaniya:

I solved error GL Error EGL_BAD_ALLOC. This error occurs due to I am not handling Renderer properly with activity life cycle.

Activity Life-cycle

A GLSurfaceView must be notified when to pause and resume rendering. GLSurfaceView clients are required to call onPause() when the activity stops and onResume() when the activity starts. These calls allow GLSurfaceView to pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate the OpenGL display.

EGL Context Lost

There are situations where the EGL rendering context will be lost. This typically happens when device wakes up after going to sleep. When the EGL context is lost, all OpenGL resources (such as textures) that are associated with that context will be automatically deleted. In order to keep rendering correctly, a renderer must recreate any lost resources that it still needs. The onSurfaceCreated(GL10, EGLConfig) method is a convenient place to do this.

Workaround-to-losing-the-opengl-context-when-android-pauses

So your Activity's onPause() should look like this:

@Override
public void onPause() {
    glsurf.setVisibility(View.GONE);
    super.onPause();
    ...
}

And you restore your GLSurfaceView to the hierarchy not from onResume() but from onWindowFocusChanged() :

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && glsurf.getVisibility() == View.GONE) {
         glsurf.setVisibility(View.VISIBLE);
    }
    ...
}

Other things to try

  1. You'd need to debug to figure out why it's unhappy.
  2. Try use OpenglView Visible always and startPreview when you get permissions. An invisible holder is not valid for opengl and this could cause your crash.
  3. Bad release of Opengl ?
  4. Handle onSurfaceTextureSizeChanged in TextureViewGLActivity ?
  5. EGL_BAD_ALLOC and eglSwapBuffers failed: EGL_BAD_SURFACE is a big clue...
  6. !readyToDraw() delete and recreate the Surface ?

Further

Observation:

The error never happen if I put android:hardwareAccelerated to true

Hardware acceleration is enabled by default if your Target API level is >=14, but can also be explicitly enabled (at the Application or Activity level).

Document Links

GLSurfaceView, GLSurfaceView.Renderer, hardware-acceleration