2017-09-27 4 views
2

Google Play에 어제 업데이트 된 앱이 있습니다. 앱이 Android 4.x가 설치된 삼성 기기에서만 충돌하는 Crashlytics에서 수많은 보고서를 받기 시작했습니다 (4.1.2 - 4.4.4).Android 기기의 경우에만 java.lang.OutOfMemoryError가 적용됩니다.

다음과 같이 예외의 추적은 다음과 같습니다 나는 다음과 같은 추적받은 다른 경우

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) 

: 오류가 발생하는 위치

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) 

나는 코드의 일부를 남겨 :

AES256Cipher.java

APK에 포함 된 자산 디렉토리에서 AES256와 (자산 파일 이름) 그 시점이 암호화 된 파일을 얻을 수 있습니다에서

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; 
     } 

    ... 
} 

내 응용 프로그램 않습니다. 그런 다음 파일이 해독되고 Byte Array에 저장됩니다. 파일의 크기는 약 4.4MB입니다. initializeDb() 메서드는 doInBackground()에서 AsyncTask에서 호출됩니다. 즉, 이전 코드가 모두 AsyncTask에서 실행됩니다.

답변

4

이렇게하면이 특히 Android 5.0 이전에 제공 될 가능성이 큽니다. 반드시 4.4MB 연속 메모리 블록이있는 것은 아닙니다.

보안을 제공하지 않으므로 (누구든지 파일을 해독 할 수 있음) CPU, 배터리 및 메모리를 낭비하므로 암호화를 제거합니다.

최소한 전체 내용을 메모리로 읽지 말고 스트리밍 방식으로 데이터를 해독 (예 : 한 번에 16KB)하고, 해독 된 데이터를 출력 파일로 스트리밍합니다 (충분한 메모리가 없기 때문에). 그 중 하나를 잡아라.