]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
android: Replace deprecated AsyncTask instances
authorTobias Brunner <tobias@strongswan.org>
Mon, 12 Jul 2021 15:58:16 +0000 (17:58 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 14 Jul 2021 07:59:02 +0000 (09:59 +0200)
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.

src/frontends/android/app/src/main/java/org/strongswan/android/logic/StrongSwanApplication.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java

index a868b72cd4cdf583ba3c75cc71fdf0169baa440d..505c00cc9916daeb15627d3b3e9c77aaf7bd7122 100644 (file)
@@ -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.
index 18953d18581e5d8bb32320f0d3ecb403dcec56a2..9b47b7f21953efc73b10ae42739c83cb40e333be 100644 (file)
@@ -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
         */
index 391c3e4dbc9da2a0db4ca8695d416ef5fb9b769d..65d97ba2168db7d28d781d0c96d6a803fb748753 100644 (file)
@@ -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));
                }
        }