Merge "Allow for more than one invalidation service in a package." into androidx-main
diff --git a/room/room-runtime/api/public_plus_experimental_current.txt b/room/room-runtime/api/public_plus_experimental_current.txt
index 5a24224..8484f3c 100644
--- a/room/room-runtime/api/public_plus_experimental_current.txt
+++ b/room/room-runtime/api/public_plus_experimental_current.txt
@@ -24,7 +24,7 @@
     field public final java.util.List<java.lang.Object!> typeConverters;
   }
 
-  @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface ExperimentalRoomApi {
+  @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD}) public @interface ExperimentalRoomApi {
   }
 
   public class InvalidationTracker {
@@ -39,6 +39,11 @@
     method public abstract void onInvalidated(java.util.Set<java.lang.String!>);
   }
 
+  @androidx.room.ExperimentalRoomApi public class MultiInstanceInvalidationService extends android.app.Service {
+    ctor public MultiInstanceInvalidationService();
+    method public android.os.IBinder? onBind(android.content.Intent);
+  }
+
   public class Room {
     ctor @Deprecated public Room();
     method public static <T extends androidx.room.RoomDatabase> androidx.room.RoomDatabase.Builder<T!> databaseBuilder(android.content.Context, Class<T!>, String);
@@ -93,6 +98,7 @@
     method public androidx.room.RoomDatabase.Builder<T!> openHelperFactory(androidx.sqlite.db.SupportSQLiteOpenHelper.Factory?);
     method @androidx.room.ExperimentalRoomApi public androidx.room.RoomDatabase.Builder<T!> setAutoCloseTimeout(@IntRange(from=0) long, java.util.concurrent.TimeUnit);
     method public androidx.room.RoomDatabase.Builder<T!> setJournalMode(androidx.room.RoomDatabase.JournalMode);
+    method @androidx.room.ExperimentalRoomApi public androidx.room.RoomDatabase.Builder<T!> setMultiInstanceInvalidationServiceIntent(android.content.Intent);
     method public androidx.room.RoomDatabase.Builder<T!> setQueryCallback(androidx.room.RoomDatabase.QueryCallback, java.util.concurrent.Executor);
     method public androidx.room.RoomDatabase.Builder<T!> setQueryExecutor(java.util.concurrent.Executor);
     method public androidx.room.RoomDatabase.Builder<T!> setTransactionExecutor(java.util.concurrent.Executor);
diff --git a/room/room-runtime/api/restricted_current.ignore b/room/room-runtime/api/restricted_current.ignore
index 6984c60..aeb6a9e 100644
--- a/room/room-runtime/api/restricted_current.ignore
+++ b/room/room-runtime/api/restricted_current.ignore
@@ -1,19 +1,3 @@
 // Baseline format: 1.0
-ChangedType: androidx.room.InvalidationTracker#createLiveData(String[], boolean, java.util.concurrent.Callable<T>):
-    Method androidx.room.InvalidationTracker.createLiveData has changed return type from LiveData<T> to androidx.lifecycle.LiveData<T>
-ChangedType: androidx.room.InvalidationTracker#createLiveData(String[], java.util.concurrent.Callable<T>):
-    Method androidx.room.InvalidationTracker.createLiveData has changed return type from LiveData<T> to androidx.lifecycle.LiveData<T>
-
-
-InvalidNullConversion: androidx.room.InvalidationTracker#createLiveData(String[], boolean, java.util.concurrent.Callable<T>):
-    Attempted to remove @NonNull annotation from method androidx.room.InvalidationTracker.createLiveData(String[],boolean,java.util.concurrent.Callable<T>)
-InvalidNullConversion: androidx.room.InvalidationTracker#createLiveData(String[], java.util.concurrent.Callable<T>):
-    Attempted to remove @NonNull annotation from method androidx.room.InvalidationTracker.createLiveData(String[],java.util.concurrent.Callable<T>)
-
-
-RemovedMethod: androidx.room.paging.LimitOffsetDataSource#isInvalid():
-    Removed method androidx.room.paging.LimitOffsetDataSource.isInvalid()
-RemovedMethod: androidx.room.paging.LimitOffsetDataSource#loadInitial(LoadInitialParams, LoadInitialCallback<T>):
-    Removed method androidx.room.paging.LimitOffsetDataSource.loadInitial(LoadInitialParams,LoadInitialCallback<T>)
-RemovedMethod: androidx.room.paging.LimitOffsetDataSource#loadRange(LoadRangeParams, LoadRangeCallback<T>):
-    Removed method androidx.room.paging.LimitOffsetDataSource.loadRange(LoadRangeParams,LoadRangeCallback<T>)
+RemovedClass: androidx.room.MultiInstanceInvalidationService:
+    Removed class androidx.room.MultiInstanceInvalidationService
diff --git a/room/room-runtime/api/restricted_current.txt b/room/room-runtime/api/restricted_current.txt
index 19a1975..17a238e 100644
--- a/room/room-runtime/api/restricted_current.txt
+++ b/room/room-runtime/api/restricted_current.txt
@@ -8,7 +8,8 @@
     ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?);
     ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?);
     ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?, java.util.List<java.lang.Object!>?);
-    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?, java.util.List<java.lang.Object!>?, java.util.List<androidx.room.migration.AutoMigrationSpec!>?);
+    ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?, java.util.List<java.lang.Object!>?, java.util.List<androidx.room.migration.AutoMigrationSpec!>?);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, android.content.Intent?, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?, java.util.List<java.lang.Object!>?, java.util.List<androidx.room.migration.AutoMigrationSpec!>?);
     method public boolean isMigrationRequired(int, int);
     method @Deprecated public boolean isMigrationRequiredFrom(int);
     field public final boolean allowDestructiveMigrationOnDowngrade;
@@ -22,6 +23,7 @@
     field public final androidx.room.RoomDatabase.JournalMode! journalMode;
     field public final androidx.room.RoomDatabase.MigrationContainer migrationContainer;
     field public final boolean multiInstanceInvalidation;
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final android.content.Intent! multiInstanceInvalidationServiceIntent;
     field public final String? name;
     field public final androidx.room.RoomDatabase.PrepackagedDatabaseCallback? prepackagedDatabaseCallback;
     field public final java.util.concurrent.Executor queryExecutor;
@@ -72,11 +74,6 @@
     method public abstract void onInvalidated(java.util.Set<java.lang.String!>);
   }
 
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class MultiInstanceInvalidationService extends android.app.Service {
-    ctor public MultiInstanceInvalidationService();
-    method public android.os.IBinder? onBind(android.content.Intent!);
-  }
-
   public class Room {
     ctor @Deprecated public Room();
     method public static <T extends androidx.room.RoomDatabase> androidx.room.RoomDatabase.Builder<T!> databaseBuilder(android.content.Context, Class<T!>, String);
diff --git a/room/room-runtime/src/main/java/androidx/room/DatabaseConfiguration.java b/room/room-runtime/src/main/java/androidx/room/DatabaseConfiguration.java
index 1861836..01e96bc 100644
--- a/room/room-runtime/src/main/java/androidx/room/DatabaseConfiguration.java
+++ b/room/room-runtime/src/main/java/androidx/room/DatabaseConfiguration.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.content.Intent;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -103,6 +104,15 @@
     public final boolean multiInstanceInvalidation;
 
     /**
+     * Intent that should be bound to acquire the invalidation service or {@code null} if not used.
+     *
+     * @see {@link #multiInstanceInvalidation}
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    public final Intent multiInstanceInvalidationServiceIntent;
+
+    /**
      * If true, Room should crash if a migration is missing.
      */
     public final boolean requireMigration;
@@ -142,8 +152,8 @@
      *
      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
      * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
-     * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
-     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>, List<AutoMigrationSpec>)}
+     * RoomDatabase.JournalMode, Executor, Executor, Intent, boolean, boolean, Set, String, File,
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List, List)}
      *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
@@ -182,8 +192,8 @@
      *
      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
      * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
-     * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
-     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>, List<AutoMigrationSpec>)}
+     * RoomDatabase.JournalMode, Executor, Executor, Intent, boolean, boolean, Set, String, File,
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List, List)}
      *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
@@ -228,8 +238,8 @@
      *
      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
      * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
-     * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
-     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>, List<AutoMigrationSpec>)}
+     * RoomDatabase.JournalMode, Executor, Executor, Intent, boolean, boolean, Set, String, File,
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List, List)}
      *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
@@ -278,8 +288,8 @@
      *
      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
      * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
-     * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
-     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>, List<AutoMigrationSpec>)}
+     * RoomDatabase.JournalMode, Executor, Executor, Intent, boolean, boolean, Set, String, File,
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List, List)}
      *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
@@ -332,8 +342,8 @@
      *
      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
      * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
-     * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
-     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>, List<AutoMigrationSpec>)}
+     * RoomDatabase.JournalMode, Executor, Executor, Intent, boolean, boolean, Set, String, File,
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List, List)}
      *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
@@ -389,8 +399,8 @@
      *
      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
      * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
-     * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
-     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>, List<AutoMigrationSpec>)}
+     * RoomDatabase.JournalMode, Executor, Executor, Intent, boolean, boolean, Set, String, File,
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List, List)}
      *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
@@ -446,6 +456,11 @@
     /**
      * Creates a database configuration with the given values.
      *
+     * @deprecated Use {@link #DatabaseConfiguration(Context, String,
+     * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
+     * RoomDatabase.JournalMode, Executor, Executor, Intent, boolean, boolean, Set, String, File,
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List, List)}
+     *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
      * @param sqliteOpenHelperFactory The open helper factory to use.
@@ -471,6 +486,7 @@
      *
      * @hide
      */
+    @Deprecated
     @SuppressLint("LambdaLast")
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
     public DatabaseConfiguration(@NonNull Context context, @Nullable String name,
@@ -491,6 +507,65 @@
             @Nullable RoomDatabase.PrepackagedDatabaseCallback prepackagedDatabaseCallback,
             @Nullable List<Object> typeConverters,
             @Nullable List<AutoMigrationSpec> autoMigrationSpecs) {
+        this(context, name, sqliteOpenHelperFactory, migrationContainer, callbacks,
+                allowMainThreadQueries, journalMode, queryExecutor, transactionExecutor,
+                multiInstanceInvalidation ? new Intent(context,
+                MultiInstanceInvalidationService.class) : null,
+                requireMigration, allowDestructiveMigrationOnDowngrade, migrationNotRequiredFrom,
+                copyFromAssetPath, copyFromFile, copyFromInputStream, prepackagedDatabaseCallback,
+                typeConverters, autoMigrationSpecs);
+    }
+
+    /**
+     * Creates a database configuration with the given values.
+     *
+     * @param context The application context.
+     * @param name Name of the database, can be null if it is in memory.
+     * @param sqliteOpenHelperFactory The open helper factory to use.
+     * @param migrationContainer The migration container for migrations.
+     * @param callbacks The list of callbacks for database events.
+     * @param allowMainThreadQueries Whether to allow main thread reads/writes or not.
+     * @param journalMode The journal mode. This has to be either TRUNCATE or WRITE_AHEAD_LOGGING.
+     * @param queryExecutor The Executor used to execute asynchronous queries.
+     * @param transactionExecutor The Executor used to execute asynchronous transactions.
+     * @param multiInstanceInvalidationServiceIntent The intent to use to bind to the
+     *                                               invalidation service or {@code null} if not
+     *                                               used.
+     * @param requireMigration True if Room should require a valid migration if version changes,
+     * @param allowDestructiveMigrationOnDowngrade True if Room should recreate tables if no
+     *                                             migration is supplied during a downgrade.
+     * @param migrationNotRequiredFrom The collection of schema versions from which migrations
+     *                                 aren't required.
+     * @param copyFromAssetPath The assets path to the pre-packaged database.
+     * @param copyFromFile The pre-packaged database file.
+     * @param copyFromInputStream The callable to get the input stream from which a
+     *                            pre-package database file will be copied from.
+     * @param prepackagedDatabaseCallback The pre-packaged callback.
+     * @param typeConverters The type converters.
+     * @param autoMigrationSpecs The auto migration specs.
+     *
+     * @hide
+     */
+    @SuppressLint("LambdaLast")
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    public DatabaseConfiguration(@NonNull Context context, @Nullable String name,
+            @NonNull SupportSQLiteOpenHelper.Factory sqliteOpenHelperFactory,
+            @NonNull RoomDatabase.MigrationContainer migrationContainer,
+            @Nullable List<RoomDatabase.Callback> callbacks,
+            boolean allowMainThreadQueries,
+            @NonNull RoomDatabase.JournalMode journalMode,
+            @NonNull Executor queryExecutor,
+            @NonNull Executor transactionExecutor,
+            @Nullable Intent multiInstanceInvalidationServiceIntent,
+            boolean requireMigration,
+            boolean allowDestructiveMigrationOnDowngrade,
+            @Nullable Set<Integer> migrationNotRequiredFrom,
+            @Nullable String copyFromAssetPath,
+            @Nullable File copyFromFile,
+            @Nullable Callable<InputStream> copyFromInputStream,
+            @Nullable RoomDatabase.PrepackagedDatabaseCallback prepackagedDatabaseCallback,
+            @Nullable List<Object> typeConverters,
+            @Nullable List<AutoMigrationSpec> autoMigrationSpecs) {
         this.sqliteOpenHelperFactory = sqliteOpenHelperFactory;
         this.context = context;
         this.name = name;
@@ -500,7 +575,9 @@
         this.journalMode = journalMode;
         this.queryExecutor = queryExecutor;
         this.transactionExecutor = transactionExecutor;
-        this.multiInstanceInvalidation = multiInstanceInvalidation;
+        this.multiInstanceInvalidationServiceIntent =
+                multiInstanceInvalidationServiceIntent;
+        this.multiInstanceInvalidation = multiInstanceInvalidationServiceIntent != null;
         this.requireMigration = requireMigration;
         this.allowDestructiveMigrationOnDowngrade = allowDestructiveMigrationOnDowngrade;
         this.mMigrationNotRequiredFrom = migrationNotRequiredFrom;
diff --git a/room/room-runtime/src/main/java/androidx/room/ExperimentalRoomApi.java b/room/room-runtime/src/main/java/androidx/room/ExperimentalRoomApi.java
index 729a4a9..14896bf 100644
--- a/room/room-runtime/src/main/java/androidx/room/ExperimentalRoomApi.java
+++ b/room/room-runtime/src/main/java/androidx/room/ExperimentalRoomApi.java
@@ -24,6 +24,6 @@
 /**
  * APIs marked with ExperimentalRoomApi are experimental and may change.
  */
-@Target({ElementType.METHOD})
+@Target({ElementType.TYPE, ElementType.METHOD})
 @RequiresOptIn()
 public @interface ExperimentalRoomApi {}
diff --git a/room/room-runtime/src/main/java/androidx/room/InvalidationTracker.java b/room/room-runtime/src/main/java/androidx/room/InvalidationTracker.java
index de59d64..fe0ae9a 100644
--- a/room/room-runtime/src/main/java/androidx/room/InvalidationTracker.java
+++ b/room/room-runtime/src/main/java/androidx/room/InvalidationTracker.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.content.Intent;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteException;
 import android.os.Build;
@@ -210,9 +211,9 @@
         }
     }
 
-    void startMultiInstanceInvalidation(Context context, String name) {
-        mMultiInstanceInvalidationClient = new MultiInstanceInvalidationClient(context, name, this,
-                mDatabase.getQueryExecutor());
+    void startMultiInstanceInvalidation(Context context, String name, Intent serviceIntent) {
+        mMultiInstanceInvalidationClient = new MultiInstanceInvalidationClient(context, name,
+                serviceIntent, this, mDatabase.getQueryExecutor());
     }
 
     void stopMultiInstanceInvalidation() {
diff --git a/room/room-runtime/src/main/java/androidx/room/MultiInstanceInvalidationClient.java b/room/room-runtime/src/main/java/androidx/room/MultiInstanceInvalidationClient.java
index c8a7b5d..cd847acc 100644
--- a/room/room-runtime/src/main/java/androidx/room/MultiInstanceInvalidationClient.java
+++ b/room/room-runtime/src/main/java/androidx/room/MultiInstanceInvalidationClient.java
@@ -142,10 +142,12 @@
      * @param context             The Context to be used for binding
      *                            {@link IMultiInstanceInvalidationService}.
      * @param name                The name of the database file.
+     * @param serviceIntent       The {@link Intent} used for binding
+     *                            {@link IMultiInstanceInvalidationService}.
      * @param invalidationTracker The {@link InvalidationTracker}
      * @param executor            The background executor.
      */
-    MultiInstanceInvalidationClient(Context context, String name,
+    MultiInstanceInvalidationClient(Context context, String name, Intent serviceIntent,
             InvalidationTracker invalidationTracker, Executor executor) {
         mAppContext = context.getApplicationContext();
         mName = name;
@@ -174,8 +176,7 @@
                 return true;
             }
         };
-        Intent intent = new Intent(mAppContext, MultiInstanceInvalidationService.class);
-        mAppContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
+        mAppContext.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
     }
 
     void stop() {
diff --git a/room/room-runtime/src/main/java/androidx/room/MultiInstanceInvalidationService.java b/room/room-runtime/src/main/java/androidx/room/MultiInstanceInvalidationService.java
index 2e98f12..0c82f93 100644
--- a/room/room-runtime/src/main/java/androidx/room/MultiInstanceInvalidationService.java
+++ b/room/room-runtime/src/main/java/androidx/room/MultiInstanceInvalidationService.java
@@ -23,8 +23,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
 
 import java.util.HashMap;
 
@@ -33,9 +33,12 @@
  * This service runs in the main app process. All the instances of {@link InvalidationTracker}
  * (potentially in other processes) has to connect to this service.
  *
- * @hide
+ * <p>The intent to launch it can be specified by
+ * {@link RoomDatabase.Builder#setMultiInstanceInvalidationServiceIntent}, although the service is
+ * defined in the manifest by default so there should be no need to override it in a normal
+ * situation.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@ExperimentalRoomApi
 public class MultiInstanceInvalidationService extends Service {
 
     // synthetic access
@@ -128,7 +131,7 @@
 
     @Nullable
     @Override
-    public IBinder onBind(Intent intent) {
+    public IBinder onBind(@NonNull Intent intent) {
         return mBinder;
     }
 }
diff --git a/room/room-runtime/src/main/java/androidx/room/RoomDatabase.java b/room/room-runtime/src/main/java/androidx/room/RoomDatabase.java
index 1b5ef23..54427d6 100644
--- a/room/room-runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/room-runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -19,6 +19,7 @@
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.content.Context;
+import android.content.Intent;
 import android.database.Cursor;
 import android.os.Build;
 import android.os.CancellationSignal;
@@ -263,9 +264,9 @@
         mTransactionExecutor = new TransactionExecutor(configuration.transactionExecutor);
         mAllowMainThreadQueries = configuration.allowMainThreadQueries;
         mWriteAheadLoggingEnabled = wal;
-        if (configuration.multiInstanceInvalidation) {
+        if (configuration.multiInstanceInvalidationServiceIntent != null) {
             mInvalidationTracker.startMultiInstanceInvalidation(configuration.context,
-                    configuration.name);
+                    configuration.name, configuration.multiInstanceInvalidationServiceIntent);
         }
 
         Map<Class<?>, List<Class<?>>> requiredFactories = getRequiredTypeConverters();
@@ -781,7 +782,7 @@
         private SupportSQLiteOpenHelper.Factory mFactory;
         private boolean mAllowMainThreadQueries;
         private JournalMode mJournalMode;
-        private boolean mMultiInstanceInvalidation;
+        private Intent mMultiInstanceInvalidationIntent;
         private boolean mRequireMigration;
         private boolean mAllowDestructiveMigrationOnDowngrade;
 
@@ -1167,7 +1168,33 @@
          */
         @NonNull
         public Builder<T> enableMultiInstanceInvalidation() {
-            mMultiInstanceInvalidation = mName != null;
+            mMultiInstanceInvalidationIntent = mName != null ? new Intent(mContext,
+                    MultiInstanceInvalidationService.class) : null;
+            return this;
+        }
+
+        /**
+         * Sets whether table invalidation in this instance of {@link RoomDatabase} should be
+         * broadcast and synchronized with other instances of the same {@link RoomDatabase},
+         * including those in a separate process. In order to enable multi-instance invalidation,
+         * this has to be turned on both ends and need to point to the same
+         * {@link MultiInstanceInvalidationService}.
+         * <p>
+         * This is not enabled by default.
+         * <p>
+         * This does not work for in-memory databases. This does not work between database instances
+         * targeting different database files.
+         *
+         * @return This {@link Builder} instance.
+         * @param invalidationServiceIntent Intent to bind to the
+         * {@link MultiInstanceInvalidationService}.
+         */
+        @SuppressWarnings("MissingGetterMatchingBuilder")
+        @NonNull
+        @ExperimentalRoomApi
+        public Builder<T> setMultiInstanceInvalidationServiceIntent(
+                @NonNull Intent invalidationServiceIntent) {
+            mMultiInstanceInvalidationIntent = mName != null ? invalidationServiceIntent : null;
             return this;
         }
 
@@ -1446,7 +1473,7 @@
                             mJournalMode.resolve(mContext),
                             mQueryExecutor,
                             mTransactionExecutor,
-                            mMultiInstanceInvalidation,
+                            mMultiInstanceInvalidationIntent,
                             mRequireMigration,
                             mAllowDestructiveMigrationOnDowngrade,
                             mMigrationsNotRequiredFrom,
diff --git a/room/room-testing/src/main/java/androidx/room/testing/MigrationTestHelper.java b/room/room-testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
index 1431498..4f0e4569 100644
--- a/room/room-testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
+++ b/room/room-testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
@@ -247,7 +247,7 @@
                 RoomDatabase.JournalMode.TRUNCATE,
                 ArchTaskExecutor.getIOThreadExecutor(),
                 ArchTaskExecutor.getIOThreadExecutor(),
-                false,
+                null,
                 true,
                 false,
                 Collections.<Integer>emptySet(),
@@ -312,7 +312,7 @@
                 RoomDatabase.JournalMode.TRUNCATE,
                 ArchTaskExecutor.getIOThreadExecutor(),
                 ArchTaskExecutor.getIOThreadExecutor(),
-                false,
+                null,
                 true,
                 false,
                 Collections.<Integer>emptySet(),