android: Replace deprecated AsyncTask instances
As suggested by the Android docs, we use a global thread pool and handler to avoid recreating them repeatedly. Four threads should be more than enough as we only use this to load CA certificates when the app starts initially and to load user certs when editing a profile.
This commit is contained in:
parent
a8cc146240
commit
26354d0aba
|
@ -16,6 +16,9 @@
|
|||
package org.strongswan.android.logic;
|
||||
|
||||
import java.security.Security;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.strongswan.android.security.LocalCertificateKeyStoreProvider;
|
||||
import org.strongswan.android.ui.MainActivity;
|
||||
|
@ -23,10 +26,16 @@ import org.strongswan.android.ui.MainActivity;
|
|||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.core.os.HandlerCompat;
|
||||
|
||||
public class StrongSwanApplication extends Application
|
||||
{
|
||||
private static Context mContext;
|
||||
private final ExecutorService mExecutorService = Executors.newFixedThreadPool(4);
|
||||
private final Handler mMainHandler = HandlerCompat.createAsync(Looper.getMainLooper());
|
||||
|
||||
static {
|
||||
Security.addProvider(new LocalCertificateKeyStoreProvider());
|
||||
|
@ -48,6 +57,24 @@ public class StrongSwanApplication extends Application
|
|||
return StrongSwanApplication.mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a thread pool to run tasks in separate threads
|
||||
* @return thread pool
|
||||
*/
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return mExecutorService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a handler to execute stuff by the main thread.
|
||||
* @return handler
|
||||
*/
|
||||
public Handler getHandler()
|
||||
{
|
||||
return mMainHandler;
|
||||
}
|
||||
|
||||
/*
|
||||
* The libraries are extracted to /data/data/org.strongswan.android/...
|
||||
* during installation. On newer releases most are loaded in JNI_OnLoad.
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.strongswan.android.ui;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.format.Formatter;
|
||||
|
@ -30,6 +29,7 @@ import android.widget.Toast;
|
|||
|
||||
import org.strongswan.android.R;
|
||||
import org.strongswan.android.data.VpnProfile;
|
||||
import org.strongswan.android.logic.StrongSwanApplication;
|
||||
import org.strongswan.android.logic.TrustedCertificateManager;
|
||||
import org.strongswan.android.ui.VpnProfileListFragment.OnVpnProfileSelectedListener;
|
||||
|
||||
|
@ -68,8 +68,10 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec
|
|||
bar.setDisplayShowTitleEnabled(false);
|
||||
bar.setIcon(R.mipmap.ic_app);
|
||||
|
||||
/* load CA certificates in a background task */
|
||||
new LoadCertificatesTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
/* load CA certificates in a background thread */
|
||||
((StrongSwanApplication)getApplication()).getExecutor().execute(() -> {
|
||||
TrustedCertificateManager.getInstance().load();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -157,18 +159,6 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec
|
|||
dialog.show(this.getSupportFragmentManager(), DIALOG_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that loads the cached CA certificates.
|
||||
*/
|
||||
private class LoadCertificatesTask extends AsyncTask<Void, Void, TrustedCertificateManager>
|
||||
{
|
||||
@Override
|
||||
protected TrustedCertificateManager doInBackground(Void... params)
|
||||
{
|
||||
return TrustedCertificateManager.getInstance().load();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss dialog if shown
|
||||
*/
|
||||
|
|
|
@ -21,9 +21,9 @@ import android.app.Dialog;
|
|||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.security.KeyChain;
|
||||
import android.security.KeyChainAliasCallback;
|
||||
import android.security.KeyChainException;
|
||||
|
@ -59,6 +59,7 @@ import org.strongswan.android.data.VpnProfile.SelectedAppsHandling;
|
|||
import org.strongswan.android.data.VpnProfileDataSource;
|
||||
import org.strongswan.android.data.VpnType;
|
||||
import org.strongswan.android.data.VpnType.VpnTypeFeature;
|
||||
import org.strongswan.android.logic.StrongSwanApplication;
|
||||
import org.strongswan.android.logic.TrustedCertificateManager;
|
||||
import org.strongswan.android.security.TrustedCertificateEntry;
|
||||
import org.strongswan.android.ui.adapter.CertificateIdentitiesAdapter;
|
||||
|
@ -73,6 +74,7 @@ import java.util.ArrayList;
|
|||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
|
@ -788,9 +790,22 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
useralias = savedInstanceState == null ? useralias : savedInstanceState.getString(VpnProfileDataSource.KEY_USER_CERTIFICATE);
|
||||
if (useralias != null)
|
||||
{
|
||||
UserCertificateLoader loader = new UserCertificateLoader(this, useralias);
|
||||
mUserCertLoading = useralias;
|
||||
loader.execute();
|
||||
UserCertificateLoader loader = new UserCertificateLoader(((StrongSwanApplication)getApplication()).getExecutor(),
|
||||
((StrongSwanApplication)getApplication()).getHandler());
|
||||
loader.loadCertifiate(this, useralias, result -> {
|
||||
if (result != null)
|
||||
{
|
||||
mUserCertEntry = new TrustedCertificateEntry(mUserCertLoading, result);
|
||||
}
|
||||
else
|
||||
{ /* previously selected certificate is not here anymore */
|
||||
((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setError("");
|
||||
mUserCertEntry = null;
|
||||
}
|
||||
mUserCertLoading = null;
|
||||
updateCredentialView();
|
||||
});
|
||||
}
|
||||
|
||||
/* check if the user selected a CA certificate previously */
|
||||
|
@ -958,55 +973,53 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for the user certificate loader.
|
||||
*/
|
||||
private interface UserCertificateLoaderCallback {
|
||||
void onComplete(X509Certificate result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the selected user certificate asynchronously. This cannot be done
|
||||
* from the main thread as getCertificateChain() calls back to our main
|
||||
* thread to bind to the KeyChain service resulting in a deadlock.
|
||||
*/
|
||||
private class UserCertificateLoader extends AsyncTask<Void, Void, X509Certificate>
|
||||
private class UserCertificateLoader
|
||||
{
|
||||
private final Context mContext;
|
||||
private final String mAlias;
|
||||
private final Executor mExecutor;
|
||||
private final Handler mHandler;
|
||||
|
||||
public UserCertificateLoader(Context context, String alias)
|
||||
public UserCertificateLoader(Executor executor, Handler handler)
|
||||
{
|
||||
mContext = context;
|
||||
mAlias = alias;
|
||||
mExecutor = executor;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X509Certificate doInBackground(Void... params)
|
||||
public void loadCertifiate(Context context, String alias, UserCertificateLoaderCallback callback)
|
||||
{
|
||||
X509Certificate[] chain = null;
|
||||
try
|
||||
{
|
||||
chain = KeyChain.getCertificateChain(mContext, mAlias);
|
||||
}
|
||||
catch (KeyChainException | InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (chain != null && chain.length > 0)
|
||||
{
|
||||
return chain[0];
|
||||
}
|
||||
return null;
|
||||
mExecutor.execute(() -> {
|
||||
X509Certificate[] chain = null;
|
||||
try
|
||||
{
|
||||
chain = KeyChain.getCertificateChain(context, alias);
|
||||
}
|
||||
catch (KeyChainException | InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (chain != null && chain.length > 0)
|
||||
{
|
||||
complete(chain[0], callback);
|
||||
return;
|
||||
}
|
||||
complete(null, callback);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(X509Certificate result)
|
||||
protected void complete(X509Certificate result, UserCertificateLoaderCallback callback)
|
||||
{
|
||||
if (result != null)
|
||||
{
|
||||
mUserCertEntry = new TrustedCertificateEntry(mAlias, result);
|
||||
}
|
||||
else
|
||||
{ /* previously selected certificate is not here anymore */
|
||||
((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setError("");
|
||||
mUserCertEntry = null;
|
||||
}
|
||||
mUserCertLoading = null;
|
||||
updateCredentialView();
|
||||
mHandler.post(() -> callback.onComplete(result));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue