Android app rare production out-of-bounds exception.
My production app sometimes has a rare out-of-bounds-exception crash, which has only ever occurred on a Samsung Galaxy Tab A (2016), 2048 MB RAM, Android 8.1. I cannot properly diagnose which index is OOB. Also I cannot see how any of the indexes can possible be wrong anyway. Am I missing something obvious, can anyone help please?
The app has prod versions 1.0, 1.1, 1.2 & 1.3.
There are crash reports of this happening in v 1.0 on March 30th, and again this week in v 1.2 on May 11th,
Although I could not diagnose it, I attempted some fixes for the 1.0 March 30th crash. These ‘fixes’ are live in version 1.2. So, moving on, 1.2 had a similar crash this week on May 11th (actually 5 crashes over several hours, all on the same device).
The code is:
public Bitmap[][] balloonBitmap = new Bitmap[6][6];
public int[] dynamicObjectRId = new int[10];
for (int j = 1; j <= totalNoOfDynamicImages; j++) {
// PROD CRASH March 30th: OOB was on the next line
**balloonBitmap[correctOptionColourNo][j] = ImageUtil.loadImage(res, db.dynamicObjectRId[j],
dynamicImageWidthQT3, dynamicImageHeightQT3)**;
// PROD CRASH May 11th seems to be on this line:
*byteCountforBitmaps += balloonBitmap[correctOptionColourNo][j].getByteCount();*
}
The fix I tried is done earlier in the method: (live in v1.2)
if ((correctOptionColourNo < 0) || (correctOptionColourNo > 5)) {
correctOptionColourNo = 3;
}
So correctOptionColourNo should be ok, not OOB.
The OOB on May 11th appears to be on the next statement:
byteCountforBitmaps += balloonBitmap[correctOptionColourNo][j].getByteCount();
However, I’m not sure if I can fully believe this, because surely the previous statement would have OOB’d first. Anyway my v 1.2 code backup points to this line of code – I just don’t believe it somehow. But whichever is the actual offending line of code, it’s still the same problem, which index is OOB and why is it happening?
I suspect the problem is here: for (int j = 1; j <= totalNoOfDynamicImages; j++)
Try changing it to for (int j = 0; j < totalNoOfDynamicImages; j++)
Related
I am building an app in which I use the spongycastle library (which is run-down version of bouncycastle), but the problem is when I perform this:
KeyParameter key = (KeyParameter) generator.generateDerivedMacParameters(keyLength * 8); // key length in bits
and build it on any phone which has API of 6.0 or below the operation is extremely slow. To pinpoint the exact code which runs very slow (note that this code is in spongy library):
for (int count = 1; count < iterationCount; count++)
{
hMac.update(state, 0, state.length);
hMac.doFinal(state, 0);
for (int j = 0; j != state.length; j++)
{
out[outOff + j] ^= state[j];
}
}
The iteration count is always 800000 because I need it to be very secure, but the process to execute this code takes almost 5 minutes on these devices. The interesting part is that on API 4.4 it only takes about a minute. So, is there any workaround for this without reducing the iteration count, maybe I should just use bouncycastle or something else?
I have the following code ( from a class member function of mine):
this->mLengOfPath = mFirst->mLengOfPath + mSecond->mLengOfPath;
unsigned short* data = mMiddle->mPathContainer;
mMiddle->mLengOfPath = 0;
for (int index = 0; index < mMiddle->mSize; index++) { //crash here
if (index % 2 == 1 && index > 2){
mMiddle->mLengOfPath +=
GestureUtils::distance(data[index - 3], data[index - 2],
data[index - 1], data[index]);
}
}
In most case, this code doesn't crash. But crashlytics told me that my code "sometimes" crash at line 4, which I don't understand why. If mMiddle is nullptr, it should have crashed at line 2 (I already use mMiddle there).
But crashlytics consistently reports that line 4 is the problem. Anyone know how can my code go wrong at line 4?
Yeah, it's UB, if pointer is invalid. But we have particular platform and compiler in mind, while talking Android NDK and a statistical tool. With native ARM code lines 1,2,4 lines may crash sometimes on invalid pointer, only writing to null pointer is 100% failure.
Line 3 will always fail if mMiddle is null, but may or may not if it points into data segment or not. Statistical tool would highlight line 4 as it is one more often executed one: comparing expression is evaluated on every iteration. Failures on other lines may become statistical noise.
Updates here:
Devices exposing the issue so far (output 160):
Meizu M2 Note; CPU Mediatek MT6753; Android 5.1; Root: NO
Doogee Leo DG280; CPU Mediatek MT6582; Android 4.4.2; Root: NO
============
I have a really weird behavior of a while loop happening on a DooGee Leo LG280.
The output of this loop is 60 on every emulator and phone that I've tested. I can run it 100 times and the result will always be 60.
The code:
public class JavaActivity extends AppCompatActivity {
#Override public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int limitValue = 50;
int result = startWeirdLoop(limitValue);
System.out.println("my weird loop in java " + result);
((TextView)findViewById(R.id.textView)).setText(String.valueOf(result));
}
private int startWeirdLoop(int limitValue) {
int index = 0;
while (index <= limitValue) {
index += 20;
}
return index;
}
}
If you run the same code on the devices listed above, the output is 160.
To let it output the right value (60) there are some things I tried so far:
just add an empty print statement in the loop
hardcode the limitValue in the while by replacing it with 50.
replace Integer to int in the parameter limitValue
flip the condition in the while: while (limitValue >= index)
add 0 to limitValue: while (index <= limitValue + 0)
It really doesn't make sense to me! Why a System.out.println("") should magically fix the result of a while loop? Why hardcoding the parameter should fix it as well? And most importantly, why is this happening only on this device?
It seems that any instruction added into the loop makes the loop work as expected. And this scares me.
Could it be related to the CPU (MediaTek MT6582 ARM Cortex-A7)? To the system version? I don't know but this really pisses me off, because it's happening only on this device and I'm scared it could be on others. I repeat, on emulators and Huawey, LG, Samsung devices works fine.
My only doubt here is somehow related to combination CPU <-> Android Runtime ART. If you have this model of phone or another phone with MT6582, please try to run this code.
Screenshots:
Instrumented test run on the DooGee device (to avoid any layout related issues)
I'm trying to compare "Cross platform mobile application development tools" vs "Android Native development" from a performance perspective. In order to do that I developed an application which makes a calculation of a serie. Below I transcript Android and Phonegap code.
Android
double serie;
long t1 = System.currentTimeMillis();
serie = 0;
for (int j = 1; j <= 5; j++) {
for (int k = 1; k <= 100000; k++) {
serie = serie + Math.log(k) / Math.log(2) + (3 * k / (2 * j)) + Math.sqrt(k) + Math.pow(k, j - 1);
}
}
long duration = System.currentTimeMillis() - t1;
Phonegap
var start = new Date().getTime();
var serie = 0;
for ( var j=1; j <= 5; j++ ){
for ( var k=1; k <= 100000; k++ ){
serie = serie + ( Math.log(k)/Math.LN2 ) + (3*k/2*j) + Math.sqrt(k) + Math.pow(k, j-1);
}
}
var end = new Date().getTime();
var duration = end - start;
Each timing was taken thirty times and the results were averaged.
Results
Android average time = 532.93ms
Phonegap average time = 230.33ms
The results are far from what I expected. I don't understand why Android performance is worse than Phonegap's. Both applications are run as release versions.
The device is a Moto G2 (Android 4.4)
Am I missing something?
I am not sure if this performance comparison makes any sense. You simply perform some computation in Java and then in JavaScript. After that, you measure computation time. It doesn't prove anything.
The only conclusion you could have is the fact that JavaScript performed this particular computation faster than Java for some reason. Maybe JavaScript optimized something under the hood. As it's dynamically typed language, you should check if Java and JavaScript code returned the same result, because I'm not sure about that. Moreover, you are measuring time in a different ways in two tests. Maybe System.currentTimeMillis(); simply takes more time than new Date().getTime(); ?
In real life, you put non-deterministic and long operations to a separate thread different than UI thread. When operation is done, you can pass the result to the UI thread. Bad project structure and bad programming practices can slow down your application. With cross-platform tools like Phonegap, you have no control over Java code and you have very limited access to low level optimization techniques and multi-threading. You also have no direct access to Android SDK.
If you really want to analyze performance, you should prepare more realistic instrumentation test. For example, create application (in two versions: Android & Phone Gap), which reads some data from a file and images from disk and then displays it on the list and with instrumentation test, you can scroll the list down to the bottom. Afterwards, you can measure time of whole instrumentation test in both cases. Having something like that, you can make some assumptions.
My app targets version 2.2 and seems to run fine on the 3 devices I've tested it on (version 2.2 and 2.3)
However, I just ran it on a Google Nexus 10 tablet and the splash screen works OK and takes a touch input to start the next activity (a menu system based off of SurfaceView using multiple threads) and although it displays / animates OK, none of the buttons are working - I'm not really sure where to begin, am I wrong in assuming apps written for older Android API's are not compatible with newer releases of the OS? Surely newer versions are backwardly compatible?
Thanks all!!
Edit: If I repeatedly hit the start button, Logcat is showing this:
So not sure why this is doing this on JB but OK on devices running older OS's - thank you all.
Edit 2:
Code for 'button' release (after 'button' press):
if (event.getAction()==MotionEvent.ACTION_UP){
Intent StartNewGame = new Intent((Activity) getContext(), StartGame.class);
getContext().startActivity(StartGame);
// Oddly, if I put a System.exit(0); here, game activity starts and everything is fine - obviously this is only for testing and needs to be removed.
return true;}
}
public int nextInt(int n) {
if (n > 0) {
if ((n & -n) == n) {
return (int) ((n * (long) next(31)) >> 31);
}
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n - 1) < 0);
return val;
}
throw new IllegalArgumentException();
}
That is the code from the source for 4.1 so it looks like you are some how passing a 0 to the function , is there any way this could happen in your code?