Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / android / java / src / org / chromium / chrome / browser / sync / ChromiumSyncAdapter.java
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.sync;
6
7 import android.accounts.Account;
8 import android.app.Application;
9 import android.content.AbstractThreadedSyncAdapter;
10 import android.content.ContentProviderClient;
11 import android.content.Context;
12 import android.content.SyncResult;
13 import android.os.Bundle;
14 import android.os.Handler;
15 import android.util.Log;
16
17 import com.google.protos.ipc.invalidation.Types;
18
19 import org.chromium.base.ThreadUtils;
20 import org.chromium.base.VisibleForTesting;
21 import org.chromium.base.library_loader.ProcessInitException;
22 import org.chromium.content.browser.BrowserStartupController;
23
24 import java.util.concurrent.Semaphore;
25
26 /**
27  * A sync adapter for Chromium.
28  */
29 public abstract class ChromiumSyncAdapter extends AbstractThreadedSyncAdapter {
30     private static final String TAG = "ChromiumSyncAdapter";
31
32     // TODO(nyquist) Make these fields package protected once downstream sync adapter tests are
33     // removed.
34     @VisibleForTesting
35     public static final String INVALIDATION_OBJECT_SOURCE_KEY = "objectSource";
36     @VisibleForTesting
37     public static final String INVALIDATION_OBJECT_ID_KEY = "objectId";
38     @VisibleForTesting
39     public static final String INVALIDATION_VERSION_KEY = "version";
40     @VisibleForTesting
41     public static final String INVALIDATION_PAYLOAD_KEY = "payload";
42
43     private final Application mApplication;
44     private final boolean mAsyncStartup;
45
46     public ChromiumSyncAdapter(Context context, Application application) {
47         super(context, false);
48         mApplication = application;
49         mAsyncStartup = useAsyncStartup();
50     }
51
52     protected abstract boolean useAsyncStartup();
53
54     protected abstract void initCommandLine();
55
56     @Override
57     public void onPerformSync(Account account, Bundle extras, String authority,
58                               ContentProviderClient provider, SyncResult syncResult) {
59         if (!DelayedSyncController.getInstance().shouldPerformSync(getContext(), extras, account)) {
60             return;
61         }
62
63         // Browser startup is asynchronous, so we will need to wait for startup to finish.
64         Semaphore semaphore = new Semaphore(0);
65
66         // Configure the callback with all the data it needs.
67         BrowserStartupController.StartupCallback callback =
68                 getStartupCallback(mApplication, account, extras, syncResult, semaphore);
69         startBrowserProcess(callback, syncResult, semaphore);
70
71         try {
72             // Wait for startup to complete.
73             semaphore.acquire();
74         } catch (InterruptedException e) {
75             Log.w(TAG, "Got InterruptedException when trying to request a sync.", e);
76             // Using numIoExceptions so Android will treat this as a soft error.
77             syncResult.stats.numIoExceptions++;
78         }
79     }
80
81     private void startBrowserProcess(
82             final BrowserStartupController.StartupCallback callback,
83             final SyncResult syncResult, Semaphore semaphore) {
84         try {
85             ThreadUtils.runOnUiThreadBlocking(new Runnable() {
86                 @Override
87                 public void run() {
88                     initCommandLine();
89                     if (mAsyncStartup) {
90                         try {
91                             BrowserStartupController.get(mApplication)
92                                     .startBrowserProcessesAsync(callback);
93                         } catch (ProcessInitException e) {
94                             Log.e(TAG, "Unable to load native library.", e);
95                             System.exit(-1);
96                         }
97                     } else {
98                         startBrowserProcessesSync(callback);
99                     }
100                 }
101             });
102         } catch (RuntimeException e) {
103             // It is still unknown why we ever experience this. See http://crbug.com/180044.
104             Log.w(TAG, "Got exception when trying to request a sync. Informing Android system.", e);
105             // Using numIoExceptions so Android will treat this as a soft error.
106             syncResult.stats.numIoExceptions++;
107             semaphore.release();
108         }
109     }
110
111     private void startBrowserProcessesSync(
112             final BrowserStartupController.StartupCallback callback) {
113         try {
114             BrowserStartupController.get(mApplication).startBrowserProcessesSync(false);
115         } catch (ProcessInitException e) {
116             Log.e(TAG, "Unable to load native library.", e);
117             System.exit(-1);
118         }
119         new Handler().post(new Runnable() {
120             @Override
121             public void run() {
122                 callback.onSuccess(false);
123             }
124         });
125     }
126
127     private BrowserStartupController.StartupCallback getStartupCallback(
128             final Context context, final Account acct, Bundle extras,
129             final SyncResult syncResult, final Semaphore semaphore) {
130         final boolean syncAllTypes = extras.getString(INVALIDATION_OBJECT_ID_KEY) == null;
131         final int objectSource = syncAllTypes ? 0 : extras.getInt(INVALIDATION_OBJECT_SOURCE_KEY);
132         final String objectId = syncAllTypes ? "" : extras.getString(INVALIDATION_OBJECT_ID_KEY);
133         final long version = syncAllTypes ? 0 : extras.getLong(INVALIDATION_VERSION_KEY);
134         final String payload = syncAllTypes ? "" : extras.getString(INVALIDATION_PAYLOAD_KEY);
135
136         return new BrowserStartupController.StartupCallback() {
137             @Override
138             public void onSuccess(boolean alreadyStarted) {
139                 // Startup succeeded, so we can tickle the sync engine.
140                 if (syncAllTypes) {
141                     Log.v(TAG, "Received sync tickle for all types.");
142                     requestSyncForAllTypes();
143                 } else {
144                     // Invalidations persisted before objectSource was added should be assumed to be
145                     // for Sync objects. TODO(stepco): Remove this check once all persisted
146                     // invalidations can be expected to have the objectSource.
147                     int resolvedSource = objectSource;
148                     if (resolvedSource == 0) {
149                         resolvedSource = Types.ObjectSource.CHROME_SYNC;
150                     }
151                     Log.v(TAG, "Received sync tickle for " + resolvedSource + " " + objectId + ".");
152                     requestSync(resolvedSource, objectId, version, payload);
153                 }
154                 semaphore.release();
155             }
156
157             @Override
158             public void onFailure() {
159                 // The startup failed, so we reset the delayed sync state.
160                 DelayedSyncController.getInstance().setDelayedSync(context, acct.name);
161                 // Using numIoExceptions so Android will treat this as a soft error.
162                 syncResult.stats.numIoExceptions++;
163                 semaphore.release();
164             }
165         };
166     }
167
168     @VisibleForTesting
169     public void requestSync(int objectSource, String objectId, long version, String payload) {
170         ProfileSyncService.get(mApplication)
171                 .requestSyncFromNativeChrome(objectSource, objectId, version, payload);
172     }
173
174     @VisibleForTesting
175     public void requestSyncForAllTypes() {
176         ProfileSyncService.get(mApplication).requestSyncFromNativeChromeForAllTypes();
177     }
178 }