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