Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(945)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaClient.java

Issue 2665133005: [Omaha] Make the whole pipeline run each time (Closed)
Patch Set: Comments Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.omaha; 5 package org.chromium.chrome.browser.omaha;
6 6
7 import android.app.AlarmManager;
8 import android.app.IntentService; 7 import android.app.IntentService;
9 import android.app.PendingIntent;
10 import android.content.Context; 8 import android.content.Context;
11 import android.content.Intent; 9 import android.content.Intent;
12 import android.content.SharedPreferences; 10 import android.content.SharedPreferences;
13 import android.content.pm.ApplicationInfo;
14 import android.os.Build; 11 import android.os.Build;
15 import android.os.Looper; 12 import android.support.annotation.IntDef;
16 13
17 import org.chromium.base.ApiCompatibilityUtils;
18 import org.chromium.base.ApplicationStatus;
19 import org.chromium.base.Log; 14 import org.chromium.base.Log;
15 import org.chromium.base.ThreadUtils;
20 import org.chromium.base.VisibleForTesting; 16 import org.chromium.base.VisibleForTesting;
21 import org.chromium.chrome.browser.ChromeApplication;
22 17
23 import java.io.IOException; 18 import java.io.IOException;
19 import java.lang.annotation.Retention;
20 import java.lang.annotation.RetentionPolicy;
24 import java.net.HttpURLConnection; 21 import java.net.HttpURLConnection;
25 import java.net.MalformedURLException; 22 import java.net.MalformedURLException;
26 import java.net.URL; 23 import java.net.URL;
27 import java.util.UUID;
28 import java.util.concurrent.TimeUnit; 24 import java.util.concurrent.TimeUnit;
29 25
30 /** 26 /**
31 * Keeps tabs on the current state of Chrome, tracking if and when a request sho uld be sent to the 27 * Keeps tabs on the current state of Chrome, tracking if and when a request sho uld be sent to the
32 * Omaha Server. 28 * Omaha Server.
33 * 29 *
34 * A hook in ChromeActivity's doDeferredResume() initializes the service. Furth er attempts to 30 * A hook in ChromeActivity's doDeferredResume() initializes the service. Furth er attempts to
35 * reschedule events will be scheduled by the class itself. 31 * reschedule events will be scheduled by the class itself.
36 * 32 *
37 * Each request to the server will perform an update check and ping the server. 33 * Each request to the server will perform an update check and ping the server.
(...skipping 10 matching lines...) Expand all
48 * handled in onCreate(). 44 * handled in onCreate().
49 * 45 *
50 * Implementation notes: 46 * Implementation notes:
51 * http://docs.google.com/a/google.com/document/d/1scTCovqASf5ktkOeVj8wFRkWTCeDY w2LrOBNn05CDB0/edit 47 * http://docs.google.com/a/google.com/document/d/1scTCovqASf5ktkOeVj8wFRkWTCeDY w2LrOBNn05CDB0/edit
52 * 48 *
53 * NOTE: This class can never be renamed because the user may have Intents float ing around that 49 * NOTE: This class can never be renamed because the user may have Intents float ing around that
54 * reference this class specifically. 50 * reference this class specifically.
55 */ 51 */
56 public class OmahaClient extends IntentService { 52 public class OmahaClient extends IntentService {
57 // Results of {@link #handlePostRequest()}. 53 // Results of {@link #handlePostRequest()}.
54 @Retention(RetentionPolicy.SOURCE)
55 @IntDef({POST_RESULT_NO_REQUEST, POST_RESULT_SENT, POST_RESULT_FAILED, POST_ RESULT_SCHEDULED})
56 @interface PostResult {}
58 static final int POST_RESULT_NO_REQUEST = 0; 57 static final int POST_RESULT_NO_REQUEST = 0;
59 static final int POST_RESULT_SENT = 1; 58 static final int POST_RESULT_SENT = 1;
60 static final int POST_RESULT_FAILED = 2; 59 static final int POST_RESULT_FAILED = 2;
61 static final int POST_RESULT_SCHEDULED = 3; 60 static final int POST_RESULT_SCHEDULED = 3;
62 61
63 private static final String TAG = "omaha"; 62 private static final String TAG = "omaha";
64 63
65 // Intent actions. 64 /** Deprecated; kept around to cancel alarms set for OmahaClient pre-M58. */
66 private static final String ACTION_INITIALIZE =
67 "org.chromium.chrome.browser.omaha.ACTION_INITIALIZE";
68 private static final String ACTION_REGISTER_REQUEST = 65 private static final String ACTION_REGISTER_REQUEST =
69 "org.chromium.chrome.browser.omaha.ACTION_REGISTER_REQUEST"; 66 "org.chromium.chrome.browser.omaha.ACTION_REGISTER_REQUEST";
70 private static final String ACTION_POST_REQUEST =
71 "org.chromium.chrome.browser.omaha.ACTION_POST_REQUEST";
72 67
73 // Delays between events. 68 // Delays between events.
74 private static final long MS_POST_BASE_DELAY = TimeUnit.HOURS.toMillis(1); 69 static final long MS_POST_BASE_DELAY = TimeUnit.HOURS.toMillis(1);
75 private static final long MS_POST_MAX_DELAY = TimeUnit.HOURS.toMillis(5); 70 static final long MS_POST_MAX_DELAY = TimeUnit.HOURS.toMillis(5);
76 static final long MS_BETWEEN_REQUESTS = TimeUnit.HOURS.toMillis(5); 71 static final long MS_BETWEEN_REQUESTS = TimeUnit.HOURS.toMillis(5);
77 private static final int MS_CONNECTION_TIMEOUT = (int) TimeUnit.MINUTES.toMi llis(1); 72 static final int MS_CONNECTION_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(1);
78 73
79 // Strings indicating how the Chrome APK arrived on the user's device. These values MUST NOT 74 // Strings indicating how the Chrome APK arrived on the user's device. These values MUST NOT
80 // be changed without updating the corresponding Omaha server strings. 75 // be changed without updating the corresponding Omaha server strings.
81 static final String INSTALL_SOURCE_SYSTEM = "system_image"; 76 static final String INSTALL_SOURCE_SYSTEM = "system_image";
82 static final String INSTALL_SOURCE_ORGANIC = "organic"; 77 static final String INSTALL_SOURCE_ORGANIC = "organic";
83 78
84 private static final long INVALID_TIMESTAMP = -1; 79 private static final long INVALID_TIMESTAMP = -1;
85 @VisibleForTesting 80 @VisibleForTesting
86 static final String INVALID_REQUEST_ID = "invalid"; 81 static final String INVALID_REQUEST_ID = "invalid";
87 82
88 // Member fields not persisted to disk. 83 // Member fields not persisted to disk.
89 private boolean mStateHasBeenRestored; 84 private boolean mStateHasBeenRestored;
90 private ExponentialBackoffScheduler mBackoffScheduler; 85 private OmahaDelegate mDelegate;
91 private RequestGenerator mGenerator;
92 86
93 // State saved written to and read from disk. 87 // State saved written to and read from disk.
94 private RequestData mCurrentRequest; 88 private RequestData mCurrentRequest;
95 private long mTimestampOfInstall; 89 private long mTimestampOfInstall;
96 private long mTimestampForNextPostAttempt; 90 private long mTimestampForNextPostAttempt;
97 private long mTimestampForNewRequest; 91 private long mTimestampForNewRequest;
98 private String mLatestVersion; 92 private String mLatestVersion;
99 private String mMarketURL; 93 private String mMarketURL;
100 private String mInstallSource; 94 private String mInstallSource;
101 protected boolean mSendInstallEvent; 95 protected boolean mSendInstallEvent;
102 96
103 public OmahaClient() { 97 public OmahaClient() {
104 super(TAG); 98 super(TAG);
105 setIntentRedelivery(true); 99 setIntentRedelivery(true);
106 } 100 }
107 101
108 @VisibleForTesting
109 long getTimestampForNextPostAttempt() {
110 return mTimestampForNextPostAttempt;
111 }
112
113 @VisibleForTesting
114 long getTimestampForNewRequest() {
115 return mTimestampForNewRequest;
116 }
117
118 @VisibleForTesting
119 int getCumulativeFailedAttempts() {
120 return getBackoffScheduler().getNumFailedAttempts();
121 }
122
123 /**
124 * Creates the scheduler used to space out POST attempts.
125 */
126 @VisibleForTesting
127 ExponentialBackoffScheduler createBackoffScheduler(String prefPackage, Conte xt context,
128 long base, long max) {
129 return new ExponentialBackoffScheduler(prefPackage, context, base, max);
130 }
131
132 /**
133 * Creates the request generator used to create Omaha XML.
134 */
135 @VisibleForTesting
136 RequestGenerator createRequestGenerator(Context context) {
137 return ((ChromeApplication) context.getApplicationContext()).createOmaha RequestGenerator();
138 }
139
140 /** 102 /**
141 * Handles an action on a thread separate from the UI thread. 103 * Handles an action on a thread separate from the UI thread.
142 * @param intent Intent fired by some part of Chrome. 104 * @param intent Intent fired by some part of Chrome.
143 */ 105 */
144 @Override 106 @Override
145 public void onHandleIntent(Intent intent) { 107 public void onHandleIntent(Intent intent) {
146 assert Looper.myLooper() != Looper.getMainLooper(); 108 assert !ThreadUtils.runningOnUiThread();
109 run();
110 }
147 111
112 protected void run() {
148 if (OmahaBase.isDisabled() || Build.VERSION.SDK_INT > Build.VERSION_CODE S.N 113 if (OmahaBase.isDisabled() || Build.VERSION.SDK_INT > Build.VERSION_CODE S.N
149 || getRequestGenerator() == null) { 114 || getRequestGenerator() == null) {
150 Log.v(TAG, "Disabled. Ignoring intent."); 115 Log.v(TAG, "Disabled. Ignoring intent.");
151 return; 116 return;
152 } 117 }
153 118
154 restoreState(this); 119 if (mDelegate == null) mDelegate = new OmahaDelegateImpl(this);
155 120
156 if (ACTION_INITIALIZE.equals(intent.getAction())) { 121 restoreState(getContext());
157 handleInitialize(); 122
158 } else if (ACTION_REGISTER_REQUEST.equals(intent.getAction())) { 123 long nextTimestamp = Long.MAX_VALUE;
159 handleRegisterRequest(); 124 if (mDelegate.isChromeBeingUsed()) {
160 } else if (ACTION_POST_REQUEST.equals(intent.getAction())) { 125 handleRegisterActiveRequest();
161 handlePostRequest(); 126 nextTimestamp = Math.min(nextTimestamp, mTimestampForNewRequest);
162 } else {
163 Log.e(TAG, "Got unknown action from intent: " + intent.getAction());
164 } 127 }
165 128
166 saveState(this); 129 if (hasRequest()) {
130 int result = handlePostRequest();
131 if (result == POST_RESULT_FAILED || result == POST_RESULT_SCHEDULED) {
132 nextTimestamp = Math.min(nextTimestamp, mTimestampForNextPostAtt empt);
133 }
134 }
135
136 // TODO(dfalcantara): Prevent Omaha code from repeatedly rescheduling it self immediately in
137 // case a scheduling error occurs.
138 if (nextTimestamp != Long.MAX_VALUE && nextTimestamp >= 0) {
139 mDelegate.scheduleService(this, nextTimestamp);
140 }
141 saveState(getContext());
167 } 142 }
168 143
169 /** 144 /**
170 * Begin communicating with the Omaha Update Server. 145 * Begin communicating with the Omaha Update Server.
171 */ 146 */
172 static void startService(Context context) { 147 static void startService(Context context) {
173 Intent omahaIntent = createInitializeIntent(context); 148 context.startService(createOmahaIntent(context));
174 context.startService(omahaIntent);
175 } 149 }
176 150
177 static Intent createInitializeIntent(Context context) { 151 static Intent createOmahaIntent(Context context) {
178 Intent intent = new Intent(context, OmahaClient.class); 152 return new Intent(context, OmahaClient.class);
179 intent.setAction(ACTION_INITIALIZE);
180 return intent;
181 }
182
183 /**
184 * Start a recurring alarm to fire request generation intents.
185 */
186 private void handleInitialize() {
187 scheduleActiveUserCheck();
188
189 // If a request exists, kick off POSTing it to the server immediately.
190 if (hasRequest()) handlePostRequest();
191 }
192
193 /**
194 * Returns an Intent for registering a new request to send to the server.
195 */
196 static Intent createRegisterRequestIntent(Context context) {
197 Intent intent = new Intent(context, OmahaClient.class);
198 intent.setAction(ACTION_REGISTER_REQUEST);
199 return intent;
200 } 153 }
201 154
202 /** 155 /**
203 * Determines if a new request should be generated. New requests are only g enerated if enough 156 * Determines if a new request should be generated. New requests are only g enerated if enough
204 * time has passed between now and the last time a request was generated. 157 * time has passed between now and the last time a request was generated.
205 */ 158 */
206 private void handleRegisterRequest() { 159 private void handleRegisterActiveRequest() {
207 if (!isChromeBeingUsed()) {
208 getBackoffScheduler().cancelAlarm(createRegisterRequestIntent(this)) ;
209 return;
210 }
211
212 // If the current request is too old, generate a new one. 160 // If the current request is too old, generate a new one.
213 long currentTimestamp = getBackoffScheduler().getCurrentTime(); 161 long currentTimestamp = getBackoffScheduler().getCurrentTime();
214 boolean isTooOld = hasRequest() 162 boolean isTooOld = hasRequest()
215 && mCurrentRequest.getAgeInMilliseconds(currentTimestamp) >= MS_ BETWEEN_REQUESTS; 163 && mCurrentRequest.getAgeInMilliseconds(currentTimestamp) >= MS_ BETWEEN_REQUESTS;
216 boolean isOverdue = !hasRequest() && currentTimestamp >= mTimestampForNe wRequest; 164 boolean isOverdue = currentTimestamp >= mTimestampForNewRequest;
217 if (isTooOld || isOverdue) { 165 if (isTooOld || isOverdue) {
218 registerNewRequest(currentTimestamp); 166 registerNewRequest(currentTimestamp);
219 } 167 }
220
221 // Send the request.
222 if (hasRequest()) {
223 handlePostRequest();
224 }
225 }
226
227 /**
228 * Returns an Intent for POSTing the current request to the Omaha server.
229 */
230 static Intent createPostRequestIntent(Context context) {
231 Intent intent = new Intent(context, OmahaClient.class);
232 intent.setAction(ACTION_POST_REQUEST);
233 return intent;
234 } 168 }
235 169
236 /** 170 /**
237 * Sends the request it is holding. 171 * Sends the request it is holding.
238 */ 172 */
239 @VisibleForTesting 173 private int handlePostRequest() {
240 protected int handlePostRequest() { 174 if (!hasRequest()) {
241 if (!hasRequest()) return POST_RESULT_NO_REQUEST; 175 mDelegate.onHandlePostRequestDone(POST_RESULT_NO_REQUEST, false);
176 return POST_RESULT_NO_REQUEST;
177 }
242 178
243 // If enough time has passed since the last attempt, try sending a reque st. 179 // If enough time has passed since the last attempt, try sending a reque st.
244 int result; 180 int result;
245 long currentTimestamp = getBackoffScheduler().getCurrentTime(); 181 long currentTimestamp = getBackoffScheduler().getCurrentTime();
182 boolean installEventWasSent = false;
246 if (currentTimestamp >= mTimestampForNextPostAttempt) { 183 if (currentTimestamp >= mTimestampForNextPostAttempt) {
247 // All requests made during the same session should have the same ID . 184 // All requests made during the same session should have the same ID .
248 String sessionID = generateRandomUUID(); 185 String sessionID = mDelegate.generateUUID();
249 boolean sendingInstallRequest = mSendInstallEvent; 186 boolean sendingInstallRequest = mSendInstallEvent;
250 boolean succeeded = generateAndPostRequest(currentTimestamp, session ID); 187 boolean succeeded = generateAndPostRequest(currentTimestamp, session ID);
251 188
252 if (succeeded && sendingInstallRequest) { 189 if (succeeded && sendingInstallRequest) {
253 // Only the first request ever generated should contain an insta ll event. 190 // Only the first request ever generated should contain an insta ll event.
254 mSendInstallEvent = false; 191 mSendInstallEvent = false;
192 installEventWasSent = true;
255 193
256 // Create and immediately send another request for a ping and up date check. 194 // Create and immediately send another request for a ping and up date check.
257 registerNewRequest(currentTimestamp); 195 registerNewRequest(currentTimestamp);
258 generateAndPostRequest(currentTimestamp, sessionID); 196 succeeded &= generateAndPostRequest(currentTimestamp, sessionID) ;
259 } 197 }
260 198
261 result = succeeded ? POST_RESULT_SENT : POST_RESULT_FAILED; 199 result = succeeded ? POST_RESULT_SENT : POST_RESULT_FAILED;
262 } else { 200 } else {
263 schedulePost();
264 result = POST_RESULT_SCHEDULED; 201 result = POST_RESULT_SCHEDULED;
265 } 202 }
266 203
204 mDelegate.onHandlePostRequestDone(result, installEventWasSent);
267 return result; 205 return result;
268 } 206 }
269 207
270 /** Set an alarm to POST at the proper time. Previous alarms are destroyed. */
271 private void schedulePost() {
272 Intent postIntent = createPostRequestIntent(this);
273 getBackoffScheduler().createAlarm(postIntent, mTimestampForNextPostAttem pt);
274 }
275
276 private boolean generateAndPostRequest(long currentTimestamp, String session ID) { 208 private boolean generateAndPostRequest(long currentTimestamp, String session ID) {
277 ExponentialBackoffScheduler scheduler = getBackoffScheduler(); 209 ExponentialBackoffScheduler scheduler = getBackoffScheduler();
210 boolean succeeded = false;
278 try { 211 try {
279 // Generate the XML for the current request. 212 // Generate the XML for the current request.
280 long installAgeInDays = RequestGenerator.installAge(currentTimestamp , 213 long installAgeInDays = RequestGenerator.installAge(currentTimestamp ,
281 mTimestampOfInstall, mCurrentRequest.isSendInstallEvent()); 214 mTimestampOfInstall, mCurrentRequest.isSendInstallEvent());
282 String version = VersionNumberGetter.getInstance().getCurrentlyUsedV ersion(this); 215 String version = VersionNumberGetter.getInstance().getCurrentlyUsedV ersion(this);
283 String xml = getRequestGenerator().generateXML( 216 String xml = getRequestGenerator().generateXML(
284 sessionID, version, installAgeInDays, mCurrentRequest); 217 sessionID, version, installAgeInDays, mCurrentRequest);
285 218
286 // Send the request to the server & wait for a response. 219 // Send the request to the server & wait for a response.
287 String response = postRequest(currentTimestamp, xml); 220 String response = postRequest(currentTimestamp, xml);
288 221
289 // Parse out the response. 222 // Parse out the response.
290 String appId = getRequestGenerator().getAppId(); 223 String appId = getRequestGenerator().getAppId();
291 boolean sentPingAndUpdate = !mSendInstallEvent; 224 boolean sentPingAndUpdate = !mSendInstallEvent;
292 ResponseParser parser = new ResponseParser( 225 ResponseParser parser = new ResponseParser(
293 appId, mSendInstallEvent, sentPingAndUpdate, sentPingAndUpda te); 226 appId, mSendInstallEvent, sentPingAndUpdate, sentPingAndUpda te);
294 parser.parseResponse(response); 227 parser.parseResponse(response);
295 mLatestVersion = parser.getNewVersion(); 228 mLatestVersion = parser.getNewVersion();
296 mMarketURL = parser.getURL(); 229 mMarketURL = parser.getURL();
297 230
231 succeeded = true;
232 } catch (RequestFailureException e) {
233 Log.e(TAG, "Failed to contact server: ", e);
234 }
235
236 if (succeeded) {
298 // If we've gotten this far, we've successfully sent a request. 237 // If we've gotten this far, we've successfully sent a request.
299 mCurrentRequest = null; 238 mCurrentRequest = null;
300 239
301 mTimestampForNewRequest = getBackoffScheduler().getCurrentTime() + M S_BETWEEN_REQUESTS;
302 scheduleActiveUserCheck();
303
304 scheduler.resetFailedAttempts(); 240 scheduler.resetFailedAttempts();
241 mTimestampForNewRequest = scheduler.getCurrentTime() + MS_BETWEEN_RE QUESTS;
305 mTimestampForNextPostAttempt = scheduler.calculateNextTimestamp(); 242 mTimestampForNextPostAttempt = scheduler.calculateNextTimestamp();
306 Log.i(TAG, "Request to Server Successful. Timestamp for next request :" 243 Log.i(TAG, "Request to Server Successful. Timestamp for next request :"
307 + String.valueOf(mTimestampForNextPostAttempt)); 244 + String.valueOf(mTimestampForNextPostAttempt));
245 } else {
246 // Set the alarm to try again later. Failures are incremented after setting the timer
247 // to allow the first failure to incur the minimum base delay betwee n POSTs.
248 mTimestampForNextPostAttempt = scheduler.calculateNextTimestamp();
249 scheduler.increaseFailedAttempts();
250 }
308 251
309 return true; 252 mDelegate.onGenerateAndPostRequestDone(succeeded);
310 } catch (RequestFailureException e) { 253 return succeeded;
311 // Set the alarm to try again later.
312 Log.e(TAG, "Failed to contact server: ", e);
313 scheduler.increaseFailedAttempts();
314 mTimestampForNextPostAttempt = scheduler.calculateNextTimestamp();
315 scheduler.createAlarm(createPostRequestIntent(this), mTimestampForNe xtPostAttempt);
316 return false;
317 }
318 } 254 }
319 255
320 /** 256 /**
321 * Sets a repeating alarm that fires request registration Intents.
322 * Setting the alarm overwrites whatever alarm is already there, and rebooti ng
323 * clears whatever alarms are currently set.
324 */
325 private void scheduleActiveUserCheck() {
326 Intent registerIntent = createRegisterRequestIntent(this);
327 PendingIntent pIntent = PendingIntent.getService(this, 0, registerIntent , 0);
328 AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE) ;
329 setAlarm(am, pIntent, mTimestampForNewRequest);
330 }
331
332 /**
333 * Sets up a timer to fire after each interval.
334 * Override to prevent a real alarm from being set.
335 */
336 @VisibleForTesting
337 protected void setAlarm(AlarmManager am, PendingIntent operation, long trigg erAtTime) {
338 try {
339 am.setRepeating(AlarmManager.RTC, triggerAtTime, MS_BETWEEN_REQUESTS , operation);
340 } catch (SecurityException e) {
341 Log.e(TAG, "Failed to set repeating alarm.");
342 }
343 }
344
345 /**
346 * Determine whether or not Chrome is currently being used actively.
347 */
348 @VisibleForTesting
349 protected boolean isChromeBeingUsed() {
350 boolean isChromeVisible = ApplicationStatus.hasVisibleActivities();
351 boolean isScreenOn = ApiCompatibilityUtils.isInteractive(this);
352 return isChromeVisible && isScreenOn;
353 }
354
355 /**
356 * Registers a new request with the current timestamp. Internal timestamps are reset to start 257 * Registers a new request with the current timestamp. Internal timestamps are reset to start
357 * fresh. 258 * fresh.
358 * @param currentTimestamp Current time. 259 * @param currentTimestamp Current time.
359 */ 260 */
360 @VisibleForTesting 261 private void registerNewRequest(long currentTimestamp) {
361 void registerNewRequest(long currentTimestamp) {
362 mCurrentRequest = createRequestData(currentTimestamp, null); 262 mCurrentRequest = createRequestData(currentTimestamp, null);
363 getBackoffScheduler().resetFailedAttempts(); 263 getBackoffScheduler().resetFailedAttempts();
364 mTimestampForNextPostAttempt = currentTimestamp; 264 mTimestampForNextPostAttempt = currentTimestamp;
365 265
366 // Tentatively set the timestamp for a new request. This will be update d when the server 266 // Tentatively set the timestamp for a new request. This will be update d when the server
367 // is successfully contacted. 267 // is successfully contacted.
368 mTimestampForNewRequest = currentTimestamp + MS_BETWEEN_REQUESTS; 268 mTimestampForNewRequest = currentTimestamp + MS_BETWEEN_REQUESTS;
369 scheduleActiveUserCheck(); 269
270 mDelegate.onRegisterNewRequestDone(mTimestampForNewRequest, mTimestampFo rNextPostAttempt);
370 } 271 }
371 272
372 private RequestData createRequestData(long currentTimestamp, String persiste dID) { 273 private RequestData createRequestData(long currentTimestamp, String persiste dID) {
373 // If we're sending a persisted event, keep trying to send the same requ est ID. 274 // If we're sending a persisted event, keep trying to send the same requ est ID.
374 String requestID; 275 String requestID;
375 if (persistedID == null || INVALID_REQUEST_ID.equals(persistedID)) { 276 if (persistedID == null || INVALID_REQUEST_ID.equals(persistedID)) {
376 requestID = generateRandomUUID(); 277 requestID = mDelegate.generateUUID();
377 } else { 278 } else {
378 requestID = persistedID; 279 requestID = persistedID;
379 } 280 }
380 return new RequestData(mSendInstallEvent, currentTimestamp, requestID, m InstallSource); 281 return new RequestData(mSendInstallEvent, currentTimestamp, requestID, m InstallSource);
381 } 282 }
382 283
383 @VisibleForTesting 284 private boolean hasRequest() {
384 boolean hasRequest() {
385 return mCurrentRequest != null; 285 return mCurrentRequest != null;
386 } 286 }
387 287
388 /** 288 /**
389 * Posts the request to the Omaha server. 289 * Posts the request to the Omaha server.
390 * @return the XML response as a String. 290 * @return the XML response as a String.
391 * @throws RequestFailureException if the request fails. 291 * @throws RequestFailureException if the request fails.
392 */ 292 */
393 @VisibleForTesting 293 private String postRequest(long timestamp, String xml) throws RequestFailure Exception {
394 String postRequest(long timestamp, String xml) throws RequestFailureExceptio n {
395 String response = null; 294 String response = null;
396 295
397 HttpURLConnection urlConnection = null; 296 HttpURLConnection urlConnection = null;
398 try { 297 try {
399 urlConnection = createConnection(); 298 urlConnection = createConnection();
400 299
401 // Prepare the HTTP header. 300 // Prepare the HTTP header.
402 urlConnection.setDoOutput(true); 301 urlConnection.setDoOutput(true);
403 urlConnection.setFixedLengthStreamingMode(xml.getBytes().length); 302 urlConnection.setFixedLengthStreamingMode(xml.getBytes().length);
404 if (mSendInstallEvent && getCumulativeFailedAttempts() > 0) { 303 if (mSendInstallEvent && getBackoffScheduler().getNumFailedAttempts( ) > 0) {
405 String age = Long.toString(mCurrentRequest.getAgeInSeconds(times tamp)); 304 String age = Long.toString(mCurrentRequest.getAgeInSeconds(times tamp));
406 urlConnection.addRequestProperty("X-RequestAge", age); 305 urlConnection.addRequestProperty("X-RequestAge", age);
407 } 306 }
408 307
409 response = OmahaBase.sendRequestToServer(urlConnection, xml); 308 response = OmahaBase.sendRequestToServer(urlConnection, xml);
410 } catch (IllegalAccessError e) { 309 } catch (IllegalAccessError e) {
411 throw new RequestFailureException("Caught an IllegalAccessError:", e ); 310 throw new RequestFailureException("Caught an IllegalAccessError:", e );
412 } catch (IllegalArgumentException e) { 311 } catch (IllegalArgumentException e) {
413 throw new RequestFailureException("Caught an IllegalArgumentExceptio n:", e); 312 throw new RequestFailureException("Caught an IllegalArgumentExceptio n:", e);
414 } catch (IllegalStateException e) { 313 } catch (IllegalStateException e) {
(...skipping 19 matching lines...) Expand all
434 connection.setReadTimeout(MS_CONNECTION_TIMEOUT); 333 connection.setReadTimeout(MS_CONNECTION_TIMEOUT);
435 return connection; 334 return connection;
436 } catch (MalformedURLException e) { 335 } catch (MalformedURLException e) {
437 throw new RequestFailureException("Caught a malformed URL exception. ", e); 336 throw new RequestFailureException("Caught a malformed URL exception. ", e);
438 } catch (IOException e) { 337 } catch (IOException e) {
439 throw new RequestFailureException("Failed to open connection to URL" , e); 338 throw new RequestFailureException("Failed to open connection to URL" , e);
440 } 339 }
441 } 340 }
442 341
443 /** 342 /**
444 * Determine how the Chrome APK arrived on the device.
445 * @param context Context to pull resources from.
446 * @return A String indicating the install source.
447 */
448 String determineInstallSource() {
449 boolean isInSystemImage = (getApplicationFlags() & ApplicationInfo.FLAG_ SYSTEM) != 0;
450 return isInSystemImage ? INSTALL_SOURCE_SYSTEM : INSTALL_SOURCE_ORGANIC;
451 }
452
453 /**
454 * Returns the Application's flags, used to determine if Chrome was installe d as part of the
455 * system image.
456 * @return The Application's flags.
457 */
458 @VisibleForTesting
459 int getApplicationFlags() {
460 return getApplicationInfo().flags;
461 }
462
463 /**
464 * Reads the data back from the file it was saved to. Uses SharedPreference s to handle I/O. 343 * Reads the data back from the file it was saved to. Uses SharedPreference s to handle I/O.
465 * Sanity checks are performed on the timestamps to guard against clock chan ging. 344 * Sanity checks are performed on the timestamps to guard against clock chan ging.
466 */ 345 */
467 @VisibleForTesting 346 @VisibleForTesting
468 void restoreState(Context context) { 347 void restoreState(Context context) {
469 if (mStateHasBeenRestored) return; 348 if (mStateHasBeenRestored) return;
470 long currentTime = getBackoffScheduler().getCurrentTime(); 349
350 String installSource =
351 mDelegate.isInSystemImage() ? INSTALL_SOURCE_SYSTEM : INSTALL_SO URCE_ORGANIC;
352 ExponentialBackoffScheduler scheduler = getBackoffScheduler();
353 long currentTime = scheduler.getCurrentTime();
471 354
472 SharedPreferences preferences = OmahaBase.getSharedPreferences(context); 355 SharedPreferences preferences = OmahaBase.getSharedPreferences(context);
473 mTimestampForNewRequest = 356 mTimestampForNewRequest =
474 preferences.getLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, cu rrentTime); 357 preferences.getLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, cu rrentTime);
475 mTimestampForNextPostAttempt = 358 mTimestampForNextPostAttempt =
476 preferences.getLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEM PT, currentTime); 359 preferences.getLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEM PT, currentTime);
477 mTimestampOfInstall = preferences.getLong(OmahaBase.PREF_TIMESTAMP_OF_IN STALL, currentTime); 360 mTimestampOfInstall = preferences.getLong(OmahaBase.PREF_TIMESTAMP_OF_IN STALL, currentTime);
478 mSendInstallEvent = preferences.getBoolean(OmahaBase.PREF_SEND_INSTALL_E VENT, true); 361 mSendInstallEvent = preferences.getBoolean(OmahaBase.PREF_SEND_INSTALL_E VENT, true);
479 mInstallSource = 362 mInstallSource = preferences.getString(OmahaBase.PREF_INSTALL_SOURCE, in stallSource);
480 preferences.getString(OmahaBase.PREF_INSTALL_SOURCE, determineIn stallSource());
481 mLatestVersion = preferences.getString(OmahaBase.PREF_LATEST_VERSION, "" ); 363 mLatestVersion = preferences.getString(OmahaBase.PREF_LATEST_VERSION, "" );
482 mMarketURL = preferences.getString(OmahaBase.PREF_MARKET_URL, ""); 364 mMarketURL = preferences.getString(OmahaBase.PREF_MARKET_URL, "");
483 365
484 // If we're not sending an install event, don't bother restoring the req uest ID: 366 // If we're not sending an install event, don't bother restoring the req uest ID:
485 // the server does not expect to have persisted request IDs for pings or update checks. 367 // the server does not expect to have persisted request IDs for pings or update checks.
486 String persistedRequestId = mSendInstallEvent 368 String persistedRequestId = mSendInstallEvent
487 ? preferences.getString(OmahaBase.PREF_PERSISTED_REQUEST_ID, INV ALID_REQUEST_ID) 369 ? preferences.getString(OmahaBase.PREF_PERSISTED_REQUEST_ID, INV ALID_REQUEST_ID)
488 : INVALID_REQUEST_ID; 370 : INVALID_REQUEST_ID;
489 long requestTimestamp = 371 long requestTimestamp =
490 preferences.getLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, INVALID _TIMESTAMP); 372 preferences.getLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, INVALID _TIMESTAMP);
491 mCurrentRequest = requestTimestamp == INVALID_TIMESTAMP 373 mCurrentRequest = requestTimestamp == INVALID_TIMESTAMP
492 ? null : createRequestData(requestTimestamp, persistedRequestId) ; 374 ? null : createRequestData(requestTimestamp, persistedRequestId) ;
493 375
494 // Confirm that the timestamp for the next request is less than the base delay. 376 // Confirm that the timestamp for the next request is less than the base delay.
495 long delayToNewRequest = mTimestampForNewRequest - currentTime; 377 long delayToNewRequest = mTimestampForNewRequest - currentTime;
496 if (delayToNewRequest > MS_BETWEEN_REQUESTS) { 378 if (delayToNewRequest > MS_BETWEEN_REQUESTS) {
497 Log.w(TAG, "Delay to next request (" + delayToNewRequest 379 Log.w(TAG, "Delay to next request (" + delayToNewRequest
498 + ") is longer than expected. Resetting to now."); 380 + ") is longer than expected. Resetting to now.");
499 mTimestampForNewRequest = currentTime; 381 mTimestampForNewRequest = currentTime;
500 } 382 }
501 383
502 // Confirm that the timestamp for the next POST is less than the current delay. 384 // Confirm that the timestamp for the next POST is less than the current delay.
503 long delayToNextPost = mTimestampForNextPostAttempt - currentTime; 385 long delayToNextPost = mTimestampForNextPostAttempt - currentTime;
504 if (delayToNextPost > getBackoffScheduler().getGeneratedDelay()) { 386 long lastGeneratedDelay = scheduler.getGeneratedDelay();
387 if (delayToNextPost > lastGeneratedDelay) {
505 Log.w(TAG, "Delay to next post attempt (" + delayToNextPost 388 Log.w(TAG, "Delay to next post attempt (" + delayToNextPost
506 + ") is greater than expected (" + getBackoffScheduler().get GeneratedDelay() 389 + ") is greater than expected (" + lastGeneratedDelay
507 + "). Resetting to now."); 390 + "). Resetting to now.");
508 mTimestampForNextPostAttempt = currentTime; 391 mTimestampForNextPostAttempt = currentTime;
509 } 392 }
510 393
394 migrateToNewerChromeVersions();
511 mStateHasBeenRestored = true; 395 mStateHasBeenRestored = true;
512 } 396 }
513 397
514 /** 398 /**
515 * Writes out the current state to a file. 399 * Writes out the current state to a file.
516 */ 400 */
517 private void saveState(Context context) { 401 private void saveState(Context context) {
518 SharedPreferences prefs = OmahaBase.getSharedPreferences(context); 402 SharedPreferences prefs = OmahaBase.getSharedPreferences(context);
519 SharedPreferences.Editor editor = prefs.edit(); 403 SharedPreferences.Editor editor = prefs.edit();
520 editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, mSendInstallEvent); 404 editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, mSendInstallEvent);
521 editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_INSTALL, mTimestampOfInstall) ; 405 editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_INSTALL, mTimestampOfInstall) ;
522 editor.putLong( 406 editor.putLong(
523 OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, mTimestampForNex tPostAttempt); 407 OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, mTimestampForNex tPostAttempt);
524 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, mTimestampForNe wRequest); 408 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, mTimestampForNe wRequest);
525 editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, 409 editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST,
526 hasRequest() ? mCurrentRequest.getCreationTimestamp() : INVALID_ TIMESTAMP); 410 hasRequest() ? mCurrentRequest.getCreationTimestamp() : INVALID_ TIMESTAMP);
527 editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, 411 editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID,
528 hasRequest() ? mCurrentRequest.getRequestID() : INVALID_REQUEST_ ID); 412 hasRequest() ? mCurrentRequest.getRequestID() : INVALID_REQUEST_ ID);
529 editor.putString( 413 editor.putString(
530 OmahaBase.PREF_LATEST_VERSION, mLatestVersion == null ? "" : mLa testVersion); 414 OmahaBase.PREF_LATEST_VERSION, mLatestVersion == null ? "" : mLa testVersion);
531 editor.putString(OmahaBase.PREF_MARKET_URL, mMarketURL == null ? "" : mM arketURL); 415 editor.putString(OmahaBase.PREF_MARKET_URL, mMarketURL == null ? "" : mM arketURL);
532 editor.putString(OmahaBase.PREF_INSTALL_SOURCE, mInstallSource); 416 editor.putString(OmahaBase.PREF_INSTALL_SOURCE, mInstallSource);
533 editor.apply(); 417 editor.apply();
418
419 mDelegate.onSaveStateDone(mTimestampForNewRequest, mTimestampForNextPost Attempt);
534 } 420 }
535 421
536 /** 422 private void migrateToNewerChromeVersions() {
537 * Generates a random UUID. 423 // Remove any repeating alarms in favor of the new scheduling setup on M 58 and up.
538 */ 424 // Seems cheaper to cancel the alarm repeatedly than to store a SharedPr eference and never
539 @VisibleForTesting 425 // do it again.
540 protected String generateRandomUUID() { 426 Intent intent = new Intent(getContext(), OmahaClient.class);
541 return UUID.randomUUID().toString(); 427 intent.setAction(ACTION_REGISTER_REQUEST);
428 getBackoffScheduler().cancelAlarm(intent);
542 } 429 }
543 430
544 protected final RequestGenerator getRequestGenerator() { 431 Context getContext() {
545 if (mGenerator == null) mGenerator = createRequestGenerator(this); 432 return mDelegate.getContext();
546 return mGenerator;
547 } 433 }
548 434
549 protected final ExponentialBackoffScheduler getBackoffScheduler() { 435 private RequestGenerator getRequestGenerator() {
550 if (mBackoffScheduler == null) { 436 return mDelegate.getRequestGenerator();
551 mBackoffScheduler = createBackoffScheduler( 437 }
552 OmahaBase.PREF_PACKAGE, this, MS_POST_BASE_DELAY, MS_POST_MA X_DELAY); 438
553 } 439 private ExponentialBackoffScheduler getBackoffScheduler() {
554 return mBackoffScheduler; 440 return mDelegate.getScheduler();
441 }
442
443 void setDelegateForTests(OmahaDelegate delegate) {
444 mDelegate = delegate;
555 } 445 }
556 } 446 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698