Bounty
Since this is an important issue for me, I have earned generosity. I am not looking for the exact answer - no matter what answer explains to me, this problem gets generosity. Please make sure you see the changes below.
Edit: I have since managed to catch a crash in Gdb the same way that it dies (via "adb shell setprop debug.db.uid 32767") and noticed that this is the same issue that was mentioned in this post in Google groups . The return line shown is the same (except for the exact addresses) as my bad thread. I admit that I am not a debugging master, so if you have ideas about what I should look for, let me know.
Quick and dirty cutting
I removed most of my application code large enough for the application to do the following: load a bunch of textures through JNI'd wrappers (from C ++ β Java) so that the Java libraries handle decoding for me, create OpenGL textures from them and clear the screen to pretty beautiful but mocking blue. It dies in libc, but only once every ten times.
To make matters worse, it doesn't even seem like he is dying due to any of the code I wrote - it seems to be delayed, but it doesn't seem to be connected with something like conveniently blaming as a garbage collector. There is no special point in my own code that causes a crash - it seems to move based on each run.
Longer story
, , : libc , . libc pthread_mutex_unlock. , . ( .)
pthread_mutex_unlock , 0, ( 0x200), 0. ( ) Bionic , segfault, pthread_mutex_t. ( ) . , , libc , libdvm (, ).
, , : ( /) , OpenGL OpenGL, glTexImage2D.
, OpenGL . , , .
, , :
- JNI , - .
- , .
- OpenGL ES - , - (tm).
- .
( !) . , , , . , , . ( gdb , , )
- CheckJNI.
- , , , .
- , , , .
- ( ) .
- . .
- 100% . ( .)
- , , , , , , . (, !)
LogCat:
I/DEBUG ( 5818): signal 11 (SIGSEGV), fault addr 00000000
I/DEBUG ( 5818): r0 0000006e r1 00000080 r2 fffffc5e r3 100ffe58
I/DEBUG ( 5818): r4 00000000 r5 00000000 r6 00000000 r7 00000000
I/DEBUG ( 5818): r8 00000000 r9 8054f999 10 10000000 fp 0013e768
I/DEBUG ( 5818): ip 3b9aca00 sp 100ffe58 lr afd10640 pc 00000000 cpsr 60000010
I/DEBUG ( 5818): d0 643a64696f72646e d1 6472656767756265
I/DEBUG ( 5818): d2 8083297880832965 d3 8083298880832973
I/DEBUG ( 5818): d4 8083291080832908 d5 8083292080832918
I/DEBUG ( 5818): d6 8083293080832928 d7 8083294880832938
I/DEBUG ( 5818): d8 0000000000000000 d9 0000000000000000
I/DEBUG ( 5818): d10 0000000000000000 d11 0000000000000000
I/DEBUG ( 5818): d12 0000000000000000 d13 0000000000000000
I/DEBUG ( 5818): d14 0000000000000000 d15 0000000000000000
I/DEBUG ( 5818): d16 0000000000000000 d17 3fe999999999999a
I/DEBUG ( 5818): d18 42eccefa43de3400 d19 3fe00000000000b4
I/DEBUG ( 5818): d20 4008000000000000 d21 3fd99a27ad32ddf5
I/DEBUG ( 5818): d22 3fd24998d6307188 d23 3fcc7288e957b53b
I/DEBUG ( 5818): d24 3fc74721cad6b0ed d25 3fc39a09d078c69f
I/DEBUG ( 5818): d26 0000000000000000 d27 0000000000000000
I/DEBUG ( 5818): d28 0000000000000000 d29 0000000000000000
I/DEBUG ( 5818): d30 0000000000000000 d31 0000000000000000
I/DEBUG ( 5818): scr 80000012
I/DEBUG ( 5818):
I/DEBUG ( 5818):
I/DEBUG ( 5818):
I/DEBUG ( 5818):
I/DEBUG ( 5818): code around pc:
I/DEBUG ( 5818):
I/DEBUG ( 5818): code around lr:
I/DEBUG ( 5818): afd10620 e1a01008 e1a02007 e1a03006 e1a00005
I/DEBUG ( 5818): afd10630 ebfff95d e1a05000 e1a00004 ebffff46
I/DEBUG ( 5818): afd10640 e375006e 03a0006e 13a00000 e8bd81f0
I/DEBUG ( 5818): afd10650 e304cdd3 e3043240 e92d4010 e341c062
I/DEBUG ( 5818): afd10660 e1a0e002 e24dd008 e340300f e1a0200d
I/DEBUG ( 5818):
I/DEBUG ( 5818): stack:
I/DEBUG ( 5818): 100ffe18 00000000
I/DEBUG ( 5818): 100ffe1c 00000000
I/DEBUG ( 5818): 100ffe20 00000000
I/DEBUG ( 5818): 100ffe24 ffffff92
I/DEBUG ( 5818): 100ffe28 100ffe58
I/DEBUG ( 5818): 100ffe2c 00000000
I/DEBUG ( 5818): 100ffe30 00000080
I/DEBUG ( 5818): 100ffe34 8054f999 /system/lib/libdvm.so
I/DEBUG ( 5818): 100ffe38 10000000
I/DEBUG ( 5818): 100ffe3c afd10640 /system/lib/libc.so
I/DEBUG ( 5818): 100ffe40 00000000
I/DEBUG ( 5818): 100ffe44 00000000
I/DEBUG ( 5818): 100ffe48 00000000
I/DEBUG ( 5818): 100ffe4c 00000000
I/DEBUG ( 5818): 100ffe50 e3a07077
I/DEBUG ( 5818): 100ffe54 ef900077
I/DEBUG ( 5818):
I/DEBUG ( 5818): 100ffe5c 00000000
I/DEBUG ( 5818): 100ffe60 00000000
I/DEBUG ( 5818): 100ffe64 00000000
I/DEBUG ( 5818): 100ffe68 00000000
I/DEBUG ( 5818): 100ffe6c 00000000
I/DEBUG ( 5818): 100ffe70 00000000
I/DEBUG ( 5818): 100ffe74 00000000
I/DEBUG ( 5818): 100ffe78 00000000
I/DEBUG ( 5818): 100ffe7c 00000000
I/DEBUG ( 5818): 100ffe80 00000000
I/DEBUG ( 5818): 100ffe84 00000000
I/DEBUG ( 5818): 100ffe88 00000000
I/DEBUG ( 5818): 100ffe8c 00000000
I/DEBUG ( 5818): 100ffe90 00000000
I/DEBUG ( 5818): 100ffe94 00000000
I/DEBUG ( 5818): 100ffe98 00000000
I/DEBUG ( 5818): 100ffe9c 00000000
ndk r6, Android 2.2 ( API 8), -Wall -Werror, ARM.
, , . , ( , ), . , !
JNI
j2n, n2j. j2n :
private static class Renderer implements GLSurfaceView.Renderer {
public void onDrawFrame(GL10 gl) {
GraphicsLib.graphicsStep();
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
GraphicsLib.graphicsInit(width, height);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
}
:
public class GraphicsLib {
static {
System.loadLibrary("graphicslib");
}
public static native void graphicsInit(int width, int height);
public static native void graphicsStep();
}
:
extern "C" {
JNIEXPORT void JNICALL FN(graphicsInit)(JNIEnv* env, jobject obj, jint width, jint height);
JNIEXPORT void JNICALL FN(graphicsStep)(JNIEnv* env, jobject obj);
};
.
graphicsInit OpenGL . graphicsStep LoadSprites(env).
n2j , LoadSprites(), . , , .
LoadSprites :
GameAssetsInfo gai;
void LoadSprites(JNIEnv* env)
{
InitGameAssets(gai, env);
CatchJNIException(env, "j0");
...
static int z = 0;
if (z < numSprites)
{
CatchJNIException(env, "j1");
OpenGameImage(gai, SpriteIDFromNumber(z));
CatchJNIException(env, "j2");
unsigned int actualWidth = GetGameImageWidth(gai);
CatchJNIException(env, "j3");
unsigned int actualHeight = GetGameImageHeight(gai);
CatchJNIException(env, "j4");
...
jint i;
int r = 0;
CatchJNIException(env, "j5");
do {
CatchJNIException(env, "j6");
i = ReadGameImage(gai);
CatchJNIException(env, "j7");
if (i > 0)
{
CatchJNIException(env, "j8");
StoreGameImageChunk(gai, (int*)sprites[z].data + r, 0, i);
...
r += sprites[z].width;
CatchJNIException(env, "j9");
UnreadGameImage(gai);
CatchJNIException(env, "j10");
} else {
break;
}
} while (true);
CatchJNIException(env, "j11");
CloseGameImage(gai);
CatchJNIException(env, "j12");
... OpenGL ES calls ...
glTexImage2D( ... );
z++;
}
CatchJNIException(env, "j13");
}
CatchJNIException ( ):
void CatchJNIException(JNIEnv* env, const char* str)
{
jthrowable exc = env->ExceptionOccurred();
if (exc) {
jclass newExcCls;
env->ExceptionDescribe();
env->ExceptionClear();
newExcCls = env->FindClass(
"java/lang/IllegalArgumentException");
if (newExcCls == NULL) {
LOGE("Failed to catch JNI exception entirely -- could not find exception class.");
return;
abort();
}
LOGE("Caught JNI exception. (%s)", str);
env->ThrowNew( newExcCls, "thrown from C code");
}
}
GameAssetInfo :
void InitGameAssets(GameAssetsInfo& gameasset, JNIEnv* env)
{
CatchJNIException(env, "jS0");
FST;
char str[64];
sprintf(str, "%s/GameAssets", ROOTSTR);
gameasset.env = env;
CatchJNIException(gameasset.env, "jS1");
gameasset.cls = gameasset.env->FindClass(str);
CatchJNIException(gameasset.env, "jS2");
gameasset.openAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "OpenAsset", "(I)V");
CatchJNIException(gameasset.env, "jS3");
gameasset.readAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "ReadAsset", "()I");
CatchJNIException(gameasset.env, "jS4");
gameasset.closeAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "CloseAsset", "()V");
CatchJNIException(gameasset.env, "jS5");
gameasset.buffID = gameasset.env->GetStaticFieldID(gameasset.cls, "buff", "[B");
CatchJNIException(gameasset.env, "jS6");
gameasset.openImage = gameasset.env->GetStaticMethodID(gameasset.cls, "OpenImage", "(I)V");
CatchJNIException(gameasset.env, "jS7");
gameasset.readImage = gameasset.env->GetStaticMethodID(gameasset.cls, "ReadImage", "()I");
CatchJNIException(gameasset.env, "jS8");
gameasset.closeImage = gameasset.env->GetStaticMethodID(gameasset.cls, "CloseImage", "()V");
CatchJNIException(gameasset.env, "jS9");
gameasset.buffIntID = gameasset.env->GetStaticFieldID(gameasset.cls, "buffInt", "[I");
CatchJNIException(gameasset.env, "jS10");
gameasset.imageWidth = gameasset.env->GetStaticFieldID(gameasset.cls, "imageWidth", "I");
CatchJNIException(gameasset.env, "jS11");
gameasset.imageHeight = gameasset.env->GetStaticFieldID(gameasset.cls, "imageHeight", "I");
CatchJNIException(gameasset.env, "jS12");
gameasset.imageHasAlpha = gameasset.env->GetStaticFieldID(gameasset.cls, "imageHasAlpha", "I");
CatchJNIException(gameasset.env, "jS13");
}
void OpenGameAsset(GameAssetsInfo& gameasset, int rsc)
{
FST;
CatchJNIException(gameasset.env, "jS14");
gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.openAsset, rsc);
CatchJNIException(gameasset.env, "jS15");
}
void CloseGameAsset(GameAssetsInfo& gameasset)
{
FST;
CatchJNIException(gameasset.env, "jS16");
gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.closeAsset);
CatchJNIException(gameasset.env, "jS17");
}
int ReadGameAsset(GameAssetsInfo& gameasset)
{
FST;
CatchJNIException(gameasset.env, "jS18");
int ret = gameasset.env->CallStaticIntMethod(gameasset.cls, gameasset.readAsset);
CatchJNIException(gameasset.env, "jS19");
if (ret > 0)
{
CatchJNIException(gameasset.env, "jS20");
gameasset.obj = gameasset.env->GetStaticObjectField(gameasset.cls, gameasset.buffID);
CatchJNIException(gameasset.env, "jS21");
gameasset.arr = reinterpret_cast<jbyteArray*>(&gameasset.obj);
}
return ret;
}
void UnreadGameAsset(GameAssetsInfo& gameasset)
{
FST;
CatchJNIException(gameasset.env, "jS22");
gameasset.env->DeleteLocalRef(gameasset.obj);
CatchJNIException(gameasset.env, "jS23");
}
void StoreGameAssetChunk(GameAssetsInfo& gameasset, void* store, int offset, int length)
{
FST;
CatchJNIException(gameasset.env, "jS24");
gameasset.env->GetByteArrayRegion(*gameasset.arr, offset, length, (jbyte*)store);
CatchJNIException(gameasset.env, "jS25");
}
void OpenGameImage(GameAssetsInfo& gameasset, int rsc)
{
FST;
CatchJNIException(gameasset.env, "jS26");
gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.openImage, rsc);
CatchJNIException(gameasset.env, "jS27");
gameasset.l_imageWidth = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageWidth);
CatchJNIException(gameasset.env, "jS28");
gameasset.l_imageHeight = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageHeight);
CatchJNIException(gameasset.env, "jS29");
gameasset.l_imageHasAlpha = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageHasAlpha);
CatchJNIException(gameasset.env, "jS30");
}
void CloseGameImage(GameAssetsInfo& gameasset)
{
FST;
CatchJNIException(gameasset.env, "jS31");
gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.closeImage);
CatchJNIException(gameasset.env, "jS32");
}
int ReadGameImage(GameAssetsInfo& gameasset)
{
FST;
CatchJNIException(gameasset.env, "jS33");
int ret = gameasset.env->CallStaticIntMethod(gameasset.cls, gameasset.readImage);
CatchJNIException(gameasset.env, "jS34");
if ( ret > 0 )
{
CatchJNIException(gameasset.env, "jS35");
gameasset.obj = gameasset.env->GetStaticObjectField(gameasset.cls, gameasset.buffIntID);
CatchJNIException(gameasset.env, "jS36");
gameasset.arrInt = reinterpret_cast<jintArray*>(&gameasset.obj);
}
return ret;
}
void UnreadGameImage(GameAssetsInfo& gameasset)
{
FST;
CatchJNIException(gameasset.env, "jS37");
gameasset.env->DeleteLocalRef(gameasset.obj);
CatchJNIException(gameasset.env, "jS38");
}
void StoreGameImageChunk(GameAssetsInfo& gameasset, void* store, int offset, int length)
{
FST;
CatchJNIException(gameasset.env, "jS39");
gameasset.env->GetIntArrayRegion(*gameasset.arrInt, offset, length, (jint*)store);
CatchJNIException(gameasset.env, "jS40");
}
int GetGameImageWidth(GameAssetsInfo& gameasset) { return gameasset.l_imageWidth; }
int GetGameImageHeight(GameAssetsInfo& gameasset) { return gameasset.l_imageHeight; }
int GetGameImageHasAlpha(GameAssetsInfo& gameasset) { return gameasset.l_imageHasAlpha; }
Java:
public class GameAssets {
static public Resources res = null;
static public InputStream is = null;
static public byte buff[];
static public int buffInt[];
static public final int buffSize = 1024;
static public final int buffIntSize = 2048;
static public int imageWidth;
static public int imageHeight;
static public int imageHasAlpha;
static public int imageLocX;
static public int imageLocY;
static public Bitmap mBitmap;
static public BitmapFactory.Options decodeResourceOptions = new BitmapFactory.Options();
public GameAssets(Resources r) {
res = r;
buff = new byte[buffSize];
buffInt = new int[buffIntSize];
decodeResourceOptions.inScaled = false;
}
public static final void OpenAsset(int id) {
is = res.openRawResource(id);
}
public static final int ReadAsset() {
int num = 0;
try {
num = is.read(buff);
} catch (Exception e) {
;
}
return num;
}
public static final void CloseAsset() {
try {
is.close();
} catch (Exception e) {
;
}
is = null;
}
public static final void OpenImage(int id) {
mBitmap = BitmapFactory.decodeResource(res, id, decodeResourceOptions);
imageWidth = mBitmap.getWidth();
imageHeight = mBitmap.getHeight();
imageHasAlpha = mBitmap.hasAlpha() ? 1 : 0;
imageLocX = 0;
imageLocY = 0;
}
public static final int ReadImage() {
if (imageLocY >= imageHeight) return 0;
int numReadPixels = buffIntSize;
if (imageLocX + buffIntSize >= imageWidth)
{
numReadPixels = imageWidth - imageLocX;
mBitmap.getPixels(buffInt, 0, imageWidth, imageLocX, imageLocY, numReadPixels, 1);
imageLocY++;
}
else
{
mBitmap.getPixels(buffInt, 0, imageWidth, imageLocX, imageLocY, numReadPixels, 1);
imageLocX += numReadPixels;
}
return numReadPixels;
}
public static final void CloseImage() {
}
}
.
, .