Home | History | Annotate | Download | only in sync
      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     /**
    233      * Returns the current explicit passphrase time in milliseconds since epoch.
    234      */
    235     public long getExplicitPassphraseTime() {
    236         assert isSyncInitialized();
    237         return nativeGetExplicitPassphraseTime(mNativeProfileSyncServiceAndroid);
    238     }
    239 
    240     public String getSyncEnterGooglePassphraseBodyWithDateText() {
    241         assert isSyncInitialized();
    242         return nativeGetSyncEnterGooglePassphraseBodyWithDateText(mNativeProfileSyncServiceAndroid);
    243     }
    244 
    245     public String getSyncEnterCustomPassphraseBodyWithDateText() {
    246         assert isSyncInitialized();
    247         return nativeGetSyncEnterCustomPassphraseBodyWithDateText(mNativeProfileSyncServiceAndroid);
    248     }
    249 
    250     public String getCurrentSignedInAccountText() {
    251         assert isSyncInitialized();
    252         return nativeGetCurrentSignedInAccountText(mNativeProfileSyncServiceAndroid);
    253     }
    254 
    255     public String getSyncEnterCustomPassphraseBodyText() {
    256         return nativeGetSyncEnterCustomPassphraseBodyText(mNativeProfileSyncServiceAndroid);
    257     }
    258 
    259     /**
    260      * Checks if sync is currently set to use a custom passphrase. The sync backend must be running
    261      * (isSyncInitialized() returns true) before calling this function.
    262      *
    263      * @return true if sync is using a custom passphrase.
    264      */
    265     public boolean isUsingSecondaryPassphrase() {
    266         assert isSyncInitialized();
    267         return nativeIsUsingSecondaryPassphrase(mNativeProfileSyncServiceAndroid);
    268     }
    269 
    270     /**
    271      * Checks if we need a passphrase to decrypt a currently-enabled data type. This returns false
    272      * if a passphrase is needed for a type that is not currently enabled.
    273      *
    274      * @return true if we need a passphrase.
    275      */
    276     public boolean isPassphraseRequiredForDecryption() {
    277         assert isSyncInitialized();
    278         return nativeIsPassphraseRequiredForDecryption(mNativeProfileSyncServiceAndroid);
    279     }
    280 
    281     /**
    282      * Checks if we need a passphrase to decrypt any data type (including types that aren't
    283      * currently enabled or supported, such as passwords). This API is used to determine if we
    284      * need to provide a decryption passphrase before we can re-encrypt with a custom passphrase.
    285      *
    286      * @return true if we need a passphrase for some type.
    287      */
    288     public boolean isPassphraseRequiredForExternalType() {
    289         assert isSyncInitialized();
    290         return nativeIsPassphraseRequiredForExternalType(mNativeProfileSyncServiceAndroid);
    291     }
    292 
    293     /**
    294      * Checks if the sync backend is running.
    295      *
    296      * @return true if sync is initialized/running.
    297      */
    298     public boolean isSyncInitialized() {
    299         return nativeIsSyncInitialized(mNativeProfileSyncServiceAndroid);
    300     }
    301 
    302     /**
    303      * Checks if the first sync setup is currently in progress.
    304      *
    305      * @return true if first sync setup is in progress
    306      */
    307     public boolean isFirstSetupInProgress() {
    308         return nativeIsFirstSetupInProgress(mNativeProfileSyncServiceAndroid);
    309     }
    310 
    311     /**
    312      * Checks if encrypting all the data types is allowed.
    313      *
    314      * @return true if encrypting all data types is allowed, false if only passwords are allowed to
    315      * be encrypted.
    316      */
    317     public boolean isEncryptEverythingAllowed() {
    318         assert isSyncInitialized();
    319         return nativeIsEncryptEverythingAllowed(mNativeProfileSyncServiceAndroid);
    320     }
    321 
    322     /**
    323      * Checks if the all the data types are encrypted.
    324      *
    325      * @return true if all data types are encrypted, false if only passwords are encrypted.
    326      */
    327     public boolean isEncryptEverythingEnabled() {
    328         assert isSyncInitialized();
    329         return nativeIsEncryptEverythingEnabled(mNativeProfileSyncServiceAndroid);
    330     }
    331 
    332     /**
    333      * Turns on encryption of all data types. This only takes effect after sync configuration is
    334      * completed and setPreferredDataTypes() is invoked.
    335      */
    336     public void enableEncryptEverything() {
    337         assert isSyncInitialized();
    338         nativeEnableEncryptEverything(mNativeProfileSyncServiceAndroid);
    339     }
    340 
    341     public void setEncryptionPassphrase(String passphrase, boolean isGaia) {
    342         assert isSyncInitialized();
    343         nativeSetEncryptionPassphrase(mNativeProfileSyncServiceAndroid, passphrase, isGaia);
    344     }
    345 
    346     public boolean isCryptographerReady() {
    347         assert isSyncInitialized();
    348         return nativeIsCryptographerReady(mNativeProfileSyncServiceAndroid);
    349     }
    350 
    351     public boolean setDecryptionPassphrase(String passphrase) {
    352         assert isSyncInitialized();
    353         return nativeSetDecryptionPassphrase(mNativeProfileSyncServiceAndroid, passphrase);
    354     }
    355 
    356     public GoogleServiceAuthError.State getAuthError() {
    357         int authErrorCode = nativeGetAuthError(mNativeProfileSyncServiceAndroid);
    358         return GoogleServiceAuthError.State.fromCode(authErrorCode);
    359     }
    360 
    361     /**
    362      * Gets the set of data types that are currently enabled to sync.
    363      *
    364      * @return Set of enabled types.
    365      */
    366     public Set<ModelType> getPreferredDataTypes() {
    367         long modelTypeSelection =
    368                 nativeGetEnabledDataTypes(mNativeProfileSyncServiceAndroid);
    369         return modelTypeSelectionToSet(modelTypeSelection);
    370     }
    371 
    372     @VisibleForTesting
    373     public static Set<ModelType> modelTypeSelectionToSet(long modelTypeSelection) {
    374         Set<ModelType> syncTypes = new HashSet<ModelType>();
    375         if ((modelTypeSelection & ModelTypeSelection.AUTOFILL) != 0) {
    376             syncTypes.add(ModelType.AUTOFILL);
    377         }
    378         if ((modelTypeSelection & ModelTypeSelection.AUTOFILL_PROFILE) != 0) {
    379             syncTypes.add(ModelType.AUTOFILL_PROFILE);
    380         }
    381         if ((modelTypeSelection & ModelTypeSelection.BOOKMARK) != 0) {
    382             syncTypes.add(ModelType.BOOKMARK);
    383         }
    384         if ((modelTypeSelection & ModelTypeSelection.EXPERIMENTS) != 0) {
    385             syncTypes.add(ModelType.EXPERIMENTS);
    386         }
    387         if ((modelTypeSelection & ModelTypeSelection.NIGORI) != 0) {
    388             syncTypes.add(ModelType.NIGORI);
    389         }
    390         if ((modelTypeSelection & ModelTypeSelection.PASSWORD) != 0) {
    391             syncTypes.add(ModelType.PASSWORD);
    392         }
    393         if ((modelTypeSelection & ModelTypeSelection.SESSION) != 0) {
    394             syncTypes.add(ModelType.SESSION);
    395         }
    396         if ((modelTypeSelection & ModelTypeSelection.TYPED_URL) != 0) {
    397             syncTypes.add(ModelType.TYPED_URL);
    398         }
    399         if ((modelTypeSelection & ModelTypeSelection.HISTORY_DELETE_DIRECTIVE) != 0) {
    400             syncTypes.add(ModelType.HISTORY_DELETE_DIRECTIVE);
    401         }
    402         if ((modelTypeSelection & ModelTypeSelection.DEVICE_INFO) != 0) {
    403             syncTypes.add(ModelType.DEVICE_INFO);
    404         }
    405         if ((modelTypeSelection & ModelTypeSelection.PROXY_TABS) != 0) {
    406             syncTypes.add(ModelType.PROXY_TABS);
    407         }
    408         if ((modelTypeSelection & ModelTypeSelection.FAVICON_IMAGE) != 0) {
    409             syncTypes.add(ModelType.FAVICON_IMAGE);
    410         }
    411         if ((modelTypeSelection & ModelTypeSelection.FAVICON_TRACKING) != 0) {
    412             syncTypes.add(ModelType.FAVICON_TRACKING);
    413         }
    414         if ((modelTypeSelection & ModelTypeSelection.SUPERVISED_USER_SETTING) != 0) {
    415             syncTypes.add(ModelType.MANAGED_USER_SETTING);
    416         }
    417         return syncTypes;
    418     }
    419 
    420     public boolean hasKeepEverythingSynced() {
    421         return nativeHasKeepEverythingSynced(mNativeProfileSyncServiceAndroid);
    422     }
    423 
    424     /**
    425      * Enables syncing for the passed data types.
    426      *
    427      * @param syncEverything Set to true if the user wants to sync all data types
    428      *                       (including new data types we add in the future).
    429      * @param enabledTypes   The set of types to enable. Ignored (can be null) if
    430      *                       syncEverything is true.
    431      */
    432     public void setPreferredDataTypes(boolean syncEverything, Set<ModelType> enabledTypes) {
    433         long modelTypeSelection = 0;
    434         if (syncEverything || enabledTypes.contains(ModelType.AUTOFILL)) {
    435             modelTypeSelection |= ModelTypeSelection.AUTOFILL;
    436         }
    437         if (syncEverything || enabledTypes.contains(ModelType.BOOKMARK)) {
    438             modelTypeSelection |= ModelTypeSelection.BOOKMARK;
    439         }
    440         if (syncEverything || enabledTypes.contains(ModelType.PASSWORD)) {
    441             modelTypeSelection |= ModelTypeSelection.PASSWORD;
    442         }
    443         if (syncEverything || enabledTypes.contains(ModelType.PROXY_TABS)) {
    444             modelTypeSelection |= ModelTypeSelection.PROXY_TABS;
    445         }
    446         if (syncEverything || enabledTypes.contains(ModelType.TYPED_URL)) {
    447             modelTypeSelection |= ModelTypeSelection.TYPED_URL;
    448         }
    449         nativeSetPreferredDataTypes(
    450                 mNativeProfileSyncServiceAndroid, syncEverything, modelTypeSelection);
    451     }
    452 
    453     public void setSyncSetupCompleted() {
    454         nativeSetSyncSetupCompleted(mNativeProfileSyncServiceAndroid);
    455     }
    456 
    457     public boolean hasSyncSetupCompleted() {
    458         return nativeHasSyncSetupCompleted(mNativeProfileSyncServiceAndroid);
    459     }
    460 
    461     public boolean isStartSuppressed() {
    462         return nativeIsStartSuppressed(mNativeProfileSyncServiceAndroid);
    463     }
    464 
    465     /**
    466      * Notifies sync whether sync setup is in progress - this tells sync whether it should start
    467      * syncing data types when it starts up, or if it should just stay in "configuration mode".
    468      *
    469      * @param inProgress True to put sync in configuration mode, false to turn off configuration
    470      *                   and allow syncing.
    471      */
    472     public void setSetupInProgress(boolean inProgress) {
    473         nativeSetSetupInProgress(mNativeProfileSyncServiceAndroid, inProgress);
    474     }
    475 
    476     public void addSyncStateChangedListener(SyncStateChangedListener listener) {
    477         ThreadUtils.assertOnUiThread();
    478         mListeners.add(listener);
    479     }
    480 
    481     public void removeSyncStateChangedListener(SyncStateChangedListener listener) {
    482         ThreadUtils.assertOnUiThread();
    483         mListeners.remove(listener);
    484     }
    485 
    486     public boolean hasUnrecoverableError() {
    487         return nativeHasUnrecoverableError(mNativeProfileSyncServiceAndroid);
    488     }
    489 
    490     /**
    491      * Called when the state of the native sync engine has changed, so various
    492      * UI elements can update themselves.
    493      */
    494     @CalledByNative
    495     public void syncStateChanged() {
    496         if (!mListeners.isEmpty()) {
    497             for (SyncStateChangedListener listener : mListeners) {
    498                 listener.syncStateChanged();
    499             }
    500         }
    501     }
    502 
    503     @VisibleForTesting
    504     public String getSyncInternalsInfoForTest() {
    505         ThreadUtils.assertOnUiThread();
    506         return nativeGetAboutInfoForTest(mNativeProfileSyncServiceAndroid);
    507     }
    508 
    509     /**
    510      * Starts the sync engine.
    511      */
    512     public void enableSync() {
    513         nativeEnableSync(mNativeProfileSyncServiceAndroid);
    514     }
    515 
    516     /**
    517      * Stops the sync engine.
    518      */
    519     public void disableSync() {
    520         nativeDisableSync(mNativeProfileSyncServiceAndroid);
    521     }
    522 
    523     /**
    524      * Returns the time when the last sync cycle was completed.
    525      *
    526      * @return The difference measured in microseconds, between last sync cycle completion time
    527      * and 1 January 1970 00:00:00 UTC.
    528      */
    529     @VisibleForTesting
    530     public long getLastSyncedTimeForTest() {
    531         return nativeGetLastSyncedTimeForTest(mNativeProfileSyncServiceAndroid);
    532     }
    533 
    534     /**
    535      * Overrides the Sync engine's NetworkResources. This is used to set up the Sync FakeServer for
    536      * testing.
    537      *
    538      * @param networkResources the pointer to the NetworkResources created by the native code. It
    539      *                         is assumed that the Java caller has ownership of this pointer;
    540      *                         ownership is transferred as part of this call.
    541      */
    542     public void overrideNetworkResourcesForTest(long networkResources) {
    543         nativeOverrideNetworkResourcesForTest(mNativeProfileSyncServiceAndroid, networkResources);
    544     }
    545 
    546     @CalledByNative
    547     private static String modelTypeSelectionToStringForTest(long modelTypeSelection) {
    548         SortedSet<String> set = new TreeSet<String>();
    549         Set<ModelType> filteredTypes = ModelType.filterOutNonInvalidationTypes(
    550                 modelTypeSelectionToSet(modelTypeSelection));
    551         for (ModelType type : filteredTypes) {
    552             set.add(type.toString());
    553         }
    554         StringBuilder sb = new StringBuilder();
    555         Iterator<String> it = set.iterator();
    556         if (it.hasNext()) {
    557             sb.append(it.next());
    558             while (it.hasNext()) {
    559                 sb.append(", ");
    560                 sb.append(it.next());
    561             }
    562         }
    563         return sb.toString();
    564     }
    565 
    566     // Native methods
    567     private native void nativeNudgeSyncer(
    568             long nativeProfileSyncServiceAndroid, int objectSource, String objectId, long version,
    569             String payload);
    570     private native void nativeNudgeSyncerForAllTypes(long nativeProfileSyncServiceAndroid);
    571     private native long nativeInit();
    572     private native void nativeEnableSync(long nativeProfileSyncServiceAndroid);
    573     private native void nativeDisableSync(long nativeProfileSyncServiceAndroid);
    574     private native void nativeSignInSync(long nativeProfileSyncServiceAndroid);
    575     private native void nativeSignOutSync(long nativeProfileSyncServiceAndroid);
    576     private native boolean nativeSetSyncSessionsId(
    577             long nativeProfileSyncServiceAndroid, String tag);
    578     private native String nativeQuerySyncStatusSummary(long nativeProfileSyncServiceAndroid);
    579     private native int nativeGetAuthError(long nativeProfileSyncServiceAndroid);
    580     private native boolean nativeIsSyncInitialized(long nativeProfileSyncServiceAndroid);
    581     private native boolean nativeIsFirstSetupInProgress(long nativeProfileSyncServiceAndroid);
    582     private native boolean nativeIsEncryptEverythingAllowed(long nativeProfileSyncServiceAndroid);
    583     private native boolean nativeIsEncryptEverythingEnabled(long nativeProfileSyncServiceAndroid);
    584     private native void nativeEnableEncryptEverything(long nativeProfileSyncServiceAndroid);
    585     private native boolean nativeIsPassphraseRequiredForDecryption(
    586             long nativeProfileSyncServiceAndroid);
    587     private native boolean nativeIsPassphraseRequiredForExternalType(
    588             long nativeProfileSyncServiceAndroid);
    589     private native boolean nativeIsUsingSecondaryPassphrase(long nativeProfileSyncServiceAndroid);
    590     private native boolean nativeSetDecryptionPassphrase(
    591             long nativeProfileSyncServiceAndroid, String passphrase);
    592     private native void nativeSetEncryptionPassphrase(
    593             long nativeProfileSyncServiceAndroid, String passphrase, boolean isGaia);
    594     private native boolean nativeIsCryptographerReady(long nativeProfileSyncServiceAndroid);
    595     private native int nativeGetPassphraseType(long nativeProfileSyncServiceAndroid);
    596     private native boolean nativeHasExplicitPassphraseTime(long nativeProfileSyncServiceAndroid);
    597     private native long nativeGetExplicitPassphraseTime(long nativeProfileSyncServiceAndroid);
    598     private native String nativeGetSyncEnterGooglePassphraseBodyWithDateText(
    599             long nativeProfileSyncServiceAndroid);
    600     private native String nativeGetSyncEnterCustomPassphraseBodyWithDateText(
    601             long nativeProfileSyncServiceAndroid);
    602     private native String nativeGetCurrentSignedInAccountText(long nativeProfileSyncServiceAndroid);
    603     private native String nativeGetSyncEnterCustomPassphraseBodyText(
    604             long nativeProfileSyncServiceAndroid);
    605     private native boolean nativeIsSyncKeystoreMigrationDone(long nativeProfileSyncServiceAndroid);
    606     private native long nativeGetEnabledDataTypes(
    607         long nativeProfileSyncServiceAndroid);
    608     private native void nativeSetPreferredDataTypes(
    609             long nativeProfileSyncServiceAndroid, boolean syncEverything, long modelTypeSelection);
    610     private native void nativeSetSetupInProgress(
    611             long nativeProfileSyncServiceAndroid, boolean inProgress);
    612     private native void nativeSetSyncSetupCompleted(long nativeProfileSyncServiceAndroid);
    613     private native boolean nativeHasSyncSetupCompleted(long nativeProfileSyncServiceAndroid);
    614     private native boolean nativeIsStartSuppressed(long nativeProfileSyncServiceAndroid);
    615     private native boolean nativeHasKeepEverythingSynced(long nativeProfileSyncServiceAndroid);
    616     private native boolean nativeHasUnrecoverableError(long nativeProfileSyncServiceAndroid);
    617     private native String nativeGetAboutInfoForTest(long nativeProfileSyncServiceAndroid);
    618     private native long nativeGetLastSyncedTimeForTest(long nativeProfileSyncServiceAndroid);
    619     private native void nativeOverrideNetworkResourcesForTest(
    620             long nativeProfileSyncServiceAndroid, long networkResources);
    621 }
    622