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 #include "chrome/browser/sync/profile_sync_service_android.h"
      6 
      7 #include "base/android/jni_android.h"
      8 #include "base/android/jni_string.h"
      9 #include "base/bind.h"
     10 #include "base/i18n/time_formatting.h"
     11 #include "base/json/json_writer.h"
     12 #include "base/logging.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/prefs/pref_service.h"
     15 #include "base/strings/utf_string_conversions.h"
     16 #include "base/time/time.h"
     17 #include "chrome/browser/browser_process.h"
     18 #include "chrome/browser/chrome_notification_types.h"
     19 #include "chrome/browser/profiles/profile_manager.h"
     20 #include "chrome/browser/signin/signin_manager_factory.h"
     21 #include "chrome/browser/sync/about_sync_util.h"
     22 #include "chrome/browser/sync/profile_sync_service.h"
     23 #include "chrome/browser/sync/profile_sync_service_factory.h"
     24 #include "chrome/browser/sync/sync_ui_util.h"
     25 #include "components/signin/core/browser/signin_manager.h"
     26 #include "components/sync_driver/pref_names.h"
     27 #include "components/sync_driver/sync_prefs.h"
     28 #include "content/public/browser/browser_thread.h"
     29 #include "content/public/browser/notification_service.h"
     30 #include "content/public/browser/notification_source.h"
     31 #include "google/cacheinvalidation/types.pb.h"
     32 #include "google_apis/gaia/gaia_constants.h"
     33 #include "google_apis/gaia/google_service_auth_error.h"
     34 #include "grit/generated_resources.h"
     35 #include "jni/ProfileSyncService_jni.h"
     36 #include "sync/internal_api/public/read_transaction.h"
     37 #include "sync/notifier/object_id_invalidation_map.h"
     38 #include "ui/base/l10n/l10n_util.h"
     39 
     40 using base::android::AttachCurrentThread;
     41 using base::android::CheckException;
     42 using base::android::ConvertJavaStringToUTF8;
     43 using base::android::ConvertUTF8ToJavaString;
     44 using base::android::ScopedJavaLocalRef;
     45 using content::BrowserThread;
     46 
     47 namespace {
     48 
     49 enum {
     50 #define DEFINE_MODEL_TYPE_SELECTION(name,value)  name = value,
     51 #include "chrome/browser/sync/profile_sync_service_model_type_selection_android.h"
     52 #undef DEFINE_MODEL_TYPE_SELECTION
     53 };
     54 
     55 }  // namespace
     56 
     57 ProfileSyncServiceAndroid::ProfileSyncServiceAndroid(JNIEnv* env, jobject obj)
     58     : profile_(NULL),
     59       sync_service_(NULL),
     60       weak_java_profile_sync_service_(env, obj) {
     61   if (g_browser_process == NULL ||
     62       g_browser_process->profile_manager() == NULL) {
     63     NOTREACHED() << "Browser process or profile manager not initialized";
     64     return;
     65   }
     66 
     67   profile_ = ProfileManager::GetActiveUserProfile();
     68   if (profile_ == NULL) {
     69     NOTREACHED() << "Sync Init: Profile not found.";
     70     return;
     71   }
     72 
     73   sync_prefs_.reset(new sync_driver::SyncPrefs(profile_->GetPrefs()));
     74 
     75   sync_service_ =
     76       ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_);
     77   DCHECK(sync_service_);
     78 }
     79 
     80 void ProfileSyncServiceAndroid::Init() {
     81   sync_service_->AddObserver(this);
     82 }
     83 
     84 void ProfileSyncServiceAndroid::RemoveObserver() {
     85   if (sync_service_->HasObserver(this)) {
     86     sync_service_->RemoveObserver(this);
     87   }
     88 }
     89 
     90 ProfileSyncServiceAndroid::~ProfileSyncServiceAndroid() {
     91   RemoveObserver();
     92 }
     93 
     94 void ProfileSyncServiceAndroid::SendNudgeNotification(
     95     int object_source,
     96     const std::string& str_object_id,
     97     int64 version,
     98     const std::string& state) {
     99   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    100 
    101   // TODO(nileshagrawal): Merge this with ChromeInvalidationClient::Invalidate.
    102   // Construct the ModelTypeStateMap and send it over with the notification.
    103   invalidation::ObjectId object_id(
    104       object_source,
    105       str_object_id);
    106   syncer::ObjectIdInvalidationMap object_ids_with_states;
    107   if (version == ipc::invalidation::Constants::UNKNOWN) {
    108     object_ids_with_states.Insert(
    109         syncer::Invalidation::InitUnknownVersion(object_id));
    110   } else {
    111     ObjectIdVersionMap::iterator it =
    112         max_invalidation_versions_.find(object_id);
    113     if ((it != max_invalidation_versions_.end()) &&
    114         (version <= it->second)) {
    115       DVLOG(1) << "Dropping redundant invalidation with version " << version;
    116       return;
    117     }
    118     max_invalidation_versions_[object_id] = version;
    119     object_ids_with_states.Insert(
    120         syncer::Invalidation::Init(object_id, version, state));
    121   }
    122 
    123   content::NotificationService::current()->Notify(
    124       chrome::NOTIFICATION_SYNC_REFRESH_REMOTE,
    125       content::Source<Profile>(profile_),
    126       content::Details<const syncer::ObjectIdInvalidationMap>(
    127           &object_ids_with_states));
    128 }
    129 
    130 void ProfileSyncServiceAndroid::OnStateChanged() {
    131   // Notify the java world that our sync state has changed.
    132   JNIEnv* env = AttachCurrentThread();
    133   Java_ProfileSyncService_syncStateChanged(
    134       env, weak_java_profile_sync_service_.get(env).obj());
    135 }
    136 
    137 void ProfileSyncServiceAndroid::EnableSync(JNIEnv* env, jobject) {
    138   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    139   // Don't need to do anything if we're already enabled.
    140   if (sync_prefs_->IsStartSuppressed())
    141     sync_service_->UnsuppressAndStart();
    142   else
    143     DVLOG(2) << "Ignoring call to EnableSync() because sync is already enabled";
    144 }
    145 
    146 void ProfileSyncServiceAndroid::DisableSync(JNIEnv* env, jobject) {
    147   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    148   // Don't need to do anything if we're already disabled.
    149   if (!sync_prefs_->IsStartSuppressed()) {
    150     sync_service_->StopAndSuppress();
    151   } else {
    152     DVLOG(2)
    153         << "Ignoring call to DisableSync() because sync is already disabled";
    154   }
    155 }
    156 
    157 void ProfileSyncServiceAndroid::SignInSync(JNIEnv* env, jobject) {
    158   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    159   // Just return if sync already has everything it needs to start up (sync
    160   // should start up automatically as long as it has credentials). This can
    161   // happen normally if (for example) the user closes and reopens the sync
    162   // settings window quickly during initial startup.
    163   if (sync_service_->IsSyncEnabledAndLoggedIn() &&
    164       sync_service_->IsOAuthRefreshTokenAvailable() &&
    165       sync_service_->HasSyncSetupCompleted()) {
    166     return;
    167   }
    168 
    169   // Enable sync (if we don't have credentials yet, this will enable sync but
    170   // will not start it up - sync will start once credentials arrive).
    171   sync_service_->UnsuppressAndStart();
    172 }
    173 
    174 void ProfileSyncServiceAndroid::SignOutSync(JNIEnv* env, jobject) {
    175   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    176   DCHECK(profile_);
    177   sync_service_->DisableForUser();
    178 
    179   // Need to clear suppress start flag manually
    180   sync_prefs_->SetStartSuppressed(false);
    181 }
    182 
    183 ScopedJavaLocalRef<jstring> ProfileSyncServiceAndroid::QuerySyncStatusSummary(
    184     JNIEnv* env, jobject) {
    185   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    186   DCHECK(profile_);
    187   std::string status(sync_service_->QuerySyncStatusSummaryString());
    188   return ConvertUTF8ToJavaString(env, status);
    189 }
    190 
    191 jboolean ProfileSyncServiceAndroid::SetSyncSessionsId(
    192     JNIEnv* env, jobject obj, jstring tag) {
    193   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    194   DCHECK(profile_);
    195   std::string machine_tag = ConvertJavaStringToUTF8(env, tag);
    196   sync_prefs_->SetSyncSessionsGUID(machine_tag);
    197   return true;
    198 }
    199 
    200 jint ProfileSyncServiceAndroid::GetAuthError(JNIEnv* env, jobject) {
    201   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    202   return sync_service_->GetAuthError().state();
    203 }
    204 
    205 jboolean ProfileSyncServiceAndroid::IsEncryptEverythingEnabled(
    206     JNIEnv* env, jobject) {
    207   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    208   return sync_service_->EncryptEverythingEnabled();
    209 }
    210 
    211 jboolean ProfileSyncServiceAndroid::IsSyncInitialized(JNIEnv* env, jobject) {
    212   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    213   return sync_service_->sync_initialized();
    214 }
    215 
    216 jboolean ProfileSyncServiceAndroid::IsFirstSetupInProgress(
    217     JNIEnv* env, jobject) {
    218   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    219   return sync_service_->FirstSetupInProgress();
    220 }
    221 
    222 jboolean ProfileSyncServiceAndroid::IsPassphraseRequired(JNIEnv* env, jobject) {
    223   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    224   return sync_service_->IsPassphraseRequired();
    225 }
    226 
    227 jboolean ProfileSyncServiceAndroid::IsPassphraseRequiredForDecryption(
    228     JNIEnv* env, jobject obj) {
    229   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    230   // In case of CUSTOM_PASSPHRASE we always sync passwords. Prompt the user for
    231   // a passphrase if cryptographer has any pending keys.
    232   if (sync_service_->GetPassphraseType() == syncer::CUSTOM_PASSPHRASE) {
    233     return !IsCryptographerReady(env, obj);
    234   }
    235   if (sync_service_->IsPassphraseRequiredForDecryption()) {
    236     // Passwords datatype should never prompt for a passphrase, except when
    237     // user is using a custom passphrase. Do not prompt for a passphrase if
    238     // passwords are the only encrypted datatype. This prevents a temporary
    239     // notification for passphrase  when PSS has not completed configuring
    240     // DataTypeManager, after configuration password datatype shall be disabled.
    241     const syncer::ModelTypeSet encrypted_types =
    242         sync_service_->GetEncryptedDataTypes();
    243     return !encrypted_types.Equals(syncer::ModelTypeSet(syncer::PASSWORDS));
    244   }
    245   return false;
    246 }
    247 
    248 jboolean ProfileSyncServiceAndroid::IsPassphraseRequiredForExternalType(
    249     JNIEnv* env, jobject) {
    250   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    251   return
    252       sync_service_->passphrase_required_reason() == syncer::REASON_DECRYPTION;
    253 }
    254 
    255 jboolean ProfileSyncServiceAndroid::IsUsingSecondaryPassphrase(
    256     JNIEnv* env, jobject) {
    257   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    258   return sync_service_->IsUsingSecondaryPassphrase();
    259 }
    260 
    261 jboolean ProfileSyncServiceAndroid::SetDecryptionPassphrase(
    262     JNIEnv* env, jobject obj, jstring passphrase) {
    263   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    264   std::string key = ConvertJavaStringToUTF8(env, passphrase);
    265   return sync_service_->SetDecryptionPassphrase(key);
    266 }
    267 
    268 void ProfileSyncServiceAndroid::SetEncryptionPassphrase(
    269     JNIEnv* env, jobject obj, jstring passphrase, jboolean is_gaia) {
    270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    271   std::string key = ConvertJavaStringToUTF8(env, passphrase);
    272   sync_service_->SetEncryptionPassphrase(
    273       key,
    274       is_gaia ? ProfileSyncService::IMPLICIT : ProfileSyncService::EXPLICIT);
    275 }
    276 
    277 jboolean ProfileSyncServiceAndroid::IsCryptographerReady(JNIEnv* env, jobject) {
    278   syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
    279   return sync_service_->IsCryptographerReady(&trans);
    280 }
    281 
    282 jint ProfileSyncServiceAndroid::GetPassphraseType(JNIEnv* env, jobject) {
    283   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    284   return sync_service_->GetPassphraseType();
    285 }
    286 
    287 jboolean ProfileSyncServiceAndroid::HasExplicitPassphraseTime(
    288     JNIEnv* env, jobject) {
    289   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    290   base::Time passphrase_time = sync_service_->GetExplicitPassphraseTime();
    291   return !passphrase_time.is_null();
    292 }
    293 
    294 ScopedJavaLocalRef<jstring>
    295     ProfileSyncServiceAndroid::GetSyncEnterGooglePassphraseBodyWithDateText(
    296         JNIEnv* env, jobject) {
    297   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    298   base::Time passphrase_time = sync_service_->GetExplicitPassphraseTime();
    299   base::string16 passphrase_time_str =
    300       base::TimeFormatShortDate(passphrase_time);
    301   return base::android::ConvertUTF16ToJavaString(env,
    302       l10n_util::GetStringFUTF16(
    303         IDS_SYNC_ENTER_GOOGLE_PASSPHRASE_BODY_WITH_DATE,
    304         passphrase_time_str));
    305 }
    306 
    307 ScopedJavaLocalRef<jstring>
    308     ProfileSyncServiceAndroid::GetSyncEnterCustomPassphraseBodyWithDateText(
    309         JNIEnv* env, jobject) {
    310   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    311   base::Time passphrase_time = sync_service_->GetExplicitPassphraseTime();
    312   base::string16 passphrase_time_str =
    313       base::TimeFormatShortDate(passphrase_time);
    314   return base::android::ConvertUTF16ToJavaString(env,
    315       l10n_util::GetStringFUTF16(IDS_SYNC_ENTER_PASSPHRASE_BODY_WITH_DATE,
    316         passphrase_time_str));
    317 }
    318 
    319 ScopedJavaLocalRef<jstring>
    320     ProfileSyncServiceAndroid::GetCurrentSignedInAccountText(
    321         JNIEnv* env, jobject) {
    322   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    323   const std::string& sync_username =
    324       SigninManagerFactory::GetForProfile(profile_)->GetAuthenticatedUsername();
    325   return base::android::ConvertUTF16ToJavaString(env,
    326       l10n_util::GetStringFUTF16(
    327           IDS_SYNC_ACCOUNT_SYNCING_TO_USER,
    328           base::ASCIIToUTF16(sync_username)));
    329 }
    330 
    331 ScopedJavaLocalRef<jstring>
    332     ProfileSyncServiceAndroid::GetSyncEnterCustomPassphraseBodyText(
    333         JNIEnv* env, jobject) {
    334   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    335   return ConvertUTF8ToJavaString(
    336       env, l10n_util::GetStringUTF8(IDS_SYNC_ENTER_PASSPHRASE_BODY));
    337 }
    338 
    339 jboolean ProfileSyncServiceAndroid::IsSyncKeystoreMigrationDone(
    340       JNIEnv* env, jobject) {
    341   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    342   syncer::SyncStatus status;
    343   bool is_status_valid = sync_service_->QueryDetailedSyncStatus(&status);
    344   return is_status_valid && !status.keystore_migration_time.is_null();
    345 }
    346 
    347 jlong ProfileSyncServiceAndroid::GetEnabledDataTypes(JNIEnv* env,
    348                                                      jobject obj) {
    349   jlong model_type_selection = 0;
    350   syncer::ModelTypeSet types = sync_service_->GetActiveDataTypes();
    351   types.PutAll(syncer::ControlTypes());
    352   if (types.Has(syncer::BOOKMARKS)) {
    353     model_type_selection |= BOOKMARK;
    354   }
    355   if (types.Has(syncer::AUTOFILL)) {
    356     model_type_selection |= AUTOFILL;
    357   }
    358   if (types.Has(syncer::AUTOFILL_PROFILE)) {
    359     model_type_selection |= AUTOFILL_PROFILE;
    360   }
    361   if (types.Has(syncer::PASSWORDS)) {
    362     model_type_selection |= PASSWORD;
    363   }
    364   if (types.Has(syncer::TYPED_URLS)) {
    365     model_type_selection |= TYPED_URL;
    366   }
    367   if (types.Has(syncer::SESSIONS)) {
    368     model_type_selection |= SESSION;
    369   }
    370   if (types.Has(syncer::HISTORY_DELETE_DIRECTIVES)) {
    371     model_type_selection |= HISTORY_DELETE_DIRECTIVE;
    372   }
    373   if (types.Has(syncer::PROXY_TABS)) {
    374     model_type_selection |= PROXY_TABS;
    375   }
    376   if (types.Has(syncer::FAVICON_IMAGES)) {
    377     model_type_selection |= FAVICON_IMAGE;
    378   }
    379   if (types.Has(syncer::FAVICON_TRACKING)) {
    380     model_type_selection |= FAVICON_TRACKING;
    381   }
    382   if (types.Has(syncer::DEVICE_INFO)) {
    383     model_type_selection |= DEVICE_INFO;
    384   }
    385   if (types.Has(syncer::NIGORI)) {
    386     model_type_selection |= NIGORI;
    387   }
    388   if (types.Has(syncer::EXPERIMENTS)) {
    389     model_type_selection |= EXPERIMENTS;
    390   }
    391   return model_type_selection;
    392 }
    393 
    394 void ProfileSyncServiceAndroid::SetPreferredDataTypes(
    395     JNIEnv* env, jobject obj,
    396     jboolean sync_everything,
    397     jlong model_type_selection) {
    398   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    399   syncer::ModelTypeSet types;
    400   // Note: only user selectable types should be included here.
    401   if (model_type_selection & AUTOFILL)
    402     types.Put(syncer::AUTOFILL);
    403   if (model_type_selection & BOOKMARK)
    404     types.Put(syncer::BOOKMARKS);
    405   if (model_type_selection & PASSWORD)
    406     types.Put(syncer::PASSWORDS);
    407   if (model_type_selection & PROXY_TABS)
    408     types.Put(syncer::PROXY_TABS);
    409   if (model_type_selection & TYPED_URL)
    410     types.Put(syncer::TYPED_URLS);
    411   DCHECK(syncer::UserSelectableTypes().HasAll(types));
    412   sync_service_->OnUserChoseDatatypes(sync_everything, types);
    413 }
    414 
    415 void ProfileSyncServiceAndroid::SetSetupInProgress(
    416     JNIEnv* env, jobject obj, jboolean in_progress) {
    417   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    418   sync_service_->SetSetupInProgress(in_progress);
    419 }
    420 
    421 void ProfileSyncServiceAndroid::SetSyncSetupCompleted(
    422     JNIEnv* env, jobject obj) {
    423   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    424   sync_service_->SetSyncSetupCompleted();
    425 }
    426 
    427 jboolean ProfileSyncServiceAndroid::HasSyncSetupCompleted(
    428     JNIEnv* env, jobject obj) {
    429   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    430   return sync_service_->HasSyncSetupCompleted();
    431 }
    432 
    433 jboolean ProfileSyncServiceAndroid::IsStartSuppressed(
    434     JNIEnv* env, jobject obj) {
    435   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    436   return sync_prefs_->IsStartSuppressed();
    437 }
    438 
    439 void ProfileSyncServiceAndroid::EnableEncryptEverything(
    440     JNIEnv* env, jobject obj) {
    441   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    442   sync_service_->EnableEncryptEverything();
    443 }
    444 
    445 jboolean ProfileSyncServiceAndroid::HasKeepEverythingSynced(
    446     JNIEnv* env, jobject) {
    447   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    448   return sync_prefs_->HasKeepEverythingSynced();
    449 }
    450 
    451 jboolean ProfileSyncServiceAndroid::HasUnrecoverableError(
    452     JNIEnv* env, jobject) {
    453   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    454   return sync_service_->HasUnrecoverableError();
    455 }
    456 
    457 ScopedJavaLocalRef<jstring> ProfileSyncServiceAndroid::GetAboutInfoForTest(
    458     JNIEnv* env, jobject) {
    459   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    460 
    461   scoped_ptr<base::DictionaryValue> about_info =
    462       sync_ui_util::ConstructAboutInformation(sync_service_);
    463   std::string about_info_json;
    464   base::JSONWriter::Write(about_info.get(), &about_info_json);
    465 
    466   return ConvertUTF8ToJavaString(env, about_info_json);
    467 }
    468 
    469 jlong ProfileSyncServiceAndroid::GetLastSyncedTimeForTest(
    470     JNIEnv* env, jobject obj) {
    471   // Use profile preferences here instead of SyncPrefs to avoid an extra
    472   // conversion, since SyncPrefs::GetLastSyncedTime() converts the stored value
    473   // to to base::Time.
    474   return static_cast<jlong>(
    475       profile_->GetPrefs()->GetInt64(sync_driver::prefs::kSyncLastSyncedTime));
    476 }
    477 
    478 void ProfileSyncServiceAndroid::NudgeSyncer(JNIEnv* env,
    479                                             jobject obj,
    480                                             jint objectSource,
    481                                             jstring objectId,
    482                                             jlong version,
    483                                             jstring state) {
    484   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    485   SendNudgeNotification(objectSource, ConvertJavaStringToUTF8(env, objectId),
    486                         version, ConvertJavaStringToUTF8(env, state));
    487 }
    488 
    489 void ProfileSyncServiceAndroid::NudgeSyncerForAllTypes(JNIEnv* env,
    490                                                        jobject obj) {
    491   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    492   syncer::ObjectIdInvalidationMap object_ids_with_states;
    493   content::NotificationService::current()->Notify(
    494         chrome::NOTIFICATION_SYNC_REFRESH_REMOTE,
    495         content::Source<Profile>(profile_),
    496         content::Details<const syncer::ObjectIdInvalidationMap>(
    497             &object_ids_with_states));
    498 }
    499 
    500 // static
    501 ProfileSyncServiceAndroid*
    502     ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid() {
    503   return reinterpret_cast<ProfileSyncServiceAndroid*>(
    504           Java_ProfileSyncService_getProfileSyncServiceAndroid(
    505       AttachCurrentThread(), base::android::GetApplicationContext()));
    506 }
    507 
    508 static jlong Init(JNIEnv* env, jobject obj) {
    509   ProfileSyncServiceAndroid* profile_sync_service_android =
    510       new ProfileSyncServiceAndroid(env, obj);
    511   profile_sync_service_android->Init();
    512   return reinterpret_cast<intptr_t>(profile_sync_service_android);
    513 }
    514 
    515 // static
    516 bool ProfileSyncServiceAndroid::Register(JNIEnv* env) {
    517   return RegisterNativesImpl(env);
    518 }
    519