Handle memory leak in NativeAESCipherSpi.

This commit is contained in:
Brian Pellin
2009-12-27 20:16:12 -06:00
parent 085f2d86dc
commit 9087a10ebf
2 changed files with 66 additions and 13 deletions

View File

@@ -5,9 +5,9 @@
#include <android/log.h> #include <android/log.h>
//#define LOGD(...) __android_log_print(ANDROID_LOG_VERBOSE, "KeePassDroidNative", __VA_ARGS__) #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "KeePassDroidNative", __VA_ARGS__)
#define LOGD(...) #define LOGD(...)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "KeePassDroidNative", __VA_ARGS__) //#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "KeePassDroidNative", __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , "KeePassDroidNative", __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO , "KeePassDroidNative", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , "KeePassDroidNative", __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN , "KeePassDroidNative", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "KeePassDroidNative", __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "KeePassDroidNative", __VA_ARGS__)
@@ -54,7 +54,7 @@ jlong Java_com_keepassdroid_crypto_NativeAESCipherSpi_nativeInit(JNIEnv *env,
} }
void Java_com_keepassdroid_crypto_NativeAESCipherSpi_nativeCleanup(JNIEnv *env, void Java_com_keepassdroid_crypto_NativeAESCipherSpi_nativeCleanup(JNIEnv *env,
jobject this, jlong ctxPtr) { jclass this, jlong ctxPtr) {
LOGD("cleanup"); LOGD("cleanup");
EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *) ctxPtr; EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *) ctxPtr;

View File

@@ -19,6 +19,9 @@
*/ */
package com.keepassdroid.crypto; package com.keepassdroid.crypto;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.security.AlgorithmParameters; import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
@@ -27,6 +30,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec; import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException; import java.security.spec.InvalidParameterSpecException;
import java.util.HashMap;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
@@ -36,8 +40,14 @@ import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException; import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
public class NativeAESCipherSpi extends CipherSpi { import android.util.Log;
public class NativeAESCipherSpi extends CipherSpi {
private static boolean mIsStaticInit = false;
private static HashMap<PhantomReference<NativeAESCipherSpi>, Long> mCleanup = new HashMap<PhantomReference<NativeAESCipherSpi>, Long>();
private static ReferenceQueue<NativeAESCipherSpi> mQueue = new ReferenceQueue<NativeAESCipherSpi>();
private final int AES_BLOCK_SIZE = 16; private final int AES_BLOCK_SIZE = 16;
private byte[] mIV; private byte[] mIV;
@@ -47,7 +57,53 @@ public class NativeAESCipherSpi extends CipherSpi {
private int mBuffered; private int mBuffered;
private boolean mPadding = false; private boolean mPadding = false;
private static void staticInit() {
mIsStaticInit = true;
// Start the cipher context cleanup thread to run forever
(new Thread(new Cleanup())).start();
}
private static void addToCleanupQueue(NativeAESCipherSpi ref, long ptr) {
Log.d("KeepassDroid", "queued cipher context: " + ptr);
mCleanup.put(new PhantomReference<NativeAESCipherSpi>(ref, mQueue), ptr);
}
/** Work with the garabage collector to clean up openssl memory when the cipher
* context is garbage collected.
* @author bpellin
*
*/
private static class Cleanup implements Runnable {
@Override
public void run() {
while (true) {
try {
Reference<? extends NativeAESCipherSpi> ref = mQueue.remove();
long ctx = mCleanup.remove(ref);
nativeCleanup(ctx);
Log.d("KeePassDroid", "Cleaned up cipher context: " + ctx);
} catch (InterruptedException e) {
// Do nothing, but resume looping if mQueue.remove is interrupted
}
}
}
}
private static native void nativeCleanup(long ctxPtr);
public NativeAESCipherSpi() {
if ( ! mIsStaticInit ) {
staticInit();
}
}
@Override @Override
protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException { throws IllegalBlockSizeException, BadPaddingException {
@@ -166,26 +222,23 @@ public class NativeAESCipherSpi extends CipherSpi {
private void init(int opmode, Key key, IvParameterSpec params) { private void init(int opmode, Key key, IvParameterSpec params) {
if ( mIsInited ) { if ( mIsInited ) {
cleanup(); // Do not allow multiple inits
assert(true);
throw new RuntimeException("Don't allow multiple inits");
} else {
NativeLib.init(); NativeLib.init();
mIsInited = true;
} }
mIV = params.getIV(); mIV = params.getIV();
mEncrypting = opmode == Cipher.ENCRYPT_MODE; mEncrypting = opmode == Cipher.ENCRYPT_MODE;
mBuffered = 0; mBuffered = 0;
mCtxPtr = nativeInit(mEncrypting, key.getEncoded(), mIV, mPadding); mCtxPtr = nativeInit(mEncrypting, key.getEncoded(), mIV, mPadding);
addToCleanupQueue(this, mCtxPtr);
} }
private native long nativeInit(boolean encrypt, byte[] key, byte[] iv, boolean mPadding); private native long nativeInit(boolean encrypt, byte[] key, byte[] iv, boolean mPadding);
private void cleanup() {
nativeCleanup(mCtxPtr);
mCtxPtr = 0;
}
private native void nativeCleanup(long ctxPtr);
@Override @Override
protected void engineSetMode(String mode) throws NoSuchAlgorithmException { protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
if ( ! mode.equals("CBC") ) { if ( ! mode.equals("CBC") ) {