Bug 1408585 - Remove RepositorySession begin delegates r=rnewman draft
authorGrigory Kruglov <gkruglov@mozilla.com>
Fri, 13 Oct 2017 20:20:09 -0400
changeset 680405 2221246c7136f4f367b5c23c902587c4588dab8e
parent 680024 196dadb2fe500e75c6fbddcac78106648676cf10
child 680515 228b46fdff24b5ab0f2c874267c691a8662f9af8
child 680516 b21c64df98e21c6e0edbd6320f0134825fc7dc4c
child 680517 93d80ccd9c288d91329324fc4b9ee5216f08ba63
child 681974 7b97c17b6ae2581211f37d1ded4c7c88000a5a2f
push id84496
push userbmo:gkruglov@mozilla.com
push dateSat, 14 Oct 2017 00:20:51 +0000
reviewersrnewman
bugs1408585
milestone58.0a1
Bug 1408585 - Remove RepositorySession begin delegates r=rnewman 'begin' now throws in case things go wrong. MozReview-Commit-ID: 8jcxYiPcsii
mobile/android/base/android-services.mozbuild
mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/MiddlewareRepositorySession.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/RepositorySession.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/StoreTrackingRepositorySession.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BookmarksRepositorySession.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BookmarksValidationRepository.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/HistoryRepositorySession.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/delegates/DeferredRepositorySessionBeginDelegate.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/delegates/RepositorySessionBeginDelegate.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/ServerSyncStage.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/synchronizer/RecordsChannel.java
mobile/android/tests/background/junit3/background_junit3_sources.mozbuild
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestBookmarks.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/ThreadedRepositoryTestCase.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestStoreTracking.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultBeginDelegate.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginDelegate.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginFailDelegate.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessBeginDelegate.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WBORepository.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/SynchronizerHelpers.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionBeginDelegate.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WBORepository.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/middleware/test/TestCrypto5MiddlewareRepositorySession.java
--- a/mobile/android/base/android-services.mozbuild
+++ b/mobile/android/base/android-services.mozbuild
@@ -970,21 +970,19 @@ sync_java_files = [TOPSRCDIR + '/mobile/
     'sync/repositories/android/RepoUtils.java',
     'sync/repositories/android/SessionHelper.java',
     'sync/repositories/android/ThreadedRepository.java',
     'sync/repositories/android/VisitsHelper.java',
     'sync/repositories/BookmarkNeedsReparentingException.java',
     'sync/repositories/BookmarksRepository.java',
     'sync/repositories/ConfigurableServer15Repository.java',
     'sync/repositories/delegates/DeferrableRepositorySessionCreationDelegate.java',
-    'sync/repositories/delegates/DeferredRepositorySessionBeginDelegate.java',
     'sync/repositories/delegates/DeferredRepositorySessionFetchRecordsDelegate.java',
     'sync/repositories/delegates/DeferredRepositorySessionFinishDelegate.java',
     'sync/repositories/delegates/DeferredRepositorySessionStoreDelegate.java',
-    'sync/repositories/delegates/RepositorySessionBeginDelegate.java',
     'sync/repositories/delegates/RepositorySessionCleanDelegate.java',
     'sync/repositories/delegates/RepositorySessionCreationDelegate.java',
     'sync/repositories/delegates/RepositorySessionFetchRecordsDelegate.java',
     'sync/repositories/delegates/RepositorySessionFinishDelegate.java',
     'sync/repositories/delegates/RepositorySessionStoreDelegate.java',
     'sync/repositories/delegates/RepositorySessionWipeDelegate.java',
     'sync/repositories/domain/BookmarkRecord.java',
     'sync/repositories/domain/BookmarkRecordFactory.java',
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/MiddlewareRepositorySession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/MiddlewareRepositorySession.java
@@ -1,22 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.middleware;
 
 import java.util.concurrent.ExecutorService;
 
-import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 
 public abstract class MiddlewareRepositorySession extends RepositorySession {
   private static final String LOG_TAG = "MiddlewareSession";
   protected final RepositorySession inner;
 
   public MiddlewareRepositorySession(RepositorySession innerSession, MiddlewareRepository repository) {
@@ -24,64 +23,19 @@ public abstract class MiddlewareReposito
     this.inner = innerSession;
   }
 
   @Override
   public void wipe(RepositorySessionWipeDelegate delegate) {
     inner.wipe(delegate);
   }
 
-  public class MiddlewareRepositorySessionBeginDelegate implements RepositorySessionBeginDelegate {
-
-    private final MiddlewareRepositorySession outerSession;
-    private final RepositorySessionBeginDelegate next;
-
-    public MiddlewareRepositorySessionBeginDelegate(MiddlewareRepositorySession outerSession, RepositorySessionBeginDelegate next) {
-      this.outerSession = outerSession;
-      this.next = next;
-    }
-
-    @Override
-    public void onBeginFailed(Exception ex) {
-      next.onBeginFailed(ex);
-    }
-
-    @Override
-    public void onBeginSucceeded(RepositorySession session) {
-      next.onBeginSucceeded(outerSession);
-    }
-
-    @Override
-    public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
-      final RepositorySessionBeginDelegate deferred = next.deferredBeginDelegate(executor);
-      return new RepositorySessionBeginDelegate() {
-        @Override
-        public void onBeginSucceeded(RepositorySession session) {
-          if (inner != session) {
-            Logger.warn(LOG_TAG, "Got onBeginSucceeded for session " + session + ", not our inner session!");
-          }
-          deferred.onBeginSucceeded(outerSession);
-        }
-
-        @Override
-        public void onBeginFailed(Exception ex) {
-          deferred.onBeginFailed(ex);
-        }
-
-        @Override
-        public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
-          return this;
-        }
-      };
-    }
-  }
-
   @Override
-  public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
-    inner.begin(new MiddlewareRepositorySessionBeginDelegate(this, delegate));
+  public void begin() throws SyncException {
+    inner.begin();
   }
 
   public class MiddlewareRepositorySessionFinishDelegate implements RepositorySessionFinishDelegate {
     private final MiddlewareRepositorySession outerSession;
     private final RepositorySessionFinishDelegate next;
 
     public MiddlewareRepositorySessionFinishDelegate(MiddlewareRepositorySession outerSession, RepositorySessionFinishDelegate next) {
       this.outerSession = outerSession;
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/RepositorySession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/RepositorySession.java
@@ -1,39 +1,36 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories;
 
-import android.support.annotation.Nullable;
-import android.util.Log;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 /**
  * A <code>RepositorySession</code> is created and used thusly:
  *
  *<ul>
  * <li>Construct, with a reference to its parent {@link Repository}, by calling
  *   {@link Repository#createSession(org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate, android.content.Context)}.</li>
  * <li>Populate with saved information by calling {@link #unbundle(RepositorySessionBundle)}.</li>
- * <li>Begin a sync by calling {@link #begin(RepositorySessionBeginDelegate)}. <code>begin()</code>
+ * <li>Begin a sync by calling {@link #begin()}. <code>begin()</code>
  *   is an appropriate place to initialize expensive resources.</li>
  * <li>Perform operations such as {@link #fetchModified(RepositorySessionFetchRecordsDelegate)} and
  *   {@link #store(Record)}.</li>
  * <li>Finish by calling {@link #finish(RepositorySessionFinishDelegate)}, retrieving and storing
  *   the current bundle.</li>
  *</ul>
  *
  * If <code>finish()</code> is not called, {@link #abort()} must be called. These calls must
@@ -214,22 +211,20 @@ public abstract class RepositorySession 
     }
     this.transitionFrom(SessionStatus.UNSTARTED, SessionStatus.ACTIVE);
   }
 
   /**
    * Start the session. This is an appropriate place to initialize
    * data access components such as database handles.
    *
-   * @param delegate
    * @throws InvalidSessionTransitionException
    */
-  public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
+  public void begin() throws SyncException {
     sharedBegin();
-    delegate.deferredBeginDelegate(delegateQueue).onBeginSucceeded(this);
   }
 
   public void unbundle(RepositorySessionBundle bundle) {
     this.lastSyncTimestamp = bundle == null ? 0 : bundle.getTimestamp();
   }
 
   /**
    * Override this in your subclasses to return values to save between sessions.
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/StoreTrackingRepositorySession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/StoreTrackingRepositorySession.java
@@ -3,44 +3,37 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories;
 
 import java.util.Collection;
 import java.util.Iterator;
 
 import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 public abstract class StoreTrackingRepositorySession extends RepositorySession {
   private static final String LOG_TAG = "StoreTrackSession";
   protected StoreTracker storeTracker;
 
   protected static StoreTracker createStoreTracker() {
     return new HashSetStoreTracker();
   }
 
   public StoreTrackingRepositorySession(Repository repository) {
     super(repository);
   }
 
   @Override
-  public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
-    RepositorySessionBeginDelegate deferredDelegate = delegate.deferredBeginDelegate(delegateQueue);
-    try {
-      super.sharedBegin();
-    } catch (InvalidSessionTransitionException e) {
-      deferredDelegate.onBeginFailed(e);
-      return;
-    }
+  public void begin() throws SyncException {
+    super.sharedBegin();
     // Or do this in your own subclass.
     storeTracker = createStoreTracker();
-    deferredDelegate.onBeginSucceeded(this);
   }
 
   @Override
   protected synchronized void trackGUID(String guid) {
     if (this.storeTracker == null) {
       throw new IllegalStateException("Store tracker not yet initialized!");
     }
     this.storeTracker.trackRecordForExclusion(guid);
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BookmarksRepositorySession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BookmarksRepositorySession.java
@@ -5,25 +5,23 @@
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
-import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.ProfileDatabaseException;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.StoreTrackingRepositorySession;
 import org.mozilla.gecko.sync.repositories.VersioningDelegateHelper;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 import android.content.Context;
 
@@ -211,57 +209,45 @@ public class BookmarksRepositorySession 
 
   @Override
   public void performCleanup() {
     versioningDelegateHelper.persistSyncVersions();
     super.performCleanup();
   }
 
   @Override
-  public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
+  public void begin() throws SyncException {
     // Check for the existence of special folders
     // and insert them if they don't exist.
     try {
       Logger.debug(LOG_TAG, "Check and build special GUIDs.");
       dataAccessor.checkAndBuildSpecialGuids();
       Logger.debug(LOG_TAG, "Got GUIDs for folders.");
-    } catch (android.database.sqlite.SQLiteConstraintException e) {
-      Logger.error(LOG_TAG, "Got sqlite constraint exception working with Fennec bookmark DB.", e);
-      delegate.onBeginFailed(e);
-      return;
     } catch (Exception e) {
-      delegate.onBeginFailed(e);
-      return;
+      Logger.error(LOG_TAG, "Got an exception while working with Fennec bookmark DB.", e);
+      throw e;
     }
 
-    try {
-      sessionHelper.doBegin();
-    } catch (NullCursorException e) {
-      delegate.onBeginFailed(e);
-      return;
-    }
+    sessionHelper.doBegin();
 
-    RepositorySessionBeginDelegate deferredDelegate = delegate.deferredBeginDelegate(delegateQueue);
     super.sharedBegin();
 
     try {
       // We do this check here even though it results in one extra call to the DB
       // because if we didn't, we have to do a check on every other call since there
       // is no way of knowing which call would be hit first.
       sessionHelper.checkDatabase();
     } catch (ProfileDatabaseException e) {
       Logger.error(LOG_TAG, "ProfileDatabaseException from begin. Fennec must be launched once until this error is fixed");
-      deferredDelegate.onBeginFailed(e);
-      return;
+      throw e;
     } catch (Exception e) {
-      deferredDelegate.onBeginFailed(e);
-      return;
+      Logger.error(LOG_TAG, "Hit an exception while checking a database in begin.", e);
+      throw e;
     }
     storeTracker = createStoreTracker();
-    deferredDelegate.onBeginSucceeded(this);
   }
 
   @Override
   public void finish(RepositorySessionFinishDelegate delegate) throws InactiveSessionException {
     sessionHelper.finish();
     super.finish(delegate);
   };
 
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BookmarksValidationRepository.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BookmarksValidationRepository.java
@@ -6,24 +6,23 @@ package org.mozilla.gecko.sync.repositor
 
 
 
 import android.content.Context;
 import android.os.SystemClock;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 import org.mozilla.gecko.sync.telemetry.TelemetryStageCollector;
 import org.mozilla.gecko.sync.validation.BookmarkValidationResults;
@@ -93,53 +92,18 @@ public class BookmarksValidationReposito
 
         @Override
         public synchronized boolean isActive() {
             return this.wrappedSession.isActive();
         }
 
 
         @Override
-        public void begin(final RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
-            wrappedSession.begin(new RepositorySessionBeginDelegate() {
-
-                @Override
-                public void onBeginFailed(Exception ex) {
-                    delegate.onBeginFailed(ex);
-                }
-
-                @Override
-                public void onBeginSucceeded(RepositorySession session) {
-                    delegate.onBeginSucceeded(BookmarksValidationRepositorySession.this);
-                }
-
-                @Override
-                public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
-                    final RepositorySessionBeginDelegate deferred = delegate.deferredBeginDelegate(executor);
-                    return new RepositorySessionBeginDelegate() {
-                        @Override
-                        public void onBeginSucceeded(RepositorySession session) {
-                            if (wrappedSession != session) {
-                                Logger.warn(LOG_TAG, "Got onBeginSucceeded for session " + session + ", not our inner session!");
-                            }
-                            deferred.onBeginSucceeded(BookmarksValidationRepositorySession.this);
-                        }
-
-                        @Override
-                        public void onBeginFailed(Exception ex) {
-                            deferred.onBeginFailed(ex);
-                        }
-
-                        @Override
-                        public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
-                            return this;
-                        }
-                    };
-                }
-            });
+        public void begin() throws SyncException {
+            wrappedSession.begin();
         }
 
         @Override
         public void finish(final RepositorySessionFinishDelegate delegate) throws InactiveSessionException {
             wrappedSession.finish(new RepositorySessionFinishDelegate() {
                 @Override
                 public void onFinishFailed(Exception ex) {
                     delegate.onFinishFailed(ex);
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/HistoryRepositorySession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/HistoryRepositorySession.java
@@ -1,70 +1,67 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.ProfileDatabaseException;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.StoreTrackingRepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 import android.content.Context;
 
 public class HistoryRepositorySession extends StoreTrackingRepositorySession {
   public static final String LOG_TAG = "ABHistoryRepoSess";
 
   private final HistoryDataAccessor dbHelper;
   private final HistorySessionHelper sessionHelper;
   private int storeCount = 0;
 
-  public HistoryRepositorySession(Repository repository, Context context) {
+  protected HistoryRepositorySession(Repository repository, Context context) {
     super(repository);
     dbHelper = new HistoryDataAccessor(context);
     sessionHelper = new HistorySessionHelper(this, dbHelper);
   }
 
   @Override
-  public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
+  public void begin() throws SyncException {
     // HACK: Fennec creates history records without a GUID. Mercilessly drop
     // them on the floor. See Bug 739514.
     try {
       dbHelper.delete(BrowserContract.History.GUID + " IS NULL", null);
     } catch (Exception e) {
       // Ignore.
     }
-    RepositorySessionBeginDelegate deferredDelegate = delegate.deferredBeginDelegate(delegateQueue);
+
     super.sharedBegin();
 
     try {
       // We do this check here even though it results in one extra call to the DB
       // because if we didn't, we have to do a check on every other call since there
       // is no way of knowing which call would be hit first.
       sessionHelper.checkDatabase();
     } catch (ProfileDatabaseException e) {
       Logger.error(LOG_TAG, "ProfileDatabaseException from begin. Fennec must be launched once until this error is fixed");
-      deferredDelegate.onBeginFailed(e);
-      return;
+      throw e;
     } catch (Exception e) {
-      deferredDelegate.onBeginFailed(e);
-      return;
+      Logger.error(LOG_TAG, "Hit an exception while checking a database in begin.", e);
+      throw e;
     }
     storeTracker = createStoreTracker();
-    deferredDelegate.onBeginSucceeded(this);
   }
 
   @Override
   public void fetchModified(RepositorySessionFetchRecordsDelegate delegate) {
     this.fetchSince(getLastSyncTimestamp(), delegate);
   }
 
   @Override
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/delegates/DeferredRepositorySessionBeginDelegate.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.repositories.delegates;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-
-public class DeferredRepositorySessionBeginDelegate implements RepositorySessionBeginDelegate {
-  private final RepositorySessionBeginDelegate inner;
-  private final ExecutorService executor;
-  public DeferredRepositorySessionBeginDelegate(final RepositorySessionBeginDelegate inner, final ExecutorService executor) {
-    this.inner = inner;
-    this.executor = executor;
-  }
-
-  @Override
-  public void onBeginSucceeded(final RepositorySession session) {
-    executor.execute(new Runnable() {
-      @Override
-      public void run() {
-        inner.onBeginSucceeded(session);
-      }
-    });
-  }
-
-  @Override
-  public void onBeginFailed(final Exception ex) {
-    executor.execute(new Runnable() {
-      @Override
-      public void run() {
-        inner.onBeginFailed(ex);
-      }
-    });
-  }
-  
-  @Override
-  public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService newExecutor) {
-    if (newExecutor == executor) {
-      return this;
-    }
-    throw new IllegalArgumentException("Can't re-defer this delegate.");
-  }
-}
\ No newline at end of file
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/delegates/RepositorySessionBeginDelegate.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.repositories.delegates;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-
-/**
- * One of these two methods is guaranteed to be called after session.begin() is
- * invoked (possibly during the invocation). The callback will be invoked prior
- * to any other RepositorySession callbacks.
- *
- * @author rnewman
- *
- */
-public interface RepositorySessionBeginDelegate {
-  public void onBeginFailed(Exception ex);
-  public void onBeginSucceeded(RepositorySession session);
-  public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor);
-}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/ServerSyncStage.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/ServerSyncStage.java
@@ -10,16 +10,17 @@ import android.os.SystemClock;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.EngineSettings;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.HTTPFailureException;
 import org.mozilla.gecko.sync.MetaGlobalException;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.ReflowIsNecessaryException;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.SynchronizerConfiguration;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.WipeServerDelegate;
 import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepository;
 import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.SyncStorageRequest;
@@ -29,17 +30,16 @@ import org.mozilla.gecko.sync.repositori
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NonPersistentRepositoryStateProvider;
 import org.mozilla.gecko.sync.repositories.RecordFactory;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
 import org.mozilla.gecko.sync.repositories.RepositoryStateProvider;
 import org.mozilla.gecko.sync.repositories.Server15Repository;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.synchronizer.ServerLocalSynchronizer;
 import org.mozilla.gecko.sync.synchronizer.Synchronizer;
 import org.mozilla.gecko.sync.synchronizer.SynchronizerDelegate;
 import org.mozilla.gecko.sync.synchronizer.SynchronizerSession;
 import org.mozilla.gecko.sync.telemetry.TelemetryCollector;
@@ -313,90 +313,75 @@ public abstract class ServerSyncStage ex
     final Runnable doWipe = new Runnable() {
       @Override
       public void run() {
         r.createSession(new RepositorySessionCreationDelegate() {
 
           @Override
           public void onSessionCreated(final RepositorySession session) {
             try {
-              session.begin(new RepositorySessionBeginDelegate() {
-
-                @Override
-                public void onBeginSucceeded(final RepositorySession session) {
-                  session.wipe(new RepositorySessionWipeDelegate() {
-                    @Override
-                    public void onWipeSucceeded() {
-                      try {
-                        session.finish(new RepositorySessionFinishDelegate() {
-
-                          @Override
-                          public void onFinishSucceeded(RepositorySession session,
-                                                        RepositorySessionBundle bundle) {
-                            // Hurrah.
-                            synchronized (monitor) {
-                              monitor.notify();
-                            }
-                          }
+              session.begin();
+            } catch (SyncException e) {
+              e.printStackTrace();
+              session.abort();
+              synchronized (monitor) {
+                monitor.notify(e, true);
+              }
+              return;
+            }
 
-                          @Override
-                          public void onFinishFailed(Exception ex) {
-                            // Assume that no finish => no wipe.
-                            synchronized (monitor) {
-                              monitor.notify(ex, true);
-                            }
-                          }
+            session.wipe(new RepositorySessionWipeDelegate() {
+              @Override
+              public void onWipeSucceeded() {
+                try {
+                  session.finish(new RepositorySessionFinishDelegate() {
 
-                          @Override
-                          public RepositorySessionFinishDelegate deferredFinishDelegate(ExecutorService executor) {
-                            return this;
-                          }
-                        });
-                      } catch (InactiveSessionException e) {
-                        // Cannot happen. Call for safety.
-                        synchronized (monitor) {
-                          monitor.notify(e, true);
-                        }
+                    @Override
+                    public void onFinishSucceeded(RepositorySession session,
+                                                  RepositorySessionBundle bundle) {
+                      // Hurrah.
+                      synchronized (monitor) {
+                        monitor.notify();
                       }
                     }
 
                     @Override
-                    public void onWipeFailed(Exception ex) {
-                      session.abort();
+                    public void onFinishFailed(Exception ex) {
+                      // Assume that no finish => no wipe.
                       synchronized (monitor) {
                         monitor.notify(ex, true);
                       }
                     }
 
                     @Override
-                    public RepositorySessionWipeDelegate deferredWipeDelegate(ExecutorService executor) {
+                    public RepositorySessionFinishDelegate deferredFinishDelegate(ExecutorService executor) {
                       return this;
                     }
                   });
-                }
-
-                @Override
-                public void onBeginFailed(Exception ex) {
-                  session.abort();
+                } catch (InactiveSessionException e) {
+                  // Cannot happen. Call for safety.
                   synchronized (monitor) {
-                    monitor.notify(ex, true);
+                    monitor.notify(e, true);
                   }
                 }
+              }
 
-                @Override
-                public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
-                  return this;
+              @Override
+              public void onWipeFailed(Exception ex) {
+                session.abort();
+                synchronized (monitor) {
+                  monitor.notify(ex, true);
                 }
-              });
-            } catch (InvalidSessionTransitionException e) {
-              session.abort();
-              synchronized (monitor) {
-                monitor.notify(e, true);
               }
-            }
+
+              @Override
+              public RepositorySessionWipeDelegate deferredWipeDelegate(ExecutorService executor) {
+                return this;
+              }
+            });
           }
 
           @Override
           public void onSessionCreateFailed(Exception ex) {
             synchronized (monitor) {
               monitor.notify(ex, false);
             }
           }
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/synchronizer/RecordsChannel.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/synchronizer/RecordsChannel.java
@@ -8,23 +8,22 @@ import android.support.annotation.NonNul
 import android.support.annotation.Nullable;
 
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ReflowIsNecessaryException;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.DeferredRepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.DeferredRepositorySessionStoreDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 /**
  * Pulls records from `source`, applying them to `sink`.
  * Notifies its delegate of errors and completion.
  *
@@ -62,18 +61,17 @@ import org.mozilla.gecko.sync.repositori
  * RecordsChannel exists to enforce this ordering of operations.
  *
  * @author rnewman
  *
  */
 public class RecordsChannel implements
   RepositorySessionFetchRecordsDelegate,
   RepositorySessionStoreDelegate,
-  RecordsConsumerDelegate,
-  RepositorySessionBeginDelegate {
+  RecordsConsumerDelegate {
 
   private static final String LOG_TAG = "RecordsChannel";
   public RepositorySession source;
   private RepositorySession sink;
   private final RecordsChannelDelegate delegate;
 
   private volatile ReflowIsNecessaryException reflowException;
 
@@ -194,18 +192,27 @@ public class RecordsChannel implements
     source.fetchModified(this);
   }
 
   /**
    * Begin both sessions, invoking flow() when done.
    * @throws InvalidSessionTransitionException
    */
   public void beginAndFlow() throws InvalidSessionTransitionException {
-    Logger.trace(LOG_TAG, "Beginning source.");
-    source.begin(this);
+    try {
+      Logger.trace(LOG_TAG, "Beginning source.");
+      source.begin();
+      Logger.trace(LOG_TAG, "Beginning sink.");
+      sink.begin();
+    } catch (SyncException e) {
+      delegate.onFlowBeginFailed(this, e);
+      return;
+    }
+
+    this.flow();
   }
 
   @Override
   public void store(Record record) {
     storeAttemptedCount.incrementAndGet();
     try {
       sink.store(record);
     } catch (NoStoreDelegateException e) {
@@ -328,51 +335,21 @@ public class RecordsChannel implements
     // If consumer is still going at it, tell it to stop.
     this.consumer.halt();
 
     delegate.onFlowStoreFailed(this, ex, null);
     delegate.onFlowCompleted(this);
   }
 
   @Override
-  public void onBeginFailed(Exception ex) {
-    delegate.onFlowBeginFailed(this, ex);
-  }
-
-  @Override
-  public void onBeginSucceeded(RepositorySession session) {
-    if (session == source) {
-      Logger.trace(LOG_TAG, "Source session began. Beginning sink session.");
-      try {
-        sink.begin(this);
-      } catch (InvalidSessionTransitionException e) {
-        onBeginFailed(e);
-        return;
-      }
-    }
-    if (session == sink) {
-      Logger.trace(LOG_TAG, "Sink session began. Beginning flow.");
-      this.flow();
-      return;
-    }
-
-    // TODO: error!
-  }
-
-  @Override
   public RepositorySessionStoreDelegate deferredStoreDelegate(final ExecutorService executor) {
     return new DeferredRepositorySessionStoreDelegate(this, executor);
   }
 
   @Override
-  public RepositorySessionBeginDelegate deferredBeginDelegate(final ExecutorService executor) {
-    return new DeferredRepositorySessionBeginDelegate(this, executor);
-  }
-
-  @Override
   public RepositorySessionFetchRecordsDelegate deferredFetchDelegate(ExecutorService executor) {
     // Lie outright. We know that all of our fetch methods are safe.
     return this;
   }
 
   @Nullable
   public synchronized ReflowIsNecessaryException getReflowException() {
     return reflowException;
--- a/mobile/android/tests/background/junit3/background_junit3_sources.mozbuild
+++ b/mobile/android/tests/background/junit3/background_junit3_sources.mozbuild
@@ -22,39 +22,35 @@ background_junit3_sources = [
     'src/org/mozilla/gecko/background/fxa/TestAccountLoader.java',
     'src/org/mozilla/gecko/background/fxa/TestBrowserIDKeyPairGeneration.java',
     'src/org/mozilla/gecko/background/helpers/AndroidSyncTestCase.java',
     'src/org/mozilla/gecko/background/helpers/DBHelpers.java',
     'src/org/mozilla/gecko/background/helpers/DBProviderTestCase.java',
     'src/org/mozilla/gecko/background/nativecode/test/TestNativeCrypto.java',
     'src/org/mozilla/gecko/background/sync/AndroidSyncTestCaseWithAccounts.java',
     'src/org/mozilla/gecko/background/sync/helpers/BookmarkHelpers.java',
-    'src/org/mozilla/gecko/background/sync/helpers/DefaultBeginDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/DefaultCleanDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/DefaultDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/DefaultFetchDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/DefaultFinishDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/DefaultSessionCreationDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/DefaultStoreDelegate.java',
-    'src/org/mozilla/gecko/background/sync/helpers/ExpectBeginDelegate.java',
-    'src/org/mozilla/gecko/background/sync/helpers/ExpectBeginFailDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/ExpectFetchDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/ExpectFetchSinceDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/ExpectFinishDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/ExpectFinishFailDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidRequestFetchDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidTypeStoreDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/ExpectManyStoredDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/ExpectNoStoreDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/ExpectStoreCompletedDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/ExpectStoredDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/HistoryHelpers.java',
     'src/org/mozilla/gecko/background/sync/helpers/PasswordHelpers.java',
     'src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java',
-    'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessBeginDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessCreationDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFetchDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFinishDelegate.java',
     'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessStoreDelegate.java',
     'src/org/mozilla/gecko/background/sync/TestClientsStage.java',
     'src/org/mozilla/gecko/background/sync/TestResetting.java',
     'src/org/mozilla/gecko/background/sync/TestStoreTracking.java',
     'src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java',
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestBookmarks.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestBookmarks.java
@@ -9,35 +9,32 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 
 import org.json.simple.JSONArray;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
 import org.mozilla.gecko.background.sync.helpers.BookmarkHelpers;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessBeginDelegate;
 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessCreationDelegate;
 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessFetchDelegate;
 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessFinishDelegate;
 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessStoreDelegate;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.db.BrowserContract.Bookmarks;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
 import org.mozilla.gecko.sync.repositories.android.BookmarksDataAccessor;
 import org.mozilla.gecko.sync.repositories.android.BookmarksRepository;
 import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -564,32 +561,31 @@ public class TestBookmarks extends Andro
     assertEquals(folder1.title, fetchGUID(repo, folder1.guid).title);
     assertEquals(bmk2.title, fetchGUID(repo, bmk2.guid).title);
   }
 
   /**
    * Create and begin a new session, handing control to the delegate when started.
    * Returns when the delegate has notified.
    */
-  public void inBegunSession(final BookmarksRepository repo,
-                             final RepositorySessionBeginDelegate beginDelegate) {
+  private void inBegunSession(final BookmarksRepository repo) {
     Runnable go = new Runnable() {
       @Override
       public void run() {
-        RepositorySessionCreationDelegate delegate = new SimpleSuccessCreationDelegate() {
+        repo.createSession(new SimpleSuccessCreationDelegate() {
           @Override
           public void onSessionCreated(final RepositorySession session) {
             try {
-              session.begin(beginDelegate);
-            } catch (InvalidSessionTransitionException e) {
-              performNotify(e);
+              session.begin();
+              performNotify();
+            } catch (SyncException e) {
+              performNotify("Begin failed", e);
             }
           }
-        };
-        repo.createSession(delegate, getApplicationContext());
+        }, getApplicationContext());
       }
     };
     performWait(go);
   }
 
   /**
    * Finish the provided session, notifying on success.
    *
@@ -605,101 +601,37 @@ public class TestBookmarks extends Andro
         }
       });
     } catch (InactiveSessionException e) {
       performNotify(e);
     }
   }
 
   /**
-   * Simple helper class for fetching all records.
-   * The fetched records' GUIDs are stored in `fetchedGUIDs`.
-   */
-  public class SimpleFetchAllBeginDelegate extends SimpleSuccessBeginDelegate {
-    public final ArrayList<String> fetchedGUIDs = new ArrayList<String>();
-
-    @Override
-    public void onBeginSucceeded(final RepositorySession session) {
-      RepositorySessionFetchRecordsDelegate fetchDelegate = new SimpleSuccessFetchDelegate() {
-
-        @Override
-        public void onFetchedRecord(Record record) {
-          fetchedGUIDs.add(record.guid);
-        }
-
-        @Override
-        public void onFetchCompleted() {
-          finishAndNotify(session);
-        }
-
-        @Override
-        public void onBatchCompleted() {
-
-        }
-      };
-      session.fetchModified(fetchDelegate);
-    }
-  }
-
-  /**
-   * Simple helper class for fetching a single record by GUID.
-   * The fetched record is stored in `fetchedRecord`.
-   */
-  public class SimpleFetchOneBeginDelegate extends SimpleSuccessBeginDelegate {
-    public final String guid;
-    public Record fetchedRecord = null;
-
-    public SimpleFetchOneBeginDelegate(String guid) {
-      this.guid = guid;
-    }
-
-    @Override
-    public void onBeginSucceeded(final RepositorySession session) {
-      RepositorySessionFetchRecordsDelegate fetchDelegate = new SimpleSuccessFetchDelegate() {
-
-        @Override
-        public void onFetchedRecord(Record record) {
-          fetchedRecord = record;
-        }
-
-        @Override
-        public void onFetchCompleted() {
-          finishAndNotify(session);
-        }
-
-        @Override
-        public void onBatchCompleted() {
-
-        }
-      };
-      try {
-        session.fetch(new String[] { guid }, fetchDelegate);
-      } catch (InactiveSessionException e) {
-        performNotify("Session is inactive.", e);
-      }
-    }
-  }
-
-  /**
    * Create a new session for the given repository, storing each record
    * from the provided array. Notifies on failure or success.
    *
    * Optionally populates a provided Collection with tracked items.
    * @param repo
    * @param records
    * @param tracked
    */
-  public void storeRecordsInSession(BookmarksRepository repo,
+  private void storeRecordsInSession(BookmarksRepository repo,
                                     final BookmarkRecord[] records,
                                     final Collection<String> tracked) {
-    SimpleSuccessBeginDelegate beginDelegate = new SimpleSuccessBeginDelegate() {
+    repo.createSession(new SimpleSuccessCreationDelegate() {
       @Override
-      public void onBeginSucceeded(final RepositorySession session) {
+      public void onSessionCreated(final RepositorySession session) {
+        try {
+          session.begin();
+        } catch (SyncException e) {
+          performNotify("Begin failed", e);
+        }
+
         RepositorySessionStoreDelegate storeDelegate = new SimpleSuccessStoreDelegate() {
-
           @Override
           public void onStoreCompleted() {
             // Pass back whatever we tracked.
             if (tracked != null) {
               Iterator<String> iter = session.getTrackedRecordIDs();
               while (iter.hasNext()) {
                 tracked.add(iter.next());
               }
@@ -725,34 +657,97 @@ public class TestBookmarks extends Andro
           try {
             session.store(record);
           } catch (NoStoreDelegateException e) {
             // Never happens.
           }
         }
         session.storeDone();
       }
-    };
-    inBegunSession(repo, beginDelegate);
+    }, getApplicationContext());
   }
 
   public ArrayList<String> fetchGUIDs(BookmarksRepository repo) {
-    SimpleFetchAllBeginDelegate beginDelegate = new SimpleFetchAllBeginDelegate();
-    inBegunSession(repo, beginDelegate);
-    return beginDelegate.fetchedGUIDs;
+    final ArrayList<String> fetchedGUIDs = new ArrayList<String>();
+
+    repo.createSession(new SimpleSuccessCreationDelegate() {
+      @Override
+      public void onSessionCreated(final RepositorySession session) {
+        try {
+          session.begin();
+        } catch (SyncException e) {
+          performNotify("Begin failed", e);
+        }
+
+        RepositorySessionFetchRecordsDelegate fetchDelegate = new SimpleSuccessFetchDelegate() {
+          @Override
+          public void onFetchedRecord(Record record) {
+            fetchedGUIDs.add(record.guid);
+          }
+
+          @Override
+          public void onFetchCompleted() {
+            finishAndNotify(session);
+          }
+
+          @Override
+          public void onBatchCompleted() {
+
+          }
+        };
+        session.fetchModified(fetchDelegate);
+      }
+    }, getApplicationContext());
+
+    return fetchedGUIDs;
   }
 
-  public BookmarkRecord fetchGUID(BookmarksRepository repo,
+  private BookmarkRecord fetchGUID(BookmarksRepository repo,
                                   final String guid) {
     Logger.info(LOG_TAG, "Fetching for " + guid);
-    SimpleFetchOneBeginDelegate beginDelegate = new SimpleFetchOneBeginDelegate(guid);
-    inBegunSession(repo, beginDelegate);
-    Logger.info(LOG_TAG, "Fetched " + beginDelegate.fetchedRecord);
-    assertTrue(beginDelegate.fetchedRecord != null);
-    return (BookmarkRecord) beginDelegate.fetchedRecord;
+    final ArrayList<Record> fetchedRecords = new ArrayList<>();
+
+    repo.createSession(new SimpleSuccessCreationDelegate() {
+      @Override
+      public void onSessionCreated(final RepositorySession session) {
+        try {
+          session.begin();
+        } catch (SyncException e) {
+          performNotify("Begin failed", e);
+        }
+
+        RepositorySessionFetchRecordsDelegate fetchDelegate = new SimpleSuccessFetchDelegate() {
+          @Override
+          public void onFetchedRecord(Record record) {
+            fetchedRecords.add(record);
+          }
+
+          @Override
+          public void onFetchCompleted() {
+            finishAndNotify(session);
+          }
+
+          @Override
+          public void onBatchCompleted() {
+
+          }
+        };
+        try {
+          session.fetch(new String[] { guid }, fetchDelegate);
+        } catch (InactiveSessionException e) {
+          performNotify("Session is inactive.", e);
+        }
+      }
+    }, getApplicationContext());
+
+    assertEquals(1, fetchedRecords.size());
+    Record fetchedRecord = fetchedRecords.get(0);
+
+    Logger.info(LOG_TAG, "Fetched " + fetchedRecord);
+    return (BookmarkRecord) fetchedRecord;
   }
 
   public JSONArray fetchChildrenForGUID(BookmarksRepository repo,
       final String guid) {
     return fetchGUID(repo, guid).children;
   }
 
   @SuppressWarnings("unchecked")
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/ThreadedRepositoryTestCase.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/ThreadedRepositoryTestCase.java
@@ -2,24 +2,21 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.db;
 
 import java.util.concurrent.ExecutorService;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.sync.helpers.DefaultBeginDelegate;
 import org.mozilla.gecko.background.sync.helpers.DefaultCleanDelegate;
 import org.mozilla.gecko.background.sync.helpers.DefaultFetchDelegate;
 import org.mozilla.gecko.background.sync.helpers.DefaultFinishDelegate;
 import org.mozilla.gecko.background.sync.helpers.DefaultSessionCreationDelegate;
 import org.mozilla.gecko.background.sync.helpers.DefaultStoreDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectBeginDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectBeginFailDelegate;
 import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate;
 import org.mozilla.gecko.background.sync.helpers.ExpectFetchSinceDelegate;
 import org.mozilla.gecko.background.sync.helpers.ExpectFinishDelegate;
 import org.mozilla.gecko.background.sync.helpers.ExpectFinishFailDelegate;
 import org.mozilla.gecko.background.sync.helpers.ExpectInvalidRequestFetchDelegate;
 import org.mozilla.gecko.background.sync.helpers.ExpectManyStoredDelegate;
 import org.mozilla.gecko.background.sync.helpers.ExpectStoreCompletedDelegate;
 import org.mozilla.gecko.background.sync.helpers.ExpectStoredDelegate;
@@ -148,25 +145,28 @@ public abstract class ThreadedRepository
    * @param session
    * @param record
    * @return Runnable.
    */
   public static Runnable quietStoreRunnable(final RepositorySession session, final Record record) {
     return storeRunnable(session, record, new ExpectStoreCompletedDelegate());
   }
 
-  public static Runnable beginRunnable(final RepositorySession session, final DefaultBeginDelegate delegate) {
+  public static Runnable beginRunnable(final RepositorySession session) {
     return new Runnable() {
       @Override
       public void run() {
         try {
-          session.begin(delegate);
+          session.begin();
         } catch (InvalidSessionTransitionException e) {
           performNotify(e);
+        } catch (org.mozilla.gecko.sync.SyncException e) {
+          e.printStackTrace();
         }
+        performNotify();
       }
     };
   }
 
   public static Runnable finishRunnable(final RepositorySession session, final DefaultFinishDelegate delegate) {
     return new Runnable() {
       @Override
       public void run() {
@@ -653,36 +653,38 @@ public abstract class ThreadedRepository
    public void testFetchNullGuids() {
      final RepositorySession session = createAndBeginSession();
      performWait(fetchRunnable(session, null, new ExpectInvalidRequestFetchDelegate()));
      dispose(session);
    }
 
    public void testBeginOnNewSession() {
      final RepositorySession session = createSession();
-     performWait(beginRunnable(session, new ExpectBeginDelegate()));
+     performWait(beginRunnable(session));
      dispose(session);
    }
 
    public void testBeginOnRunningSession() {
      final RepositorySession session = createAndBeginSession();
      try {
-       session.begin(new ExpectBeginFailDelegate());
+       session.begin();
      } catch (InvalidSessionTransitionException e) {
        dispose(session);
        return;
+     } catch (org.mozilla.gecko.sync.SyncException e) {
+       e.printStackTrace();
      }
      fail("Should have caught InvalidSessionTransitionException.");
    }
 
    public void testBeginOnFinishedSession() throws InactiveSessionException {
      final RepositorySession session = createAndBeginSession();
      performWait(finishRunnable(session, new ExpectFinishDelegate()));
      try {
-       session.begin(new ExpectBeginFailDelegate());
+       session.begin();
      } catch (InvalidSessionTransitionException e) {
        Logger.debug(getName(), "Yay! Got an exception.", e);
        dispose(session);
        return;
      } catch (Exception e) {
        Logger.debug(getName(), "Yay! Got an exception.", e);
        dispose(session);
        return;
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestStoreTracking.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestStoreTracking.java
@@ -5,24 +5,24 @@ package org.mozilla.gecko.background.syn
 
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
 import junit.framework.AssertionFailedError;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessBeginDelegate;
 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessCreationDelegate;
 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessFetchDelegate;
 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessFinishDelegate;
 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessStoreDelegate;
 import org.mozilla.gecko.background.testhelpers.WBORepository;
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
 import org.mozilla.gecko.sync.repositories.domain.Record;
@@ -146,53 +146,49 @@ public class TestStoreTracking extends A
 
   private void doTestNewSessionRetrieveByTime(final WBORepository repository,
                                               final String expectedGUID) {
     final SimpleSuccessCreationDelegate createDelegate = new SimpleSuccessCreationDelegate() {
       @Override
       public void onSessionCreated(final RepositorySession session) {
         Logger.debug(getName(), "Session created.");
         try {
-          session.begin(new SimpleSuccessBeginDelegate() {
-            @Override
-            public void onBeginSucceeded(final RepositorySession session) {
-              // Now we get a result.
-              session.fetchModified(new SimpleSuccessFetchDelegate() {
+          session.begin();
+        } catch (SyncException e) {
+          e.printStackTrace();
+          performNotify(e);
+        }
 
-                @Override
-                public void onFetchedRecord(Record record) {
-                  assertEq(expectedGUID, record.guid);
-                }
+        // Now we get a result.
+        session.fetchModified(new SimpleSuccessFetchDelegate() {
+          @Override
+          public void onFetchedRecord(Record record) {
+            assertEq(expectedGUID, record.guid);
+          }
 
+          @Override
+          public void onFetchCompleted() {
+            try {
+              session.finish(new SimpleSuccessFinishDelegate() {
                 @Override
-                public void onFetchCompleted() {
-                  try {
-                    session.finish(new SimpleSuccessFinishDelegate() {
-                      @Override
-                      public void onFinishSucceeded(RepositorySession session,
-                                                    RepositorySessionBundle bundle) {
-                        // Hooray!
-                        performNotify();
-                      }
-                    });
-                  } catch (InactiveSessionException e) {
-                    performNotify(e);
-                  }
-                }
-
-                @Override
-                public void onBatchCompleted() {
-
+                public void onFinishSucceeded(RepositorySession session,
+                                              RepositorySessionBundle bundle) {
+                  // Hooray!
+                  performNotify();
                 }
               });
+            } catch (InactiveSessionException e) {
+              performNotify(e);
             }
-          });
-        } catch (InvalidSessionTransitionException e) {
-          performNotify(e);
-        }
+          }
+
+          @Override
+          public void onBatchCompleted() {
+          }
+        });
       }
     };
     Runnable create = new Runnable() {
       @Override
       public void run() {
         repository.createSession(createDelegate, getApplicationContext());
       }
     };
@@ -215,25 +211,23 @@ public class TestStoreTracking extends A
     final String expectedGUID = "abcdefghijkl";
     final Record record = new BookmarkRecord(expectedGUID, "bookmarks", now , false);
 
     final RepositorySessionCreationDelegate createDelegate = new SimpleSuccessCreationDelegate() {
       @Override
       public void onSessionCreated(RepositorySession session) {
         Logger.debug(getName(), "Session created: " + session);
         try {
-          session.begin(new SimpleSuccessBeginDelegate() {
-            @Override
-            public void onBeginSucceeded(final RepositorySession session) {
-              doTestStoreRetrieveByGUID(r, session, expectedGUID, record);
-            }
-          });
-        } catch (InvalidSessionTransitionException e) {
+          session.begin();
+        } catch (SyncException e) {
+          e.printStackTrace();
           performNotify(e);
         }
+
+        doTestStoreRetrieveByGUID(r, session, expectedGUID, record);
       }
     };
 
     final Context applicationContext = getApplicationContext();
 
     // This has to happen on a new thread so that we
     // can wait for it!
     Runnable create = onThreadRunnable(new Runnable() {
deleted file mode 100644
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultBeginDelegate.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-
-public class DefaultBeginDelegate extends DefaultDelegate implements RepositorySessionBeginDelegate {
-  @Override
-  public void onBeginFailed(Exception ex) {
-    performNotify("Begin failed", ex);
-  }
-
-  @Override
-  public void onBeginSucceeded(RepositorySession session) {
-    performNotify("Default begin delegate hit.", null);
-  }
-
-  @Override
-  public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
-    DefaultBeginDelegate copy;
-    try {
-      copy = (DefaultBeginDelegate) this.clone();
-      copy.executor = executor;
-      return copy;
-    } catch (CloneNotSupportedException e) {
-      return this;
-    }
-  }
-}
deleted file mode 100644
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginDelegate.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import static junit.framework.Assert.assertNotNull;
-import junit.framework.AssertionFailedError;
-
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-
-public class ExpectBeginDelegate extends DefaultBeginDelegate {
-  @Override
-  public void onBeginSucceeded(RepositorySession session) {
-    try {
-      assertNotNull(session);
-    } catch (AssertionFailedError e) {
-      performNotify("Expected non-null session", e);
-      return;
-    }
-    performNotify();
-  }
-}
deleted file mode 100644
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginFailDelegate.java
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-
-public class ExpectBeginFailDelegate extends DefaultBeginDelegate {
-
-  @Override
-  public void onBeginFailed(Exception ex) {
-    if (!(ex instanceof InvalidSessionTransitionException)) {
-      performNotify("Expected InvalidSessionTransititionException but got ", ex);
-    }
-  }
-}
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java
@@ -2,16 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.sync.helpers;
 
 import static junit.framework.Assert.assertNotNull;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.testhelpers.WaitHelper;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
 
 import android.content.Context;
 
 public class SessionTestHelper {
 
@@ -36,20 +37,21 @@ public class SessionTestHelper {
       public void onSessionCreated(final RepositorySession session) {
         assertNotNull(session);
         Logger.info(logTag, "Setting session to " + session);
         setSession(session);
         if (begin) {
           Logger.info(logTag, "Calling session.begin on new session.");
           // The begin callbacks will notify.
           try {
-            session.begin(new ExpectBeginDelegate());
-          } catch (InvalidSessionTransitionException e) {
+            session.begin();
+          } catch (SyncException e) {
             testWaiter.performNotify(e);
           }
+          testWaiter.performNotify();
         } else {
           Logger.info(logTag, "Notifying after setting new session.");
           testWaiter.performNotify();
         }
       }
     }
 
     final CreationDelegate delegate = new CreationDelegate();
deleted file mode 100644
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessBeginDelegate.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-
-public abstract class SimpleSuccessBeginDelegate extends DefaultDelegate implements RepositorySessionBeginDelegate {
-  @Override
-  public void onBeginFailed(Exception ex) {
-    performNotify("Begin failed", ex);
-  }
-
-  @Override
-  public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
-    return this;
-  }
-}
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WBORepository.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WBORepository.java
@@ -4,23 +4,22 @@
 package org.mozilla.gecko.background.testhelpers;
 
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.RecordFilter;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.StoreTrackingRepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 import android.content.Context;
 
@@ -171,20 +170,20 @@ public class WBORepository extends Repos
     public void finish(RepositorySessionFinishDelegate delegate) throws InactiveSessionException {
       Logger.info(LOG_TAG, "Finishing WBORepositorySession: handing back " + this.wbos.size() + " WBOs.");
       wboRepository.wbos = this.wbos;
       stats.finished = now();
       super.finish(delegate);
     }
 
     @Override
-    public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
+    public void begin() throws SyncException {
       this.wbos = wboRepository.cloneWBOs();
       stats.begun = now();
-      super.begin(delegate);
+      super.begin();
     }
 
     @Override
     public void storeDone() {
       // TODO: this is not guaranteed to be called after all of the record
       // store callbacks have completed!
       final long end = now();
       if (stats.storeBegan < 0) {
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/SynchronizerHelpers.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/SynchronizerHelpers.java
@@ -3,22 +3,21 @@
 
 package org.mozilla.android.sync.test;
 
 import android.content.Context;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.testhelpers.WBORepository;
 import org.mozilla.gecko.sync.CollectionConcurrentModificationException;
 import org.mozilla.gecko.sync.SyncDeadlineReachedException;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.repositories.FetchFailedException;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.StoreFailedException;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 import java.util.ArrayList;
 import java.util.concurrent.ExecutorService;
 
@@ -225,17 +224,17 @@ public class SynchronizerHelpers {
 
   public static class TrackingWBORepository extends WBORepository {
     @Override
     public synchronized boolean shouldTrack() {
       return true;
     }
   }
 
-  public static class BeginFailedException extends Exception {
+  public static class BeginFailedException extends SyncException {
     private static final long serialVersionUID = -2349459755976915096L;
   }
 
   public static class FinishFailedException extends Exception {
     private static final long serialVersionUID = -4644528423867070934L;
   }
 
   public static class BeginErrorWBORepository extends TrackingWBORepository {
@@ -246,18 +245,18 @@ public class SynchronizerHelpers {
     }
 
     public class BeginErrorWBORepositorySession extends WBORepositorySession {
       public BeginErrorWBORepositorySession(WBORepository repository) {
         super(repository);
       }
 
       @Override
-      public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
-        delegate.onBeginFailed(new BeginFailedException());
+      public void begin() throws SyncException {
+        throw new BeginFailedException();
       }
     }
   }
 
   public static class FinishErrorWBORepository extends TrackingWBORepository {
     @Override
     public void createSession(RepositorySessionCreationDelegate delegate,
                               Context context) {
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionBeginDelegate.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import junit.framework.AssertionFailedError;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-
-import java.util.concurrent.ExecutorService;
-
-public class ExpectSuccessRepositorySessionBeginDelegate
-extends ExpectSuccessDelegate
-implements RepositorySessionBeginDelegate {
-
-  public ExpectSuccessRepositorySessionBeginDelegate(WaitHelper waitHelper) {
-    super(waitHelper);
-  }
-
-  @Override
-  public void onBeginFailed(Exception ex) {
-    log("Session begin failed.", ex);
-    performNotify(new AssertionFailedError("Session begin failed: " + ex.getMessage()));
-  }
-
-  @Override
-  public void onBeginSucceeded(RepositorySession session) {
-    log("Session begin succeeded.");
-    performNotify();
-  }
-
-  @Override
-  public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
-    log("Session begin delegate deferred.");
-    return this;
-  }
-}
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WBORepository.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WBORepository.java
@@ -1,22 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.testhelpers;
 
 import android.content.Context;
 import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.RecordFilter;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.StoreTrackingRepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
@@ -170,20 +169,20 @@ public class WBORepository extends Repos
     public void finish(RepositorySessionFinishDelegate delegate) throws InactiveSessionException {
       Logger.info(LOG_TAG, "Finishing WBORepositorySession: handing back " + this.wbos.size() + " WBOs.");
       wboRepository.wbos = this.wbos;
       stats.finished = now();
       super.finish(delegate);
     }
 
     @Override
-    public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
+    public void begin() throws SyncException {
       this.wbos = wboRepository.cloneWBOs();
       stats.begun = now();
-      super.begin(delegate);
+      super.begin();
     }
 
     @Override
     public void storeDone() {
       // TODO: this is not guaranteed to be called after all of the record
       // store callbacks have completed!
       final long end = now();
       if (stats.storeBegan < 0) {
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/middleware/test/TestCrypto5MiddlewareRepositorySession.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/middleware/test/TestCrypto5MiddlewareRepositorySession.java
@@ -2,28 +2,28 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.sync.middleware.test;
 
 import junit.framework.AssertionFailedError;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionBeginDelegate;
 import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionCreationDelegate;
 import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionFetchRecordsDelegate;
 import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionFinishDelegate;
 import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionStoreDelegate;
 import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositoryWipeDelegate;
 import org.mozilla.gecko.background.testhelpers.MockRecord;
 import org.mozilla.gecko.background.testhelpers.TestRunner;
 import org.mozilla.gecko.background.testhelpers.WBORepository;
 import org.mozilla.gecko.background.testhelpers.WaitHelper;
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.NonObjectJSONException;
+import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepository;
 import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepositorySession;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
@@ -49,17 +49,17 @@ public class TestCrypto5MiddlewareReposi
   }
 
   protected static void performNotify(InactiveSessionException e) {
     final AssertionFailedError failed = new AssertionFailedError("Inactive session.");
     failed.initCause(e);
     getTestWaiter().performNotify(failed);
   }
 
-  protected static void performNotify(InvalidSessionTransitionException e) {
+  protected static void performNotify(SyncException e) {
     final AssertionFailedError failed = new AssertionFailedError("Invalid session transition.");
     failed.initCause(e);
     getTestWaiter().performNotify(failed);
   }
 
   public Runnable onThreadRunnable(Runnable runnable) {
     return WaitHelper.onThreadRunnable(runnable);
   }
@@ -91,26 +91,21 @@ public class TestCrypto5MiddlewareReposi
       public void run() {
         cmwRepo.createSession(new ExpectSuccessRepositorySessionCreationDelegate(getTestWaiter()) {
           @Override
           public void onSessionCreated(RepositorySession session) {
             self.cmwSession = (Crypto5MiddlewareRepositorySession)session;
             assertSame(RepositorySession.SessionStatus.UNSTARTED, cmwSession.getStatus());
 
             try {
-              session.begin(new ExpectSuccessRepositorySessionBeginDelegate(getTestWaiter()) {
-                @Override
-                public void onBeginSucceeded(RepositorySession _session) {
-                  assertSame(self.cmwSession, _session);
-                  runnable.run();
-                }
-              });
-            } catch (InvalidSessionTransitionException e) {
+              session.begin();
+            } catch (SyncException e) {
               TestCrypto5MiddlewareRepositorySession.performNotify(e);
             }
+            runnable.run();
           }
         }, null);
       }
     }));
   }
 
   @Test
   /**
@@ -120,19 +115,19 @@ public class TestCrypto5MiddlewareReposi
     runInOnBeginSucceeded(new Runnable() {
       @Override public void run() {
         assertSame(RepositorySession.SessionStatus.ACTIVE, cmwSession.getStatus());
         try {
           cmwSession.finish(new ExpectSuccessRepositorySessionFinishDelegate(getTestWaiter()));
         } catch (InactiveSessionException e) {
           performNotify(e);
         }
+        assertSame(RepositorySession.SessionStatus.DONE, cmwSession.getStatus());
       }
     });
-    assertSame(RepositorySession.SessionStatus.DONE, cmwSession.getStatus());
   }
 
   @Test
   /**
    * Verify that wipe is actually wiping the underlying repository.
    */
   public void testWipe() {
     Record record = new MockRecord("nncdefghiaaa", "coll", System.currentTimeMillis(), false);