OSDN Git Service

Separating the DB upgrade into two paths:
authorSunny Goyal <sunnygoyal@google.com>
Thu, 13 Apr 2017 19:01:47 +0000 (12:01 -0700)
committerSunny Goyal <sunnygoyal@google.com>
Mon, 17 Apr 2017 16:36:05 +0000 (09:36 -0700)
> schema update: changes in the table schema
> data update: backward compatible changes to the data

Bug: 37257575
Change-Id: I856854ff2bffa2701f903a24fdc3baf6641175fd

src/com/android/launcher3/LauncherProvider.java

index 65d7672..6302744 100644 (file)
@@ -76,7 +76,18 @@ public class LauncherProvider extends ContentProvider {
     private static final String TAG = "LauncherProvider";
     private static final boolean LOGD = false;
 
-    private static final int DATABASE_VERSION = 28;
+    /**
+     * Represents the schema of the database. Changes in scheme need not be backwards compatible.
+     */
+    private static final int SCHEMA_VERSION = 27;
+    /**
+     * Represents the actual data. It could include additional validations and normalizations added
+     * overtime. These must be backwards compatible, else we risk breaking old devices during
+     * restore or binary version downgrade.
+     */
+    private static final int DATA_VERSION = 2;
+
+    private static final String PREF_KEY_DATA_VERISON = "provider_data_version";
 
     public static final String AUTHORITY = ProviderConfig.AUTHORITY;
 
@@ -599,7 +610,7 @@ public class LauncherProvider extends ContentProvider {
          */
         public DatabaseHelper(
                 Context context, Handler widgetHostResetHandler, String tableName) {
-            super(new NoLocaleSqliteContext(context), tableName, null, DATABASE_VERSION);
+            super(new NoLocaleSqliteContext(context), tableName, null, SCHEMA_VERSION);
             mContext = context;
             mWidgetHostResetHandler = widgetHostResetHandler;
         }
@@ -711,6 +722,55 @@ public class LauncherProvider extends ContentProvider {
         }
 
         @Override
+        public void onOpen(SQLiteDatabase db) {
+            super.onOpen(db);
+            SharedPreferences prefs = mContext
+                    .getSharedPreferences(LauncherFiles.DEVICE_PREFERENCES_KEY, 0);
+            int oldVersion = prefs.getInt(PREF_KEY_DATA_VERISON, 0);
+            if (oldVersion != DATA_VERSION) {
+                // Only run the data upgrade path for an existing db.
+                if (!Utilities.getPrefs(mContext).getBoolean(EMPTY_DATABASE_CREATED, false)) {
+                    db.beginTransaction();
+                    try {
+                        onDataUpgrade(db, oldVersion);
+                        db.setTransactionSuccessful();
+                    } catch (Exception e) {
+                        Log.d(TAG, "Error updating data version, ignoring", e);
+                        return;
+                    } finally {
+                        db.endTransaction();
+                    }
+                }
+                prefs.edit().putInt(PREF_KEY_DATA_VERISON, DATA_VERSION).apply();
+            }
+        }
+
+        /**
+         * Called when the data is updated as part of app update. It can be called multiple times
+         * with old version, even though it had been run before. The changes made here must be
+         * backwards compatible, else we risk breaking old devices during restore or binary
+         * version downgrade.
+         */
+        protected void onDataUpgrade(SQLiteDatabase db, int oldVersion) {
+            switch (oldVersion) {
+                case 0:
+                case 1: {
+                    // Remove "profile extra"
+                    UserManagerCompat um = UserManagerCompat.getInstance(mContext);
+                    for (UserHandle user : um.getUserProfiles()) {
+                        long serial = um.getSerialNumberForUser(user);
+                        String sql = "update favorites set intent = replace(intent, "
+                                + "';l.profile=" + serial + ";', ';') where itemType = 0;";
+                        db.execSQL(sql);
+                    }
+                }
+                case 2:
+                    // data updated
+                    return;
+            }
+        }
+
+        @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
             if (LOGD) Log.d(TAG, "onUpgrade triggered: " + oldVersion);
             switch (oldVersion) {
@@ -807,30 +867,9 @@ public class LauncherProvider extends ContentProvider {
                             !LauncherDbUtils.prepareScreenZeroToHostQsb(mContext, db)) {
                         break;
                     }
-                case 27: {
-                    // Remove "profile extra"
-                    db.beginTransaction();
-                    try {
-                        UserManagerCompat um = UserManagerCompat.getInstance(mContext);
-                        for (UserHandle user : um.getUserProfiles()) {
-                            long serial = um.getSerialNumberForUser(user);
-                            String sql = "update favorites set intent = replace(intent, "
-                                    + "';l.profile=" + serial + ";', ';') where itemType = 0;";
-                            db.execSQL(sql);
-                        }
-                        db.setTransactionSuccessful();
-                    } catch (SQLException ex) {
-                        Log.e(TAG, ex.getMessage(), ex);
-                        // Old version remains, which means we wipe old data
-                        break;
-                    } finally {
-                        db.endTransaction();
-                    }
-                }
-                case 28: {
+                case 27:
                     // DB Upgraded successfully
                     return;
-                }
             }
 
             // DB was not upgraded
@@ -840,6 +879,11 @@ public class LauncherProvider extends ContentProvider {
 
         @Override
         public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            if (oldVersion == 28 && newVersion == 27) {
+                // TODO: remove this check. This is only applicable for internal development/testing
+                // and for any released version of Launcher.
+                return;
+            }
             // This shouldn't happen -- throw our hands up in the air and start over.
             Log.w(TAG, "Database version downgrade from: " + oldVersion + " to " + newVersion +
                     ". Wiping databse.");