From 600b44b9fcaeb1858664ad7e9edf459b3060913d Mon Sep 17 00:00:00 2001 From: Thialfihar Date: Thu, 3 Jun 2010 16:17:55 +0000 Subject: [PATCH] added a service to handle the caching, this'll ensure the cache works while no activity is around, which is better for k9mail integration it also is a more efficient and much smarter cache, not requiring an own timer thread, just a service that sleeps must of the time, it also is more accurate in cleaning up the entries, ensuring that the worst case of too late removal is 5 seconds --- AndroidManifest.xml | 2 + src/org/thialfihar/android/apg/Apg.java | 17 +++- .../thialfihar/android/apg/BaseActivity.java | 34 ++------ .../android/apg/PreferencesActivity.java | 1 - src/org/thialfihar/android/apg/Service.java | 79 +++++++++++++++++++ 5 files changed, 101 insertions(+), 32 deletions(-) create mode 100644 src/org/thialfihar/android/apg/Service.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 0596fc9a4..de5869988 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -128,6 +128,8 @@ android:label="@string/title_preferences" android:configChanges="keyboardHidden|orientation|keyboard"/> + + oldKeys = new Vector(); for (Map.Entry pair : mPassPhraseCache.entrySet()) { - if ((now - pair.getValue().timestamp) >= 1000 * ttl) { + long lived = now - pair.getValue().timestamp; + if (lived >= realTtl) { oldKeys.add(pair.getKey()); + } else { + // see, whether the remaining time for this cache entry improves our + // check delay + long nextCheck = realTtl - lived + 1000; + if (nextCheck < delay) { + delay = (int)nextCheck; + } } } for (long keyId : oldKeys) { mPassPhraseCache.remove(keyId); } + + return delay; } public static PGPSecretKey createKey(Context context, diff --git a/src/org/thialfihar/android/apg/BaseActivity.java b/src/org/thialfihar/android/apg/BaseActivity.java index 282057975..3e302b6cc 100644 --- a/src/org/thialfihar/android/apg/BaseActivity.java +++ b/src/org/thialfihar/android/apg/BaseActivity.java @@ -17,8 +17,6 @@ package org.thialfihar.android.apg; import java.io.File; -import java.util.Timer; -import java.util.TimerTask; import org.bouncycastle2.bcpg.HashAlgorithmTags; import org.bouncycastle2.openpgp.PGPEncryptedData; @@ -53,8 +51,6 @@ public class BaseActivity extends Activity private String mDeleteFile = null; protected static SharedPreferences mPreferences = null; - private static Timer mCacheTimer = new Timer(); - private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -80,29 +76,9 @@ public class BaseActivity extends Activity } } - if (mCacheTimer == null) { - setPassPhraseCacheTimer(); - } - } - - private void setPassPhraseCacheTimer() { - if (mCacheTimer != null) { - mCacheTimer.cancel(); - mCacheTimer = null; - } - int ttl = getPassPhraseCacheTtl(); - if (ttl == 0) { - // no timer needed - return; - } - // check every ttl/2 seconds, which shouldn't be heavy on the device (even if ttl = 15), - // and makes sure the longest a pass phrase survives int the cache is 1.5 * ttl - mCacheTimer = new Timer(); - mCacheTimer.scheduleAtFixedRate(new TimerTask() { - public void run() { - Apg.cleanUpCache(BaseActivity.this.getPassPhraseCacheTtl()); - } - }, 0, ttl * 1000 / 2); + Intent intent = new Intent(this, Service.class); + intent.putExtra(Service.EXTRA_TTL, getPassPhraseCacheTtl()); + startService(intent); } @Override @@ -400,7 +376,9 @@ public class BaseActivity extends Activity editor.putInt(Constants.pref.pass_phrase_cache_ttl, value); editor.commit(); - setPassPhraseCacheTimer(); + Intent intent = new Intent(this, Service.class); + intent.putExtra(Service.EXTRA_TTL, getPassPhraseCacheTtl()); + startService(intent); } public int getDefaultEncryptionAlgorithm() { diff --git a/src/org/thialfihar/android/apg/PreferencesActivity.java b/src/org/thialfihar/android/apg/PreferencesActivity.java index fae63d63b..e80e1ad5f 100644 --- a/src/org/thialfihar/android/apg/PreferencesActivity.java +++ b/src/org/thialfihar/android/apg/PreferencesActivity.java @@ -50,7 +50,6 @@ public class PreferencesActivity extends BaseActivity { new Choice(180, getString(R.string.choice_3mins)), new Choice(300, getString(R.string.choice_5mins)), new Choice(600, getString(R.string.choice_10mins)), - new Choice(0, getString(R.string.choice_untilQuit)), }; ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, choices); diff --git a/src/org/thialfihar/android/apg/Service.java b/src/org/thialfihar/android/apg/Service.java new file mode 100644 index 000000000..2c8fd8496 --- /dev/null +++ b/src/org/thialfihar/android/apg/Service.java @@ -0,0 +1,79 @@ +package org.thialfihar.android.apg; + +import android.content.Intent; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; + +public class Service extends android.app.Service { + private final IBinder mBinder = new LocalBinder(); + + public static final String EXTRA_TTL = "ttl"; + + private int mPassPhraseCacheTtl = 15; + private Handler mCacheHandler = new Handler(); + private Runnable mCacheTask = new Runnable() { + public void run() { + // TODO: I suppose we could read out the time left until the first cache entry + // expiration, then use that for the timer... + + // check every ttl/2 seconds, which shouldn't be heavy on the device (even if ttl = 15), + // and makes sure the longest a pass phrase survives in the cache is 1.5 * ttl + int delay = mPassPhraseCacheTtl * 1000 / 2; + // also make sure the delay is not longer than one minute + if (delay > 60000) { + delay = 60000; + } + + delay = Apg.cleanUpCache(mPassPhraseCacheTtl, delay); + // don't check too often, even if we were close + if (delay < 5000) { + delay = 5000; + } + + mCacheHandler.postDelayed(this, delay); + } + }; + + static private boolean mIsRunning = false; + + @Override + public void onCreate() { + super.onCreate(); + + mIsRunning = true; + } + + @Override + public void onDestroy() { + super.onDestroy(); + mIsRunning = false; + } + + @Override + public void onStart(Intent intent, int startId) { + super.onStart(intent, startId); + + mPassPhraseCacheTtl = intent.getIntExtra(EXTRA_TTL, 15); + if (mPassPhraseCacheTtl < 15) { + mPassPhraseCacheTtl = 15; + } + mCacheHandler.removeCallbacks(mCacheTask); + mCacheHandler.postDelayed(mCacheTask, 1000); + } + + static public boolean isRunning() { + return mIsRunning; + } + + public class LocalBinder extends Binder { + Service getService() { + return Service.this; + } + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } +}