From adfb3a920a3e09a0cbcd719ac2ae1899b16b9747 Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Sat, 23 Jan 2016 23:30:51 +0100 Subject: [PATCH] Fixed problem with proof of work --- app/build.gradle | 11 ++- .../notification/ProofOfWorkNotification.java | 33 ++++--- .../apps/abit/service/ProofOfWorkService.java | 91 +++++++++++-------- .../apps/abit/service/ServicePowEngine.java | 47 +++++----- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 6 files changed, 107 insertions(+), 79 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 4b3a404..642a542 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ android { applicationId "ch.dissem.apps.abit" minSdkVersion 19 targetSdkVersion 23 - versionCode 3 + versionCode 5 versionName "1.0-beta" } signingConfigs { @@ -29,16 +29,17 @@ android { } } +ext.jabitVersion = '1.0.0' dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:support-v4:23.1.1' compile 'com.android.support:design:23.1.1' - compile 'ch.dissem.jabit:jabit-core:0.2.1-SNAPSHOT' - compile 'ch.dissem.jabit:jabit-networking:0.2.1-SNAPSHOT' - compile 'ch.dissem.jabit:jabit-cryptography-spongy:0.2.1-SNAPSHOT' - compile 'ch.dissem.jabit:jabit-extensions:0.2.1-SNAPSHOT' + compile "ch.dissem.jabit:jabit-core:$jabitVersion" + compile "ch.dissem.jabit:jabit-networking:$jabitVersion" + compile "ch.dissem.jabit:jabit-cryptography-spongy:$jabitVersion" + compile "ch.dissem.jabit:jabit-extensions:$jabitVersion" compile 'org.slf4j:slf4j-android:1.7.12' diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/ProofOfWorkNotification.java b/app/src/main/java/ch/dissem/apps/abit/notification/ProofOfWorkNotification.java index f677130..408bc5d 100644 --- a/app/src/main/java/ch/dissem/apps/abit/notification/ProofOfWorkNotification.java +++ b/app/src/main/java/ch/dissem/apps/abit/notification/ProofOfWorkNotification.java @@ -32,23 +32,30 @@ public class ProofOfWorkNotification extends AbstractNotification { public ProofOfWorkNotification(Context ctx) { super(ctx); - NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx); - - Intent showMessageIntent = new Intent(ctx, MainActivity.class); - PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0, showMessageIntent, PendingIntent.FLAG_UPDATE_CURRENT); - - builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - .setUsesChronometer(true) - .setSmallIcon(R.drawable.ic_notification_proof_of_work) - .setContentTitle(ctx.getString(R.string.proof_of_work_title)) - .setContentText(ctx.getString(R.string.proof_of_work_text)) - .setContentIntent(pendingIntent); - - notification = builder.build(); + update(1); } @Override protected int getNotificationId() { return ONGOING_NOTIFICATION_ID; } + + public ProofOfWorkNotification update(int numberOfItems) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx); + + Intent showMessageIntent = new Intent(ctx, MainActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0, showMessageIntent, + PendingIntent.FLAG_UPDATE_CURRENT); + + builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setUsesChronometer(true) + .setOngoing(true) + .setSmallIcon(R.drawable.ic_notification_proof_of_work) + .setContentTitle(ctx.getString(R.string.proof_of_work_title)) + .setContentText(ctx.getString(R.string.proof_of_work_text, numberOfItems)) + .setContentIntent(pendingIntent); + + notification = builder.build(); + return this; + } } diff --git a/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.java b/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.java index 94b5620..7eee67d 100644 --- a/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.java +++ b/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.java @@ -22,10 +22,8 @@ import android.os.Binder; import android.os.IBinder; import android.support.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.ref.WeakReference; +import java.util.LinkedList; +import java.util.Queue; import ch.dissem.apps.abit.notification.ProofOfWorkNotification; import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine; @@ -38,11 +36,12 @@ import static ch.dissem.apps.abit.notification.ProofOfWorkNotification.ONGOING_N * killed by the system before the nonce is found. */ public class ProofOfWorkService extends Service { - public static final Logger LOG = LoggerFactory.getLogger(ProofOfWorkService.class); - // Object to use as a thread-safe lock private static final Object lock = new Object(); private static ProofOfWorkEngine engine; + private static boolean calculating; + private static final Queue queue = new LinkedList<>(); + private static ProofOfWorkNotification notification; @Override public void onCreate() { @@ -51,54 +50,74 @@ public class ProofOfWorkService extends Service { engine = new MultiThreadedPOWEngine(); } } + notification = new ProofOfWorkNotification(this); } @Nullable @Override public IBinder onBind(Intent intent) { - return new PowBinder(engine, this); + return new PowBinder(this); } public static class PowBinder extends Binder { - private final ProofOfWorkEngine engine; + private final ProofOfWorkService service; - private PowBinder(ProofOfWorkEngine engine, ProofOfWorkService service) { - this.engine = new EngineWrapper(engine, service); + private PowBinder(ProofOfWorkService service) { + this.service = service; } - public ProofOfWorkEngine getEngine() { - return engine; + public void process(PowItem item) { + synchronized (queue) { + service.startService(new Intent(service, ProofOfWorkService.class)); + service.startForeground(ONGOING_NOTIFICATION_ID, + notification.getNotification()); + if (!calculating) { + calculating = true; + service.calculateNonce(item); + } else { + queue.add(item); + notification.update(queue.size()).show(); + } + } } } - private static class EngineWrapper implements ProofOfWorkEngine { - private final ProofOfWorkNotification notification; - private final ProofOfWorkEngine engine; - private final WeakReference serviceRef; - private EngineWrapper(ProofOfWorkEngine engine, ProofOfWorkService service) { - this.engine = engine; - this.serviceRef = new WeakReference<>(service); - this.notification = new ProofOfWorkNotification(service); + static class PowItem { + private final byte[] initialHash; + private final byte[] targetValue; + private final ProofOfWorkEngine.Callback callback; + + PowItem(byte[] initialHash, byte[] targetValue, ProofOfWorkEngine.Callback callback) { + this.initialHash = initialHash; + this.targetValue = targetValue; + this.callback = callback; } + } - @Override - public void calculateNonce(byte[] initialHash, byte[] target, final Callback callback) { - final ProofOfWorkService service = serviceRef.get(); - service.startService(new Intent(service, ProofOfWorkService.class)); - service.startForeground(ONGOING_NOTIFICATION_ID, notification.getNotification()); - engine.calculateNonce(initialHash, target, new ProofOfWorkEngine.Callback() { - @Override - public void onNonceCalculated(byte[] initialHash, byte[] nonce) { - try { - callback.onNonceCalculated(initialHash, nonce); - } finally { - service.stopForeground(true); - service.stopSelf(); + private void calculateNonce(final PowItem item) { + engine.calculateNonce(item.initialHash, item.targetValue, new ProofOfWorkEngine.Callback() { + @Override + public void onNonceCalculated(byte[] initialHash, byte[] nonce) { + try { + item.callback.onNonceCalculated(initialHash, nonce); + } finally { + PowItem item; + synchronized (queue) { + item = queue.poll(); + if (item == null) { + calculating = false; + stopForeground(true); + stopSelf(); + } else { + notification.update(queue.size()).show(); + } + } + if (item != null) { + calculateNonce(item); } } - }); - - } + } + }); } } \ No newline at end of file diff --git a/app/src/main/java/ch/dissem/apps/abit/service/ServicePowEngine.java b/app/src/main/java/ch/dissem/apps/abit/service/ServicePowEngine.java index f986a7f..7211dcf 100644 --- a/app/src/main/java/ch/dissem/apps/abit/service/ServicePowEngine.java +++ b/app/src/main/java/ch/dissem/apps/abit/service/ServicePowEngine.java @@ -22,9 +22,11 @@ import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; -import java.util.concurrent.Semaphore; +import java.util.LinkedList; +import java.util.Queue; import ch.dissem.apps.abit.service.ProofOfWorkService.PowBinder; +import ch.dissem.apps.abit.service.ProofOfWorkService.PowItem; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; import static android.content.Context.BIND_AUTO_CREATE; @@ -32,12 +34,12 @@ import static android.content.Context.BIND_AUTO_CREATE; /** * Proof of Work engine that uses the Proof of Work service. */ -public class ServicePowEngine implements ProofOfWorkEngine, ProofOfWorkEngine.Callback { - private final Semaphore semaphore = new Semaphore(1, true); +public class ServicePowEngine implements ProofOfWorkEngine { private final Context ctx; - private byte[] initialHash, targetValue; - private Callback callback; + private static final Object lock = new Object(); + private Queue queue = new LinkedList<>(); + private PowBinder service; public ServicePowEngine(Context ctx) { this.ctx = ctx; @@ -46,32 +48,31 @@ public class ServicePowEngine implements ProofOfWorkEngine, ProofOfWorkEngine.Ca private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { - ((PowBinder) service).getEngine().calculateNonce(initialHash, targetValue, ServicePowEngine.this); + synchronized (lock) { + ServicePowEngine.this.service = (PowBinder) service; + while (!queue.isEmpty()) { + ServicePowEngine.this.service.process(queue.poll()); + } + } } @Override public void onServiceDisconnected(ComponentName name) { - semaphore.release(); + service = null; } }; @Override public void calculateNonce(byte[] initialHash, byte[] targetValue, Callback callback) { - try { - semaphore.acquire(); - } catch (InterruptedException e) { - throw new RuntimeException(e); + PowItem item = new PowItem(initialHash, targetValue, callback); + synchronized (lock) { + if (service != null) { + service.process(item); + } else { + queue.add(item); + ctx.bindService(new Intent(ctx, ProofOfWorkService.class), connection, + BIND_AUTO_CREATE); + } } - this.initialHash = initialHash; - this.targetValue = targetValue; - this.callback = callback; - ctx.bindService(new Intent(ctx, ProofOfWorkService.class), connection, BIND_AUTO_CREATE); } - - @Override - public void onNonceCalculated(byte[] initialHash, byte[] bytes) { - callback.onNonceCalculated(initialHash, bytes); - ctx.unbindService(connection); - } - -} +} \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index bc0d062..8a153f1 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -42,7 +42,7 @@ Stream %1$d: %2$d Verbindungen Getrennt Verbindung wird aufgebaut… - Warnung: dies könnte das Gerät erwärmen bis die Batterie leer ist. + Arbeite am Versenden (%1$d in Warteschlange) Proof of Work Synchronisation fehlgeschlagen: der vertrauenswürdige Knoten konnte nicht erreicht werden. Ungültiger Port in den Synchronisationseinstellungen: %s diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7a4e21c..82daeff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,7 +44,7 @@ Disconnected Connecting… Proof of Work - Warning: This might heat your device until the battery\'s dead. + Doing work to send message (%1$d queued) Invalid port in synchronization settings: %s Synchronization failed: Trusted node could not be reached. Write message