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 |