OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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.content.Context; | 7 import android.content.Context; |
| 8 import android.content.Intent; |
8 import android.content.SharedPreferences; | 9 import android.content.SharedPreferences; |
9 import android.os.Build; | 10 import android.os.Build; |
| 11 import android.support.annotation.IntDef; |
10 | 12 |
| 13 import org.chromium.base.Log; |
11 import org.chromium.base.StreamUtil; | 14 import org.chromium.base.StreamUtil; |
| 15 import org.chromium.base.VisibleForTesting; |
12 import org.chromium.chrome.browser.ChromeVersionInfo; | 16 import org.chromium.chrome.browser.ChromeVersionInfo; |
13 | 17 |
14 import java.io.BufferedOutputStream; | 18 import java.io.BufferedOutputStream; |
15 import java.io.BufferedReader; | 19 import java.io.BufferedReader; |
16 import java.io.IOException; | 20 import java.io.IOException; |
17 import java.io.InputStreamReader; | 21 import java.io.InputStreamReader; |
18 import java.io.OutputStream; | 22 import java.io.OutputStream; |
19 import java.io.OutputStreamWriter; | 23 import java.io.OutputStreamWriter; |
| 24 import java.lang.annotation.Retention; |
| 25 import java.lang.annotation.RetentionPolicy; |
20 import java.net.HttpURLConnection; | 26 import java.net.HttpURLConnection; |
| 27 import java.net.MalformedURLException; |
| 28 import java.net.URL; |
| 29 import java.util.Date; |
| 30 import java.util.concurrent.TimeUnit; |
21 | 31 |
22 /** | 32 /** |
23 * Logic used for communicating with the Omaha server. | 33 * Keeps tabs on the current state of Chrome, tracking if and when a request sho
uld be sent to the |
24 * TODO(dfalcantara): Move everything from OmahaClient over. | 34 * Omaha Server. |
| 35 * |
| 36 * When Chrome is brought to the foreground, it will trigger a call to |
| 37 * {@link OmahaBase#onForegroundSessionStart}, which kicks off a series of sched
uled events |
| 38 * that allow the class to run. A single alarm is used to trigger the whole pip
eline when needed. |
| 39 * - If Chrome isn't running when the alarm is fired, no pings or update checks
will be performed. |
| 40 * - If Chrome doesn't have a pending request to POST, no POST will be performed
. |
| 41 * |
| 42 * When a fresh install is detected (or the user clears their data), OmahaBase w
ill send an XML |
| 43 * request saying that a new install was detected, then follow up with an XML re
quest saying that |
| 44 * the user was active and that we need to check for Chrome updates. |
| 45 * |
| 46 * mevissen suggested being conservative with our timers for sending requests. |
| 47 * POST attempts that fail to be acknowledged by the server are re-attempted, wi
th at least |
| 48 * one hour between each attempt. |
| 49 * |
| 50 * Status is saved directly to the the disk after every run of the pipeline. |
| 51 * |
| 52 * Implementation notes: |
| 53 * http://docs.google.com/a/google.com/document/d/1scTCovqASf5ktkOeVj8wFRkWTCeDY
w2LrOBNn05CDB0/edit |
25 */ | 54 */ |
26 public abstract class OmahaBase { | 55 public class OmahaBase { |
| 56 private static final String TAG = "omaha"; |
27 | 57 |
28 // Flags for retrieving the OmahaClient's state after it's written to disk. | 58 // Flags for retrieving the OmahaClient's state after it's written to disk. |
29 // The PREF_PACKAGE doesn't match the current OmahaClient package for histor
ical reasons. | 59 // The PREF_PACKAGE doesn't match the current OmahaClient package for histor
ical reasons. |
30 static final String PREF_PACKAGE = "com.google.android.apps.chrome.omaha"; | 60 static final String PREF_PACKAGE = "com.google.android.apps.chrome.omaha"; |
31 static final String PREF_INSTALL_SOURCE = "installSource"; | 61 static final String PREF_INSTALL_SOURCE = "installSource"; |
32 static final String PREF_LATEST_VERSION = "latestVersion"; | 62 static final String PREF_LATEST_VERSION = "latestVersion"; |
33 static final String PREF_MARKET_URL = "marketURL"; | 63 static final String PREF_MARKET_URL = "marketURL"; |
34 static final String PREF_PERSISTED_REQUEST_ID = "persistedRequestID"; | 64 static final String PREF_PERSISTED_REQUEST_ID = "persistedRequestID"; |
35 static final String PREF_SEND_INSTALL_EVENT = "sendInstallEvent"; | 65 static final String PREF_SEND_INSTALL_EVENT = "sendInstallEvent"; |
36 static final String PREF_TIMESTAMP_FOR_NEW_REQUEST = "timestampForNewRequest
"; | 66 static final String PREF_TIMESTAMP_FOR_NEW_REQUEST = "timestampForNewRequest
"; |
37 static final String PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT = "timestampForNext
PostAttempt"; | 67 static final String PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT = "timestampForNext
PostAttempt"; |
38 static final String PREF_TIMESTAMP_OF_INSTALL = "timestampOfInstall"; | 68 static final String PREF_TIMESTAMP_OF_INSTALL = "timestampOfInstall"; |
39 static final String PREF_TIMESTAMP_OF_REQUEST = "timestampOfRequest"; | 69 static final String PREF_TIMESTAMP_OF_REQUEST = "timestampOfRequest"; |
40 | 70 |
| 71 static final int MIN_API_JOB_SCHEDULER = Build.VERSION_CODES.M; |
| 72 |
41 /** Whether or not the Omaha server should really be contacted. */ | 73 /** Whether or not the Omaha server should really be contacted. */ |
42 private static boolean sIsDisabled; | 74 private static boolean sIsDisabled; |
43 | 75 |
| 76 // Results of {@link #handlePostRequest()}. |
| 77 @Retention(RetentionPolicy.SOURCE) |
| 78 @IntDef({POST_RESULT_NO_REQUEST, POST_RESULT_SENT, POST_RESULT_FAILED, POST_
RESULT_SCHEDULED}) |
| 79 @interface PostResult {} |
| 80 static final int POST_RESULT_NO_REQUEST = 0; |
| 81 static final int POST_RESULT_SENT = 1; |
| 82 static final int POST_RESULT_FAILED = 2; |
| 83 static final int POST_RESULT_SCHEDULED = 3; |
| 84 |
| 85 /** Deprecated; kept around to cancel alarms set for OmahaClient pre-M58. */ |
| 86 private static final String ACTION_REGISTER_REQUEST = |
| 87 "org.chromium.chrome.browser.omaha.ACTION_REGISTER_REQUEST"; |
| 88 |
| 89 // Delays between events. |
| 90 static final long MS_POST_BASE_DELAY = TimeUnit.HOURS.toMillis(1); |
| 91 static final long MS_POST_MAX_DELAY = TimeUnit.HOURS.toMillis(5); |
| 92 static final long MS_BETWEEN_REQUESTS = TimeUnit.HOURS.toMillis(5); |
| 93 static final int MS_CONNECTION_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(1); |
| 94 |
| 95 // Strings indicating how the Chrome APK arrived on the user's device. These
values MUST NOT |
| 96 // be changed without updating the corresponding Omaha server strings. |
| 97 private static final String INSTALL_SOURCE_SYSTEM = "system_image"; |
| 98 private static final String INSTALL_SOURCE_ORGANIC = "organic"; |
| 99 |
| 100 private static final long INVALID_TIMESTAMP = -1; |
| 101 private static final String INVALID_REQUEST_ID = "invalid"; |
| 102 |
| 103 // Member fields not persisted to disk. |
| 104 private final OmahaDelegate mDelegate; |
| 105 private boolean mStateHasBeenRestored; |
| 106 |
| 107 // State saved written to and read from disk. |
| 108 private RequestData mCurrentRequest; |
| 109 private long mTimestampOfInstall; |
| 110 private long mTimestampForNextPostAttempt; |
| 111 private long mTimestampForNewRequest; |
| 112 private String mLatestVersion; |
| 113 private String mMarketURL; |
| 114 private String mInstallSource; |
| 115 protected boolean mSendInstallEvent; |
| 116 |
44 /** See {@link #sIsDisabled}. */ | 117 /** See {@link #sIsDisabled}. */ |
45 public static void setIsDisabledForTesting(boolean state) { | 118 public static void setIsDisabledForTesting(boolean state) { |
46 sIsDisabled = state; | 119 sIsDisabled = state; |
47 } | 120 } |
48 | 121 |
49 /** See {@link #sIsDisabled}. */ | 122 /** See {@link #sIsDisabled}. */ |
50 static boolean isDisabled() { | 123 static boolean isDisabled() { |
51 return sIsDisabled; | 124 return sIsDisabled; |
52 } | 125 } |
53 | 126 |
| 127 /** |
| 128 * Constructs a new OmahaBase. |
| 129 * @param delegate The {@link OmahaDelegate} used to interact with the syste
m. |
| 130 */ |
| 131 OmahaBase(OmahaDelegate delegate) { |
| 132 mDelegate = delegate; |
| 133 } |
| 134 |
| 135 protected void run() { |
| 136 if (OmahaBase.isDisabled() || getRequestGenerator() == null) { |
| 137 Log.v(TAG, "Disabled. Ignoring intent."); |
| 138 return; |
| 139 } |
| 140 |
| 141 restoreState(getContext()); |
| 142 |
| 143 long nextTimestamp = Long.MAX_VALUE; |
| 144 if (mDelegate.isChromeBeingUsed()) { |
| 145 handleRegisterActiveRequest(); |
| 146 nextTimestamp = Math.min(nextTimestamp, mTimestampForNewRequest); |
| 147 } |
| 148 |
| 149 if (hasRequest()) { |
| 150 int result = handlePostRequest(); |
| 151 if (result == POST_RESULT_FAILED || result == POST_RESULT_SCHEDULED)
{ |
| 152 nextTimestamp = Math.min(nextTimestamp, mTimestampForNextPostAtt
empt); |
| 153 } |
| 154 } |
| 155 |
| 156 // TODO(dfalcantara): Prevent Omaha code from repeatedly rescheduling it
self immediately in |
| 157 // case a scheduling error occurs. |
| 158 if (nextTimestamp != Long.MAX_VALUE && nextTimestamp >= 0) { |
| 159 long currentTimestamp = mDelegate.getScheduler().getCurrentTime(); |
| 160 Log.i(TAG, "Attempting to schedule next job for: " + new Date(nextTi
mestamp)); |
| 161 mDelegate.scheduleService(currentTimestamp, nextTimestamp); |
| 162 } |
| 163 |
| 164 saveState(getContext()); |
| 165 } |
| 166 |
| 167 /** |
| 168 * Determines if a new request should be generated. New requests are only g
enerated if enough |
| 169 * time has passed between now and the last time a request was generated. |
| 170 */ |
| 171 private void handleRegisterActiveRequest() { |
| 172 // If the current request is too old, generate a new one. |
| 173 long currentTimestamp = getBackoffScheduler().getCurrentTime(); |
| 174 boolean isTooOld = hasRequest() |
| 175 && mCurrentRequest.getAgeInMilliseconds(currentTimestamp) >= MS_
BETWEEN_REQUESTS; |
| 176 boolean isOverdue = currentTimestamp >= mTimestampForNewRequest; |
| 177 if (isTooOld || isOverdue) { |
| 178 registerNewRequest(currentTimestamp); |
| 179 } |
| 180 } |
| 181 |
| 182 /** |
| 183 * Sends the request it is holding. |
| 184 */ |
| 185 private int handlePostRequest() { |
| 186 if (!hasRequest()) { |
| 187 mDelegate.onHandlePostRequestDone(POST_RESULT_NO_REQUEST, false); |
| 188 return POST_RESULT_NO_REQUEST; |
| 189 } |
| 190 |
| 191 // If enough time has passed since the last attempt, try sending a reque
st. |
| 192 int result; |
| 193 long currentTimestamp = getBackoffScheduler().getCurrentTime(); |
| 194 boolean installEventWasSent = false; |
| 195 if (currentTimestamp >= mTimestampForNextPostAttempt) { |
| 196 // All requests made during the same session should have the same ID
. |
| 197 String sessionID = mDelegate.generateUUID(); |
| 198 boolean sendingInstallRequest = mSendInstallEvent; |
| 199 boolean succeeded = generateAndPostRequest(currentTimestamp, session
ID); |
| 200 |
| 201 if (succeeded && sendingInstallRequest) { |
| 202 // Only the first request ever generated should contain an insta
ll event. |
| 203 mSendInstallEvent = false; |
| 204 installEventWasSent = true; |
| 205 |
| 206 // Create and immediately send another request for a ping and up
date check. |
| 207 registerNewRequest(currentTimestamp); |
| 208 succeeded &= generateAndPostRequest(currentTimestamp, sessionID)
; |
| 209 } |
| 210 |
| 211 result = succeeded ? POST_RESULT_SENT : POST_RESULT_FAILED; |
| 212 } else { |
| 213 result = POST_RESULT_SCHEDULED; |
| 214 } |
| 215 |
| 216 mDelegate.onHandlePostRequestDone(result, installEventWasSent); |
| 217 return result; |
| 218 } |
| 219 |
| 220 private boolean generateAndPostRequest(long currentTimestamp, String session
ID) { |
| 221 ExponentialBackoffScheduler scheduler = getBackoffScheduler(); |
| 222 boolean succeeded = false; |
| 223 try { |
| 224 // Generate the XML for the current request. |
| 225 long installAgeInDays = RequestGenerator.installAge( |
| 226 currentTimestamp, mTimestampOfInstall, mCurrentRequest.isSen
dInstallEvent()); |
| 227 String version = |
| 228 VersionNumberGetter.getInstance().getCurrentlyUsedVersion(ge
tContext()); |
| 229 String xml = getRequestGenerator().generateXML( |
| 230 sessionID, version, installAgeInDays, mCurrentRequest); |
| 231 |
| 232 // Send the request to the server & wait for a response. |
| 233 String response = postRequest(currentTimestamp, xml); |
| 234 |
| 235 // Parse out the response. |
| 236 String appId = getRequestGenerator().getAppId(); |
| 237 boolean sentPingAndUpdate = !mSendInstallEvent; |
| 238 ResponseParser parser = new ResponseParser( |
| 239 appId, mSendInstallEvent, sentPingAndUpdate, sentPingAndUpda
te); |
| 240 parser.parseResponse(response); |
| 241 mLatestVersion = parser.getNewVersion(); |
| 242 mMarketURL = parser.getURL(); |
| 243 |
| 244 succeeded = true; |
| 245 } catch (RequestFailureException e) { |
| 246 Log.e(TAG, "Failed to contact server: ", e); |
| 247 } |
| 248 |
| 249 if (succeeded) { |
| 250 // If we've gotten this far, we've successfully sent a request. |
| 251 mCurrentRequest = null; |
| 252 |
| 253 scheduler.resetFailedAttempts(); |
| 254 mTimestampForNewRequest = scheduler.getCurrentTime() + MS_BETWEEN_RE
QUESTS; |
| 255 mTimestampForNextPostAttempt = scheduler.calculateNextTimestamp(); |
| 256 Log.i(TAG, |
| 257 "Request to Server Successful. Timestamp for next request:" |
| 258 + mTimestampForNextPostAttempt); |
| 259 } else { |
| 260 // Set the alarm to try again later. Failures are incremented after
setting the timer |
| 261 // to allow the first failure to incur the minimum base delay betwee
n POSTs. |
| 262 mTimestampForNextPostAttempt = scheduler.calculateNextTimestamp(); |
| 263 scheduler.increaseFailedAttempts(); |
| 264 } |
| 265 |
| 266 mDelegate.onGenerateAndPostRequestDone(succeeded); |
| 267 return succeeded; |
| 268 } |
| 269 |
| 270 /** |
| 271 * Registers a new request with the current timestamp. Internal timestamps
are reset to start |
| 272 * fresh. |
| 273 * @param currentTimestamp Current time. |
| 274 */ |
| 275 private void registerNewRequest(long currentTimestamp) { |
| 276 mCurrentRequest = createRequestData(currentTimestamp, null); |
| 277 getBackoffScheduler().resetFailedAttempts(); |
| 278 mTimestampForNextPostAttempt = currentTimestamp; |
| 279 |
| 280 // Tentatively set the timestamp for a new request. This will be update
d when the server |
| 281 // is successfully contacted. |
| 282 mTimestampForNewRequest = currentTimestamp + MS_BETWEEN_REQUESTS; |
| 283 |
| 284 mDelegate.onRegisterNewRequestDone(mTimestampForNewRequest, mTimestampFo
rNextPostAttempt); |
| 285 } |
| 286 |
| 287 private RequestData createRequestData(long currentTimestamp, String persiste
dID) { |
| 288 // If we're sending a persisted event, keep trying to send the same requ
est ID. |
| 289 String requestID; |
| 290 if (persistedID == null || INVALID_REQUEST_ID.equals(persistedID)) { |
| 291 requestID = mDelegate.generateUUID(); |
| 292 } else { |
| 293 requestID = persistedID; |
| 294 } |
| 295 return new RequestData(mSendInstallEvent, currentTimestamp, requestID, m
InstallSource); |
| 296 } |
| 297 |
| 298 private boolean hasRequest() { |
| 299 return mCurrentRequest != null; |
| 300 } |
| 301 |
| 302 /** |
| 303 * Posts the request to the Omaha server. |
| 304 * @return the XML response as a String. |
| 305 * @throws RequestFailureException if the request fails. |
| 306 */ |
| 307 private String postRequest(long timestamp, String xml) throws RequestFailure
Exception { |
| 308 String response = null; |
| 309 |
| 310 HttpURLConnection urlConnection = null; |
| 311 try { |
| 312 urlConnection = createConnection(); |
| 313 |
| 314 // Prepare the HTTP header. |
| 315 urlConnection.setDoOutput(true); |
| 316 urlConnection.setFixedLengthStreamingMode(xml.getBytes().length); |
| 317 if (mSendInstallEvent && getBackoffScheduler().getNumFailedAttempts(
) > 0) { |
| 318 String age = Long.toString(mCurrentRequest.getAgeInSeconds(times
tamp)); |
| 319 urlConnection.addRequestProperty("X-RequestAge", age); |
| 320 } |
| 321 |
| 322 response = OmahaBase.sendRequestToServer(urlConnection, xml); |
| 323 } catch (IllegalAccessError e) { |
| 324 throw new RequestFailureException("Caught an IllegalAccessError:", e
); |
| 325 } catch (IllegalArgumentException e) { |
| 326 throw new RequestFailureException("Caught an IllegalArgumentExceptio
n:", e); |
| 327 } catch (IllegalStateException e) { |
| 328 throw new RequestFailureException("Caught an IllegalStateException:"
, e); |
| 329 } finally { |
| 330 if (urlConnection != null) { |
| 331 urlConnection.disconnect(); |
| 332 } |
| 333 } |
| 334 |
| 335 return response; |
| 336 } |
| 337 |
| 338 /** |
| 339 * Returns a HttpURLConnection to the server. |
| 340 */ |
| 341 @VisibleForTesting |
| 342 protected HttpURLConnection createConnection() throws RequestFailureExceptio
n { |
| 343 try { |
| 344 URL url = new URL(getRequestGenerator().getServerUrl()); |
| 345 HttpURLConnection connection = (HttpURLConnection) url.openConnectio
n(); |
| 346 connection.setConnectTimeout(MS_CONNECTION_TIMEOUT); |
| 347 connection.setReadTimeout(MS_CONNECTION_TIMEOUT); |
| 348 return connection; |
| 349 } catch (MalformedURLException e) { |
| 350 throw new RequestFailureException("Caught a malformed URL exception.
", e); |
| 351 } catch (IOException e) { |
| 352 throw new RequestFailureException("Failed to open connection to URL"
, e); |
| 353 } |
| 354 } |
| 355 |
| 356 /** |
| 357 * Reads the data back from the file it was saved to. Uses SharedPreference
s to handle I/O. |
| 358 * Sanity checks are performed on the timestamps to guard against clock chan
ging. |
| 359 */ |
| 360 private void restoreState(Context context) { |
| 361 if (mStateHasBeenRestored) return; |
| 362 |
| 363 String installSource = |
| 364 mDelegate.isInSystemImage() ? INSTALL_SOURCE_SYSTEM : INSTALL_SO
URCE_ORGANIC; |
| 365 ExponentialBackoffScheduler scheduler = getBackoffScheduler(); |
| 366 long currentTime = scheduler.getCurrentTime(); |
| 367 |
| 368 SharedPreferences preferences = OmahaBase.getSharedPreferences(context); |
| 369 mTimestampForNewRequest = |
| 370 preferences.getLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, cu
rrentTime); |
| 371 mTimestampForNextPostAttempt = |
| 372 preferences.getLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEM
PT, currentTime); |
| 373 mTimestampOfInstall = preferences.getLong(OmahaBase.PREF_TIMESTAMP_OF_IN
STALL, currentTime); |
| 374 mSendInstallEvent = preferences.getBoolean(OmahaBase.PREF_SEND_INSTALL_E
VENT, true); |
| 375 mInstallSource = preferences.getString(OmahaBase.PREF_INSTALL_SOURCE, in
stallSource); |
| 376 mLatestVersion = preferences.getString(OmahaBase.PREF_LATEST_VERSION, ""
); |
| 377 mMarketURL = preferences.getString(OmahaBase.PREF_MARKET_URL, ""); |
| 378 |
| 379 // If we're not sending an install event, don't bother restoring the req
uest ID: |
| 380 // the server does not expect to have persisted request IDs for pings or
update checks. |
| 381 String persistedRequestId = mSendInstallEvent |
| 382 ? preferences.getString(OmahaBase.PREF_PERSISTED_REQUEST_ID, INV
ALID_REQUEST_ID) |
| 383 : INVALID_REQUEST_ID; |
| 384 long requestTimestamp = |
| 385 preferences.getLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, INVALID
_TIMESTAMP); |
| 386 mCurrentRequest = requestTimestamp == INVALID_TIMESTAMP |
| 387 ? null |
| 388 : createRequestData(requestTimestamp, persistedRequestId); |
| 389 |
| 390 // Confirm that the timestamp for the next request is less than the base
delay. |
| 391 long delayToNewRequest = mTimestampForNewRequest - currentTime; |
| 392 if (delayToNewRequest > MS_BETWEEN_REQUESTS) { |
| 393 Log.w(TAG, |
| 394 "Delay to next request (" + delayToNewRequest |
| 395 + ") is longer than expected. Resetting to now."); |
| 396 mTimestampForNewRequest = currentTime; |
| 397 } |
| 398 |
| 399 // Confirm that the timestamp for the next POST is less than the current
delay. |
| 400 long delayToNextPost = mTimestampForNextPostAttempt - currentTime; |
| 401 long lastGeneratedDelay = scheduler.getGeneratedDelay(); |
| 402 if (delayToNextPost > lastGeneratedDelay) { |
| 403 Log.w(TAG, |
| 404 "Delay to next post attempt (" + delayToNextPost |
| 405 + ") is greater than expected (" + lastGeneratedDela
y |
| 406 + "). Resetting to now."); |
| 407 mTimestampForNextPostAttempt = currentTime; |
| 408 } |
| 409 |
| 410 migrateToNewerChromeVersions(); |
| 411 mStateHasBeenRestored = true; |
| 412 } |
| 413 |
| 414 /** |
| 415 * Writes out the current state to a file. |
| 416 */ |
| 417 private void saveState(Context context) { |
| 418 SharedPreferences prefs = OmahaBase.getSharedPreferences(context); |
| 419 SharedPreferences.Editor editor = prefs.edit(); |
| 420 editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, mSendInstallEvent); |
| 421 editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_INSTALL, mTimestampOfInstall)
; |
| 422 editor.putLong( |
| 423 OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, mTimestampForNex
tPostAttempt); |
| 424 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, mTimestampForNe
wRequest); |
| 425 editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, |
| 426 hasRequest() ? mCurrentRequest.getCreationTimestamp() : INVALID_
TIMESTAMP); |
| 427 editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, |
| 428 hasRequest() ? mCurrentRequest.getRequestID() : INVALID_REQUEST_
ID); |
| 429 editor.putString( |
| 430 OmahaBase.PREF_LATEST_VERSION, mLatestVersion == null ? "" : mLa
testVersion); |
| 431 editor.putString(OmahaBase.PREF_MARKET_URL, mMarketURL == null ? "" : mM
arketURL); |
| 432 editor.putString(OmahaBase.PREF_INSTALL_SOURCE, mInstallSource); |
| 433 editor.apply(); |
| 434 |
| 435 mDelegate.onSaveStateDone(mTimestampForNewRequest, mTimestampForNextPost
Attempt); |
| 436 } |
| 437 |
| 438 private void migrateToNewerChromeVersions() { |
| 439 // Remove any repeating alarms in favor of the new scheduling setup on M
58 and up. |
| 440 // Seems cheaper to cancel the alarm repeatedly than to store a SharedPr
eference and never |
| 441 // do it again. |
| 442 Intent intent = new Intent(getContext(), OmahaClient.class); |
| 443 intent.setAction(ACTION_REGISTER_REQUEST); |
| 444 getBackoffScheduler().cancelAlarm(intent); |
| 445 } |
| 446 |
| 447 private Context getContext() { |
| 448 return mDelegate.getContext(); |
| 449 } |
| 450 |
| 451 private RequestGenerator getRequestGenerator() { |
| 452 return mDelegate.getRequestGenerator(); |
| 453 } |
| 454 |
| 455 private ExponentialBackoffScheduler getBackoffScheduler() { |
| 456 return mDelegate.getScheduler(); |
| 457 } |
| 458 |
54 /** Begin communicating with the Omaha Update Server. */ | 459 /** Begin communicating with the Omaha Update Server. */ |
55 public static void onForegroundSessionStart(Context context) { | 460 public static void onForegroundSessionStart(Context context) { |
56 if (!ChromeVersionInfo.isOfficialBuild() || isDisabled()) return; | 461 if (!ChromeVersionInfo.isOfficialBuild() || isDisabled()) return; |
57 | 462 OmahaService.startServiceImmediately(context); |
58 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) { | |
59 OmahaClient.startService(context); | |
60 } | |
61 } | 463 } |
62 | 464 |
63 /** Checks whether Chrome has ever tried contacting Omaha before. */ | 465 /** Checks whether Chrome has ever tried contacting Omaha before. */ |
64 public static boolean isProbablyFreshInstall(Context context) { | 466 public static boolean isProbablyFreshInstall(Context context) { |
65 SharedPreferences prefs = getSharedPreferences(context); | 467 SharedPreferences prefs = getSharedPreferences(context); |
66 return prefs.getLong(PREF_TIMESTAMP_OF_INSTALL, -1) == -1; | 468 return prefs.getLong(PREF_TIMESTAMP_OF_INSTALL, -1) == -1; |
67 } | 469 } |
68 | 470 |
69 /** Sends the request to the server and returns the response. */ | 471 /** Sends the request to the server and returns the response. */ |
70 static String sendRequestToServer(HttpURLConnection urlConnection, String re
quest) | 472 static String sendRequestToServer(HttpURLConnection urlConnection, String re
quest) |
(...skipping 24 matching lines...) Expand all Loading... |
95 } catch (IOException e) { | 497 } catch (IOException e) { |
96 throw new RequestFailureException("Failed when reading response from
server: ", e); | 498 throw new RequestFailureException("Failed when reading response from
server: ", e); |
97 } | 499 } |
98 } | 500 } |
99 | 501 |
100 /** Confirms that the Omaha server sent back an "OK" code. */ | 502 /** Confirms that the Omaha server sent back an "OK" code. */ |
101 private static void checkServerResponseCode(HttpURLConnection urlConnection) | 503 private static void checkServerResponseCode(HttpURLConnection urlConnection) |
102 throws RequestFailureException { | 504 throws RequestFailureException { |
103 try { | 505 try { |
104 if (urlConnection.getResponseCode() != 200) { | 506 if (urlConnection.getResponseCode() != 200) { |
105 throw new RequestFailureException( | 507 throw new RequestFailureException("Received " + urlConnection.ge
tResponseCode() |
106 "Received " + urlConnection.getResponseCode() | |
107 + " code instead of 200 (OK) from the server. Aborting.
"); | 508 + " code instead of 200 (OK) from the server. Aborting.
"); |
108 } | 509 } |
109 } catch (IOException e) { | 510 } catch (IOException e) { |
110 throw new RequestFailureException("Failed to read response code from
server: ", e); | 511 throw new RequestFailureException("Failed to read response code from
server: ", e); |
111 } | 512 } |
112 } | 513 } |
113 | 514 |
114 /** Returns the Omaha SharedPreferences. */ | 515 /** Returns the Omaha SharedPreferences. */ |
115 static SharedPreferences getSharedPreferences(Context context) { | 516 static SharedPreferences getSharedPreferences(Context context) { |
116 return context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE); | 517 return context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE); |
117 } | 518 } |
118 } | 519 } |
OLD | NEW |