aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org
diff options
context:
space:
mode:
authorMorgan Gangwere <morgan.gangwere@gmail.com>2015-03-03 00:51:44 -0700
committerMorgan Gangwere <morgan.gangwere@gmail.com>2015-03-03 00:51:44 -0700
commit73a1ceb7323f951e92cdb5ce577689adf880d799 (patch)
tree1ba55b62a7218fd9c18e32215d2f859d7e1df34d /OpenKeychain/src/main/java/org
parent1a12eb1a7af9f7fc80846f1925aeab72a752eb6f (diff)
downloadopen-keychain-73a1ceb7323f951e92cdb5ce577689adf880d799.tar.gz
open-keychain-73a1ceb7323f951e92cdb5ce577689adf880d799.tar.bz2
open-keychain-73a1ceb7323f951e92cdb5ce577689adf880d799.zip
Fix root cause of #1077
When importing lots of keys, lots of messages about the status of keys is generated, including some debug slime and general fluff that isn't really needed a lot of the time. As a result, a serious bug can come along after key imports or certain operations which cause a log to become parceled. This commit implements a pool to "dehydrate" logs into: they are placed into the pool (a ConcurrentHashMap) and a UUID assigned to them, which is parceled along. When the OperationResult is un-parceled, it reads in the appropriate UUID bits and rehydrates the appropriate log. In order to avoid any memory leaks, the log pool removes a reference to the log itself, allowing the log to die a natural death at the hands of the GC..
Diffstat (limited to 'OpenKeychain/src/main/java/org')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java76
1 files changed, 70 insertions, 6 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
index f79900aab..02379e917 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
@@ -38,6 +38,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
/** Represent the result of an operation.
*
@@ -52,6 +54,63 @@ public abstract class OperationResult implements Parcelable {
public static final String EXTRA_RESULT = "operation_result";
+
+ /**
+ * A HashMap of UUID:OperationLog which contains logs that we don't need
+ * to care about. This is used such that when we become parceled, we are
+ * well below the 1Mbit boundary that is specified.
+ */
+ private static ConcurrentHashMap<UUID, OperationLog> dehydratedLogs;
+ static {
+ // Static initializer for ConcurrentHashMap
+ dehydratedLogs = new ConcurrentHashMap<UUID,OperationLog>();
+ }
+
+ /**
+ * Dehydrate a log (such that it is available after deparcelization)
+ *
+ * Returns the NULL uuid (0) if you hand it null.
+ * @param log An OperationLog to dehydrate
+ * @return a UUID, the ticket for your dehydrated log
+ *
+ */
+ private static UUID dehydrateLog(OperationLog log) {
+ if(log == null) {
+ return new UUID(0,0);
+ }
+ else {
+ UUID ticket = UUID.randomUUID();
+ dehydratedLogs.put(ticket, log);
+ return ticket;
+ }
+ }
+
+ /***
+ * Rehydrate a log after going through parcelization, invalidating its place in the
+ * dehydration pool.
+ * This is used such that when parcelized, the parcel is no larger than 1mbit.
+ * @param ticket A UUID ticket that identifies the log in question.
+ * @return An OperationLog.
+ */
+ private static OperationLog rehydrateLog(UUID ticket) {
+ if(ticket.getMostSignificantBits() == 0 && ticket.getLeastSignificantBits() == 0) {
+ return null;
+ }
+ else
+ {
+ OperationLog log = dehydratedLogs.get(ticket);
+ invalidateDehydrateTicket(ticket);
+ return log;
+ }
+ }
+ private static void invalidateDehydrateTicket(UUID ticket) {
+ if(ticket.getLeastSignificantBits() != 0 && ticket.getMostSignificantBits() != 0
+ && dehydratedLogs.containsKey(ticket))
+ {
+ dehydratedLogs.remove(ticket);
+ }
+ }
+
/** Holds the overall result, the number specifying varying degrees of success:
* - The first bit is 0 on overall success, 1 on overall failure
* - The second bit indicates if the action was cancelled - may still be an error or success!
@@ -65,7 +124,7 @@ public abstract class OperationResult implements Parcelable {
public static final int RESULT_WARNINGS = 4;
/// A list of log entries tied to the operation result.
- final OperationLog mLog;
+ protected OperationLog mLog;
public OperationResult(int result, OperationLog log) {
mResult = result;
@@ -74,8 +133,11 @@ public abstract class OperationResult implements Parcelable {
public OperationResult(Parcel source) {
mResult = source.readInt();
- mLog = new OperationLog();
- mLog.addAll(source.createTypedArrayList(LogEntryParcel.CREATOR));
+ long mostSig = source.readLong();
+ long leastSig = source.readLong();
+ UUID mTicket = new UUID(mostSig, leastSig);
+ // fetch the dehydrated log out of storage (this removes it from the dehydration pool)
+ mLog = rehydrateLog(mTicket);
}
public int getResult() {
@@ -739,9 +801,11 @@ public abstract class OperationResult implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mResult);
- if (mLog != null) {
- dest.writeTypedList(mLog.toList());
- }
+ // Get a ticket for our log.
+ UUID mTicket = dehydrateLog(mLog);
+ // And write out the UUID most and least significant bits.
+ dest.writeLong(mTicket.getMostSignificantBits());
+ dest.writeLong(mTicket.getLeastSignificantBits());
}
public static class OperationLog implements Iterable<LogEntryParcel> {
'n402' href='#n402'>402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435