diff --git a/briar-android/src/net/sf/briar/android/AndroidModule.java b/briar-android/src/net/sf/briar/android/AndroidModule.java index ceac1c7a437415d1e53f25b2c77c00a43eab04b3..ee700f82086b2afeecedff37c239e7e5023bfe9a 100644 --- a/briar-android/src/net/sf/briar/android/AndroidModule.java +++ b/briar-android/src/net/sf/briar/android/AndroidModule.java @@ -1,11 +1,16 @@ package net.sf.briar.android; +import static java.util.concurrent.TimeUnit.SECONDS; + import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; import net.sf.briar.api.android.AndroidExecutor; import net.sf.briar.api.android.DatabaseUiExecutor; @@ -34,15 +39,22 @@ public class AndroidModule extends AbstractModule { bind(AndroidExecutor.class).to(AndroidExecutorImpl.class); bind(ReferenceManager.class).to(ReferenceManagerImpl.class).in( Singleton.class); - // Use a single thread so DB accesses from the UI don't overlap, with - // an unbounded queue so submissions don't block - bind(Executor.class).annotatedWith(DatabaseUiExecutor.class).toInstance( - Executors.newSingleThreadExecutor()); + // The queue is unbounded, so tasks can be dependent + BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(); + // Discard tasks that are submitted during shutdown + RejectedExecutionHandler policy = + new ThreadPoolExecutor.DiscardPolicy(); + // Use a single thread so DB accesses from the UI don't overlap + ExecutorService e = new ThreadPoolExecutor(1, 1, 60, SECONDS, queue, + policy); + bind(Executor.class).annotatedWith( + DatabaseUiExecutor.class).toInstance(e); + bind(ExecutorService.class).annotatedWith( + DatabaseUiExecutor.class).toInstance(e); } @Provides - SimplexPluginConfig getSimplexPluginConfig( - @PluginExecutor ExecutorService pluginExecutor) { + SimplexPluginConfig getSimplexPluginConfig() { return new SimplexPluginConfig() { public Collection<SimplexPluginFactory> getFactories() { return Collections.emptyList(); @@ -52,7 +64,7 @@ public class AndroidModule extends AbstractModule { @Provides DuplexPluginConfig getDuplexPluginConfig( - @PluginExecutor ExecutorService pluginExecutor, + @PluginExecutor Executor pluginExecutor, AndroidExecutor androidExecutor, Context appContext, CryptoComponent crypto, ShutdownManager shutdownManager) { DuplexPluginFactory droidtooth = new DroidtoothPluginFactory( diff --git a/briar-android/src/net/sf/briar/android/BriarService.java b/briar-android/src/net/sf/briar/android/BriarService.java index 3582efc54f3962f556827a1bec284669176af2a3..5cbc516a2bb7e511081688670a026384f146cea2 100644 --- a/briar-android/src/net/sf/briar/android/BriarService.java +++ b/briar-android/src/net/sf/briar/android/BriarService.java @@ -3,18 +3,15 @@ package net.sf.briar.android; import static android.app.PendingIntent.FLAG_ONE_SHOT; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; -import java.io.IOException; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.api.crypto.KeyManager; -import net.sf.briar.api.db.DatabaseComponent; -import net.sf.briar.api.db.DatabaseConfig; -import net.sf.briar.api.db.DbException; -import net.sf.briar.api.plugins.PluginManager; +import net.sf.briar.api.android.AndroidExecutor; +import net.sf.briar.api.android.DatabaseUiExecutor; +import net.sf.briar.api.lifecycle.LifecycleManager; import roboguice.service.RoboService; import android.app.PendingIntent; import android.content.ComponentName; @@ -31,15 +28,12 @@ public class BriarService extends RoboService { private static final Logger LOG = Logger.getLogger(BriarService.class.getName()); - private final CountDownLatch dbLatch = new CountDownLatch(1); - private final CountDownLatch startupLatch = new CountDownLatch(1); - private final CountDownLatch shutdownLatch = new CountDownLatch(1); private final Binder binder = new BriarBinder(); - @Inject private DatabaseConfig databaseConfig = null; - @Inject private DatabaseComponent db = null; - @Inject private KeyManager keyManager = null; - @Inject private PluginManager pluginManager = null; + // Fields that are accessed from background threads must be volatile + @Inject private volatile LifecycleManager lifecycleManager; + @Inject private volatile AndroidExecutor androidExecutor; + @Inject @DatabaseUiExecutor private volatile ExecutorService dbUiExecutor; @Override public void onCreate() { @@ -63,7 +57,7 @@ public class BriarService extends RoboService { new Thread() { @Override public void run() { - startServices(); + lifecycleManager.startServices(); } }.start(); } @@ -71,11 +65,11 @@ public class BriarService extends RoboService { @Override public int onStartCommand(Intent intent, int flags, int startId) { if(LOG.isLoggable(INFO)) LOG.info("Started"); - return START_STICKY; + return START_NOT_STICKY; // Don't restart automatically if killed } - @Override public IBinder onBind(Intent intent) { + if(LOG.isLoggable(INFO)) LOG.info("Bound"); return binder; } @@ -87,71 +81,38 @@ public class BriarService extends RoboService { new Thread() { @Override public void run() { - stopServices(); + // FIXME: This is ugly - executors should register themselves + // with the lifecycle manager + androidExecutor.shutdown(); + dbUiExecutor.shutdown(); + lifecycleManager.stopServices(); } }.start(); } - private void startServices() { - if(databaseConfig.getEncryptionKey() == null) - throw new IllegalStateException(); - try { - if(LOG.isLoggable(INFO)) LOG.info("Starting"); - boolean reopened = db.open(); - if(LOG.isLoggable(INFO)) { - if(reopened) LOG.info("Database reopened"); - else LOG.info("Database created"); - } - dbLatch.countDown(); - keyManager.start(); - if(LOG.isLoggable(INFO)) LOG.info("Key manager started"); - int pluginsStarted = pluginManager.start(); - if(LOG.isLoggable(INFO)) - LOG.info(pluginsStarted + " plugins started"); - startupLatch.countDown(); - } catch(DbException e) { - if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } catch(IOException e) { - if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } - } - - private void stopServices() { - try { - if(LOG.isLoggable(INFO)) LOG.info("Shutting down"); - int pluginsStopped = pluginManager.stop(); - if(LOG.isLoggable(INFO)) - LOG.info(pluginsStopped + " plugins stopped"); - keyManager.stop(); - if(LOG.isLoggable(INFO)) LOG.info("Key manager stopped"); - db.close(); - if(LOG.isLoggable(INFO)) LOG.info("Database closed"); - shutdownLatch.countDown(); - } catch(DbException e) { - if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } catch(IOException e) { - if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } - } - + /** Waits for the database to be opened before returning. */ public void waitForDatabase() throws InterruptedException { - dbLatch.await(); + lifecycleManager.waitForDatabase(); } + /** Waits for all services to start before returning. */ public void waitForStartup() throws InterruptedException { - startupLatch.await(); + lifecycleManager.waitForStartup(); } + /** Waits for all services to stop before returning. */ public void waitForShutdown() throws InterruptedException { - shutdownLatch.await(); + lifecycleManager.waitForShutdown(); } + /** Starts the shutdown process. */ public void shutdown() { - stopSelf(); + stopSelf(); // This will call onDestroy() } public class BriarBinder extends Binder { + /** Returns the bound service. */ public BriarService getService() { return BriarService.this; } @@ -170,19 +131,10 @@ public class BriarService extends RoboService { public void onServiceDisconnected(ComponentName name) {} + /** Waits for the service to connect and returns its binder. */ public IBinder waitForBinder() throws InterruptedException { binderLatch.await(); return binder; } - - public void waitForDatabase() throws InterruptedException { - waitForBinder(); - ((BriarBinder) binder).getService().waitForDatabase(); - } - - public void waitForStartup() throws InterruptedException { - waitForBinder(); - ((BriarBinder) binder).getService().waitForStartup(); - } } } diff --git a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java index ef7ecd0a5b972ad3fd1b87f5629e549c86a1eb31..354d2d1b2371624b8cc662cd12b72e14302526fe 100644 --- a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java +++ b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java @@ -35,6 +35,7 @@ import net.sf.briar.api.crypto.CryptoExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseConfig; import net.sf.briar.api.db.DbException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.util.StringUtils; import roboguice.activity.RoboActivity; import android.content.Intent; @@ -70,18 +71,19 @@ public class HomeScreenActivity extends RoboActivity { private final BriarServiceConnection serviceConnection = new BriarServiceConnection(); - @Inject private ReferenceManager referenceManager = null; - @Inject private DatabaseConfig databaseConfig = null; - @Inject @DatabaseUiExecutor private Executor dbUiExecutor = null; - @Inject @CryptoExecutor private Executor cryptoExecutor = null; + @Inject private ReferenceManager referenceManager; + @Inject private DatabaseConfig databaseConfig; + @Inject @DatabaseUiExecutor private Executor dbUiExecutor; + @Inject @CryptoExecutor private Executor cryptoExecutor; private boolean bound = false; private TextView enterPassword = null; private Button continueButton = null; private ProgressBar progress = null; // Fields that are accessed from background threads must be volatile - @Inject private volatile DatabaseComponent db = null; - @Inject private volatile CryptoComponent crypto = null; + @Inject private volatile CryptoComponent crypto; + @Inject private volatile DatabaseComponent db; + @Inject private volatile LifecycleManager lifecycleManager; @Override public void onCreate(Bundle state) { @@ -136,7 +138,7 @@ public class HomeScreenActivity extends RoboActivity { @Override public void run() { try { - // Wait for the service to be bound and started + // Wait for the service to finish starting up IBinder binder = serviceConnection.waitForBinder(); BriarService service = ((BriarBinder) binder).getService(); service.waitForStartup(); @@ -146,7 +148,7 @@ public class HomeScreenActivity extends RoboActivity { service.waitForShutdown(); } catch(InterruptedException e) { if(LOG.isLoggable(INFO)) - LOG.info("Interrupted while waiting for database"); + LOG.info("Interrupted while waiting for service"); } // Finish the activity and kill the JVM runOnUiThread(new Runnable() { @@ -164,7 +166,7 @@ public class HomeScreenActivity extends RoboActivity { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); db.addLocalAuthor(a); db.setRating(a.getId(), GOOD); diff --git a/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java b/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java index aa421875ea340b595a8b8afa073c4b40a34ce797..f603373968b315cfe3bf1821f50ceababfcfa9b2 100644 --- a/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java +++ b/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java @@ -17,8 +17,6 @@ import java.util.logging.Logger; import net.sf.briar.R; import net.sf.briar.android.AscendingHeaderComparator; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.widgets.HorizontalBorder; import net.sf.briar.android.widgets.ListLoadingProgressBar; import net.sf.briar.api.Author; @@ -33,6 +31,7 @@ import net.sf.briar.api.db.event.GroupMessageAddedEvent; import net.sf.briar.api.db.event.MessageExpiredEvent; import net.sf.briar.api.db.event.RatingChangedEvent; import net.sf.briar.api.db.event.SubscriptionRemovedEvent; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.GroupId; import roboguice.activity.RoboFragmentActivity; import android.content.Intent; @@ -53,9 +52,6 @@ implements DatabaseListener, OnClickListener, OnItemClickListener { private static final Logger LOG = Logger.getLogger(BlogActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private String groupName = null; private boolean postable = false; private BlogAdapter adapter = null; @@ -65,6 +61,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile GroupId groupId = null; @Override @@ -107,10 +104,6 @@ implements DatabaseListener, OnClickListener, OnItemClickListener { layout.addView(composeButton); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -124,7 +117,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<GroupMessageHeader> headers = db.getGroupMessageHeaders(groupId); @@ -196,12 +189,6 @@ implements DatabaseListener, OnClickListener, OnItemClickListener { db.removeListener(this); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void eventOccurred(DatabaseEvent e) { if(e instanceof GroupMessageAddedEvent) { GroupMessageAddedEvent g = (GroupMessageAddedEvent) e; diff --git a/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java b/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java index 6bc9d9d58067a31ee03331058c35d3b6a716c012..5680ad9303e9f0bc944649ca4c6b7134314b3278 100644 --- a/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java +++ b/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java @@ -21,8 +21,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.widgets.HorizontalBorder; import net.sf.briar.android.widgets.HorizontalSpace; import net.sf.briar.android.widgets.ListLoadingProgressBar; @@ -38,6 +36,7 @@ import net.sf.briar.api.db.event.MessageExpiredEvent; import net.sf.briar.api.db.event.RemoteSubscriptionsUpdatedEvent; import net.sf.briar.api.db.event.SubscriptionAddedEvent; import net.sf.briar.api.db.event.SubscriptionRemovedEvent; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.GroupStatus; @@ -61,9 +60,6 @@ OnItemClickListener { private static final Logger LOG = Logger.getLogger(BlogListActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private BlogListAdapter adapter = null; private ListView list = null; private ListLoadingProgressBar loading = null; @@ -73,6 +69,7 @@ OnItemClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; @Override public void onCreate(Bundle state) { @@ -126,10 +123,6 @@ OnItemClickListener { layout.addView(footer); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -144,7 +137,7 @@ OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Set<GroupId> local = new HashSet<GroupId>(); for(Group g : db.getLocalGroups()) local.add(g.getId()); @@ -252,12 +245,6 @@ OnItemClickListener { db.removeListener(this); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void eventOccurred(DatabaseEvent e) { if(e instanceof GroupMessageAddedEvent) { Group g = ((GroupMessageAddedEvent) e).getGroup(); @@ -292,7 +279,7 @@ OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<GroupMessageHeader> headers = db.getGroupMessageHeaders(g.getId()); @@ -333,7 +320,7 @@ OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); int available = 0; long now = System.currentTimeMillis(); for(GroupStatus s : db.getAvailableGroups()) { diff --git a/briar-android/src/net/sf/briar/android/blogs/ConfigureBlogActivity.java b/briar-android/src/net/sf/briar/android/blogs/ConfigureBlogActivity.java index 2ebd2726090792d02c7134a3b944934fcb126840..0d7ca47c2c0e6ec299f26e68a328b0c9ca19fe14 100644 --- a/briar-android/src/net/sf/briar/android/blogs/ConfigureBlogActivity.java +++ b/briar-android/src/net/sf/briar/android/blogs/ConfigureBlogActivity.java @@ -15,8 +15,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.contact.SelectContactsDialog; import net.sf.briar.android.invitation.AddContactActivity; import net.sf.briar.android.messages.NoContactsDialog; @@ -25,6 +23,7 @@ import net.sf.briar.api.ContactId; import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.GroupId; import roboguice.activity.RoboFragmentActivity; @@ -48,9 +47,6 @@ SelectContactsDialog.Listener { private static final Logger LOG = Logger.getLogger(ConfigureBlogActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private boolean subscribed = false; private CheckBox subscribeCheckBox = null; private RadioGroup radioGroup = null; @@ -61,6 +57,7 @@ SelectContactsDialog.Listener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile Group group = null; private volatile Collection<ContactId> selected = Collections.emptyList(); @@ -127,16 +124,6 @@ SelectContactsDialog.Listener { layout.addView(progress); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); - } - - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); } public void onClick(View view) { @@ -164,7 +151,7 @@ SelectContactsDialog.Listener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<Contact> contacts = db.getContacts(); long duration = System.currentTimeMillis() - now; @@ -208,7 +195,7 @@ SelectContactsDialog.Listener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); if(subscribe) { if(!wasSubscribed) db.subscribe(group); diff --git a/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java b/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java index 7232e9d773c6cb9fa1eaa8e2fe8036817a47c2a7..a92b19ea54b02b2eee151d7e28fb88710af9615d 100644 --- a/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java +++ b/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java @@ -21,8 +21,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.contact.SelectContactsDialog; import net.sf.briar.android.invitation.AddContactActivity; import net.sf.briar.android.messages.NoContactsDialog; @@ -33,6 +31,7 @@ import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.CryptoExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.GroupFactory; import net.sf.briar.api.messaging.LocalGroup; import roboguice.activity.RoboFragmentActivity; @@ -60,9 +59,6 @@ SelectContactsDialog.Listener { private static final Logger LOG = Logger.getLogger(CreateBlogActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - @Inject @CryptoExecutor private Executor cryptoExecutor; private EditText nameEntry = null; private RadioGroup radioGroup = null; @@ -75,6 +71,7 @@ SelectContactsDialog.Listener { @Inject private volatile GroupFactory groupFactory; @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile Collection<ContactId> selected = Collections.emptyList(); @Override @@ -135,10 +132,6 @@ SelectContactsDialog.Listener { layout.addView(progress); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } private void enableOrDisableCreateButton() { @@ -149,12 +142,6 @@ SelectContactsDialog.Listener { createButton.setEnabled(nameNotEmpty && visibilitySelected); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) { validateName(); return true; @@ -197,7 +184,7 @@ SelectContactsDialog.Listener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<Contact> contacts = db.getContacts(); long duration = System.currentTimeMillis() - now; @@ -240,7 +227,7 @@ SelectContactsDialog.Listener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); db.addLocalGroup(g); db.subscribe(g); diff --git a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java index 91385ccd9357887bed85ccfd9ccf98b448cf1151..1055024983845b7585776a30e988a00f174ee992 100644 --- a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java +++ b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java @@ -13,8 +13,6 @@ import java.util.List; import java.util.concurrent.Executor; import java.util.logging.Logger; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.widgets.ListLoadingProgressBar; import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; @@ -24,6 +22,7 @@ import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.db.event.RemoteSubscriptionsUpdatedEvent; import net.sf.briar.api.db.event.SubscriptionAddedEvent; import net.sf.briar.api.db.event.SubscriptionRemovedEvent; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.GroupStatus; import roboguice.activity.RoboFragmentActivity; @@ -42,9 +41,6 @@ implements DatabaseListener, OnItemClickListener { private static final Logger LOG = Logger.getLogger(ManageBlogsActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private ManageBlogsAdapter adapter = null; private ListView list = null; private ListLoadingProgressBar loading = null; @@ -52,6 +48,7 @@ implements DatabaseListener, OnItemClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; @Override public void onCreate(Bundle state) { @@ -66,10 +63,6 @@ implements DatabaseListener, OnItemClickListener { // Show a progress bar while the list is loading loading = new ListLoadingProgressBar(this); setContentView(loading); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -83,7 +76,7 @@ implements DatabaseListener, OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); List<GroupStatus> available = new ArrayList<GroupStatus>(); for(GroupStatus s : db.getAvailableGroups()) @@ -125,12 +118,6 @@ implements DatabaseListener, OnItemClickListener { db.removeListener(this); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void eventOccurred(DatabaseEvent e) { if(e instanceof RemoteSubscriptionsUpdatedEvent) { if(LOG.isLoggable(INFO)) diff --git a/briar-android/src/net/sf/briar/android/blogs/ReadBlogPostActivity.java b/briar-android/src/net/sf/briar/android/blogs/ReadBlogPostActivity.java index 4ad6cc09dfc5fc6cb9b32334d155d86cfdeb312f..7188674f240189b5fe8944bbfb7d758532abb2f5 100644 --- a/briar-android/src/net/sf/briar/android/blogs/ReadBlogPostActivity.java +++ b/briar-android/src/net/sf/briar/android/blogs/ReadBlogPostActivity.java @@ -19,14 +19,13 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.widgets.HorizontalBorder; import net.sf.briar.android.widgets.HorizontalSpace; import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.NoSuchMessageException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.MessageId; import net.sf.briar.api.messaging.Rating; @@ -55,9 +54,6 @@ implements OnClickListener { private static final Logger LOG = Logger.getLogger(ReadBlogPostActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private GroupId groupId = null; private boolean postable = false; private Rating rating = UNRATED; @@ -70,6 +66,7 @@ implements OnClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile MessageId messageId = null; @Override @@ -196,17 +193,13 @@ implements OnClickListener { layout.addView(footer); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } private void setReadInDatabase(final boolean read) { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); db.setReadFlag(messageId, read); long duration = System.currentTimeMillis() - now; @@ -239,7 +232,7 @@ implements OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); byte[] body = db.getMessageBody(messageId); long duration = System.currentTimeMillis() - now; @@ -278,12 +271,6 @@ implements OnClickListener { state.putBoolean("net.sf.briar.READ", read); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void onClick(View view) { if(view == readButton) { setReadInDatabase(!read); diff --git a/briar-android/src/net/sf/briar/android/blogs/WriteBlogPostActivity.java b/briar-android/src/net/sf/briar/android/blogs/WriteBlogPostActivity.java index 2a134bbaa4a4e0a4e1bf43c5563ca68d3f7a73c6..e3d60e2a9675b0b2bbdf6d0a1058a99670901067 100644 --- a/briar-android/src/net/sf/briar/android/blogs/WriteBlogPostActivity.java +++ b/briar-android/src/net/sf/briar/android/blogs/WriteBlogPostActivity.java @@ -17,8 +17,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.identity.CreateIdentityActivity; import net.sf.briar.android.identity.LocalAuthorItem; import net.sf.briar.android.identity.LocalAuthorItemComparator; @@ -31,6 +29,7 @@ import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.KeyParser; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.LocalGroup; import net.sf.briar.api.messaging.Message; @@ -58,9 +57,6 @@ implements OnItemSelectedListener, OnClickListener { private static final Logger LOG = Logger.getLogger(WriteBlogPostActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - @Inject private CryptoComponent crypto; @Inject private MessageFactory messageFactory; private LocalAuthorSpinnerAdapter fromAdapter = null; @@ -74,6 +70,7 @@ implements OnItemSelectedListener, OnClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile LocalAuthor localAuthor = null; private volatile LocalGroup localGroup = null; private volatile MessageId parentId = null; @@ -152,10 +149,6 @@ implements OnItemSelectedListener, OnClickListener { layout.addView(content); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -169,7 +162,7 @@ implements OnItemSelectedListener, OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<LocalAuthor> localAuthors = db.getLocalAuthors(); long duration = System.currentTimeMillis() - now; @@ -216,7 +209,7 @@ implements OnItemSelectedListener, OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<LocalGroup> groups = db.getLocalGroups(); long duration = System.currentTimeMillis() - now; @@ -269,12 +262,6 @@ implements OnItemSelectedListener, OnClickListener { } } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if(parent == fromSpinner) { @@ -350,7 +337,7 @@ implements OnItemSelectedListener, OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); db.addLocalGroupMessage(m); long duration = System.currentTimeMillis() - now; diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java index 32f92293e95e15815704b91ef4bc82e71e353a29..061d52a10b6f3fc795e03fc20b61fabeaf9a2c3c 100644 --- a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java +++ b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java @@ -22,8 +22,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.invitation.AddContactActivity; import net.sf.briar.android.widgets.HorizontalBorder; import net.sf.briar.android.widgets.HorizontalSpace; @@ -37,6 +35,7 @@ import net.sf.briar.api.db.event.ContactAddedEvent; import net.sf.briar.api.db.event.ContactRemovedEvent; import net.sf.briar.api.db.event.DatabaseEvent; import net.sf.briar.api.db.event.DatabaseListener; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.transport.ConnectionListener; import net.sf.briar.api.transport.ConnectionRegistry; import roboguice.activity.RoboActivity; @@ -60,9 +59,6 @@ ConnectionListener { private static final Logger LOG = Logger.getLogger(ContactListActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - @Inject private ConnectionRegistry connectionRegistry; private ContactListAdapter adapter = null; private ListView list = null; @@ -72,6 +68,7 @@ ConnectionListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; @Override public void onCreate(Bundle state) { @@ -118,10 +115,6 @@ ConnectionListener { layout.addView(footer); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -136,7 +129,7 @@ ConnectionListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<Contact> contacts = db.getContacts(); Map<ContactId, Long> times = db.getLastConnected(); @@ -182,12 +175,6 @@ ConnectionListener { connectionRegistry.removeListener(this); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void onClick(View view) { if(view == addContactButton) { startActivity(new Intent(this, AddContactActivity.class)); diff --git a/briar-android/src/net/sf/briar/android/groups/ConfigureGroupActivity.java b/briar-android/src/net/sf/briar/android/groups/ConfigureGroupActivity.java index df203717cd0de226f7fa73d9acaf507f9f23d4a3..cedcdc3ffdeab6c4631ec626f5e1847404fabd13 100644 --- a/briar-android/src/net/sf/briar/android/groups/ConfigureGroupActivity.java +++ b/briar-android/src/net/sf/briar/android/groups/ConfigureGroupActivity.java @@ -15,8 +15,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.contact.SelectContactsDialog; import net.sf.briar.android.invitation.AddContactActivity; import net.sf.briar.android.messages.NoContactsDialog; @@ -25,6 +23,7 @@ import net.sf.briar.api.ContactId; import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.GroupId; import roboguice.activity.RoboFragmentActivity; @@ -48,9 +47,6 @@ SelectContactsDialog.Listener { private static final Logger LOG = Logger.getLogger(ConfigureGroupActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private boolean subscribed = false; private CheckBox subscribeCheckBox = null; private RadioGroup radioGroup = null; @@ -61,6 +57,7 @@ SelectContactsDialog.Listener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile Group group = null; private volatile Collection<ContactId> selected = Collections.emptyList(); @@ -125,16 +122,6 @@ SelectContactsDialog.Listener { layout.addView(progress); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); - } - - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); } public void onClick(View view) { @@ -162,7 +149,7 @@ SelectContactsDialog.Listener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<Contact> contacts = db.getContacts(); long duration = System.currentTimeMillis() - now; @@ -206,7 +193,7 @@ SelectContactsDialog.Listener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); if(subscribe) { if(!wasSubscribed) db.subscribe(group); diff --git a/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java b/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java index e75f6fbf70566e90eba25607e03349e7f05c0110..56b5187e02d237f5496368f6af951aa9d8cc9520 100644 --- a/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java +++ b/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java @@ -20,8 +20,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.contact.SelectContactsDialog; import net.sf.briar.android.invitation.AddContactActivity; import net.sf.briar.android.messages.NoContactsDialog; @@ -30,6 +28,7 @@ import net.sf.briar.api.ContactId; import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.GroupFactory; import roboguice.activity.RoboFragmentActivity; @@ -57,9 +56,6 @@ SelectContactsDialog.Listener { private static final Logger LOG = Logger.getLogger(CreateGroupActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private EditText nameEntry = null; private RadioGroup radioGroup = null; private RadioButton visibleToAll = null, visibleToSome = null; @@ -70,6 +66,7 @@ SelectContactsDialog.Listener { @Inject private volatile GroupFactory groupFactory; @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile Collection<ContactId> selected = Collections.emptyList(); @Override @@ -129,10 +126,6 @@ SelectContactsDialog.Listener { layout.addView(progress); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } private void enableOrDisableCreateButton() { @@ -143,12 +136,6 @@ SelectContactsDialog.Listener { createButton.setEnabled(nameNotEmpty && visibilitySelected); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) { validateName(); return true; @@ -172,7 +159,7 @@ SelectContactsDialog.Listener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); Group g = groupFactory.createGroup(name); long now = System.currentTimeMillis(); db.subscribe(g); @@ -206,7 +193,7 @@ SelectContactsDialog.Listener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<Contact> contacts = db.getContacts(); long duration = System.currentTimeMillis() - now; diff --git a/briar-android/src/net/sf/briar/android/groups/GroupActivity.java b/briar-android/src/net/sf/briar/android/groups/GroupActivity.java index 0ea0adb590c2f3974cc1f32c80cbc991ed26c83e..c7de96f65c64a13bcf497ef7a0d1175f14a91c9a 100644 --- a/briar-android/src/net/sf/briar/android/groups/GroupActivity.java +++ b/briar-android/src/net/sf/briar/android/groups/GroupActivity.java @@ -17,8 +17,6 @@ import java.util.logging.Logger; import net.sf.briar.R; import net.sf.briar.android.AscendingHeaderComparator; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.widgets.HorizontalBorder; import net.sf.briar.android.widgets.ListLoadingProgressBar; import net.sf.briar.api.Author; @@ -33,6 +31,7 @@ import net.sf.briar.api.db.event.GroupMessageAddedEvent; import net.sf.briar.api.db.event.MessageExpiredEvent; import net.sf.briar.api.db.event.RatingChangedEvent; import net.sf.briar.api.db.event.SubscriptionRemovedEvent; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.GroupId; import roboguice.activity.RoboActivity; import android.content.Intent; @@ -53,9 +52,6 @@ OnClickListener, OnItemClickListener { private static final Logger LOG = Logger.getLogger(GroupActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private String groupName = null; private GroupAdapter adapter = null; private ListView list = null; @@ -64,6 +60,7 @@ OnClickListener, OnItemClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile GroupId groupId = null; @Override @@ -105,10 +102,6 @@ OnClickListener, OnItemClickListener { layout.addView(composeButton); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -122,7 +115,7 @@ OnClickListener, OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<GroupMessageHeader> headers = db.getGroupMessageHeaders(groupId); @@ -194,12 +187,6 @@ OnClickListener, OnItemClickListener { db.removeListener(this); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void eventOccurred(DatabaseEvent e) { if(e instanceof GroupMessageAddedEvent) { GroupMessageAddedEvent g = (GroupMessageAddedEvent) e; diff --git a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java index 725ea96f669173205793ae554054bde663d8eb70..bd4d274656e010d3a6fb84d718fbd09b928feed7 100644 --- a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java +++ b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java @@ -19,8 +19,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.widgets.HorizontalBorder; import net.sf.briar.android.widgets.HorizontalSpace; import net.sf.briar.android.widgets.ListLoadingProgressBar; @@ -36,6 +34,7 @@ import net.sf.briar.api.db.event.MessageExpiredEvent; import net.sf.briar.api.db.event.RemoteSubscriptionsUpdatedEvent; import net.sf.briar.api.db.event.SubscriptionAddedEvent; import net.sf.briar.api.db.event.SubscriptionRemovedEvent; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.GroupStatus; @@ -59,9 +58,6 @@ OnItemClickListener { private static final Logger LOG = Logger.getLogger(GroupListActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private GroupListAdapter adapter = null; private ListView list = null; private ListLoadingProgressBar loading = null; @@ -71,6 +67,7 @@ OnItemClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; @Override public void onCreate(Bundle state) { @@ -124,10 +121,6 @@ OnItemClickListener { layout.addView(footer); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -142,7 +135,7 @@ OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); int available = 0; long now = System.currentTimeMillis(); for(GroupStatus s : db.getAvailableGroups()) { @@ -247,12 +240,6 @@ OnItemClickListener { db.removeListener(this); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void eventOccurred(DatabaseEvent e) { if(e instanceof GroupMessageAddedEvent) { Group g = ((GroupMessageAddedEvent) e).getGroup(); @@ -287,7 +274,7 @@ OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<GroupMessageHeader> headers = db.getGroupMessageHeaders(g.getId()); @@ -327,7 +314,7 @@ OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); int available = 0; long now = System.currentTimeMillis(); for(GroupStatus s : db.getAvailableGroups()) { diff --git a/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java b/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java index aae133ce177b5ca91069ead8879a209d242c6a9b..390de0e280b0e34d80b922b1c9154e9923a4448c 100644 --- a/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java +++ b/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java @@ -13,8 +13,6 @@ import java.util.List; import java.util.concurrent.Executor; import java.util.logging.Logger; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.widgets.ListLoadingProgressBar; import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; @@ -24,6 +22,7 @@ import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.db.event.RemoteSubscriptionsUpdatedEvent; import net.sf.briar.api.db.event.SubscriptionAddedEvent; import net.sf.briar.api.db.event.SubscriptionRemovedEvent; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.GroupStatus; import roboguice.activity.RoboFragmentActivity; @@ -42,9 +41,6 @@ implements DatabaseListener, OnItemClickListener { private static final Logger LOG = Logger.getLogger(ManageGroupsActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private ManageGroupsAdapter adapter = null; private ListView list = null; private ListLoadingProgressBar loading = null; @@ -52,6 +48,7 @@ implements DatabaseListener, OnItemClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; @Override public void onCreate(Bundle state) { @@ -66,10 +63,6 @@ implements DatabaseListener, OnItemClickListener { // Show a progress bar while the list is loading loading = new ListLoadingProgressBar(this); setContentView(loading); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -83,7 +76,7 @@ implements DatabaseListener, OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); List<GroupStatus> available = new ArrayList<GroupStatus>(); for(GroupStatus s : db.getAvailableGroups()) @@ -125,12 +118,6 @@ implements DatabaseListener, OnItemClickListener { db.removeListener(this); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void eventOccurred(DatabaseEvent e) { if(e instanceof RemoteSubscriptionsUpdatedEvent) { if(LOG.isLoggable(INFO)) diff --git a/briar-android/src/net/sf/briar/android/groups/ReadGroupPostActivity.java b/briar-android/src/net/sf/briar/android/groups/ReadGroupPostActivity.java index df401605653415ec07be2974428d3e94bc81a3e1..097ce6024af32311721b58ea336bb13525d45b70 100644 --- a/briar-android/src/net/sf/briar/android/groups/ReadGroupPostActivity.java +++ b/briar-android/src/net/sf/briar/android/groups/ReadGroupPostActivity.java @@ -19,8 +19,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.widgets.HorizontalBorder; import net.sf.briar.android.widgets.HorizontalSpace; import net.sf.briar.api.AuthorId; @@ -28,6 +26,7 @@ import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.NoSuchMessageException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.MessageId; import net.sf.briar.api.messaging.Rating; @@ -56,9 +55,6 @@ implements OnClickListener { private static final Logger LOG = Logger.getLogger(ReadGroupPostActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private GroupId groupId = null; private Rating rating = UNRATED; private boolean read; @@ -71,6 +67,7 @@ implements OnClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile MessageId messageId = null; private volatile AuthorId authorId = null; @@ -220,17 +217,13 @@ implements OnClickListener { layout.addView(footer); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } private void setReadInDatabase(final boolean read) { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); db.setReadFlag(messageId, read); long duration = System.currentTimeMillis() - now; @@ -263,7 +256,7 @@ implements OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); byte[] body = db.getMessageBody(messageId); long duration = System.currentTimeMillis() - now; @@ -302,12 +295,6 @@ implements OnClickListener { state.putBoolean("net.sf.briar.READ", read); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void onClick(View view) { if(view == goodButton) { if(rating == BAD) setRatingInDatabase(UNRATED); @@ -337,7 +324,7 @@ implements OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); db.setRating(authorId, r); long duration = System.currentTimeMillis() - now; diff --git a/briar-android/src/net/sf/briar/android/groups/WriteGroupPostActivity.java b/briar-android/src/net/sf/briar/android/groups/WriteGroupPostActivity.java index 70d72e288aab16c2ebe9c5f6ea36550980abf993..f3168ad89c7eca0b6200561a8dad6a953c6a9509 100644 --- a/briar-android/src/net/sf/briar/android/groups/WriteGroupPostActivity.java +++ b/briar-android/src/net/sf/briar/android/groups/WriteGroupPostActivity.java @@ -20,8 +20,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.identity.CreateIdentityActivity; import net.sf.briar.android.identity.LocalAuthorItem; import net.sf.briar.android.identity.LocalAuthorItemComparator; @@ -34,6 +32,7 @@ import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.KeyParser; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.Message; @@ -61,9 +60,6 @@ implements OnItemSelectedListener, OnClickListener { private static final Logger LOG = Logger.getLogger(WriteGroupPostActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - @Inject private CryptoComponent crypto; @Inject private MessageFactory messageFactory; private LocalAuthorSpinnerAdapter fromAdapter = null; @@ -77,6 +73,7 @@ implements OnItemSelectedListener, OnClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile LocalAuthor localAuthor = null; private volatile Group group = null; private volatile MessageId parentId = null; @@ -155,10 +152,6 @@ implements OnItemSelectedListener, OnClickListener { layout.addView(content); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -172,7 +165,7 @@ implements OnItemSelectedListener, OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<LocalAuthor> localAuthors = db.getLocalAuthors(); long duration = System.currentTimeMillis() - now; @@ -219,7 +212,7 @@ implements OnItemSelectedListener, OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); List<Group> groups = new ArrayList<Group>(); long now = System.currentTimeMillis(); for(Group g : db.getSubscriptions()) @@ -274,12 +267,6 @@ implements OnItemSelectedListener, OnClickListener { } } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if(parent == fromSpinner) { @@ -352,7 +339,7 @@ implements OnItemSelectedListener, OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); db.addLocalGroupMessage(m); long duration = System.currentTimeMillis() - now; diff --git a/briar-android/src/net/sf/briar/android/identity/CreateIdentityActivity.java b/briar-android/src/net/sf/briar/android/identity/CreateIdentityActivity.java index 48f1c6bfb960a0555a1c36ef34b4eb6e20d0a4f1..71e82cfbdde91193c24342c261ffa982b96a7221 100644 --- a/briar-android/src/net/sf/briar/android/identity/CreateIdentityActivity.java +++ b/briar-android/src/net/sf/briar/android/identity/CreateIdentityActivity.java @@ -20,8 +20,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.api.AuthorFactory; import net.sf.briar.api.LocalAuthor; import net.sf.briar.api.android.DatabaseUiExecutor; @@ -29,8 +27,8 @@ import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.CryptoExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; +import net.sf.briar.api.lifecycle.LifecycleManager; import roboguice.activity.RoboActivity; -import android.content.Intent; import android.os.Bundle; import android.view.KeyEvent; import android.view.View; @@ -51,9 +49,6 @@ implements OnEditorActionListener, OnClickListener { private static final Logger LOG = Logger.getLogger(CreateIdentityActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - @Inject @CryptoExecutor private Executor cryptoExecutor; private EditText nicknameEntry = null; private Button createButton = null; @@ -64,6 +59,7 @@ implements OnEditorActionListener, OnClickListener { @Inject private volatile AuthorFactory authorFactory; @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; @Override public void onCreate(Bundle state) { @@ -109,16 +105,6 @@ implements OnEditorActionListener, OnClickListener { layout.addView(progress); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); - } - - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); } public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) { @@ -154,7 +140,7 @@ implements OnEditorActionListener, OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); db.addLocalAuthor(a); db.setRating(a.getId(), GOOD); diff --git a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java index 926ce1df0e891921122d7844705cef21f35801b4..204df03fe08ab8609d8c279fcaeeeed0f3d7596f 100644 --- a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java +++ b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java @@ -12,8 +12,6 @@ import java.util.Collection; import java.util.concurrent.Executor; import java.util.logging.Logger; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.identity.LocalAuthorItem; import net.sf.briar.android.identity.LocalAuthorItemComparator; import net.sf.briar.android.identity.LocalAuthorSpinnerAdapter; @@ -28,6 +26,7 @@ import net.sf.briar.api.invitation.InvitationListener; import net.sf.briar.api.invitation.InvitationState; import net.sf.briar.api.invitation.InvitationTask; import net.sf.briar.api.invitation.InvitationTaskFactory; +import net.sf.briar.api.lifecycle.LifecycleManager; import roboguice.activity.RoboActivity; import android.bluetooth.BluetoothAdapter; import android.content.BroadcastReceiver; @@ -46,9 +45,6 @@ implements InvitationListener { private static final Logger LOG = Logger.getLogger(AddContactActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - @Inject private CryptoComponent crypto; @Inject private InvitationTaskFactory invitationTaskFactory; @Inject private ReferenceManager referenceManager; @@ -69,6 +65,7 @@ implements InvitationListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; @Override public void onCreate(Bundle state) { @@ -159,10 +156,6 @@ implements InvitationListener { if(info.getNetworkId() != -1) networkName = info.getSSID(); } view.wifiStateChanged(); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -190,7 +183,6 @@ implements InvitationListener { super.onDestroy(); if(task != null) task.removeListener(this); unregisterReceiver(receiver); - unbindService(serviceConnection); } void setView(AddContactView view) { @@ -216,7 +208,7 @@ implements InvitationListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<LocalAuthor> localAuthors = db.getLocalAuthors(); long duration = System.currentTimeMillis() - now; diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java index 31b28f953ad6111f694ab9c7b999d1cd65c0e5a9..3c6fc5cce9e05369b8a700e6282588b46df65c81 100644 --- a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java +++ b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java @@ -15,8 +15,6 @@ import java.util.logging.Logger; import net.sf.briar.R; import net.sf.briar.android.AscendingHeaderComparator; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.widgets.HorizontalBorder; import net.sf.briar.android.widgets.ListLoadingProgressBar; import net.sf.briar.api.AuthorId; @@ -31,6 +29,7 @@ import net.sf.briar.api.db.event.DatabaseEvent; import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.db.event.MessageExpiredEvent; import net.sf.briar.api.db.event.PrivateMessageAddedEvent; +import net.sf.briar.api.lifecycle.LifecycleManager; import roboguice.activity.RoboActivity; import android.content.Intent; import android.os.Bundle; @@ -50,9 +49,6 @@ implements DatabaseListener, OnClickListener, OnItemClickListener { private static final Logger LOG = Logger.getLogger(ConversationActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private String contactName = null; private ConversationAdapter adapter = null; private ListView list = null; @@ -61,6 +57,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile ContactId contactId = null; private volatile AuthorId localAuthorId = null; @@ -106,10 +103,6 @@ implements DatabaseListener, OnClickListener, OnItemClickListener { layout.addView(composeButton); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -123,7 +116,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<PrivateMessageHeader> headers = db.getPrivateMessageHeaders(contactId); @@ -196,12 +189,6 @@ implements DatabaseListener, OnClickListener, OnItemClickListener { db.removeListener(this); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void eventOccurred(DatabaseEvent e) { if(e instanceof ContactRemovedEvent) { ContactRemovedEvent c = (ContactRemovedEvent) e; diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java index 9486a615068b7d320175b920c198f968e83826ad..2ffb72ba6d7a23e630627b161b5ad0652a0076d3 100644 --- a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java +++ b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java @@ -15,8 +15,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.invitation.AddContactActivity; import net.sf.briar.android.widgets.HorizontalBorder; import net.sf.briar.android.widgets.ListLoadingProgressBar; @@ -32,6 +30,7 @@ import net.sf.briar.api.db.event.DatabaseEvent; import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.db.event.MessageExpiredEvent; import net.sf.briar.api.db.event.PrivateMessageAddedEvent; +import net.sf.briar.api.lifecycle.LifecycleManager; import roboguice.activity.RoboFragmentActivity; import android.content.Intent; import android.os.Bundle; @@ -49,9 +48,6 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener { private static final Logger LOG = Logger.getLogger(ConversationListActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private ConversationListAdapter adapter = null; private ListView list = null; private ListLoadingProgressBar loading = null; @@ -59,6 +55,7 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; @Override public void onCreate(Bundle state) { @@ -90,10 +87,6 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener { layout.addView(composeButton); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -108,7 +101,7 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); for(Contact c : db.getContacts()) { try { @@ -191,12 +184,6 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener { db.removeListener(this); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void onClick(View view) { if(adapter.isEmpty()) { NoContactsDialog dialog = new NoContactsDialog(); @@ -225,7 +212,7 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Contact contact = db.getContact(c); Collection<PrivateMessageHeader> headers = diff --git a/briar-android/src/net/sf/briar/android/messages/ReadPrivateMessageActivity.java b/briar-android/src/net/sf/briar/android/messages/ReadPrivateMessageActivity.java index 5d6245229a2ad648380cd11e01053584c4e91ba2..5a66b32039897d452719ebc70de3c3ece2dc8120 100644 --- a/briar-android/src/net/sf/briar/android/messages/ReadPrivateMessageActivity.java +++ b/briar-android/src/net/sf/briar/android/messages/ReadPrivateMessageActivity.java @@ -19,8 +19,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.widgets.HorizontalBorder; import net.sf.briar.android.widgets.HorizontalSpace; import net.sf.briar.api.ContactId; @@ -28,6 +26,7 @@ import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.NoSuchMessageException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.MessageId; import net.sf.briar.api.messaging.Rating; import roboguice.activity.RoboActivity; @@ -55,9 +54,6 @@ implements OnClickListener { private static final Logger LOG = Logger.getLogger(ReadPrivateMessageActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private ContactId contactId = null; private Rating rating = UNRATED; private boolean read; @@ -68,6 +64,7 @@ implements OnClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; private volatile MessageId messageId = null; @Override @@ -190,17 +187,13 @@ implements OnClickListener { layout.addView(footer); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } private void setReadInDatabase(final boolean read) { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); db.setReadFlag(messageId, read); long duration = System.currentTimeMillis() - now; @@ -233,7 +226,7 @@ implements OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); byte[] body = db.getMessageBody(messageId); long duration = System.currentTimeMillis() - now; @@ -272,12 +265,6 @@ implements OnClickListener { state.putBoolean("net.sf.briar.READ", read); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void onClick(View view) { if(view == readButton) { setReadInDatabase(!read); diff --git a/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java b/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java index f0b4b6bac2f5322b0de038a851f61d9ebb12b523..78c46c01718c74d6712ae0ce6e4b75cd5a85da77 100644 --- a/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java +++ b/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java @@ -17,8 +17,6 @@ import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.R; -import net.sf.briar.android.BriarService; -import net.sf.briar.android.BriarService.BriarServiceConnection; import net.sf.briar.android.contact.ContactItem; import net.sf.briar.android.contact.ContactItemComparator; import net.sf.briar.android.contact.ContactSpinnerAdapter; @@ -31,6 +29,7 @@ import net.sf.briar.api.LocalAuthor; import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.messaging.Message; import net.sf.briar.api.messaging.MessageFactory; import net.sf.briar.api.messaging.MessageId; @@ -56,9 +55,6 @@ implements OnItemSelectedListener, OnClickListener { private static final Logger LOG = Logger.getLogger(WritePrivateMessageActivity.class.getName()); - private final BriarServiceConnection serviceConnection = - new BriarServiceConnection(); - private TextView from = null; private ContactSpinnerAdapter adapter = null; private Spinner spinner = null; @@ -68,6 +64,7 @@ implements OnItemSelectedListener, OnClickListener { // Fields that are accessed from background threads must be volatile @Inject private volatile DatabaseComponent db; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; + @Inject private volatile LifecycleManager lifecycleManager; @Inject private volatile MessageFactory messageFactory; private volatile LocalAuthor localAuthor = null; private volatile ContactId contactId = null; @@ -139,10 +136,6 @@ implements OnItemSelectedListener, OnClickListener { layout.addView(content); setContentView(layout); - - // Bind to the service so we can wait for it to start - bindService(new Intent(BriarService.class.getName()), - serviceConnection, 0); } @Override @@ -155,7 +148,7 @@ implements OnItemSelectedListener, OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); Collection<Contact> contacts = db.getContacts(); long duration = System.currentTimeMillis() - now; @@ -201,12 +194,6 @@ implements OnItemSelectedListener, OnClickListener { state.putInt("net.sf.briar.CONTACT_ID", contactId.getInt()); } - @Override - public void onDestroy() { - super.onDestroy(); - unbindService(serviceConnection); - } - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { ContactItem item = adapter.getItem(position); @@ -227,7 +214,7 @@ implements OnItemSelectedListener, OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); long now = System.currentTimeMillis(); localAuthor = db.getLocalAuthor(a); long duration = System.currentTimeMillis() - now; @@ -277,7 +264,7 @@ implements OnItemSelectedListener, OnClickListener { dbUiExecutor.execute(new Runnable() { public void run() { try { - serviceConnection.waitForDatabase(); + lifecycleManager.waitForDatabase(); Message m = messageFactory.createPrivateMessage(parentId, "text/plain", body); long now = System.currentTimeMillis(); diff --git a/briar-api/src/net/sf/briar/api/lifecycle/LifecycleManager.java b/briar-api/src/net/sf/briar/api/lifecycle/LifecycleManager.java new file mode 100644 index 0000000000000000000000000000000000000000..acbe586ae9d91348faeaea62ea002248670ca927 --- /dev/null +++ b/briar-api/src/net/sf/briar/api/lifecycle/LifecycleManager.java @@ -0,0 +1,19 @@ +package net.sf.briar.api.lifecycle; + +public interface LifecycleManager { + + /** Starts any services that need to be started at startup. */ + public void startServices(); + + /** Stops any services that need to be stopped at shutdown. */ + public void stopServices(); + + /** Waits for the database to be opened before returning. */ + public void waitForDatabase() throws InterruptedException; + + /** Waits for all services to start before returning. */ + public void waitForStartup() throws InterruptedException; + + /** Waits for all services to stop before returning. */ + public void waitForShutdown() throws InterruptedException; +} diff --git a/briar-core/src/net/sf/briar/reliability/ReliabilityExecutor.java b/briar-api/src/net/sf/briar/api/reliability/ReliabilityExecutor.java similarity index 82% rename from briar-core/src/net/sf/briar/reliability/ReliabilityExecutor.java rename to briar-api/src/net/sf/briar/api/reliability/ReliabilityExecutor.java index d5ce36047531c95876261ea6102444581875b019..a7ca755f3da933c883e3657d9c053376a22445fd 100644 --- a/briar-core/src/net/sf/briar/reliability/ReliabilityExecutor.java +++ b/briar-api/src/net/sf/briar/api/reliability/ReliabilityExecutor.java @@ -1,4 +1,4 @@ -package net.sf.briar.reliability; +package net.sf.briar.api.reliability; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -12,4 +12,4 @@ import com.google.inject.BindingAnnotation; @BindingAnnotation @Target({ PARAMETER }) @Retention(RUNTIME) -@interface ReliabilityExecutor {} \ No newline at end of file +public @interface ReliabilityExecutor {} \ No newline at end of file diff --git a/briar-core/src/net/sf/briar/transport/IncomingConnectionExecutor.java b/briar-api/src/net/sf/briar/api/transport/IncomingConnectionExecutor.java similarity index 82% rename from briar-core/src/net/sf/briar/transport/IncomingConnectionExecutor.java rename to briar-api/src/net/sf/briar/api/transport/IncomingConnectionExecutor.java index 6bad0c126c04b805fc7820b30ffef90aeec10d92..e3048a1eb5730c2d09fd11b3f872cd539b47d879 100644 --- a/briar-core/src/net/sf/briar/transport/IncomingConnectionExecutor.java +++ b/briar-api/src/net/sf/briar/api/transport/IncomingConnectionExecutor.java @@ -1,4 +1,4 @@ -package net.sf.briar.transport; +package net.sf.briar.api.transport; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -14,4 +14,4 @@ import com.google.inject.BindingAnnotation; @BindingAnnotation @Target({ PARAMETER }) @Retention(RUNTIME) -@interface IncomingConnectionExecutor {} \ No newline at end of file +public @interface IncomingConnectionExecutor {} \ No newline at end of file diff --git a/briar-core/src/net/sf/briar/crypto/CryptoModule.java b/briar-core/src/net/sf/briar/crypto/CryptoModule.java index d006d07c8ca4627acd035eba6fa119c1b3f67500..2f23bfc6306408c862433de96d5be7e026aa8a56 100644 --- a/briar-core/src/net/sf/briar/crypto/CryptoModule.java +++ b/briar-core/src/net/sf/briar/crypto/CryptoModule.java @@ -1,27 +1,22 @@ package net.sf.briar.crypto; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.CryptoExecutor; -import net.sf.briar.util.BoundedExecutor; import com.google.inject.AbstractModule; import com.google.inject.Singleton; public class CryptoModule extends AbstractModule { - // FIXME: Determine suitable values for these constants empirically - - /** - * The maximum number of tasks that can be queued for execution before - * submitting another task will block. - */ - private static final int MAX_QUEUED_EXECUTOR_TASKS = 10; - - /** The minimum number of executor threads to keep in the pool. */ - private static final int MIN_EXECUTOR_THREADS = 1; - /** The maximum number of executor threads. */ private static final int MAX_EXECUTOR_THREADS = Runtime.getRuntime().availableProcessors(); @@ -30,9 +25,16 @@ public class CryptoModule extends AbstractModule { protected void configure() { bind(CryptoComponent.class).to( CryptoComponentImpl.class).in(Singleton.class); - // The executor is bounded, so tasks must be independent and short-lived - bind(Executor.class).annotatedWith(CryptoExecutor.class).toInstance( - new BoundedExecutor(MAX_QUEUED_EXECUTOR_TASKS, - MIN_EXECUTOR_THREADS, MAX_EXECUTOR_THREADS)); + // The queue is unbounded, so tasks can be dependent + BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(); + // Discard tasks that are submitted during shutdown + RejectedExecutionHandler policy = + new ThreadPoolExecutor.DiscardPolicy(); + // Create a limited # of threads and keep them in the pool for 60 secs + ExecutorService e = new ThreadPoolExecutor(0, MAX_EXECUTOR_THREADS, + 60, SECONDS, queue, policy); + bind(Executor.class).annotatedWith(CryptoExecutor.class).toInstance(e); + bind(ExecutorService.class).annotatedWith( + CryptoExecutor.class).toInstance(e); } } diff --git a/briar-core/src/net/sf/briar/db/DatabaseModule.java b/briar-core/src/net/sf/briar/db/DatabaseModule.java index a500f9cf93a5272decfcd0794f4ace09a4085917..e038be9c9ae854f5914c3d9d924221a4526fadb9 100644 --- a/briar-core/src/net/sf/briar/db/DatabaseModule.java +++ b/briar-core/src/net/sf/briar/db/DatabaseModule.java @@ -1,11 +1,13 @@ package net.sf.briar.db; -import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; import java.sql.Connection; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; import net.sf.briar.api.clock.Clock; @@ -21,24 +23,24 @@ import com.google.inject.Singleton; public class DatabaseModule extends AbstractModule { - /** - * The maximum number of database threads. When a task is submitted to the - * database executor and no thread is available to run it, the task will be - * queued. - */ - private static final int MAX_DB_THREADS = 10; - - /** How many milliseconds to keep idle threads alive. */ - private static final int DB_KEEPALIVE = 60 * 1000; + /** The maximum number of executor threads. */ + private static final int MAX_EXECUTOR_THREADS = 10; @Override protected void configure() { bind(DatabaseCleaner.class).to(DatabaseCleanerImpl.class); - // Use an unbounded queue to prevent deadlock between submitted tasks + // The queue is unbounded, so tasks can be dependent BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(); - bind(Executor.class).annotatedWith(DatabaseExecutor.class).toInstance( - new ThreadPoolExecutor(MAX_DB_THREADS, MAX_DB_THREADS, - DB_KEEPALIVE, MILLISECONDS, queue)); + // Discard tasks that are submitted during shutdown + RejectedExecutionHandler policy = + new ThreadPoolExecutor.DiscardPolicy(); + // Create a limited # of threads and keep them in the pool for 60 secs + ExecutorService e = new ThreadPoolExecutor(0, MAX_EXECUTOR_THREADS, + 60, SECONDS, queue, policy); + bind(Executor.class).annotatedWith( + DatabaseExecutor.class).toInstance(e); + bind(ExecutorService.class).annotatedWith( + DatabaseExecutor.class).toInstance(e); } @Provides diff --git a/briar-core/src/net/sf/briar/lifecycle/LifecycleManagerImpl.java b/briar-core/src/net/sf/briar/lifecycle/LifecycleManagerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..d0c414cf31ff302a2a12b3b983028a559badc030 --- /dev/null +++ b/briar-core/src/net/sf/briar/lifecycle/LifecycleManagerImpl.java @@ -0,0 +1,116 @@ +package net.sf.briar.lifecycle; + +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.logging.Logger; + +import net.sf.briar.api.crypto.CryptoExecutor; +import net.sf.briar.api.crypto.KeyManager; +import net.sf.briar.api.db.DatabaseComponent; +import net.sf.briar.api.db.DatabaseExecutor; +import net.sf.briar.api.db.DbException; +import net.sf.briar.api.lifecycle.LifecycleManager; +import net.sf.briar.api.plugins.PluginExecutor; +import net.sf.briar.api.plugins.PluginManager; +import net.sf.briar.api.reliability.ReliabilityExecutor; +import net.sf.briar.api.transport.IncomingConnectionExecutor; + +import com.google.inject.Inject; + +class LifecycleManagerImpl implements LifecycleManager { + + private static final Logger LOG = + Logger.getLogger(LifecycleManagerImpl.class.getName()); + + private final DatabaseComponent db; + private final KeyManager keyManager; + private final PluginManager pluginManager; + private final ExecutorService cryptoExecutor; + private final ExecutorService dbExecutor; + private final ExecutorService connExecutor; + private final ExecutorService pluginExecutor; + private final ExecutorService reliabilityExecutor; + private final CountDownLatch dbLatch = new CountDownLatch(1); + private final CountDownLatch startupLatch = new CountDownLatch(1); + private final CountDownLatch shutdownLatch = new CountDownLatch(1); + + @Inject + LifecycleManagerImpl(DatabaseComponent db, KeyManager keyManager, + PluginManager pluginManager, + @CryptoExecutor ExecutorService cryptoExecutor, + @DatabaseExecutor ExecutorService dbExecutor, + @IncomingConnectionExecutor ExecutorService connExecutor, + @PluginExecutor ExecutorService pluginExecutor, + @ReliabilityExecutor ExecutorService reliabilityExecutor) { + this.db = db; + this.keyManager = keyManager; + this.pluginManager = pluginManager; + this.cryptoExecutor = cryptoExecutor; + this.dbExecutor = dbExecutor; + this.connExecutor = connExecutor; + this.pluginExecutor = pluginExecutor; + this.reliabilityExecutor = reliabilityExecutor; + } + + public void startServices() { + try { + if(LOG.isLoggable(INFO)) LOG.info("Starting"); + boolean reopened = db.open(); + if(LOG.isLoggable(INFO)) { + if(reopened) LOG.info("Database reopened"); + else LOG.info("Database created"); + } + dbLatch.countDown(); + keyManager.start(); + if(LOG.isLoggable(INFO)) LOG.info("Key manager started"); + int pluginsStarted = pluginManager.start(); + if(LOG.isLoggable(INFO)) + LOG.info(pluginsStarted + " plugins started"); + startupLatch.countDown(); + } catch(DbException e) { + if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + } catch(IOException e) { + if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + } + } + + public void stopServices() { + try { + if(LOG.isLoggable(INFO)) LOG.info("Shutting down"); + int pluginsStopped = pluginManager.stop(); + if(LOG.isLoggable(INFO)) + LOG.info(pluginsStopped + " plugins stopped"); + keyManager.stop(); + if(LOG.isLoggable(INFO)) LOG.info("Key manager stopped"); + db.close(); + if(LOG.isLoggable(INFO)) LOG.info("Database closed"); + cryptoExecutor.shutdownNow(); + dbExecutor.shutdownNow(); + connExecutor.shutdownNow(); + pluginExecutor.shutdownNow(); + reliabilityExecutor.shutdownNow(); + if(LOG.isLoggable(INFO)) LOG.info("Executors shut down"); + shutdownLatch.countDown(); + } catch(DbException e) { + if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + } catch(IOException e) { + if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + } + } + + public void waitForDatabase() throws InterruptedException { + dbLatch.await(); + } + + public void waitForStartup() throws InterruptedException { + startupLatch.await(); + } + + public void waitForShutdown() throws InterruptedException { + shutdownLatch.await(); + } +} diff --git a/briar-core/src/net/sf/briar/lifecycle/LifecycleModule.java b/briar-core/src/net/sf/briar/lifecycle/LifecycleModule.java index 241e41a09ae3963d87ceb47586e8d975744b3031..f4b214dea4ecd3acb50a195af420191e8bf3535b 100644 --- a/briar-core/src/net/sf/briar/lifecycle/LifecycleModule.java +++ b/briar-core/src/net/sf/briar/lifecycle/LifecycleModule.java @@ -1,14 +1,18 @@ package net.sf.briar.lifecycle; +import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.lifecycle.ShutdownManager; import net.sf.briar.util.OsUtils; import com.google.inject.AbstractModule; +import com.google.inject.Singleton; public class LifecycleModule extends AbstractModule { @Override protected void configure() { + bind(LifecycleManager.class).to(LifecycleManagerImpl.class).in( + Singleton.class); if(OsUtils.isWindows()) bind(ShutdownManager.class).to(WindowsShutdownManagerImpl.class); else bind(ShutdownManager.class).to(ShutdownManagerImpl.class); diff --git a/briar-core/src/net/sf/briar/plugins/JavaSePluginsModule.java b/briar-core/src/net/sf/briar/plugins/JavaSePluginsModule.java index 894f99df467425d44e835b5ff9876deaff7540a1..762a32e0afd650b61f98b5e7b9ab978eb10dab94 100644 --- a/briar-core/src/net/sf/briar/plugins/JavaSePluginsModule.java +++ b/briar-core/src/net/sf/briar/plugins/JavaSePluginsModule.java @@ -2,7 +2,7 @@ package net.sf.briar.plugins; import java.util.Arrays; import java.util.Collection; -import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executor; import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.lifecycle.ShutdownManager; @@ -28,7 +28,7 @@ public class JavaSePluginsModule extends AbstractModule { @Provides SimplexPluginConfig getSimplexPluginConfig( - @PluginExecutor ExecutorService pluginExecutor) { + @PluginExecutor Executor pluginExecutor) { SimplexPluginFactory removable = new RemovableDrivePluginFactory(pluginExecutor); final Collection<SimplexPluginFactory> factories = @@ -42,7 +42,7 @@ public class JavaSePluginsModule extends AbstractModule { @Provides DuplexPluginConfig getDuplexPluginConfig( - @PluginExecutor ExecutorService pluginExecutor, + @PluginExecutor Executor pluginExecutor, CryptoComponent crypto, ReliabilityLayerFactory reliabilityFactory, ShutdownManager shutdownManager) { DuplexPluginFactory bluetooth = new BluetoothPluginFactory( diff --git a/briar-core/src/net/sf/briar/plugins/PluginManagerImpl.java b/briar-core/src/net/sf/briar/plugins/PluginManagerImpl.java index 90b69bda0bb794fdd3f79eae614f68389a8ade09..bd259b8e595107d5bbce62055ae21d5256ba1443 100644 --- a/briar-core/src/net/sf/briar/plugins/PluginManagerImpl.java +++ b/briar-core/src/net/sf/briar/plugins/PluginManagerImpl.java @@ -11,7 +11,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; @@ -19,7 +19,6 @@ import net.sf.briar.api.ContactId; import net.sf.briar.api.TransportConfig; import net.sf.briar.api.TransportId; import net.sf.briar.api.TransportProperties; -import net.sf.briar.api.android.AndroidExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; import net.sf.briar.api.plugins.Plugin; @@ -49,8 +48,7 @@ class PluginManagerImpl implements PluginManager { private static final Logger LOG = Logger.getLogger(PluginManagerImpl.class.getName()); - private final ExecutorService pluginExecutor; - private final AndroidExecutor androidExecutor; + private final Executor pluginExecutor; private final SimplexPluginConfig simplexPluginConfig; private final DuplexPluginConfig duplexPluginConfig; private final DatabaseComponent db; @@ -61,14 +59,12 @@ class PluginManagerImpl implements PluginManager { private final List<DuplexPlugin> duplexPlugins; @Inject - PluginManagerImpl(@PluginExecutor ExecutorService pluginExecutor, - AndroidExecutor androidExecutor, + PluginManagerImpl(@PluginExecutor Executor pluginExecutor, SimplexPluginConfig simplexPluginConfig, DuplexPluginConfig duplexPluginConfig, DatabaseComponent db, Poller poller, ConnectionDispatcher dispatcher, UiCallback uiCallback) { this.pluginExecutor = pluginExecutor; - this.androidExecutor = androidExecutor; this.simplexPluginConfig = simplexPluginConfig; this.duplexPluginConfig = duplexPluginConfig; this.db = db; @@ -144,10 +140,6 @@ class PluginManagerImpl implements PluginManager { Thread.currentThread().interrupt(); return 0; } - // Shut down the executors - if(LOG.isLoggable(INFO)) LOG.info("Stopping executors"); - pluginExecutor.shutdown(); - androidExecutor.shutdown(); // Return the number of plugins successfully stopped return stopped.get(); } diff --git a/briar-core/src/net/sf/briar/plugins/PluginsModule.java b/briar-core/src/net/sf/briar/plugins/PluginsModule.java index 3653e6bb2b064942ea0786ab90ddea2d84c34fcd..6b584b38ac2acc57047cbeeba0bd7149f44b543b 100644 --- a/briar-core/src/net/sf/briar/plugins/PluginsModule.java +++ b/briar-core/src/net/sf/briar/plugins/PluginsModule.java @@ -1,7 +1,13 @@ package net.sf.briar.plugins; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; import net.sf.briar.api.plugins.PluginExecutor; import net.sf.briar.api.plugins.PluginManager; @@ -13,12 +19,19 @@ public class PluginsModule extends AbstractModule { @Override protected void configure() { - // The executor is unbounded, so tasks can be dependent or long-lived - ExecutorService e = Executors.newCachedThreadPool(); - bind(ExecutorService.class).annotatedWith( - PluginExecutor.class).toInstance(e); bind(PluginManager.class).to( PluginManagerImpl.class).in(Singleton.class); bind(Poller.class).to(PollerImpl.class); + // The thread pool is unbounded, so use direct handoff + BlockingQueue<Runnable> queue = new SynchronousQueue<Runnable>(); + // Discard tasks that are submitted during shutdown + RejectedExecutionHandler policy = + new ThreadPoolExecutor.DiscardPolicy(); + // Create threads as required and keep them in the pool for 60 seconds + ExecutorService e = new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60, SECONDS, queue, policy); + bind(Executor.class).annotatedWith(PluginExecutor.class).toInstance(e); + bind(ExecutorService.class).annotatedWith( + PluginExecutor.class).toInstance(e); } } diff --git a/briar-core/src/net/sf/briar/plugins/PollerImpl.java b/briar-core/src/net/sf/briar/plugins/PollerImpl.java index c5ea77feaba4897a7a6a28fe3289b1c52eb3736b..30a356feef1aacd5eaf62f7c42236dd5c26ba855 100644 --- a/briar-core/src/net/sf/briar/plugins/PollerImpl.java +++ b/briar-core/src/net/sf/briar/plugins/PollerImpl.java @@ -5,7 +5,7 @@ import static java.util.logging.Level.INFO; import java.util.Collection; import java.util.SortedSet; import java.util.TreeSet; -import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executor; import java.util.logging.Logger; import net.sf.briar.api.ContactId; @@ -21,13 +21,13 @@ class PollerImpl implements Poller, Runnable { private static final Logger LOG = Logger.getLogger(PollerImpl.class.getName()); - private final ExecutorService pluginExecutor; + private final Executor pluginExecutor; private final ConnectionRegistry connRegistry; private final Clock clock; private final SortedSet<PollTime> pollTimes; @Inject - PollerImpl(@PluginExecutor ExecutorService pluginExecutor, + PollerImpl(@PluginExecutor Executor pluginExecutor, ConnectionRegistry connRegistry, Clock clock) { this.pluginExecutor = pluginExecutor; this.connRegistry = connRegistry; @@ -71,7 +71,7 @@ class PollerImpl implements Poller, Runnable { connRegistry.getConnectedContacts(p.plugin.getId()); if(LOG.isLoggable(INFO)) LOG.info("Polling " + p.plugin.getClass().getName()); - pluginExecutor.submit(new Runnable() { + pluginExecutor.execute(new Runnable() { public void run() { p.plugin.poll(connected); } diff --git a/briar-core/src/net/sf/briar/reliability/ReliabilityLayerFactoryImpl.java b/briar-core/src/net/sf/briar/reliability/ReliabilityLayerFactoryImpl.java index 4b207b1cda0de7fdca28561f9e7c479cf161bba0..411f817b0737682cb00b447573d266f16f713681 100644 --- a/briar-core/src/net/sf/briar/reliability/ReliabilityLayerFactoryImpl.java +++ b/briar-core/src/net/sf/briar/reliability/ReliabilityLayerFactoryImpl.java @@ -4,6 +4,7 @@ import java.util.concurrent.Executor; import net.sf.briar.api.clock.Clock; import net.sf.briar.api.clock.SystemClock; +import net.sf.briar.api.reliability.ReliabilityExecutor; import net.sf.briar.api.reliability.ReliabilityLayer; import net.sf.briar.api.reliability.ReliabilityLayerFactory; import net.sf.briar.api.reliability.WriteHandler; diff --git a/briar-core/src/net/sf/briar/reliability/ReliabilityModule.java b/briar-core/src/net/sf/briar/reliability/ReliabilityModule.java index a30ae78d7980b2fcb6efab4cacbf198476906ae2..37d4a610efa64c15a2b5568f93741a0c9f765f5b 100644 --- a/briar-core/src/net/sf/briar/reliability/ReliabilityModule.java +++ b/briar-core/src/net/sf/briar/reliability/ReliabilityModule.java @@ -1,8 +1,15 @@ package net.sf.briar.reliability; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; -import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import net.sf.briar.api.reliability.ReliabilityExecutor; import net.sf.briar.api.reliability.ReliabilityLayerFactory; import com.google.inject.AbstractModule; @@ -11,11 +18,19 @@ public class ReliabilityModule extends AbstractModule { @Override protected void configure() { - // The executor is unbounded - tasks are expected to be long-lived - Executor e = Executors.newCachedThreadPool(); - bind(Executor.class).annotatedWith( - ReliabilityExecutor.class).toInstance(e); bind(ReliabilityLayerFactory.class).to( ReliabilityLayerFactoryImpl.class); + // The thread pool is unbounded, so use direct handoff + BlockingQueue<Runnable> queue = new SynchronousQueue<Runnable>(); + // Discard tasks that are submitted during shutdown + RejectedExecutionHandler policy = + new ThreadPoolExecutor.DiscardPolicy(); + // Create threads as required and keep them in the pool for 60 seconds + ExecutorService e = new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60, SECONDS, queue, policy); + bind(Executor.class).annotatedWith( + ReliabilityExecutor.class).toInstance(e); + bind(ExecutorService.class).annotatedWith( + ReliabilityExecutor.class).toInstance(e); } } diff --git a/briar-core/src/net/sf/briar/transport/ConnectionDispatcherImpl.java b/briar-core/src/net/sf/briar/transport/ConnectionDispatcherImpl.java index ddb612ba03f005ff7bad1e31ea1a8680372dc0a7..ecd57aa2b73f5846223b77ac95d4137b006cc293 100644 --- a/briar-core/src/net/sf/briar/transport/ConnectionDispatcherImpl.java +++ b/briar-core/src/net/sf/briar/transport/ConnectionDispatcherImpl.java @@ -20,6 +20,7 @@ import net.sf.briar.api.plugins.simplex.SimplexTransportWriter; import net.sf.briar.api.transport.ConnectionContext; import net.sf.briar.api.transport.ConnectionDispatcher; import net.sf.briar.api.transport.ConnectionRecogniser; +import net.sf.briar.api.transport.IncomingConnectionExecutor; import com.google.inject.Inject; diff --git a/briar-core/src/net/sf/briar/transport/TransportModule.java b/briar-core/src/net/sf/briar/transport/TransportModule.java index 0cd57082f90724d6a5b80d2bd5c597f6597bf2c1..4985bc0654ecf61b69546f6b0c9b2c70a5fa6061 100644 --- a/briar-core/src/net/sf/briar/transport/TransportModule.java +++ b/briar-core/src/net/sf/briar/transport/TransportModule.java @@ -1,7 +1,13 @@ package net.sf.briar.transport; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; -import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; import net.sf.briar.api.crypto.KeyManager; import net.sf.briar.api.transport.ConnectionDispatcher; @@ -9,6 +15,7 @@ import net.sf.briar.api.transport.ConnectionReaderFactory; import net.sf.briar.api.transport.ConnectionRecogniser; import net.sf.briar.api.transport.ConnectionRegistry; import net.sf.briar.api.transport.ConnectionWriterFactory; +import net.sf.briar.api.transport.IncomingConnectionExecutor; import com.google.inject.AbstractModule; import com.google.inject.Singleton; @@ -25,10 +32,18 @@ public class TransportModule extends AbstractModule { bind(ConnectionRegistry.class).toInstance(new ConnectionRegistryImpl()); bind(ConnectionWriterFactory.class).to( ConnectionWriterFactoryImpl.class); - // The executor is unbounded, so tasks can be dependent or long-lived - Executor e = Executors.newCachedThreadPool(); + bind(KeyManager.class).to(KeyManagerImpl.class).in(Singleton.class); + // The thread pool is unbounded, so use direct handoff + BlockingQueue<Runnable> queue = new SynchronousQueue<Runnable>(); + // Discard tasks that are submitted during shutdown + RejectedExecutionHandler policy = + new ThreadPoolExecutor.DiscardPolicy(); + // Create threads as required and keep them in the pool for 60 seconds + ExecutorService e = new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60, SECONDS, queue, policy); bind(Executor.class).annotatedWith( IncomingConnectionExecutor.class).toInstance(e); - bind(KeyManager.class).to(KeyManagerImpl.class).in(Singleton.class); + bind(ExecutorService.class).annotatedWith( + IncomingConnectionExecutor.class).toInstance(e); } } diff --git a/briar-core/src/net/sf/briar/util/BoundedExecutor.java b/briar-core/src/net/sf/briar/util/BoundedExecutor.java deleted file mode 100644 index c7d77a8af253aec96a4c56cac6442785834b1b5d..0000000000000000000000000000000000000000 --- a/briar-core/src/net/sf/briar/util/BoundedExecutor.java +++ /dev/null @@ -1,58 +0,0 @@ -package net.sf.briar.util; - -import static java.util.concurrent.TimeUnit.SECONDS; -import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.Executor; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.Semaphore; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.logging.Logger; - -/** - * An executor that limits the number of concurrently executing tasks and the - * number of tasks queued for execution. - */ -public class BoundedExecutor implements Executor { - - private static final Logger LOG = - Logger.getLogger(BoundedExecutor.class.getName()); - - private final Semaphore semaphore; - private final BlockingQueue<Runnable> queue; - private final Executor executor; - - public BoundedExecutor(int maxQueued, int minThreads, int maxThreads) { - semaphore = new Semaphore(maxQueued + maxThreads); - queue = new LinkedBlockingQueue<Runnable>(); - executor = new ThreadPoolExecutor(minThreads, maxThreads, 60, SECONDS, - queue); - } - - public void execute(final Runnable r) { - try { - semaphore.acquire(); - executor.execute(new Runnable() { - public void run() { - try { - r.run(); - } finally { - semaphore.release(); - } - } - }); - } catch(InterruptedException e) { - if(LOG.isLoggable(INFO)) - LOG.info("Interrupted while queueing task"); - Thread.currentThread().interrupt(); - throw new RejectedExecutionException(); - } catch(RejectedExecutionException e) { - if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - semaphore.release(); - throw e; - } - } -} diff --git a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java index 76e5fecb386037b6e2d3b1cdfc2b93ec4f19ab99..ee0be61085707cf7bc221b0e0a0efd8098a7691f 100644 --- a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java +++ b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java @@ -48,6 +48,9 @@ import net.sf.briar.lifecycle.LifecycleModule; import net.sf.briar.messaging.MessagingModule; import net.sf.briar.messaging.duplex.DuplexMessagingModule; import net.sf.briar.messaging.simplex.SimplexMessagingModule; +import net.sf.briar.plugins.JavaSePluginsModule; +import net.sf.briar.plugins.PluginsModule; +import net.sf.briar.reliability.ReliabilityModule; import net.sf.briar.serial.SerialModule; import net.sf.briar.transport.TransportModule; @@ -79,9 +82,11 @@ public class ProtocolIntegrationTest extends BriarTestCase { public ProtocolIntegrationTest() throws Exception { super(); Injector i = Guice.createInjector(new TestDatabaseModule(), - new ClockModule(), new CryptoModule(), new DatabaseModule(), - new LifecycleModule(), new MessagingModule(), - new DuplexMessagingModule(), new SimplexMessagingModule(), + new TestUiModule(), new ClockModule(), new CryptoModule(), + new DatabaseModule(), new LifecycleModule(), + new MessagingModule(), new DuplexMessagingModule(), + new SimplexMessagingModule(), new PluginsModule(), + new JavaSePluginsModule(), new ReliabilityModule(), new SerialModule(), new TransportModule()); connectionReaderFactory = i.getInstance(ConnectionReaderFactory.class); connectionWriterFactory = i.getInstance(ConnectionWriterFactory.class); diff --git a/briar-tests/src/net/sf/briar/TestUiModule.java b/briar-tests/src/net/sf/briar/TestUiModule.java new file mode 100644 index 0000000000000000000000000000000000000000..c8cd610b6caae2728a0647e37691a6a7f157b3e0 --- /dev/null +++ b/briar-tests/src/net/sf/briar/TestUiModule.java @@ -0,0 +1,24 @@ +package net.sf.briar; + +import net.sf.briar.api.ui.UiCallback; + +import com.google.inject.AbstractModule; + +public class TestUiModule extends AbstractModule { + + @Override + protected void configure() { + bind(UiCallback.class).toInstance(new UiCallback() { + + public int showChoice(String[] options, String... message) { + return -1; + } + + public boolean showConfirmationMessage(String... message) { + return false; + } + + public void showMessage(String... message) {} + }); + } +} diff --git a/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java b/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java index 615c2e80699736fc20323e0b68e632c002e0b820..3d4c0bc6ad45c4fd749a54e5f4af15e79f370db2 100644 --- a/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java +++ b/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java @@ -9,6 +9,7 @@ import java.util.Random; import net.sf.briar.BriarTestCase; import net.sf.briar.TestDatabaseModule; +import net.sf.briar.TestUiModule; import net.sf.briar.TestUtils; import net.sf.briar.api.Author; import net.sf.briar.api.AuthorId; @@ -38,6 +39,9 @@ import net.sf.briar.lifecycle.LifecycleModule; import net.sf.briar.messaging.MessagingModule; import net.sf.briar.messaging.duplex.DuplexMessagingModule; import net.sf.briar.plugins.ImmediateExecutor; +import net.sf.briar.plugins.JavaSePluginsModule; +import net.sf.briar.plugins.PluginsModule; +import net.sf.briar.reliability.ReliabilityModule; import net.sf.briar.serial.SerialModule; import net.sf.briar.transport.TransportModule; @@ -80,11 +84,13 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { } private Injector createInjector(File dir) { - return Guice.createInjector(new ClockModule(), new CryptoModule(), + return Guice.createInjector(new TestDatabaseModule(dir), + new TestUiModule(), new ClockModule(), new CryptoModule(), new DatabaseModule(), new LifecycleModule(), - new MessagingModule(), new SerialModule(), - new TestDatabaseModule(dir), new SimplexMessagingModule(), - new TransportModule(), new DuplexMessagingModule()); + new MessagingModule(), new DuplexMessagingModule(), + new SimplexMessagingModule(), new PluginsModule(), + new JavaSePluginsModule(), new ReliabilityModule(), + new SerialModule(), new TransportModule()); } @Test diff --git a/briar-tests/src/net/sf/briar/plugins/PluginManagerImplTest.java b/briar-tests/src/net/sf/briar/plugins/PluginManagerImplTest.java index ed25414216b2ea502d63956f3724a05a13f8475d..d224b2f142bffc1fb55b33761cb4ad7b1b009df4 100644 --- a/briar-tests/src/net/sf/briar/plugins/PluginManagerImplTest.java +++ b/briar-tests/src/net/sf/briar/plugins/PluginManagerImplTest.java @@ -1,13 +1,12 @@ package net.sf.briar.plugins; import java.util.Arrays; -import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executor; import java.util.concurrent.Executors; import net.sf.briar.BriarTestCase; import net.sf.briar.TestUtils; import net.sf.briar.api.TransportId; -import net.sf.briar.api.android.AndroidExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.plugins.duplex.DuplexPlugin; import net.sf.briar.api.plugins.duplex.DuplexPluginCallback; @@ -29,9 +28,7 @@ public class PluginManagerImplTest extends BriarTestCase { @Test public void testStartAndStop() throws Exception { Mockery context = new Mockery(); - final ExecutorService pluginExecutor = Executors.newCachedThreadPool(); - final AndroidExecutor androidExecutor = - context.mock(AndroidExecutor.class); + final Executor pluginExecutor = Executors.newCachedThreadPool(); final SimplexPluginConfig simplexPluginConfig = context.mock(SimplexPluginConfig.class); final DuplexPluginConfig duplexPluginConfig = @@ -119,12 +116,10 @@ public class PluginManagerImplTest extends BriarTestCase { // Stop the plugins oneOf(simplexPlugin).stop(); oneOf(duplexPlugin).stop(); - // Shut down the executor - oneOf(androidExecutor).shutdown(); }}); PluginManagerImpl p = new PluginManagerImpl(pluginExecutor, - androidExecutor, simplexPluginConfig, duplexPluginConfig, db, - poller, dispatcher, uiCallback); + simplexPluginConfig, duplexPluginConfig, db, poller, + dispatcher, uiCallback); // Two plugins should be started and stopped assertEquals(2, p.start()); assertEquals(2, p.stop());