Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android "cpu may be pegged" bug

Foreword: This severe bug can cause Android devices to lock up (unable to press Home/Back buttons, needs hard reset). It is associated with OpenGL surfaces and audio playback. Logcat repeats something to the effect of

W/SharedBufferStack( 398): waitForCondition(LockCondition) timed out (identity=9, status=0). CPU may be pegged. trying again.

once every second, hence the name of this bug. The fundamental cause of this is likely due to a deadlock when buffering data, be it sound or graphics.

I occasionally get this bug when testing my app on the Asus EEE Transformer tablet. The crash occurs when the sound thread populates MediaPlayer objects using MediaPlayer.create(context, R.raw.someid); and the GLSurface thread loads textures from bitmaps using

Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
                R.drawable.textureMap,opts);
gl.glGenTextures(1, texAtlas, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texAtlas[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();

I don't think the cause is the audio, as the audio does in fact still play (the thread which loads the audio then plays it after x amount of time). If so, the cause lies in the OpenGL ES buffering using the above code.

Related Material

  • This SO post refers to this bug. They use OpenGL ES 2.0 and NDK. I use OpenGL ES 1.1 (albeit most devices emulate 1.1 through 2.0, so technically they are using 2.0) and I do not use the NDK. Further, they use Android 2.1 and my crash occurs on Android 3.2.1.
  • This site links the bug to the AudioTrack object. However, I do not use that in my app.
  • The Android Bug Tracker lists this as a known bug, but as of yet there is no solution (and it's not fixed in Honeycomb+).

Common Elements

  • Freeze occurs when buffering. The thing being buffered is usually quite large, so an image (bug occurs more frequently the larger the image) or audio is typically affected.
  • Freeze only occurs on some devices.
  • Freeze is not related to a specific Android version - has been recorded on 2.1 and 3.2.1, among others.
  • Freeze is not related to use of the NDK.
  • Freeze is not related to a single programming practice (order of buffering, file types, etc)

My question is pretty simple. Is there a workaround for this issue? If you can't prevent it, is there a way to fail elegantly and prevent the whole device being bricked?

like image 283
Dororo Avatar asked Dec 10 '11 17:12

Dororo


1 Answers

In the case of my game the "waitForCondition" problem has been noticed on Samsung Galaxy S (Android 2.3.3). Of course I don't know if the issue has been noticed on different devices, but probably the problem exists there too. Fortunately I was able to reproduce it as one of my friends has got the device and he was kind enough to lent me one for a week. In my case the game is practically all written in Java (few calls through NDK to OpenGL functions), so I'm not really sure if this will apply to your problem too.

Anyway it seems that the problem is somehow related to OpenGL internal buffers. In the code presented below the line which has been commented out (1) has been changed to (2) - manual config selection. I didn't test it thoroughly yet, but since that change I haven't noticed any freezes, so there is a hope..

UPDATE 1: As an additional info, I think I read somewhere that somebody had the same problem with his CPU gets pegged and his solution was to set up all the OpenGL Surface components to 8 bits (alpha component too) rather than 565 or 4 bits (I don't remember exactly what was the faulty configuration)

UPDATE 2: Also one may consider to use the following implementation of the EGLConfigChooser: GdxEglConfigChooser.java. If this doesn't help eventually use the approach presented in GLSurfaceView20.java.

UPDATE 3: Additionally simplifying the program shaders as much as it's possible helped a bit too.

// in Activity...
glView = new GLSurfaceView(this);
glView.setEGLContextClientVersion(2); // OpenGL ES 2.0
//      glView.setEGLConfigChooser(false); // (1) false - no depth buffer
glView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
glView.setEGLConfigChooser(8,8,8,8,0,0); // (2) TODO: crashes on devices which doesn't support this particular configuration
glView.setRenderer(new MyRenderer(this));
like image 147
Eric Avatar answered Oct 17 '22 02:10

Eric