use ThreadPool for background task execution

This commit is contained in:
Vincent Breitmoser 2018-07-03 22:59:30 +02:00
parent 6ed110f1ee
commit 2c8e219aa8
18 changed files with 203 additions and 242 deletions

View file

@ -877,9 +877,6 @@
android:name=".remote.CryptoInputParcelCacheService"
android:exported="false"
android:process=":remote_api" />
<service
android:name=".service.KeychainService"
android:exported="false" />
<provider
android:name=".provider.KeychainProvider"

View file

@ -1,12 +1,13 @@
package org.sufficientlysecure.keychain.keysync;
import java.util.concurrent.atomic.AtomicBoolean;
import android.app.NotificationManager;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Builder;
import android.support.v4.os.CancellationSignal;
import androidx.work.Worker;
import org.sufficientlysecure.keychain.Constants.NotificationIds;
@ -25,7 +26,7 @@ import timber.log.Timber;
public class KeyserverSyncWorker extends Worker {
private CancellationSignal cancellationSignal = new CancellationSignal();
private AtomicBoolean cancellationSignal = new AtomicBoolean(false);
@NonNull
@Override
@ -128,6 +129,6 @@ public class KeyserverSyncWorker extends Worker {
@Override
public void onStopped() {
super.onStopped();
cancellationSignal.cancel();
cancellationSignal.set(true);
}
}

View file

@ -27,17 +27,19 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.os.CancellationSignal;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.ExportResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
@ -50,8 +52,6 @@ import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@ -83,7 +83,7 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
}
public BackupOperation(Context context, KeyRepository keyRepository,
Progressable progressable, CancellationSignal cancelled) {
Progressable progressable, AtomicBoolean cancelled) {
super(context, keyRepository, progressable, cancelled);
}

View file

@ -18,17 +18,18 @@
package org.sufficientlysecure.keychain.operations;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.Constants.key;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.util.Passphrase;
@ -37,7 +38,7 @@ public abstract class BaseOperation<T extends Parcelable> implements PassphraseC
final public Context mContext;
final public Progressable mProgressable;
final public CancellationSignal mCancelled;
final public AtomicBoolean mCancelled;
final public KeyRepository mKeyRepository;
@ -71,7 +72,7 @@ public abstract class BaseOperation<T extends Parcelable> implements PassphraseC
}
public BaseOperation(Context context, KeyRepository keyRepository,
Progressable progressable, CancellationSignal cancelled) {
Progressable progressable, AtomicBoolean cancelled) {
mContext = context;
mProgressable = progressable;
mKeyRepository = keyRepository;
@ -100,7 +101,7 @@ public abstract class BaseOperation<T extends Parcelable> implements PassphraseC
}
protected boolean checkCancelled() {
return mCancelled != null && mCancelled.isCanceled();
return mCancelled != null && mCancelled.get();
}
protected void setPreventCancel () {

View file

@ -18,12 +18,13 @@
package org.sufficientlysecure.keychain.operations;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.os.Parcelable;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.pgp.Progressable;
public abstract class BaseReadWriteOperation<T extends Parcelable> extends BaseOperation<T> {
protected final KeyWritableRepository mKeyWritableRepository;
@ -37,7 +38,7 @@ public abstract class BaseReadWriteOperation<T extends Parcelable> extends BaseO
}
protected BaseReadWriteOperation(Context context, KeyWritableRepository databaseInteractor,
Progressable progressable, CancellationSignal cancelled) {
Progressable progressable, AtomicBoolean cancelled) {
super(context, databaseInteractor, progressable, cancelled);
mKeyWritableRepository = databaseInteractor;

View file

@ -19,11 +19,14 @@ package org.sufficientlysecure.keychain.operations;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
@ -38,9 +41,6 @@ import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation.PgpCertifyResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
@ -63,8 +63,8 @@ import org.sufficientlysecure.keychain.util.Passphrase;
public class CertifyOperation extends BaseReadWriteOperation<CertifyActionsParcel> {
private final KeyMetadataDao keyMetadataDao;
public CertifyOperation(Context context, KeyWritableRepository keyWritableRepository, Progressable progressable, CancellationSignal
cancelled) {
public CertifyOperation(Context context, KeyWritableRepository keyWritableRepository, Progressable progressable,
AtomicBoolean cancelled) {
super(context, keyWritableRepository, progressable, cancelled);
this.keyMetadataDao = KeyMetadataDao.create(context);

View file

@ -19,12 +19,15 @@ package org.sufficientlysecure.keychain.operations;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
@ -35,9 +38,6 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
@ -61,7 +61,7 @@ public class EditKeyOperation extends BaseReadWriteOperation<SaveKeyringParcel>
public EditKeyOperation(Context context, KeyWritableRepository databaseInteractor,
Progressable progressable, CancellationSignal cancelled) {
Progressable progressable, AtomicBoolean cancelled) {
super(context, databaseInteractor, progressable, cancelled);
this.keyMetadataDao = KeyMetadataDao.create(context);

View file

@ -29,13 +29,15 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.keyimport.FacebookKeyserverClient;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverClient;
@ -54,8 +56,6 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@ -102,7 +102,7 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
}
public ImportOperation(Context context, KeyWritableRepository databaseInteractor,
Progressable progressable, CancellationSignal cancelled) {
Progressable progressable, AtomicBoolean cancelled) {
super(context, databaseInteractor, progressable, cancelled);
this.keyMetadataDao = KeyMetadataDao.create(context);

View file

@ -5,18 +5,18 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@ -36,7 +36,7 @@ public class KeySyncOperation extends BaseReadWriteOperation<KeySyncParcel> {
private final Preferences preferences;
public KeySyncOperation(Context context, KeyWritableRepository databaseInteractor,
Progressable progressable, CancellationSignal cancellationSignal) {
Progressable progressable, AtomicBoolean cancellationSignal) {
super(context, databaseInteractor, progressable, cancellationSignal);
keyMetadataDao = KeyMetadataDao.create(context);

View file

@ -20,12 +20,14 @@ package org.sufficientlysecure.keychain.operations;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
@ -35,8 +37,6 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.PromoteKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@ -50,7 +50,7 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
*/
public class PromoteKeyOperation extends BaseReadWriteOperation<PromoteKeyringParcel> {
public PromoteKeyOperation(Context context, KeyWritableRepository databaseInteractor,
Progressable progressable, CancellationSignal cancelled) {
Progressable progressable, AtomicBoolean cancelled) {
super(context, databaseInteractor, progressable, cancelled);
}

View file

@ -20,12 +20,13 @@ package org.sufficientlysecure.keychain.operations;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
@ -34,7 +35,6 @@ import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel;
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
@ -52,7 +52,7 @@ import org.sufficientlysecure.keychain.util.ProgressScaler;
public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
public SignEncryptOperation(Context context, KeyRepository keyRepository,
Progressable progressable, CancellationSignal cancelled) {
Progressable progressable, AtomicBoolean cancelled) {
super(context, keyRepository, progressable, cancelled);
}

View file

@ -21,11 +21,11 @@ package org.sufficientlysecure.keychain.operations;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.Proxy;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.os.CancellationSignal;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.sufficientlysecure.keychain.R;
@ -60,7 +60,7 @@ public class UploadOperation extends BaseOperation<UploadKeyringParcel> {
private KeyMetadataDao keyMetadataDao;
public UploadOperation(Context context, KeyRepository keyRepository,
Progressable progressable, CancellationSignal cancelled) {
Progressable progressable, AtomicBoolean cancelled) {
super(context, keyRepository, progressable, cancelled);
keyMetadataDao = KeyMetadataDao.create(mContext);

View file

@ -33,8 +33,7 @@ import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import android.support.v4.os.CancellationSignal;
import java.util.concurrent.atomic.AtomicBoolean;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.nist.NISTNamedCurves;
@ -109,7 +108,7 @@ import timber.log.Timber;
public class PgpKeyOperation {
private Stack<Progressable> mProgress;
private CancellationSignal mCancelled;
private AtomicBoolean mCancelled;
public PgpKeyOperation(Progressable progress) {
super();
@ -119,13 +118,13 @@ public class PgpKeyOperation {
}
}
public PgpKeyOperation(Progressable progress, CancellationSignal cancelled) {
public PgpKeyOperation(Progressable progress, AtomicBoolean cancelled) {
this(progress);
mCancelled = cancelled;
}
private boolean checkCancelled() {
return mCancelled != null && mCancelled.isCanceled();
return mCancelled != null && mCancelled.get();
}
private void subProgressPush(int from, int to) {

View file

@ -33,11 +33,11 @@ import java.security.SignatureException;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.os.CancellationSignal;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
@ -54,6 +54,9 @@ import org.bouncycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.PGPUtil;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.operations.BaseOperation;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
@ -63,9 +66,6 @@ import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants.OpenKeychainComp
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants.OpenKeychainHashAlgorithmTags;
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@ -104,7 +104,7 @@ public class PgpSignEncryptOperation extends BaseOperation<PgpSignEncryptInputPa
}
}
public PgpSignEncryptOperation(Context context, KeyRepository keyRepository, Progressable progressable, CancellationSignal cancelled) {
public PgpSignEncryptOperation(Context context, KeyRepository keyRepository, Progressable progressable, AtomicBoolean cancelled) {
super(context, keyRepository, progressable, cancelled);
}

View file

@ -18,18 +18,15 @@
package org.sufficientlysecure.keychain.service;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.Parcelable;
import android.os.RemoteException;
import android.support.v4.os.CancellationSignal;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.sufficientlysecure.keychain.operations.KeySyncOperation;
import org.sufficientlysecure.keychain.operations.KeySyncParcel;
import android.content.Context;
import android.os.Parcelable;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.operations.BackupOperation;
import org.sufficientlysecure.keychain.operations.BaseOperation;
import org.sufficientlysecure.keychain.operations.BenchmarkOperation;
@ -39,6 +36,8 @@ import org.sufficientlysecure.keychain.operations.DeleteOperation;
import org.sufficientlysecure.keychain.operations.EditKeyOperation;
import org.sufficientlysecure.keychain.operations.ImportOperation;
import org.sufficientlysecure.keychain.operations.InputDataOperation;
import org.sufficientlysecure.keychain.operations.KeySyncOperation;
import org.sufficientlysecure.keychain.operations.KeySyncParcel;
import org.sufficientlysecure.keychain.operations.KeybaseVerificationOperation;
import org.sufficientlysecure.keychain.operations.PromoteKeyOperation;
import org.sufficientlysecure.keychain.operations.RevokeOperation;
@ -49,180 +48,88 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import timber.log.Timber;
/**
* This Service contains all important long lasting operations for OpenKeychain. It receives Intents with
* data from the activities or other apps, executes them, and stops itself after doing them.
*/
public class KeychainService extends Service implements Progressable {
public class KeychainService {
private static KeychainService keychainService;
// messenger for communication (hack)
public static final String EXTRA_MESSENGER = "messenger";
public static KeychainService getInstance(Context context) {
if (keychainService == null) {
keychainService = new KeychainService(context.getApplicationContext());
}
return keychainService;
}
// extras for operation
public static final String EXTRA_OPERATION_INPUT = "op_input";
public static final String EXTRA_CRYPTO_INPUT = "crypto_input";
private KeychainService(Context context) {
this.context = context;
this.threadPoolExecutor = new ThreadPoolExecutor(0, 4, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
this.keyRepository = KeyWritableRepository.create(context);
}
public static final String ACTION_CANCEL = "action_cancel";
private final Context context;
private final ThreadPoolExecutor threadPoolExecutor;
private final KeyWritableRepository keyRepository;
// this attribute can possibly merged with the one above? not sure...
private CancellationSignal mActionCanceled;
private AtomicBoolean operationCancelledBoolean = new AtomicBoolean(false);
ThreadLocal<Messenger> mMessenger = new ThreadLocal<>();
public void startOperationInBackground(Parcelable inputParcel, CryptoInputParcel cryptoInput,
Progressable progressable, OperationCallback operationCallback) {
operationCancelledBoolean.set(false);
@Override
public IBinder onBind(Intent intent) {
return null;
}
Runnable actionRunnable = () -> {
BaseOperation op;
/**
* This is run on the main thread, we need to spawn a runnable which runs on another thread for the actual operation
*/
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
if (intent.getAction() != null && intent.getAction().equals(ACTION_CANCEL)) {
if (mActionCanceled != null) {
mActionCanceled.cancel();
if (inputParcel instanceof SignEncryptParcel) {
op = new SignEncryptOperation(context, keyRepository, progressable, operationCancelledBoolean);
} else if (inputParcel instanceof PgpDecryptVerifyInputParcel) {
op = new PgpDecryptVerifyOperation(context, keyRepository, progressable);
} else if (inputParcel instanceof SaveKeyringParcel) {
op = new EditKeyOperation(context, keyRepository, progressable, operationCancelledBoolean);
} else if (inputParcel instanceof ChangeUnlockParcel) {
op = new ChangeUnlockOperation(context, keyRepository, progressable);
} else if (inputParcel instanceof RevokeKeyringParcel) {
op = new RevokeOperation(context, keyRepository, progressable);
} else if (inputParcel instanceof CertifyActionsParcel) {
op = new CertifyOperation(context, keyRepository, progressable, operationCancelledBoolean);
} else if (inputParcel instanceof DeleteKeyringParcel) {
op = new DeleteOperation(context, keyRepository, progressable);
} else if (inputParcel instanceof PromoteKeyringParcel) {
op = new PromoteKeyOperation(context, keyRepository, progressable, operationCancelledBoolean);
} else if (inputParcel instanceof ImportKeyringParcel) {
op = new ImportOperation(context, keyRepository, progressable, operationCancelledBoolean);
} else if (inputParcel instanceof BackupKeyringParcel) {
op = new BackupOperation(context, keyRepository, progressable, operationCancelledBoolean);
} else if (inputParcel instanceof UploadKeyringParcel) {
op = new UploadOperation(context, keyRepository, progressable, operationCancelledBoolean);
} else if (inputParcel instanceof KeybaseVerificationParcel) {
op = new KeybaseVerificationOperation(context, keyRepository, progressable);
} else if (inputParcel instanceof InputDataParcel) {
op = new InputDataOperation(context, keyRepository, progressable);
} else if (inputParcel instanceof BenchmarkInputParcel) {
op = new BenchmarkOperation(context, keyRepository, progressable);
} else if (inputParcel instanceof KeySyncParcel) {
op = new KeySyncOperation(context, keyRepository, progressable, operationCancelledBoolean);
} else {
throw new AssertionError("Unrecognized input parcel in KeychainService!");
}
return START_NOT_STICKY;
}
mActionCanceled = new CancellationSignal();
Runnable actionRunnable = new Runnable() {
@Override
public void run() {
Bundle extras = intent.getExtras();
// Set messenger for communication (for this particular thread)
mMessenger.set(extras.getParcelable(EXTRA_MESSENGER));
// Input
Parcelable inputParcel = extras.getParcelable(EXTRA_OPERATION_INPUT);
CryptoInputParcel cryptoInput = extras.getParcelable(EXTRA_CRYPTO_INPUT);
// Operation
BaseOperation op;
// just for brevity
KeychainService outerThis = KeychainService.this;
KeyWritableRepository databaseInteractor =
KeyWritableRepository.create(outerThis);
if (inputParcel instanceof SignEncryptParcel) {
op = new SignEncryptOperation(outerThis, databaseInteractor, outerThis, mActionCanceled);
} else if (inputParcel instanceof PgpDecryptVerifyInputParcel) {
op = new PgpDecryptVerifyOperation(outerThis, databaseInteractor, outerThis);
} else if (inputParcel instanceof SaveKeyringParcel) {
op = new EditKeyOperation(outerThis, databaseInteractor, outerThis, mActionCanceled);
} else if (inputParcel instanceof ChangeUnlockParcel) {
op = new ChangeUnlockOperation(outerThis, databaseInteractor, outerThis);
} else if (inputParcel instanceof RevokeKeyringParcel) {
op = new RevokeOperation(outerThis, databaseInteractor, outerThis);
} else if (inputParcel instanceof CertifyActionsParcel) {
op = new CertifyOperation(outerThis, databaseInteractor, outerThis, mActionCanceled);
} else if (inputParcel instanceof DeleteKeyringParcel) {
op = new DeleteOperation(outerThis, databaseInteractor, outerThis);
} else if (inputParcel instanceof PromoteKeyringParcel) {
op = new PromoteKeyOperation(outerThis, databaseInteractor, outerThis, mActionCanceled);
} else if (inputParcel instanceof ImportKeyringParcel) {
op = new ImportOperation(outerThis, databaseInteractor, outerThis, mActionCanceled);
} else if (inputParcel instanceof BackupKeyringParcel) {
op = new BackupOperation(outerThis, databaseInteractor, outerThis, mActionCanceled);
} else if (inputParcel instanceof UploadKeyringParcel) {
op = new UploadOperation(outerThis, databaseInteractor, outerThis, mActionCanceled);
} else if (inputParcel instanceof KeybaseVerificationParcel) {
op = new KeybaseVerificationOperation(outerThis, databaseInteractor, outerThis);
} else if (inputParcel instanceof InputDataParcel) {
op = new InputDataOperation(outerThis, databaseInteractor, outerThis);
} else if (inputParcel instanceof BenchmarkInputParcel) {
op = new BenchmarkOperation(outerThis, databaseInteractor, outerThis);
} else if (inputParcel instanceof KeySyncParcel) {
op = new KeySyncOperation(outerThis, databaseInteractor, outerThis, mActionCanceled);
} else {
throw new AssertionError("Unrecognized input parcel in KeychainService!");
}
@SuppressWarnings("unchecked") // this is unchecked, we make sure it's the correct op above!
OperationResult result = op.execute(inputParcel, cryptoInput);
sendMessageToHandler(MessageStatus.OKAY, result);
}
@SuppressWarnings("unchecked") // this is unchecked, we make sure it's the correct op above!
OperationResult result = op.execute(inputParcel, cryptoInput);
operationCallback.operationFinished(result);
};
Thread actionThread = new Thread(actionRunnable);
actionThread.start();
return START_NOT_STICKY;
threadPoolExecutor.execute(actionRunnable);
}
private void sendMessageToHandler(MessageStatus status, Integer arg2, Bundle data) {
Message msg = Message.obtain();
assert msg != null;
msg.arg1 = status.ordinal();
if (arg2 != null) {
msg.arg2 = arg2;
}
if (data != null) {
msg.setData(data);
}
try {
mMessenger.get().send(msg);
} catch (RemoteException e) {
Timber.w(e, "Exception sending message, Is handler present?");
} catch (NullPointerException e) {
Timber.w(e, "Messenger is null!");
public void cancelRunningTask() {
if (operationCancelledBoolean != null) {
operationCancelledBoolean.set(true);
}
}
private void sendMessageToHandler(MessageStatus status, OperationResult data) {
Bundle bundle = new Bundle();
bundle.putParcelable(OperationResult.EXTRA_RESULT, data);
sendMessageToHandler(status, null, bundle);
public interface OperationCallback {
void operationFinished(OperationResult data);
}
private void sendMessageToHandler(MessageStatus status) {
sendMessageToHandler(status, null, null);
}
/**
* Set progress of ProgressDialog by sending message to handler on UI thread
*/
@Override
public void setProgress(String message, int progress, int max) {
Timber.d("Send message by setProgress with progress=" + progress + ", max="
+ max);
Bundle data = new Bundle();
if (message != null) {
data.putString(ServiceProgressHandler.DATA_MESSAGE, message);
}
data.putInt(ServiceProgressHandler.DATA_PROGRESS, progress);
data.putInt(ServiceProgressHandler.DATA_PROGRESS_MAX, max);
sendMessageToHandler(MessageStatus.UPDATE_PROGRESS, null, data);
}
@Override
public void setProgress(int resourceId, int progress, int max) {
setProgress(getString(resourceId), progress, max);
}
@Override
public void setProgress(int progress, int max) {
setProgress(null, progress, max);
}
@Override
public void setPreventCancel() {
sendMessageToHandler(MessageStatus.PREVENT_CANCEL);
}
}

View file

@ -29,7 +29,6 @@ import android.view.inputmethod.InputMethodManager;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.service.KeychainService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
/** This is a base class for fragments which implement a cryptoOperation.
@ -47,8 +46,6 @@ import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
* must override at least onCryptoOperationSuccess to proceed after a
* successful operation.
*
* @see KeychainService
*
*/
public abstract class CryptoOperationFragment<T extends Parcelable, S extends OperationResult>
extends Fragment implements CryptoOperationHelper.Callback<T, S> {

View file

@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui.base;
import java.util.Date;
import android.app.Activity;
@ -27,6 +28,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
@ -34,14 +36,17 @@ import android.support.v4.app.FragmentManager;
import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.service.KeychainService;
import org.sufficientlysecure.keychain.service.KeychainService.OperationCallback;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.SecurityTokenOperationActivity;
import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity;
import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
import org.sufficientlysecure.keychain.ui.RetryUploadDialogActivity;
import org.sufficientlysecure.keychain.ui.SecurityTokenOperationActivity;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import timber.log.Timber;
@ -295,12 +300,6 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
return;
}
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(activity, KeychainService.class);
intent.putExtra(KeychainService.EXTRA_OPERATION_INPUT, operationInput);
intent.putExtra(KeychainService.EXTRA_CRYPTO_INPUT, cryptoInput);
ServiceProgressHandler saveHandler = new ServiceProgressHandler(activity) {
@Override
public void handleMessage(Message message) {
@ -331,9 +330,39 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
Communicator communicator = new Communicator(messenger);
Progressable progressable = new Progressable() {
@Override
public void setProgress(String message, int progress, int max) {
Timber.d("Send message by setProgress with progress=" + progress + ", max=" + max);
Bundle data = new Bundle();
if (message != null) {
data.putString(ServiceProgressHandler.DATA_MESSAGE, message);
}
data.putInt(ServiceProgressHandler.DATA_PROGRESS, progress);
data.putInt(ServiceProgressHandler.DATA_PROGRESS_MAX, max);
communicator.sendMessageToHandler(MessageStatus.UPDATE_PROGRESS, data);
}
@Override
public void setProgress(int resourceId, int progress, int max) {
setProgress(activity.getString(resourceId), progress, max);
}
@Override
public void setProgress(int progress, int max) {
setProgress(null, progress, max);
}
@Override
public void setPreventCancel() {
communicator.sendMessageToHandler(MessageStatus.PREVENT_CANCEL, (Bundle) null);
}
};
if (mProgressMessageResource != null) {
saveHandler.showProgressDialog(
@ -341,7 +370,8 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
ProgressDialog.STYLE_HORIZONTAL, mCancellable);
}
activity.startService(intent);
KeychainService keychainService = KeychainService.getInstance(activity);
keychainService.startOperationInBackground(operationInput, cryptoInput, progressable, communicator);
}
public void cryptoOperation() {
@ -391,4 +421,37 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
+ result.getClass().getSimpleName() + "), this is a programming error!");
}
}
public static class Communicator implements OperationCallback {
final Messenger messenger;
Communicator(Messenger messenger) {
this.messenger = messenger;
}
public void sendMessageToHandler(MessageStatus status, Bundle data) {
Message msg = Message.obtain();
assert msg != null;
msg.arg1 = status.ordinal();
if (data != null) {
msg.setData(data);
}
try {
messenger.send(msg);
} catch (RemoteException e) {
Timber.w(e, "Exception sending message, Is handler present?");
} catch (NullPointerException e) {
Timber.w(e, "Messenger is null!");
}
}
@Override
public void operationFinished(OperationResult data) {
Bundle bundle = new Bundle();
bundle.putParcelable(OperationResult.EXTRA_RESULT, data);
sendMessageToHandler(MessageStatus.OKAY, bundle);
}
}
}

View file

@ -176,13 +176,8 @@ public class ProgressDialogFragment extends DialogFragment {
negative.setClickable(false);
negative.setTextColor(Color.GRAY);
// send a cancel message. note that this message will be handled by
// KeychainService.onStartCommand, which runs in this thread,
// not the service one, and will not queue up a command.
Intent serviceIntent = new Intent(getActivity(), KeychainService.class);
serviceIntent.setAction(KeychainService.ACTION_CANCEL);
getActivity().startService(serviceIntent);
KeychainService keychainService = KeychainService.getInstance(requireContext());
keychainService.cancelRunningTask();
// Set the progress bar accordingly
ProgressDialog dialog = (ProgressDialog) getDialog();