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