The mighty Bitmap.getPixel() SegFault

At least on the G1/MyTouch. I have a 32-bit ARGB bitmap stored in png format. To save memory i thought it would be a good idea to transform it to 16-bit ARGB on the flie. Here’s how i tried to do that:

All is well and good. According to the documentation of BitmapFactory.Options.inPreferredConfig says that “If this is non-null, the decoder will try to decode into this internal configuration.” which is exactly what i needed. Emphasis on the “try” here though, it might just load it in the original bit-depth, which would be fine with me too.

Now that i have my awesome bitmap loaded i wanted to go through each pixel to build a collision map for a 2D game i’m working on. I do this as follows:

Looks good to me, don’t mind the vertical flip i do in line 7, it’s only a little evil (apart from the fact that this two nested loops are incredibly slow, it’s only for testing…). I tried it on my Droid and it worked as expected. I tried it on the emulator and it worked as expected. I send it to a few of my trusty G1/MyTouch test slaves and it failed horribly:


02-01 12:13:03.107 I/DEBUG ( 48): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
02-01 12:13:03.107 I/DEBUG ( 48): Build fingerprint: 'tmobile/kila/dream/trout:1.6/DRC83/14721:user/ota-rel-keys,release-keys'
02-01 12:13:03.107 I/DEBUG ( 48): pid: 421, tid: 427 >>> com.badlogic.doodleescape <<< 02-01 12:13:03.107 I/DEBUG ( 48): signal 7 (SIGBUS), fault addr 00000000 02-01 12:13:03.107 I/DEBUG ( 48): r0 4452bd84 r1 4622b00a r2 00000001 r3 00000000 02-01 12:13:03.107 I/DEBUG ( 48): r4 00000001 r5 4622b00a r6 4452bd84 r7 4104be78 02-01 12:13:03.107 I/DEBUG ( 48): r8 4452bd9c r9 4104be6c 10 4104be5c fp 00000001 02-01 12:13:03.107 I/DEBUG ( 48): ip 4622b00a sp 4452bd70 lr ad346c1f pc ad3469a0 cpsr 00000030 02-01 12:13:03.717 I/DEBUG ( 48): #00 pc 000469a0 /system/lib/libandroid_runtime.so 02-01 12:13:03.717 I/DEBUG ( 48): #01 pc 00046c1c /system/lib/libandroid_runtime.so 02-01 12:13:03.727 I/DEBUG ( 48): #02 pc 0000e434 /system/lib/libdvm.so 02-01 12:13:03.737 I/DEBUG ( 48): stack: 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd30 ad083e1c /system/lib/libdvm.so 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd34 ad0159f4 /system/lib/libdvm.so 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd38 0000032c 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd3c 0000002a 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd40 00000054 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd44 ad083e1c /system/lib/libdvm.so 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd48 00000064 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd4c 0000001a 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd50 00000000 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd54 4104be78 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd58 00000001 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd5c 41c3a728 /system/framework/framework.odex 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd60 00000003 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd64 41c3a728 /system/framework/framework.odex 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd68 df002777 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd6c e3a070ad 02-01 12:13:03.737 I/DEBUG ( 48): #00 4452bd70 ad346999 /system/lib/libandroid_runtime.so 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd74 001c5758 [heap] 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd78 00000001 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd7c ad346c1f /system/lib/libandroid_runtime.so 02-01 12:13:03.737 I/DEBUG ( 48): #01 4452bd80 00000027 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd84 ffffffff 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd88 4452bdc0 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd8c 00000004 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd90 ad346bed /system/lib/libandroid_runtime.so 02-01 12:13:03.737 I/DEBUG ( 48): 4452bd94 ad00e438 /system/lib/libdvm.so

So i got a little suspicious as it crashes with a segfault in the android framework itself upon a call to Bitmap.getPixel(). I assume there's a big in previous versions of Android at least on the G1/MyTouch which fucks up the bit-depth reduction somewhere and stores a null pointer to the bitmap data without reporting an error. The bitmap returned by the BitmapFactory is not null indicating that all went well (my ass...).

The simple fix: don't decode your images to another bit-depth on the fly.

2 thoughts on “The mighty Bitmap.getPixel() SegFault

  1. I ran into this same problem. I didn’t get a seg fault, it just kicked the program out. The decode function will decode to a different format (8888 to 4444) if and only if you use copyPixelsToBuffer to access the data. If you use getPixel it crashes on the second call. (as you’ve found). It will also decode to a int array. Interestingly enough, it only has this trouble with alpha (which, really, it can’t handle worth shit). 565 format works fine with getPixel. I am willing to bet that on the getPixel call they calculated the address to fetch the pixel assuming the input bit depth (8888) instead of the converted bit depth (4444).

  2. That sounds like a very likely cause for the problem. The Android source is full of surprises, i’ll check out the relevant portion if i find the time.

Leave a Reply

Your email address will not be published.