Rethrow non-recoverable errors when using sqlite with a better error.
* WorkManager will hopefully not be attributed to these kinds of errors.
Test: Added unit tests.
Change-Id: Idbc91153919281535a2247ea5c0e7f0103a09c7c
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/utils/ForceStopRunnableTest.java b/work/workmanager/src/androidTest/java/androidx/work/impl/utils/ForceStopRunnableTest.java
index 9e10200..db571b1 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/utils/ForceStopRunnableTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/utils/ForceStopRunnableTest.java
@@ -30,6 +30,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.database.sqlite.SQLiteCantOpenDatabaseException;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -141,4 +142,12 @@
verify(mScheduler, times(1)).schedule(eq(workSpec));
}
+
+ @Test(expected = IllegalStateException.class)
+ public void test_rethrowForNonRecoverableSqliteExceptions() {
+ ForceStopRunnable runnable = spy(mRunnable);
+ when(runnable.cleanUp())
+ .thenThrow(new SQLiteCantOpenDatabaseException("Cannot open database."));
+ runnable.run();
+ }
}
diff --git a/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java b/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
index e54d16a..7c7e5f0 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
@@ -28,6 +28,9 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.database.sqlite.SQLiteAccessPermException;
+import android.database.sqlite.SQLiteCantOpenDatabaseException;
+import android.database.sqlite.SQLiteDatabaseCorruptException;
import android.os.Build;
import androidx.annotation.NonNull;
@@ -80,24 +83,37 @@
// Clean invalid jobs attributed to WorkManager, and Workers that might have been
// interrupted because the application crashed (RUNNING state).
Logger.get().debug(TAG, "Performing cleanup operations.");
- boolean needsScheduling = cleanUp();
-
- if (shouldRescheduleWorkers()) {
- Logger.get().debug(TAG, "Rescheduling Workers.");
- mWorkManager.rescheduleEligibleWork();
- // Mark the jobs as migrated.
- mWorkManager.getPreferenceUtils().setNeedsReschedule(false);
- } else if (isForceStopped()) {
- Logger.get().debug(TAG, "Application was force-stopped, rescheduling.");
- mWorkManager.rescheduleEligibleWork();
- } else if (needsScheduling) {
- Logger.get().debug(TAG, "Found unfinished work, scheduling it.");
- Schedulers.schedule(
- mWorkManager.getConfiguration(),
- mWorkManager.getWorkDatabase(),
- mWorkManager.getSchedulers());
+ try {
+ boolean needsScheduling = cleanUp();
+ if (shouldRescheduleWorkers()) {
+ Logger.get().debug(TAG, "Rescheduling Workers.");
+ mWorkManager.rescheduleEligibleWork();
+ // Mark the jobs as migrated.
+ mWorkManager.getPreferenceUtils().setNeedsReschedule(false);
+ } else if (isForceStopped()) {
+ Logger.get().debug(TAG, "Application was force-stopped, rescheduling.");
+ mWorkManager.rescheduleEligibleWork();
+ } else if (needsScheduling) {
+ Logger.get().debug(TAG, "Found unfinished work, scheduling it.");
+ Schedulers.schedule(
+ mWorkManager.getConfiguration(),
+ mWorkManager.getWorkDatabase(),
+ mWorkManager.getSchedulers());
+ }
+ mWorkManager.onForceStopRunnableCompleted();
+ } catch (SQLiteCantOpenDatabaseException
+ | SQLiteDatabaseCorruptException
+ | SQLiteAccessPermException exception) {
+ // ForceStopRunnable is usually the first thing that accesses a database (or an app's
+ // internal data directory). This means that weird PackageManager bugs are attributed
+ // to ForceStopRunnable, which is unfortunate. This gives the developer a better error
+ // message.
+ String message =
+ "The file system on the device is in a bad state. WorkManager cannot access "
+ + "the app's internal data store.";
+ Logger.get().error(TAG, message, exception);
+ throw new IllegalStateException(message, exception);
}
- mWorkManager.onForceStopRunnableCompleted();
}
/**