I have an app on Google Play that updated yesterday and I have started getting numerous reports from Crashlytics where my app crashes only on Samsung devices with Android 4.x (4.1.2 - 4.4.4).
The trace of the exception is as follows:
Fatal Exception: java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by java.lang.OutOfMemoryError
at java.util.Arrays.copyOfRange(Arrays.java:2684)
at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:467)
at javax.crypto.Cipher.doFinal(Cipher.java:1204)
at com.ijsoft.cpul.Util.DbMainFunctions.com.ijsoft.cpul.Util.AES256Cipher.decrypt(DbMainFunctions.java:2059)
at com.ijsoft.cpul.Util.DbMainFunctions.initializeDb(DbMainFunctions.java:94)
at com.ijsoft.cpul.SplashActivity$InitializeDb.doInBackground$9ecd34e(SplashActivity.java:2095)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
In other cases I received the following trace:
Fatal Exception: java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:299)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
Caused by java.lang.OutOfMemoryError
at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:91)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:201)
at com.ijsoft.cpul.Util.DbMainFunctions.initializeDb(DbMainFunctions.java:90)
at com.ijsoft.cpul.SplashActivity$InitializeDb.doInBackground$9ecd34e(SplashActivity.java:2095)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
I leave part of the code where the error occurs:
AES256Cipher.java
public class AES256Cipher {
public byte[] decrypt(byte[] textBytes, Context context)
throws java.io.UnsupportedEncodingException,
NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
IllegalBlockSizeException,
BadPaddingException {
byte[] keyBytes = CommonFunctions.md5Package(context).getBytes();
byte[] ivBytes = new byte[16];
for (int j = 0; j < keyBytes.length; j+=2) {
ivBytes[j/2]=keyBytes[31-j];
}
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
return cipher.doFinal(textBytes);
}
}
DbMainFunctions.java
public synchronized static int initializeDb(int release, Context context) {
int resultCode = 0;
try {
// Get the encrypted json file (database) from Assets
AssetManager am = context.getAssets();
InputStream is = am.open("assets");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[4096];
int i;
while ((i = is.read(buff, 0, buff.length)) > 0) {
baos.write(buff, 0, i);
}
is.close();
baos.close();
resultCode = updateDb(baos.toByteArray(), release, context);
//baos.close();
} catch (Exception e) {
Log.e("DbMainFunctions", e.getMessage());
//e.printStackTrace();
resultCode = -1;
}
return resultCode;
}
public synchronized static int updateDb(byte[] cipherJson, int release, Context context) {
int resultCode = 0;
AES256Cipher aes256;
try {
aes256 = new AES256Cipher();
cipherJson = aes256.decrypt(cipherJson, context);
} catch (UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
Log.e("DbMainFuctions", e.getMessage());
return -2;
}
...
}
My application does at that point is to get an encrypted file (filename: assets) with AES256 from the Assets directory included in the APK. The file is then decrypted and saved in a Byte Array. The file is approximately 4.4 MB in size. The initializeDb() method is called from an AsyncTask during doInBackground(), that is, all the previous code is executed in an AsyncTask