From b4c2e199881473fa98d7ae17177ccaee2efda0dc Mon Sep 17 00:00:00 2001 From: Greg Pomerantz Date: Wed, 26 Aug 2026 18:11:10 -0400 Subject: [PATCH] Android: fix OpenPGP service bind for modern Keychain. Keychain 6.0.4 no longer exports the legacy org.openintents.openpgp.api.OpenPgpService action, so the OpenPgpServiceConnection from openpgp-api.jar bound nothing and every encrypt/decrypt died with a NullPointerException in OpenPgpApi.executeApi. Bind our own ServiceConnection against org.openintents.openpgp.IOpenPgpService (falling back to the legacy action for older Keychain releases), and queue API calls until the service is actually connected instead of racing the async bind. Also fix the //go:generate recipe: it built one jar containing both PgpConnect and Permissions, which collides with Permissions.jar when gogio dexes every *.jar in the repo root. --- PgpConnect.jar | Bin 7821 -> 11951 bytes PgpConnect.java | 93 ++++++++++++++++++++++++++++++++++++++++++++---- impl_android.go | 8 ++--- 3 files changed, 90 insertions(+), 11 deletions(-) diff --git a/PgpConnect.jar b/PgpConnect.jar index 91a741f5fd36d21ecf99025c6dcd4d090a48ce98..a82fcfeca03d4953f0f395947bccc06c9ed01c15 100644 GIT binary patch literal 11951 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 XkcN6;85r2>mro=l7#IT0&tLx!X}G1c delta 6849 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 diff --git a/PgpConnect.java b/PgpConnect.java index 552be58..65b3bf0 100644 --- a/PgpConnect.java +++ b/PgpConnect.java @@ -5,14 +5,17 @@ import java.lang.String; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import android.os.Handler; +import android.os.IBinder; import java.io.InputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; +import org.openintents.openpgp.IOpenPgpService2; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; -import org.openintents.openpgp.util.OpenPgpServiceConnection; +import android.content.ComponentName; +import android.content.ServiceConnection; import android.content.Context; import android.content.ClipboardManager; import android.content.ClipData; @@ -36,9 +39,68 @@ public class PgpConnect extends Fragment { Context ctx; Handler handler; ClipboardManager cb; - OpenPgpServiceConnection mServiceConnection; + IOpenPgpService2 mService; final int PERMISSIONS_REQUEST = 1; + // Keychain >= 11 (and the standalone "Keychain" 5.x/6.x releases) expose + // the OpenPGP API service under org.openintents.openpgp.IOpenPgpService; + // older releases used org.openintents.openpgp.api.OpenPgpService (the + // action hardcoded in OpenPgpServiceConnection). Try the new action + // first and fall back to the legacy one. + static final String[] SERVICE_ACTIONS = { + "org.openintents.openpgp.IOpenPgpService", + "org.openintents.openpgp.api.OpenPgpService", + }; + + final ServiceConnection mConnection = new ServiceConnection() { + @Override public void onServiceConnected(ComponentName name, IBinder service) { + mService = IOpenPgpService2.Stub.asInterface(service); + Log.d("gio", "OpenPGP service connected: " + name); + } + @Override public void onServiceDisconnected(ComponentName name) { + mService = null; + Log.d("gio", "OpenPGP service disconnected"); + } + }; + + private void bindOpenPgp() { + Intent bindIntent = null; + for (String action : SERVICE_ACTIONS) { + Intent i = new Intent(action); + i.setPackage("org.sufficientlysecure.keychain"); + if (ctx.getPackageManager().resolveService(i, 0) != null) { + bindIntent = i; + break; + } + } + if (bindIntent == null) { + Log.e("gio", "No OpenPGP service found in org.sufficientlysecure.keychain"); + return; + } + Log.d("gio", "Binding OpenPGP service: " + bindIntent.getAction()); + ctx.bindService(bindIntent, mConnection, Context.BIND_AUTO_CREATE); + } + + // executeApi needs a live service; the bind is asynchronous, so if the + // service is not connected yet, retry on the main looper (up to ~10 s) + // instead of calling into a null service. + private void runWhenConnected(final int chint, final Runnable task, final int attempt) { + if (mService != null) { + task.run(); + return; + } + if (attempt > 33) { + Log.e("gio", "OpenPGP service never connected"); + stringResult(chint, null); + return; + } + handler.postDelayed(new Runnable() { + public void run() { + runWhenConnected(chint, task, attempt + 1); + } + }, 300); + } + public PgpConnect(View view) { Log.d("gio", "PgpConnect()"); this.ctx = view.getContext(); @@ -60,8 +122,7 @@ public class PgpConnect extends Fragment { if (ctx instanceof Activity) { Log.d("gio", "It's an Activity!"); } - mServiceConnection = new OpenPgpServiceConnection(ctx, "org.sufficientlysecure.keychain"); - mServiceConnection.bindToService(); + bindOpenPgp(); cb = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE); if (ctx.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ctx.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST); @@ -156,9 +217,15 @@ public class PgpConnect extends Fragment { private void _getid(Intent data, int chint) { Log.d("gio","_getid"); + runWhenConnected(chint, new Runnable() { + public void run() { doGetid(data, chint); } + }, 0); + } + + private void doGetid(Intent data, int chint) { InputStream is = null; ByteArrayOutputStream os = new ByteArrayOutputStream(); - OpenPgpApi api = new OpenPgpApi(this.ctx, mServiceConnection.getService()); + OpenPgpApi api = new OpenPgpApi(this.ctx, mService); Intent result = api.executeApi(data, is, os); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: { @@ -193,10 +260,16 @@ public class PgpConnect extends Fragment { } private void _decrypt(Intent data, int chint) { Log.d("gio","_decrypt"); + runWhenConnected(chint, new Runnable() { + public void run() { doDecrypt(data, chint); } + }, 0); + } + + private void doDecrypt(Intent data, int chint) { byte []dat = data.getByteArrayExtra("DATA"); InputStream is = new ByteArrayInputStream(dat); ByteArrayOutputStream os = new ByteArrayOutputStream(); - OpenPgpApi api = new OpenPgpApi(this.ctx, mServiceConnection.getService()); + OpenPgpApi api = new OpenPgpApi(this.ctx, mService); Intent result = api.executeApi(data, is, os); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: { @@ -246,10 +319,16 @@ public class PgpConnect extends Fragment { private void _encrypt(Intent data, int chint) { Log.d("gio","_encrypt"); + runWhenConnected(chint, new Runnable() { + public void run() { doEncrypt(data, chint); } + }, 0); + } + + private void doEncrypt(Intent data, int chint) { byte []dat = data.getByteArrayExtra("DATA"); InputStream is = new ByteArrayInputStream(dat); ByteArrayOutputStream os = new ByteArrayOutputStream(); - OpenPgpApi api = new OpenPgpApi(this.ctx, mServiceConnection.getService()); + OpenPgpApi api = new OpenPgpApi(this.ctx, mService); Intent result = api.executeApi(data, is, os); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: { diff --git a/impl_android.go b/impl_android.go index e4bf256..8b5f635 100644 --- a/impl_android.go +++ b/impl_android.go @@ -1,10 +1,10 @@ //go:build android // +build android -//go:generate mkdir -p classes -//go:generate javac -nowarn -classpath $ANDROID_HOME/platforms/android-35/android.jar:openpgp-api.jar -d classes PgpConnect.java Permissions.java -//go:generate jar cf PgpConnect.jar -C classes . -//go:generate rm -rf classes +// Regenerate PgpConnect.jar and Permissions.jar (gogio dexes every *.jar in +// the repo root; the two classes must stay in separate jars). ANDROID_HOME +// must be set. Note: go generate skips this file on non-android hosts. +//go:generate sh -c 'mkdir -p classes && javac -nowarn -classpath "$ANDROID_HOME/platforms/android-35/android.jar:openpgp-api.jar" -d classes PgpConnect.java Permissions.java && (cd classes && jar cf ../../PgpConnect.jar st/wow/git/passgo/PgpConnect* && jar cf ../../Permissions.jar st/wow/git/passgo/Permissions*) && rm -rf classes' package passgo