Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser; | 5 package org.chromium.chrome.browser; |
| 6 | 6 |
| 7 import android.app.backup.BackupAgent; | 7 import android.app.backup.BackupAgent; |
| 8 import android.app.backup.BackupDataInput; | 8 import android.app.backup.BackupDataInput; |
| 9 import android.app.backup.BackupDataOutput; | 9 import android.app.backup.BackupDataOutput; |
| 10 import android.content.Context; | 10 import android.content.Context; |
| 11 import android.content.SharedPreferences; | 11 import android.content.SharedPreferences; |
| 12 import android.os.ParcelFileDescriptor; | 12 import android.os.ParcelFileDescriptor; |
| 13 import android.support.annotation.IntDef; | |
| 13 | 14 |
| 14 import org.chromium.base.ContextUtils; | 15 import org.chromium.base.ContextUtils; |
| 15 import org.chromium.base.Log; | 16 import org.chromium.base.Log; |
| 16 import org.chromium.base.PathUtils; | 17 import org.chromium.base.PathUtils; |
| 17 import org.chromium.base.ThreadUtils; | 18 import org.chromium.base.ThreadUtils; |
| 18 import org.chromium.base.VisibleForTesting; | 19 import org.chromium.base.VisibleForTesting; |
| 19 import org.chromium.base.annotations.SuppressFBWarnings; | 20 import org.chromium.base.annotations.SuppressFBWarnings; |
| 20 import org.chromium.base.library_loader.ProcessInitException; | 21 import org.chromium.base.library_loader.ProcessInitException; |
| 22 import org.chromium.base.metrics.RecordHistogram; | |
| 21 import org.chromium.chrome.browser.firstrun.FirstRunGlueImpl; | 23 import org.chromium.chrome.browser.firstrun.FirstRunGlueImpl; |
| 22 import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor; | 24 import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor; |
| 23 import org.chromium.chrome.browser.firstrun.FirstRunStatus; | 25 import org.chromium.chrome.browser.firstrun.FirstRunStatus; |
| 24 import org.chromium.chrome.browser.init.AsyncInitTaskRunner; | 26 import org.chromium.chrome.browser.init.AsyncInitTaskRunner; |
| 25 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; | 27 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; |
| 26 import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager ; | 28 import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager ; |
| 27 import org.chromium.components.signin.AccountManagerHelper; | 29 import org.chromium.components.signin.AccountManagerHelper; |
| 28 import org.chromium.components.signin.ChromeSigninController; | 30 import org.chromium.components.signin.ChromeSigninController; |
| 29 | 31 |
| 30 import java.io.FileInputStream; | 32 import java.io.FileInputStream; |
| 31 import java.io.FileOutputStream; | 33 import java.io.FileOutputStream; |
| 32 import java.io.IOException; | 34 import java.io.IOException; |
| 33 import java.io.ObjectInputStream; | 35 import java.io.ObjectInputStream; |
| 34 import java.io.ObjectOutputStream; | 36 import java.io.ObjectOutputStream; |
| 37 import java.lang.annotation.Retention; | |
| 38 import java.lang.annotation.RetentionPolicy; | |
| 35 import java.util.ArrayList; | 39 import java.util.ArrayList; |
| 36 import java.util.Arrays; | 40 import java.util.Arrays; |
| 37 import java.util.concurrent.Callable; | 41 import java.util.concurrent.Callable; |
| 38 import java.util.concurrent.CountDownLatch; | 42 import java.util.concurrent.CountDownLatch; |
| 39 import java.util.concurrent.TimeUnit; | 43 import java.util.concurrent.TimeUnit; |
| 40 | 44 |
| 41 /** | 45 /** |
| 42 * Backup agent for Chrome, using Android key/value backup. | 46 * Backup agent for Chrome, using Android key/value backup. |
| 43 */ | 47 */ |
| 44 | 48 |
| 45 public class ChromeBackupAgent extends BackupAgent { | 49 public class ChromeBackupAgent extends BackupAgent { |
| 50 /** | |
| 51 * | |
|
Bernhard Bauer
2017/03/16 11:36:36
:)
aberent
2017/03/16 12:16:50
Done.
| |
| 52 */ | |
| 46 private static final String ANDROID_DEFAULT_PREFIX = "AndroidDefault."; | 53 private static final String ANDROID_DEFAULT_PREFIX = "AndroidDefault."; |
| 47 private static final String NATIVE_PREF_PREFIX = "native."; | 54 private static final String NATIVE_PREF_PREFIX = "native."; |
| 48 | 55 |
| 49 private static final String TAG = "ChromeBackupAgent"; | 56 private static final String TAG = "ChromeBackupAgent"; |
| 50 | 57 |
| 58 @VisibleForTesting | |
| 59 static final String HISTOGRAM_ANDROID_RESTORE_RESULT = "Android.RestoreResul t"; | |
| 60 // Restore status is used to pass the result of any restore to Chrome's firs t run, so that | |
|
Bernhard Bauer
2017/03/16 11:36:36
Can you leave empty lines before comments?
aberent
2017/03/16 12:16:50
Done here, and where I think it helps readability
Bernhard Bauer
2017/03/16 14:34:01
That's fine, I wouldn't add them there either (or
| |
| 61 // it can be recorded as a histogram. | |
| 62 @Retention(RetentionPolicy.SOURCE) | |
| 63 @IntDef({NO_RESTORE, RESTORE_COMPLETED, RESTORE_AFTER_FIRST_RUN, BROWSER_STA RTUP_FAILED, | |
| 64 NOT_SIGNED_IN, RESTORE_STATUS_RECORDED}) | |
| 65 public @interface RestoreStatus {} | |
| 66 | |
| 67 // Values must match those in histogram.xml AndroidRestoreResult. | |
| 68 static final int NO_RESTORE = 0; | |
| 69 static final int RESTORE_COMPLETED = 1; | |
| 70 static final int RESTORE_AFTER_FIRST_RUN = 2; | |
| 71 static final int BROWSER_STARTUP_FAILED = 3; | |
| 72 static final int NOT_SIGNED_IN = 4; | |
| 73 static final int RESTORE_HISTOGRAM_BOUNDARY = 5; | |
| 74 // Set RESTORE_STATUS_RECORDED when the histogram has been recorded; so that it is only recorded | |
| 75 // once. | |
| 76 public static final int RESTORE_STATUS_RECORDED = 5; | |
| 77 | |
| 78 private static final String RESTORE_STATUS = "Android_restore_status"; | |
|
Bernhard Bauer
2017/03/16 11:36:36
Nit: The combination of uppercase initial and unde
aberent
2017/03/16 12:16:50
Done.
| |
| 79 | |
| 51 // Lists of preferences that should be restored unchanged. | 80 // Lists of preferences that should be restored unchanged. |
| 52 | 81 |
| 53 static final String[] BACKUP_ANDROID_BOOL_PREFS = { | 82 static final String[] BACKUP_ANDROID_BOOL_PREFS = { |
| 54 FirstRunGlueImpl.CACHED_TOS_ACCEPTED_PREF, | 83 FirstRunGlueImpl.CACHED_TOS_ACCEPTED_PREF, |
| 55 FirstRunStatus.FIRST_RUN_FLOW_COMPLETE, | 84 FirstRunStatus.FIRST_RUN_FLOW_COMPLETE, |
| 56 FirstRunStatus.LIGHTWEIGHT_FIRST_RUN_FLOW_COMPLETE, | 85 FirstRunStatus.LIGHTWEIGHT_FIRST_RUN_FLOW_COMPLETE, |
| 57 FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_SETUP, | 86 FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_SETUP, |
| 58 PrivacyPreferencesManager.PREF_METRICS_REPORTING, | 87 PrivacyPreferencesManager.PREF_METRICS_REPORTING, |
| 59 }; | 88 }; |
| 60 | 89 |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 210 | 239 |
| 211 @Override | 240 @Override |
| 212 public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDe scriptor newState) | 241 public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDe scriptor newState) |
| 213 throws IOException { | 242 throws IOException { |
| 214 // TODO(aberent) Check that this is not running on the UI thread. Doing so, however, makes | 243 // TODO(aberent) Check that this is not running on the UI thread. Doing so, however, makes |
| 215 // testing difficult since the test code runs on the UI thread. | 244 // testing difficult since the test code runs on the UI thread. |
| 216 | 245 |
| 217 // Check that the user hasn't already seen FRE (not sure if this can eve r happen, but if it | 246 // Check that the user hasn't already seen FRE (not sure if this can eve r happen, but if it |
| 218 // does then restoring the backup will overwrite the user's choices). | 247 // does then restoring the backup will overwrite the user's choices). |
| 219 SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); | 248 SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); |
| 220 if (sharedPrefs.getBoolean(FirstRunStatus.FIRST_RUN_FLOW_COMPLETE, false ) | 249 if (FirstRunStatus.getFirstRunFlowComplete() |
| 221 || sharedPrefs.getBoolean( | 250 || FirstRunStatus.getLightweightFirstRunFlowComplete()) { |
| 222 FirstRunStatus.LIGHTWEIGHT_FIRST_RUN_FLOW_COMPLETE, f alse)) { | 251 setRestoreStatus(RESTORE_AFTER_FIRST_RUN); |
| 223 Log.w(TAG, "Restore attempted after first run"); | 252 Log.w(TAG, "Restore attempted after first run"); |
| 224 return; | 253 return; |
| 225 } | 254 } |
| 226 | 255 |
| 227 final ArrayList<String> backupNames = new ArrayList<>(); | 256 final ArrayList<String> backupNames = new ArrayList<>(); |
| 228 final ArrayList<byte[]> backupValues = new ArrayList<>(); | 257 final ArrayList<byte[]> backupValues = new ArrayList<>(); |
| 229 | 258 |
| 230 String restoredUserName = null; | 259 String restoredUserName = null; |
| 231 while (data.readNextHeader()) { | 260 while (data.readNextHeader()) { |
| 232 String key = data.getKey(); | 261 String key = data.getKey(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 boolean browserStarted = | 302 boolean browserStarted = |
| 274 ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolea n>() { | 303 ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolea n>() { |
| 275 @Override | 304 @Override |
| 276 public Boolean call() { | 305 public Boolean call() { |
| 277 // Start the browser if necessary. | 306 // Start the browser if necessary. |
| 278 return initializeBrowser(backupAgent); | 307 return initializeBrowser(backupAgent); |
| 279 } | 308 } |
| 280 }); | 309 }); |
| 281 if (!browserStarted) { | 310 if (!browserStarted) { |
| 282 // Something went wrong starting Chrome, skip the restore. | 311 // Something went wrong starting Chrome, skip the restore. |
| 312 setRestoreStatus(BROWSER_STARTUP_FAILED); | |
| 283 return; | 313 return; |
| 284 } | 314 } |
| 285 // If the user hasn't signed in, or can't sign in, then don't restore an ything. | 315 // If the user hasn't signed in, or can't sign in, then don't restore an ything. |
| 286 if (restoredUserName == null || !accountExistsOnDevice(restoredUserName) ) { | 316 if (restoredUserName == null || !accountExistsOnDevice(restoredUserName) ) { |
| 317 setRestoreStatus(NOT_SIGNED_IN); | |
| 287 Log.i(TAG, "Chrome was not signed in with a known account name, not restoring"); | 318 Log.i(TAG, "Chrome was not signed in with a known account name, not restoring"); |
| 288 return; | 319 return; |
| 289 } | 320 } |
| 290 // Restore the native preferences on the UI thread | 321 // Restore the native preferences on the UI thread |
| 291 ThreadUtils.runOnUiThreadBlocking(new Runnable() { | 322 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 292 @Override | 323 @Override |
| 293 public void run() { | 324 public void run() { |
| 294 ArrayList<String> nativeBackupNames = new ArrayList<>(); | 325 ArrayList<String> nativeBackupNames = new ArrayList<>(); |
| 295 boolean[] nativeBackupValues = new boolean[backupNames.size()]; | 326 boolean[] nativeBackupValues = new boolean[backupNames.size()]; |
| 296 int count = 0; | 327 int count = 0; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 324 | 355 |
| 325 // Because FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_COMPLETE is not restored Chrome | 356 // Because FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_COMPLETE is not restored Chrome |
| 326 // will sign in the user on first run to the account in FIRST_RUN_FLOW_S IGNIN_ACCOUNT_NAME | 357 // will sign in the user on first run to the account in FIRST_RUN_FLOW_S IGNIN_ACCOUNT_NAME |
| 327 // if any. If the rest of FRE has been completed this will happen silent ly. | 358 // if any. If the rest of FRE has been completed this will happen silent ly. |
| 328 editor.putString( | 359 editor.putString( |
| 329 FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_ACCOUNT_NAME, rest oredUserName); | 360 FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_ACCOUNT_NAME, rest oredUserName); |
| 330 editor.apply(); | 361 editor.apply(); |
| 331 | 362 |
| 332 // The silent first run will change things, so there is no point in tryi ng to prevent | 363 // The silent first run will change things, so there is no point in tryi ng to prevent |
| 333 // additional backups at this stage. Don't write anything to |newState|. | 364 // additional backups at this stage. Don't write anything to |newState|. |
| 365 setRestoreStatus(RESTORE_COMPLETED); | |
| 334 Log.i(TAG, "Restore complete"); | 366 Log.i(TAG, "Restore complete"); |
| 335 } | 367 } |
| 336 | 368 |
| 337 @VisibleForTesting | 369 @VisibleForTesting |
| 338 AsyncInitTaskRunner createAsyncInitTaskRunner(final CountDownLatch latch) { | 370 AsyncInitTaskRunner createAsyncInitTaskRunner(final CountDownLatch latch) { |
| 339 return new AsyncInitTaskRunner() { | 371 return new AsyncInitTaskRunner() { |
| 340 | 372 |
| 341 @Override | 373 @Override |
| 342 protected void onSuccess() { | 374 protected void onSuccess() { |
| 343 latch.countDown(); | 375 latch.countDown(); |
| 344 } | 376 } |
| 345 | 377 |
| 346 @Override | 378 @Override |
| 347 protected void onFailure() { | 379 protected void onFailure() { |
| 348 // Ignore failure. Problems with the variation seed can be ignor ed, and other | 380 // Ignore failure. Problems with the variation seed can be ignor ed, and other |
| 349 // problems will either recover or be repeated when Chrome is st arted synchronously. | 381 // problems will either recover or be repeated when Chrome is st arted synchronously. |
| 350 latch.countDown(); | 382 latch.countDown(); |
| 351 } | 383 } |
| 352 }; | 384 }; |
| 353 } | 385 } |
| 354 | 386 |
| 387 /** | |
| 388 * Get the saved result of any restore that may have happened. | |
| 389 * | |
| 390 * @return the restore status, a RestoreStatus value. | |
| 391 */ | |
| 392 @VisibleForTesting | |
| 393 @RestoreStatus | |
| 394 static int getRestoreStatus() { | |
| 395 return ContextUtils.getAppSharedPreferences().getInt(RESTORE_STATUS, NO_ RESTORE); | |
| 396 } | |
| 397 | |
| 398 /** | |
| 399 * Set the restore status | |
|
Bernhard Bauer
2017/03/16 11:36:36
Nit: I don't think this comments adds any value.
aberent
2017/03/16 12:16:50
Updated comment.
| |
| 400 * | |
| 401 * @param status the status. | |
| 402 */ | |
| 403 @VisibleForTesting | |
| 404 static void setRestoreStatus(@RestoreStatus int status) { | |
| 405 ContextUtils.getAppSharedPreferences().edit().putInt(RESTORE_STATUS, sta tus).apply(); | |
| 406 } | |
| 407 | |
| 408 /** | |
| 409 * Record the restore histogram. To be called from Chrome itself once it is running. | |
| 410 */ | |
| 411 static void recordRestoreHistogram() { | |
| 412 int restoreStatus = getRestoreStatus(); | |
| 413 // Ensure restore status is only recorded once | |
| 414 if (restoreStatus != RESTORE_STATUS_RECORDED) { | |
| 415 RecordHistogram.recordEnumeratedHistogram( | |
| 416 HISTOGRAM_ANDROID_RESTORE_RESULT, restoreStatus, RESTORE_HIS TOGRAM_BOUNDARY); | |
| 417 setRestoreStatus(RESTORE_STATUS_RECORDED); | |
| 418 } | |
| 419 } | |
| 420 | |
| 355 @VisibleForTesting | 421 @VisibleForTesting |
| 356 protected native String[] nativeGetBoolBackupNames(); | 422 protected native String[] nativeGetBoolBackupNames(); |
| 357 | 423 |
| 358 @VisibleForTesting | 424 @VisibleForTesting |
| 359 protected native boolean[] nativeGetBoolBackupValues(); | 425 protected native boolean[] nativeGetBoolBackupValues(); |
| 360 | 426 |
| 361 @VisibleForTesting | 427 @VisibleForTesting |
| 362 protected native void nativeSetBoolBackupPrefs(String[] name, boolean[] valu e); | 428 protected native void nativeSetBoolBackupPrefs(String[] name, boolean[] valu e); |
| 363 } | 429 } |
| OLD | NEW |