mobile/android/base/sync/config/ConfigurationMigrator.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 package org.mozilla.gecko.sync.config;
     7 import java.util.HashMap;
     8 import java.util.Map;
     9 import java.util.Map.Entry;
    11 import org.mozilla.gecko.background.common.log.Logger;
    12 import org.mozilla.gecko.sync.SyncConfiguration;
    13 import org.mozilla.gecko.sync.Utils;
    15 import android.accounts.Account;
    16 import android.accounts.AccountManager;
    17 import android.content.Context;
    18 import android.content.SharedPreferences;
    19 import android.content.SharedPreferences.Editor;
    21 /**
    22  * Migrate Sync preferences between versions.
    23  * <p>
    24  * The original preferences were un-versioned; we refer to that as "version 0".
    25  * The original preferences were stored in three places:
    26  * <ul>
    27  * <li>most prefs were kept in per-Sync account Android shared prefs;</li>
    28  * <li>some prefs were kept in per-App Android shared prefs;</li>
    29  * <li>some client prefs were kept in the (assumed unique) Android Account.</li>
    30  * </ul>
    31  * <p>
    32  * Post version 0, all preferences are stored in per-Sync account Android shared prefs.
    33  */
    34 public class ConfigurationMigrator {
    35   public static final String LOG_TAG = "ConfigMigrator";
    37   /**
    38    * Copy and rename preferences.
    39    *
    40    * @param from source.
    41    * @param to sink.
    42    * @param map map from old preference names to new preference names.
    43    * @return the number of preferences migrated.
    44    */
    45   protected static int copyPreferences(final SharedPreferences from, final Map<String, String> map, final Editor to) {
    46     int count = 0;
    48     // SharedPreferences has no way to get a key/value pair without specifying the value type, so we do this instead.
    49     for (Entry<String, ?> entry : from.getAll().entrySet()) {
    50       String fromKey = entry.getKey();
    51       String toKey = map.get(fromKey);
    52       if (toKey == null) {
    53         continue;
    54       }
    56       Object value = entry.getValue();
    57       if (value instanceof Boolean) {
    58          to.putBoolean(toKey, ((Boolean) value).booleanValue());
    59       } else if (value instanceof Float) {
    60          to.putFloat(toKey, ((Float) value).floatValue());
    61       } else if (value instanceof Integer) {
    62          to.putInt(toKey, ((Integer) value).intValue());
    63       } else if (value instanceof Long) {
    64          to.putLong(toKey, ((Long) value).longValue());
    65       } else if (value instanceof String) {
    66          to.putString(toKey, (String) value);
    67       } else {
    68         // Do nothing -- perhaps SharedPreferences accepts types we don't know about.
    69       }
    71       if (Logger.LOG_PERSONAL_INFORMATION) {
    72         Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "' (" + value + ").");
    73       } else {
    74         Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "'.");
    75       }
    76       count += 1;
    77     }
    79     return count;
    80   }
    82   protected final static String V0_PREF_CLUSTER_URL_IS_STALE = "clusterurlisstale";
    83   protected final static String V1_PREF_CLUSTER_URL_IS_STALE = V0_PREF_CLUSTER_URL_IS_STALE;
    84   protected final static String V0_PREF_EARLIEST_NEXT_SYNC = "earliestnextsync";
    85   protected final static String V1_PREF_EARLIEST_NEXT_SYNC = V0_PREF_EARLIEST_NEXT_SYNC;
    87   /**
    88    * Extract version 0 preferences from per-App Android shared prefs and write to version 1 per-Sync account shared prefs.
    89    *
    90    * @param from per-App version 0 Android shared prefs.
    91    * @param to per-Sync account version 1 shared prefs.
    92    * @return the number of preferences migrated.
    93    * @throws Exception
    94    */
    95   protected static int upgradeGlobals0to1(final SharedPreferences from, final SharedPreferences to) throws Exception {
    96     Map<String, String> map = new HashMap<String, String>();
    97     map.put(V0_PREF_CLUSTER_URL_IS_STALE, V1_PREF_CLUSTER_URL_IS_STALE);
    98     map.put(V0_PREF_EARLIEST_NEXT_SYNC, V1_PREF_EARLIEST_NEXT_SYNC);
   100     Editor editor = to.edit();
   101     int count = copyPreferences(from, map, editor);
   102     if (count > 0) {
   103       editor.commit();
   104     }
   105     return count;
   106   }
   108   /**
   109    * Extract version 1 per-Sync account shared prefs and write to version 0 preferences from per-App Android shared prefs.
   110    *
   111    * @param from per-Sync account version 1 shared prefs.
   112    * @param to per-App version 0 Android shared prefs.
   113    * @return the number of preferences migrated.
   114    * @throws Exception
   115    */
   116   protected static int downgradeGlobals1to0(final SharedPreferences from, final SharedPreferences to) throws Exception {
   117     Map<String, String> map = new HashMap<String, String>();
   118     map.put(V1_PREF_CLUSTER_URL_IS_STALE, V0_PREF_CLUSTER_URL_IS_STALE);
   119     map.put(V1_PREF_EARLIEST_NEXT_SYNC, V0_PREF_EARLIEST_NEXT_SYNC);
   121     Editor editor = to.edit();
   122     int count = copyPreferences(from, map, editor);
   123     if (count > 0) {
   124       editor.commit();
   125     }
   126     return count;
   127   }
   129   protected static final String V0_PREF_ACCOUNT_GUID = "account.guid";
   130   protected static final String V1_PREF_ACCOUNT_GUID = V0_PREF_ACCOUNT_GUID;
   131   protected static final String V0_PREF_CLIENT_NAME = "account.clientName";
   132   protected static final String V1_PREF_CLIENT_NAME = V0_PREF_CLIENT_NAME;
   133   protected static final String V0_PREF_NUM_CLIENTS = "account.numClients";
   134   protected static final String V1_PREF_NUM_CLIENTS = V0_PREF_NUM_CLIENTS;
   136   /**
   137    * Extract version 0 per-Android account user data and write to version 1 per-Sync account shared prefs.
   138    *
   139    * @param accountManager Android account manager.
   140    * @param account Android account.
   141    * @param to per-Sync account version 1 shared prefs.
   142    * @return the number of preferences migrated.
   143    * @throws Exception
   144    */
   145   protected static int upgradeAndroidAccount0to1(final AccountManager accountManager, final Account account, final SharedPreferences to) throws Exception {
   146     final String V0_PREF_ACCOUNT_GUID = "account.guid";
   147     final String V1_PREF_ACCOUNT_GUID = V0_PREF_ACCOUNT_GUID;
   148     final String V0_PREF_CLIENT_NAME = "account.clientName";
   149     final String V1_PREF_CLIENT_NAME = V0_PREF_CLIENT_NAME;
   150     final String V0_PREF_NUM_CLIENTS = "account.numClients";
   151     final String V1_PREF_NUM_CLIENTS = V0_PREF_NUM_CLIENTS;
   153     String accountGUID = null;
   154     String clientName = null;
   155     long numClients = -1;
   156     try {
   157       accountGUID = accountManager.getUserData(account, V0_PREF_ACCOUNT_GUID);
   158     } catch (Exception e) {
   159       // Do nothing.
   160     }
   161     try {
   162       clientName = accountManager.getUserData(account, V0_PREF_CLIENT_NAME);
   163     } catch (Exception e) {
   164       // Do nothing.
   165     }
   166     try {
   167       numClients = Long.parseLong(accountManager.getUserData(account, V0_PREF_NUM_CLIENTS));
   168     } catch (Exception e) {
   169       // Do nothing.
   170     }
   172     final Editor editor = to.edit();
   174     int count = 0;
   175     if (accountGUID != null) {
   176       final String fromKey = V0_PREF_ACCOUNT_GUID;
   177       final String toKey = V1_PREF_ACCOUNT_GUID;
   178       if (Logger.LOG_PERSONAL_INFORMATION) {
   179         Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "' (" + accountGUID + ").");
   180       } else {
   181         Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "'.");
   182       }
   183       editor.putString(toKey, accountGUID);
   184       count += 1;
   185     }
   186     if (clientName != null) {
   187       final String fromKey = V0_PREF_CLIENT_NAME;
   188       final String toKey = V1_PREF_CLIENT_NAME;
   189       if (Logger.LOG_PERSONAL_INFORMATION) {
   190         Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "' (" + clientName + ").");
   191       } else {
   192         Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "'.");
   193       }
   194       editor.putString(toKey, clientName);
   195       count += 1;
   196     }
   197     if (numClients > -1) {
   198       final String fromKey = V0_PREF_NUM_CLIENTS;
   199       final String toKey = V1_PREF_NUM_CLIENTS;
   200       if (Logger.LOG_PERSONAL_INFORMATION) {
   201         Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "' (" + numClients + ").");
   202       } else {
   203         Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "'.");
   204       }
   205       editor.putLong(toKey, numClients);
   206       count += 1;
   207     }
   209     if (count > 0) {
   210       editor.commit();
   211     }
   212     return count;
   213   }
   215   /**
   216    * Extract version 1 per-Sync account shared prefs and write to version 0 per-Android account user data.
   217    *
   218    * @param from per-Sync account version 1 shared prefs.
   219    * @param accountManager Android account manager.
   220    * @param account Android account.
   221    * @return the number of preferences migrated.
   222    * @throws Exception
   223    */
   224   protected static int downgradeAndroidAccount1to0(final SharedPreferences from, final AccountManager accountManager, final Account account) throws Exception {
   225     final String accountGUID = from.getString(V1_PREF_ACCOUNT_GUID, null);
   226     final String clientName = from.getString(V1_PREF_CLIENT_NAME, null);
   227     final long numClients = from.getLong(V1_PREF_NUM_CLIENTS, -1L);
   229     int count = 0;
   230     if (accountGUID != null) {
   231       Logger.debug(LOG_TAG, "Migrated account GUID.");
   232       accountManager.setUserData(account, V0_PREF_ACCOUNT_GUID, accountGUID);
   233       count += 1;
   234     }
   235     if (clientName != null) {
   236       Logger.debug(LOG_TAG, "Migrated client name.");
   237       accountManager.setUserData(account, V1_PREF_CLIENT_NAME, clientName);
   238       count += 1;
   239     }
   240     if (numClients > -1) {
   241       Logger.debug(LOG_TAG, "Migrated clients count.");
   242       accountManager.setUserData(account, V1_PREF_NUM_CLIENTS, new Long(numClients).toString());
   243       count += 1;
   244     }
   245     return count;
   246   }
   248   /**
   249    * Extract version 0 per-Android account user data and write to version 1 per-Sync account shared prefs.
   250    *
   251    * @param from per-Sync account version 0 shared prefs.
   252    * @param to per-Sync account version 1 shared prefs.
   253    * @return the number of preferences migrated.
   254    * @throws Exception
   255    */
   256   protected static int upgradeShared0to1(final SharedPreferences from, final SharedPreferences to) {
   257     final Map<String, String> map = new HashMap<String, String>();
   258     final String[] prefs = new String [] {
   259         "syncID",
   260         "clusterURL",
   261         "enabledEngineNames",
   263         "metaGlobalLastModified", "metaGlobalServerResponseBody",
   265         "crypto5KeysLastModified", "crypto5KeysServerResponseBody",
   267         "serverClientsTimestamp", "serverClientRecordTimestamp",
   269         "forms.remote", "forms.local", "forms.syncID",
   270         "tabs.remote", "tabs.local", "tabs.syncID",
   271         "passwords.remote", "passwords.local", "passwords.syncID",
   272         "history.remote", "history.local", "history.syncID",
   273         "bookmarks.remote", "bookmarks.local", "bookmarks.syncID",
   274     };
   275     for (String pref : prefs) {
   276       map.put(pref, pref);
   277     }
   279     Editor editor = to.edit();
   280     int count = copyPreferences(from, map, editor);
   281     if (count > 0) {
   282       editor.commit();
   283     }
   284     return count;
   285   }
   287   /**
   288    * Extract version 1 per-Sync account shared prefs and write to version 0 per-Android account user data.
   289    *
   290    * @param from per-Sync account version 1 shared prefs.
   291    * @param to per-Sync account version 0 shared prefs.
   292    * @return the number of preferences migrated.
   293    * @throws Exception
   294    */
   295   protected static int downgradeShared1to0(final SharedPreferences from, final SharedPreferences to) {
   296     // Strictly a copy, no re-naming, no deletions -- so just invert.
   297     return upgradeShared0to1(from, to);
   298   }
   300   public static void upgrade0to1(final Context context, final AccountManager accountManager, final Account account,
   301       final String product, final String username, final String serverURL, final String profile) throws Exception {
   303     final String GLOBAL_SHARED_PREFS = "sync.prefs.global";
   305     final SharedPreferences globalPrefs = context.getSharedPreferences(GLOBAL_SHARED_PREFS, Utils.SHARED_PREFERENCES_MODE);
   306     final SharedPreferences accountPrefs = Utils.getSharedPreferences(context, product, username, serverURL, profile, 0);
   307     final SharedPreferences newPrefs = Utils.getSharedPreferences(context, product, username, serverURL, profile, 1);
   309     upgradeGlobals0to1(globalPrefs, newPrefs);
   310     upgradeAndroidAccount0to1(accountManager, account, newPrefs);
   311     upgradeShared0to1(accountPrefs, newPrefs);
   312   }
   314   public static void downgrade1to0(final Context context, final AccountManager accountManager, final Account account,
   315       final String product, final String username, final String serverURL, final String profile) throws Exception {
   317     final String GLOBAL_SHARED_PREFS = "sync.prefs.global";
   319     final SharedPreferences globalPrefs = context.getSharedPreferences(GLOBAL_SHARED_PREFS, Utils.SHARED_PREFERENCES_MODE);
   320     final SharedPreferences accountPrefs = Utils.getSharedPreferences(context, product, username, serverURL, profile, 0);
   321     final SharedPreferences oldPrefs = Utils.getSharedPreferences(context, product, username, serverURL, profile, 1);
   323     downgradeGlobals1to0(oldPrefs, globalPrefs);
   324     downgradeAndroidAccount1to0(oldPrefs, accountManager, account);
   325     downgradeShared1to0(oldPrefs, accountPrefs);
   326   }
   328   /**
   329    * Migrate, if necessary, existing prefs to a certain version.
   330    * <p>
   331    * Stores current prefs version in Android shared prefs with root
   332    * "sync.prefs.version", which corresponds to the file
   333    * "sync.prefs.version.xml".
   334    *
   335    * @param desiredVersion
   336    *          version to finish it.
   337    * @param context
   338    * @param accountManager
   339    * @param account
   340    * @param product
   341    * @param username
   342    * @param serverURL
   343    * @param profile
   344    * @throws Exception
   345    */
   346   public static void ensurePrefsAreVersion(final long desiredVersion,
   347       final Context context, final AccountManager accountManager, final Account account,
   348       final String product, final String username, final String serverURL, final String profile) throws Exception {
   349     if (desiredVersion < 0 || desiredVersion > SyncConfiguration.CURRENT_PREFS_VERSION) {
   350       throw new IllegalArgumentException("Cannot migrate to unknown version " + desiredVersion + ".");
   351     }
   353     SharedPreferences versionPrefs = context.getSharedPreferences("sync.prefs.version", Utils.SHARED_PREFERENCES_MODE);
   355     // We default to 0 since clients getting this code for the first time will
   356     // not have "sync.prefs.version.xml" *at all*, and upgrading when all old
   357     // data is missing is expected to be safe.
   358     long currentVersion = versionPrefs.getLong(SyncConfiguration.PREF_PREFS_VERSION, 0);
   359     if (currentVersion == desiredVersion) {
   360       Logger.info(LOG_TAG, "Current version (" + currentVersion + ") is desired version; no need to migrate.");
   361       return;
   362     }
   364     if (currentVersion < 0 || currentVersion > SyncConfiguration.CURRENT_PREFS_VERSION) {
   365       throw new IllegalStateException("Cannot migrate from unknown version " + currentVersion + ".");
   366     }
   368     // Now we're down to either version 0 or version 1.
   369     if (currentVersion == 0 && desiredVersion == 1) {
   370       Logger.info(LOG_TAG, "Upgrading from version 0 to version 1.");
   371       upgrade0to1(context, accountManager, account, product, username, serverURL, profile);
   372     } else if (currentVersion == 1 && desiredVersion == 0) {
   373       Logger.info(LOG_TAG, "Upgrading from version 0 to version 1.");
   374       upgrade0to1(context, accountManager, account, product, username, serverURL, profile);
   375     } else {
   376       Logger.warn(LOG_TAG, "Don't know how to migrate from version " + currentVersion + " to " + desiredVersion + ".");
   377     }
   379     Logger.info(LOG_TAG, "Migrated from version " + currentVersion + " to version " + desiredVersion + ".");
   380     versionPrefs.edit().putLong(SyncConfiguration.PREF_PREFS_VERSION, desiredVersion).commit();
   381   }
   382 }

mercurial