diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java')
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java | 139 |
1 files changed, 74 insertions, 65 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java index 89575338f..19a05790f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java @@ -28,7 +28,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; -import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -82,6 +82,8 @@ import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; */ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { + public static final int MAX_THREADS = 10; + public ImportOperation(Context context, ProviderHelper providerHelper, Progressable progressable) { super(context, providerHelper, progressable); @@ -133,7 +135,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { @NonNull private ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num, String keyServerUri, Progressable progressable, - Proxy proxy) { + @NonNull Proxy proxy) { if (progressable != null) { progressable.setProgress(R.string.progress_importing, 0, 100); } @@ -188,7 +190,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { // Make sure we have the keyserver instance cached if (keyServer == null) { log.add(LogType.MSG_IMPORT_KEYSERVER, 1, keyServerUri); - keyServer = new HkpKeyserver(keyServerUri); + keyServer = new HkpKeyserver(keyServerUri, proxy); } try { @@ -197,11 +199,10 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { if (entry.mExpectedFingerprint != null) { log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, "0x" + entry.mExpectedFingerprint.substring(24)); - data = keyServer.get("0x" + entry.mExpectedFingerprint, proxy) - .getBytes(); + data = keyServer.get("0x" + entry.mExpectedFingerprint).getBytes(); } else { log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, entry.mKeyIdHex); - data = keyServer.get(entry.mKeyIdHex, proxy).getBytes(); + data = keyServer.get(entry.mKeyIdHex).getBytes(); } key = UncachedKeyRing.decodeFromData(data); if (key != null) { @@ -219,12 +220,12 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { if (entry.mKeybaseName != null) { // Make sure we have this cached if (keybaseServer == null) { - keybaseServer = new KeybaseKeyserver(); + keybaseServer = new KeybaseKeyserver(proxy); } try { log.add(LogType.MSG_IMPORT_FETCH_KEYBASE, 2, entry.mKeybaseName); - byte[] data = keybaseServer.get(entry.mKeybaseName, proxy).getBytes(); + byte[] data = keybaseServer.get(entry.mKeybaseName).getBytes(); UncachedKeyRing keybaseKey = UncachedKeyRing.decodeFromData(data); // If there already is a key, merge the two @@ -261,12 +262,6 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { continue; } - // Another check if we have been cancelled - if (checkCancelled()) { - cancelled = true; - break; - } - SaveKeyringResult result; // synchronizing prevents https://github.com/open-keychain/open-keychain/issues/1221 // and https://github.com/open-keychain/open-keychain/issues/1480 @@ -365,13 +360,15 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { } } - // Final log entry, it's easier to do this individually - if ((newKeys > 0 || updatedKeys > 0) && badKeys > 0) { - log.add(LogType.MSG_IMPORT_PARTIAL, 1); - } else if (newKeys > 0 || updatedKeys > 0) { - log.add(LogType.MSG_IMPORT_SUCCESS, 1); - } else { - log.add(LogType.MSG_IMPORT_ERROR, 1); + if (!cancelled) { + // Final log entry, it's easier to do this individually + if ((newKeys > 0 || updatedKeys > 0) && badKeys > 0) { + log.add(LogType.MSG_IMPORT_PARTIAL, 1); + } else if (newKeys > 0 || updatedKeys > 0) { + log.add(LogType.MSG_IMPORT_SUCCESS, 1); + } else { + log.add(LogType.MSG_IMPORT_ERROR, 1); + } } return new ImportKeyResult(resultType, log, newKeys, updatedKeys, badKeys, secret, @@ -400,8 +397,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { return new ImportKeyResult(null, RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput); } - proxy = Preferences.getPreferences(mContext).getProxyPrefs().parcelableProxy - .getProxy(); + proxy = Preferences.getPreferences(mContext).getProxyPrefs().getProxy(); } else { proxy = cryptoInput.getParcelableProxy().getProxy(); } @@ -414,62 +410,61 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { } @NonNull - private ImportKeyResult multiThreadedKeyImport(Iterator<ParcelableKeyRing> keyListIterator, + private ImportKeyResult multiThreadedKeyImport(@NonNull Iterator<ParcelableKeyRing> keyListIterator, int totKeys, final String keyServer, final Proxy proxy) { Log.d(Constants.TAG, "Multi-threaded key import starting"); - if (keyListIterator != null) { - KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable); - - final ProgressScaler ignoreProgressable = new ProgressScaler(); + KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable); - final int maxThreads = 200; - ExecutorService importExecutor = new ThreadPoolExecutor(0, maxThreads, - 30L, TimeUnit.SECONDS, - new SynchronousQueue<Runnable>()); + final ProgressScaler ignoreProgressable = new ProgressScaler(); - ExecutorCompletionService<ImportKeyResult> importCompletionService = - new ExecutorCompletionService<>(importExecutor); + ExecutorService importExecutor = new ThreadPoolExecutor(0, MAX_THREADS, 30L, TimeUnit.SECONDS, + new LinkedBlockingQueue<Runnable>()); - while (keyListIterator.hasNext()) { // submit all key rings to be imported + ExecutorCompletionService<ImportKeyResult> importCompletionService = + new ExecutorCompletionService<>(importExecutor); - final ParcelableKeyRing pkRing = keyListIterator.next(); + while (keyListIterator.hasNext()) { // submit all key rings to be imported - Callable<ImportKeyResult> importOperationCallable = new Callable<ImportKeyResult> - () { + final ParcelableKeyRing pkRing = keyListIterator.next(); - @Override - public ImportKeyResult call() { + Callable<ImportKeyResult> importOperationCallable = new Callable<ImportKeyResult> + () { - ArrayList<ParcelableKeyRing> list = new ArrayList<>(); - list.add(pkRing); + @Override + public ImportKeyResult call() { - return serialKeyRingImport(list.iterator(), 1, keyServer, - ignoreProgressable, proxy); + if (checkCancelled()) { + return null; } - }; - importCompletionService.submit(importOperationCallable); - } + ArrayList<ParcelableKeyRing> list = new ArrayList<>(); + list.add(pkRing); - while (!accumulator.isImportFinished()) { // accumulate the results of each import - try { - accumulator.accumulateKeyImport(importCompletionService.take().get()); - } catch (InterruptedException | ExecutionException e) { - Log.e(Constants.TAG, "A key could not be imported during multi-threaded " + - "import", e); - // do nothing? - if (e instanceof ExecutionException) { - // Since serialKeyRingImport does not throw any exceptions, this is what - // would have happened if - // we were importing the key on this thread - throw new RuntimeException(); - } + return serialKeyRingImport(list.iterator(), 1, keyServer, ignoreProgressable, proxy); + } + }; + + importCompletionService.submit(importOperationCallable); + } + + while (!accumulator.isImportFinished()) { // accumulate the results of each import + try { + accumulator.accumulateKeyImport(importCompletionService.take().get()); + } catch (InterruptedException | ExecutionException e) { + Log.e(Constants.TAG, "A key could not be imported during multi-threaded " + + "import", e); + // do nothing? + if (e instanceof ExecutionException) { + // Since serialKeyRingImport does not throw any exceptions, this is what + // would have happened if + // we were importing the key on this thread + throw new RuntimeException(); } } - return accumulator.getConsolidatedResult(); } - return new ImportKeyResult(ImportKeyResult.RESULT_FAIL_NOTHING, new OperationLog()); + return accumulator.getConsolidatedResult(); + } /** @@ -486,6 +481,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { private int mUpdatedKeys = 0; private int mSecret = 0; private int mResultType = 0; + private boolean mHasCancelledResult; /** * Accumulates keyring imports and updates the progressable whenever a new key is imported. @@ -503,14 +499,25 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { } } - public synchronized void accumulateKeyImport(ImportKeyResult result) { + public void accumulateKeyImport(ImportKeyResult result) { mImportedKeys++; + if (result == null) { + return; + } + if (mProgressable != null) { mProgressable.setProgress(mImportedKeys, mTotalKeys); } - mImportLog.addAll(result.getLog().toList());//accumulates log + boolean notCancelledOrFirstCancelled = !result.cancelled() || !mHasCancelledResult; + if (notCancelledOrFirstCancelled) { + mImportLog.addAll(result.getLog().toList()); //accumulates log + if (result.cancelled()) { + mHasCancelledResult = true; + } + } + mBadKeys += result.mBadKeys; mNewKeys += result.mNewKeys; mUpdatedKeys += result.mUpdatedKeys; @@ -533,7 +540,9 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { // adding required information to mResultType // special case,no keys requested for import - if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0) { + if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0 + && (mResultType & ImportKeyResult.RESULT_CANCELLED) + != ImportKeyResult.RESULT_CANCELLED) { mResultType = ImportKeyResult.RESULT_FAIL_NOTHING; } else { if (mNewKeys > 0) { |