Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / android / java / src / org / chromium / chrome / browser / sync / ProfileSyncService.java
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.sync;
6
7 import android.content.Context;
8 import android.util.Log;
9
10 import org.chromium.base.CalledByNative;
11 import org.chromium.base.ThreadUtils;
12 import org.chromium.base.VisibleForTesting;
13 import org.chromium.chrome.browser.identity.UniqueIdentificationGenerator;
14 import org.chromium.sync.internal_api.pub.SyncDecryptionPassphraseType;
15 import org.chromium.sync.internal_api.pub.base.ModelType;
16
17 import java.util.HashSet;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Set;
21 import java.util.SortedSet;
22 import java.util.TreeSet;
23 import java.util.concurrent.CopyOnWriteArrayList;
24
25 /**
26  * Android wrapper of the ProfileSyncService which provides access from the Java layer.
27  * <p/>
28  * This class mostly wraps native classes, but it make a few business logic decisions, both in Java
29  * and in native.
30  * <p/>
31  * Only usable from the UI thread as the native ProfileSyncService requires its access to be in the
32  * UI thread.
33  * <p/>
34  * See chrome/browser/sync/profile_sync_service.h for more details.
35  */
36 public class ProfileSyncService {
37
38     public interface SyncStateChangedListener {
39         // Invoked when the underlying sync status has changed.
40         public void syncStateChanged();
41     }
42
43     private static final String TAG = "ProfileSyncService";
44
45     @VisibleForTesting
46     public static final String SESSION_TAG_PREFIX = "session_sync";
47
48     private static ProfileSyncService sSyncSetupManager;
49
50     @VisibleForTesting
51     protected final Context mContext;
52
53     // Sync state changes more often than listeners are added/removed, so using CopyOnWrite.
54     private final List<SyncStateChangedListener> mListeners =
55             new CopyOnWriteArrayList<SyncStateChangedListener>();
56
57     // Native ProfileSyncServiceAndroid object. Can not be final since we set it to 0 in destroy().
58     private final long mNativeProfileSyncServiceAndroid;
59
60     /**
61      * A helper method for retrieving the application-wide SyncSetupManager.
62      * <p/>
63      * Can only be accessed on the main thread.
64      *
65      * @param context the ApplicationContext is retrieved from the context used as an argument.
66      * @return a singleton instance of the SyncSetupManager
67      */
68     public static ProfileSyncService get(Context context) {
69         ThreadUtils.assertOnUiThread();
70         if (sSyncSetupManager == null) {
71             sSyncSetupManager = new ProfileSyncService(context);
72         }
73         return sSyncSetupManager;
74     }
75
76     /**
77      * This is called pretty early in our application. Avoid any blocking operations here.
78      */
79     private ProfileSyncService(Context context) {
80         ThreadUtils.assertOnUiThread();
81         // We should store the application context, as we outlive any activity which may create us.
82         mContext = context.getApplicationContext();
83
84         // This may cause us to create ProfileSyncService even if sync has not
85         // been set up, but ProfileSyncService::Startup() won't be called until
86         // credentials are available.
87         mNativeProfileSyncServiceAndroid = nativeInit();
88     }
89
90     @CalledByNative
91     private static long getProfileSyncServiceAndroid(Context context) {
92         return get(context).mNativeProfileSyncServiceAndroid;
93     }
94
95     /**
96      * If we are currently in the process of setting up sync, this method clears the
97      * sync setup in progress flag.
98      */
99     @VisibleForTesting
100     public void finishSyncFirstSetupIfNeeded() {
101         if (isFirstSetupInProgress()) {
102             setSyncSetupCompleted();
103             setSetupInProgress(false);
104         }
105     }
106
107     public void signOut() {
108         nativeSignOutSync(mNativeProfileSyncServiceAndroid);
109     }
110
111     /**
112      * Signs in to sync, using the currently signed-in account.
113      */
114     public void syncSignIn() {
115         nativeSignInSync(mNativeProfileSyncServiceAndroid);
116         // Notify listeners right away that the sync state has changed (native side does not do
117         // this)
118         syncStateChanged();
119     }
120
121     /**
122      * Signs in to sync, using the existing auth token.
123      */
124     @Deprecated
125     public void syncSignIn(String account) {
126         syncSignIn();
127     }
128
129     /**
130      * Signs in to sync.
131      *
132      * @param account   The username of the account that is signing in.
133      * @param authToken Not used. ProfileSyncService switched to OAuth2 tokens.
134      * Deprecated. Use syncSignIn instead.
135      */
136     @Deprecated
137     public void syncSignInWithAuthToken(String account, String authToken) {
138         syncSignIn(account);
139     }
140
141     public void requestSyncFromNativeChrome(
142             int objectSource, String objectId, long version, String payload) {
143         ThreadUtils.assertOnUiThread();
144         nativeNudgeSyncer(
145                 mNativeProfileSyncServiceAndroid, objectSource, objectId, version, payload);
146     }
147
148     public void requestSyncFromNativeChromeForAllTypes() {
149         ThreadUtils.assertOnUiThread();
150         nativeNudgeSyncerForAllTypes(mNativeProfileSyncServiceAndroid);
151     }
152
153     /**
154      * Nudge the syncer to start a new sync cycle.
155      */
156     @VisibleForTesting
157     public void requestSyncCycleForTest() {
158         ThreadUtils.assertOnUiThread();
159         requestSyncFromNativeChromeForAllTypes();
160     }
161
162     public String querySyncStatus() {
163         ThreadUtils.assertOnUiThread();
164         return nativeQuerySyncStatusSummary(mNativeProfileSyncServiceAndroid);
165     }
166
167     /**
168      * Sets the the machine tag used by session sync to a unique value.
169      */
170     public void setSessionsId(UniqueIdentificationGenerator generator) {
171         ThreadUtils.assertOnUiThread();
172         String uniqueTag = generator.getUniqueId(null);
173         if (uniqueTag.isEmpty()) {
174             Log.e(TAG, "Unable to get unique tag for sync. " +
175                     "This may lead to unexpected tab sync behavior.");
176             return;
177         }
178         String sessionTag = SESSION_TAG_PREFIX + uniqueTag;
179         if (!nativeSetSyncSessionsId(mNativeProfileSyncServiceAndroid, sessionTag)) {
180             Log.e(TAG, "Unable to write session sync tag. " +
181                     "This may lead to unexpected tab sync behavior.");
182         }
183     }
184
185     /**
186      * Checks if a password or a passphrase is required for decryption of sync data.
187      * <p/>
188      * Returns NONE if the state is unavailable, or decryption passphrase/password is not required.
189      *
190      * @return the enum describing the decryption passphrase type required
191      */
192     public SyncDecryptionPassphraseType getSyncDecryptionPassphraseTypeIfRequired() {
193         // ProfileSyncService::IsUsingSecondaryPassphrase() requires the sync backend to be
194         // initialized, and that happens just after OnPassphraseRequired(). Therefore, we need to
195         // guard that call with a check of the sync backend since we can not be sure which
196         // passphrase type we should tell the user we need.
197         // This is tracked in:
198         // http://code.google.com/p/chromium/issues/detail?id=108127
199         if (isSyncInitialized() && isPassphraseRequiredForDecryption()) {
200             return getSyncDecryptionPassphraseType();
201         }
202         return SyncDecryptionPassphraseType.NONE;
203     }
204
205     /**
206      * Returns the actual passphrase type being used for encryption. The sync backend must be
207      * running (isSyncInitialized() returns true) before calling this function.
208      * <p/>
209      * This method should only be used if you want to know the raw value. For checking whether we
210      * should ask the user for a passphrase, you should instead use
211      * getSyncDecryptionPassphraseTypeIfRequired().
212      */
213     public SyncDecryptionPassphraseType getSyncDecryptionPassphraseType() {
214         assert isSyncInitialized();
215         int passphraseType = nativeGetPassphraseType(mNativeProfileSyncServiceAndroid);
216         return SyncDecryptionPassphraseType.fromInternalValue(passphraseType);
217     }
218
219     public boolean isSyncKeystoreMigrationDone() {
220         assert isSyncInitialized();
221         return nativeIsSyncKeystoreMigrationDone(mNativeProfileSyncServiceAndroid);
222     }
223
224     /**
225      * Returns true if the current explicit passphrase time is defined.
226      */
227     public boolean hasExplicitPassphraseTime() {
228         assert isSyncInitialized();
229         return nativeHasExplicitPassphraseTime(mNativeProfileSyncServiceAndroid);
230     }
231
232     public String getSyncEnterGooglePassphraseBodyWithDateText() {
233         assert isSyncInitialized();
234         return nativeGetSyncEnterGooglePassphraseBodyWithDateText(mNativeProfileSyncServiceAndroid);
235     }
236
237     public String getSyncEnterCustomPassphraseBodyWithDateText() {
238         assert isSyncInitialized();
239         return nativeGetSyncEnterCustomPassphraseBodyWithDateText(mNativeProfileSyncServiceAndroid);
240     }
241
242     public String getCurrentSignedInAccountText() {
243         assert isSyncInitialized();
244         return nativeGetCurrentSignedInAccountText(mNativeProfileSyncServiceAndroid);
245     }
246
247     public String getSyncEnterCustomPassphraseBodyText() {
248         return nativeGetSyncEnterCustomPassphraseBodyText(mNativeProfileSyncServiceAndroid);
249     }
250
251     /**
252      * Checks if sync is currently set to use a custom passphrase. The sync backend must be running
253      * (isSyncInitialized() returns true) before calling this function.
254      *
255      * @return true if sync is using a custom passphrase.
256      */
257     public boolean isUsingSecondaryPassphrase() {
258         assert isSyncInitialized();
259         return nativeIsUsingSecondaryPassphrase(mNativeProfileSyncServiceAndroid);
260     }
261
262     /**
263      * Checks if we need a passphrase to decrypt a currently-enabled data type. This returns false
264      * if a passphrase is needed for a type that is not currently enabled.
265      *
266      * @return true if we need a passphrase.
267      */
268     public boolean isPassphraseRequiredForDecryption() {
269         assert isSyncInitialized();
270         return nativeIsPassphraseRequiredForDecryption(mNativeProfileSyncServiceAndroid);
271     }
272
273     /**
274      * Checks if we need a passphrase to decrypt any data type (including types that aren't
275      * currently enabled or supported, such as passwords). This API is used to determine if we
276      * need to provide a decryption passphrase before we can re-encrypt with a custom passphrase.
277      *
278      * @return true if we need a passphrase for some type.
279      */
280     public boolean isPassphraseRequiredForExternalType() {
281         assert isSyncInitialized();
282         return nativeIsPassphraseRequiredForExternalType(mNativeProfileSyncServiceAndroid);
283     }
284
285     /**
286      * Checks if the sync backend is running.
287      *
288      * @return true if sync is initialized/running.
289      */
290     public boolean isSyncInitialized() {
291         return nativeIsSyncInitialized(mNativeProfileSyncServiceAndroid);
292     }
293
294     /**
295      * Checks if the first sync setup is currently in progress.
296      *
297      * @return true if first sync setup is in progress
298      */
299     public boolean isFirstSetupInProgress() {
300         return nativeIsFirstSetupInProgress(mNativeProfileSyncServiceAndroid);
301     }
302
303     /**
304      * Checks if the all the data types are encrypted.
305      *
306      * @return true if all data types are encrypted, false if only passwords are encrypted.
307      */
308     public boolean isEncryptEverythingEnabled() {
309         assert isSyncInitialized();
310         return nativeIsEncryptEverythingEnabled(mNativeProfileSyncServiceAndroid);
311     }
312
313     /**
314      * Turns on encryption of all data types. This only takes effect after sync configuration is
315      * completed and setPreferredDataTypes() is invoked.
316      */
317     public void enableEncryptEverything() {
318         assert isSyncInitialized();
319         nativeEnableEncryptEverything(mNativeProfileSyncServiceAndroid);
320     }
321
322     public void setEncryptionPassphrase(String passphrase, boolean isGaia) {
323         assert isSyncInitialized();
324         nativeSetEncryptionPassphrase(mNativeProfileSyncServiceAndroid, passphrase, isGaia);
325     }
326
327     public boolean isCryptographerReady() {
328         assert isSyncInitialized();
329         return nativeIsCryptographerReady(mNativeProfileSyncServiceAndroid);
330     }
331
332     public boolean setDecryptionPassphrase(String passphrase) {
333         assert isSyncInitialized();
334         return nativeSetDecryptionPassphrase(mNativeProfileSyncServiceAndroid, passphrase);
335     }
336
337     public GoogleServiceAuthError.State getAuthError() {
338         int authErrorCode = nativeGetAuthError(mNativeProfileSyncServiceAndroid);
339         return GoogleServiceAuthError.State.fromCode(authErrorCode);
340     }
341
342     /**
343      * Gets the set of data types that are currently enabled to sync.
344      *
345      * @return Set of enabled types.
346      */
347     public Set<ModelType> getPreferredDataTypes() {
348         long modelTypeSelection =
349                 nativeGetEnabledDataTypes(mNativeProfileSyncServiceAndroid);
350         return modelTypeSelectionToSet(modelTypeSelection);
351     }
352
353     @VisibleForTesting
354     public static Set<ModelType> modelTypeSelectionToSet(long modelTypeSelection) {
355         Set<ModelType> syncTypes = new HashSet<ModelType>();
356         if ((modelTypeSelection & ModelTypeSelection.AUTOFILL) != 0) {
357             syncTypes.add(ModelType.AUTOFILL);
358         }
359         if ((modelTypeSelection & ModelTypeSelection.AUTOFILL_PROFILE) != 0) {
360             syncTypes.add(ModelType.AUTOFILL_PROFILE);
361         }
362         if ((modelTypeSelection & ModelTypeSelection.BOOKMARK) != 0) {
363             syncTypes.add(ModelType.BOOKMARK);
364         }
365         if ((modelTypeSelection & ModelTypeSelection.EXPERIMENTS) != 0) {
366             syncTypes.add(ModelType.EXPERIMENTS);
367         }
368         if ((modelTypeSelection & ModelTypeSelection.NIGORI) != 0) {
369             syncTypes.add(ModelType.NIGORI);
370         }
371         if ((modelTypeSelection & ModelTypeSelection.PASSWORD) != 0) {
372             syncTypes.add(ModelType.PASSWORD);
373         }
374         if ((modelTypeSelection & ModelTypeSelection.SESSION) != 0) {
375             syncTypes.add(ModelType.SESSION);
376         }
377         if ((modelTypeSelection & ModelTypeSelection.TYPED_URL) != 0) {
378             syncTypes.add(ModelType.TYPED_URL);
379         }
380         if ((modelTypeSelection & ModelTypeSelection.HISTORY_DELETE_DIRECTIVE) != 0) {
381             syncTypes.add(ModelType.HISTORY_DELETE_DIRECTIVE);
382         }
383         if ((modelTypeSelection & ModelTypeSelection.DEVICE_INFO) != 0) {
384             syncTypes.add(ModelType.DEVICE_INFO);
385         }
386         if ((modelTypeSelection & ModelTypeSelection.PROXY_TABS) != 0) {
387             syncTypes.add(ModelType.PROXY_TABS);
388         }
389         if ((modelTypeSelection & ModelTypeSelection.FAVICON_IMAGE) != 0) {
390             syncTypes.add(ModelType.FAVICON_IMAGE);
391         }
392         if ((modelTypeSelection & ModelTypeSelection.FAVICON_TRACKING) != 0) {
393             syncTypes.add(ModelType.FAVICON_TRACKING);
394         }
395         if ((modelTypeSelection & ModelTypeSelection.SUPERVISED_USER_SETTING) != 0) {
396             syncTypes.add(ModelType.MANAGED_USER_SETTING);
397         }
398         return syncTypes;
399     }
400
401     public boolean hasKeepEverythingSynced() {
402         return nativeHasKeepEverythingSynced(mNativeProfileSyncServiceAndroid);
403     }
404
405     /**
406      * Enables syncing for the passed data types.
407      *
408      * @param syncEverything Set to true if the user wants to sync all data types
409      *                       (including new data types we add in the future).
410      * @param enabledTypes   The set of types to enable. Ignored (can be null) if
411      *                       syncEverything is true.
412      */
413     public void setPreferredDataTypes(boolean syncEverything, Set<ModelType> enabledTypes) {
414         long modelTypeSelection = 0;
415         if (syncEverything || enabledTypes.contains(ModelType.AUTOFILL)) {
416             modelTypeSelection |= ModelTypeSelection.AUTOFILL;
417         }
418         if (syncEverything || enabledTypes.contains(ModelType.BOOKMARK)) {
419             modelTypeSelection |= ModelTypeSelection.BOOKMARK;
420         }
421         if (syncEverything || enabledTypes.contains(ModelType.PASSWORD)) {
422             modelTypeSelection |= ModelTypeSelection.PASSWORD;
423         }
424         if (syncEverything || enabledTypes.contains(ModelType.PROXY_TABS)) {
425             modelTypeSelection |= ModelTypeSelection.PROXY_TABS;
426         }
427         if (syncEverything || enabledTypes.contains(ModelType.TYPED_URL)) {
428             modelTypeSelection |= ModelTypeSelection.TYPED_URL;
429         }
430         nativeSetPreferredDataTypes(
431                 mNativeProfileSyncServiceAndroid, syncEverything, modelTypeSelection);
432     }
433
434     public void setSyncSetupCompleted() {
435         nativeSetSyncSetupCompleted(mNativeProfileSyncServiceAndroid);
436     }
437
438     public boolean hasSyncSetupCompleted() {
439         return nativeHasSyncSetupCompleted(mNativeProfileSyncServiceAndroid);
440     }
441
442     public boolean isStartSuppressed() {
443         return nativeIsStartSuppressed(mNativeProfileSyncServiceAndroid);
444     }
445
446     /**
447      * Notifies sync whether sync setup is in progress - this tells sync whether it should start
448      * syncing data types when it starts up, or if it should just stay in "configuration mode".
449      *
450      * @param inProgress True to put sync in configuration mode, false to turn off configuration
451      *                   and allow syncing.
452      */
453     public void setSetupInProgress(boolean inProgress) {
454         nativeSetSetupInProgress(mNativeProfileSyncServiceAndroid, inProgress);
455     }
456
457     public void addSyncStateChangedListener(SyncStateChangedListener listener) {
458         ThreadUtils.assertOnUiThread();
459         mListeners.add(listener);
460     }
461
462     public void removeSyncStateChangedListener(SyncStateChangedListener listener) {
463         ThreadUtils.assertOnUiThread();
464         mListeners.remove(listener);
465     }
466
467     public boolean hasUnrecoverableError() {
468         return nativeHasUnrecoverableError(mNativeProfileSyncServiceAndroid);
469     }
470
471     /**
472      * Called when the state of the native sync engine has changed, so various
473      * UI elements can update themselves.
474      */
475     @CalledByNative
476     public void syncStateChanged() {
477         if (!mListeners.isEmpty()) {
478             for (SyncStateChangedListener listener : mListeners) {
479                 listener.syncStateChanged();
480             }
481         }
482     }
483
484     @VisibleForTesting
485     public String getSyncInternalsInfoForTest() {
486         ThreadUtils.assertOnUiThread();
487         return nativeGetAboutInfoForTest(mNativeProfileSyncServiceAndroid);
488     }
489
490     /**
491      * Starts the sync engine.
492      */
493     public void enableSync() {
494         nativeEnableSync(mNativeProfileSyncServiceAndroid);
495     }
496
497     /**
498      * Stops the sync engine.
499      */
500     public void disableSync() {
501         nativeDisableSync(mNativeProfileSyncServiceAndroid);
502     }
503
504     /**
505      * Returns the time when the last sync cycle was completed.
506      *
507      * @return The difference measured in microseconds, between last sync cycle completion time
508      * and 1 January 1970 00:00:00 UTC.
509      */
510     @VisibleForTesting
511     public long getLastSyncedTimeForTest() {
512         return nativeGetLastSyncedTimeForTest(mNativeProfileSyncServiceAndroid);
513     }
514
515     /**
516      * Overrides the Sync engine's NetworkResources. This is used to set up the Sync FakeServer for
517      * testing.
518      *
519      * @param networkResources the pointer to the NetworkResources created by the native code. It
520      *                         is assumed that the Java caller has ownership of this pointer;
521      *                         ownership is transferred as part of this call.
522      */
523     public void overrideNetworkResourcesForTest(long networkResources) {
524         nativeOverrideNetworkResourcesForTest(mNativeProfileSyncServiceAndroid, networkResources);
525     }
526
527     @CalledByNative
528     private static String modelTypeSelectionToStringForTest(long modelTypeSelection) {
529         SortedSet<String> set = new TreeSet<String>();
530         Set<ModelType> filteredTypes = ModelType.filterOutNonInvalidationTypes(
531                 modelTypeSelectionToSet(modelTypeSelection));
532         for (ModelType type : filteredTypes) {
533             set.add(type.toString());
534         }
535         StringBuilder sb = new StringBuilder();
536         Iterator<String> it = set.iterator();
537         if (it.hasNext()) {
538             sb.append(it.next());
539             while (it.hasNext()) {
540                 sb.append(", ");
541                 sb.append(it.next());
542             }
543         }
544         return sb.toString();
545     }
546
547     // Native methods
548     private native void nativeNudgeSyncer(
549             long nativeProfileSyncServiceAndroid, int objectSource, String objectId, long version,
550             String payload);
551     private native void nativeNudgeSyncerForAllTypes(long nativeProfileSyncServiceAndroid);
552     private native long nativeInit();
553     private native void nativeEnableSync(long nativeProfileSyncServiceAndroid);
554     private native void nativeDisableSync(long nativeProfileSyncServiceAndroid);
555     private native void nativeSignInSync(long nativeProfileSyncServiceAndroid);
556     private native void nativeSignOutSync(long nativeProfileSyncServiceAndroid);
557     private native boolean nativeSetSyncSessionsId(
558             long nativeProfileSyncServiceAndroid, String tag);
559     private native String nativeQuerySyncStatusSummary(long nativeProfileSyncServiceAndroid);
560     private native int nativeGetAuthError(long nativeProfileSyncServiceAndroid);
561     private native boolean nativeIsSyncInitialized(long nativeProfileSyncServiceAndroid);
562     private native boolean nativeIsFirstSetupInProgress(long nativeProfileSyncServiceAndroid);
563     private native boolean nativeIsEncryptEverythingEnabled(long nativeProfileSyncServiceAndroid);
564     private native void nativeEnableEncryptEverything(long nativeProfileSyncServiceAndroid);
565     private native boolean nativeIsPassphraseRequiredForDecryption(
566             long nativeProfileSyncServiceAndroid);
567     private native boolean nativeIsPassphraseRequiredForExternalType(
568             long nativeProfileSyncServiceAndroid);
569     private native boolean nativeIsUsingSecondaryPassphrase(long nativeProfileSyncServiceAndroid);
570     private native boolean nativeSetDecryptionPassphrase(
571             long nativeProfileSyncServiceAndroid, String passphrase);
572     private native void nativeSetEncryptionPassphrase(
573             long nativeProfileSyncServiceAndroid, String passphrase, boolean isGaia);
574     private native boolean nativeIsCryptographerReady(long nativeProfileSyncServiceAndroid);
575     private native int nativeGetPassphraseType(long nativeProfileSyncServiceAndroid);
576     private native boolean nativeHasExplicitPassphraseTime(long nativeProfileSyncServiceAndroid);
577     private native String nativeGetSyncEnterGooglePassphraseBodyWithDateText(
578             long nativeProfileSyncServiceAndroid);
579     private native String nativeGetSyncEnterCustomPassphraseBodyWithDateText(
580             long nativeProfileSyncServiceAndroid);
581     private native String nativeGetCurrentSignedInAccountText(long nativeProfileSyncServiceAndroid);
582     private native String nativeGetSyncEnterCustomPassphraseBodyText(
583             long nativeProfileSyncServiceAndroid);
584     private native boolean nativeIsSyncKeystoreMigrationDone(long nativeProfileSyncServiceAndroid);
585     private native long nativeGetEnabledDataTypes(
586         long nativeProfileSyncServiceAndroid);
587     private native void nativeSetPreferredDataTypes(
588             long nativeProfileSyncServiceAndroid, boolean syncEverything, long modelTypeSelection);
589     private native void nativeSetSetupInProgress(
590             long nativeProfileSyncServiceAndroid, boolean inProgress);
591     private native void nativeSetSyncSetupCompleted(long nativeProfileSyncServiceAndroid);
592     private native boolean nativeHasSyncSetupCompleted(long nativeProfileSyncServiceAndroid);
593     private native boolean nativeIsStartSuppressed(long nativeProfileSyncServiceAndroid);
594     private native boolean nativeHasKeepEverythingSynced(long nativeProfileSyncServiceAndroid);
595     private native boolean nativeHasUnrecoverableError(long nativeProfileSyncServiceAndroid);
596     private native String nativeGetAboutInfoForTest(long nativeProfileSyncServiceAndroid);
597     private native long nativeGetLastSyncedTimeForTest(long nativeProfileSyncServiceAndroid);
598     private native void nativeOverrideNetworkResourcesForTest(
599             long nativeProfileSyncServiceAndroid, long networkResources);
600 }