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

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

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 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
(Empty)
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
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.omaha;
6
7 import android.app.AlarmManager;
8 import android.app.PendingIntent;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.content.SharedPreferences;
12 import android.util.Log;
13
14 import org.chromium.base.VisibleForTesting;
15
16 import java.util.Date;
17 import java.util.Random;
18
19 import javax.annotation.concurrent.NotThreadSafe;
20
21 /**
22 * Manages a timer that implements exponential backoff for failed attempts.
23 *
24 * The first timer will fire after BASE_MILLISECONDS. On a failure, the timer i s changed to
25 * (randomInteger[0, 2^failures) + 1) * BASE_MILLISECONDS. MAX_MILLISECONDS is used to ensure that
26 * you aren't waiting years for a timer to fire.
27 *
28 * The state is stored in shared preferences to ensure that they are kept after the device sleeps.
29 * Because multiple ExponentialBackoffSchedulers can be used by different compon ents,
30 * the owning class must set the preference name.
31 *
32 * Timestamps are recorded in RTC to avoid situations where the phone is reboote d, messing up
33 * any timestamps generated using elapsedRealtime().
34 *
35 * This class is not thread-safe because any two different classes could be acce ssing the same
36 * SharedPreferences.
37 *
38 * TODO(dfalcantara): Consider making this an AlarmManagerHelper class to manage general alarms.
39 */
40 @NotThreadSafe
41 public class ExponentialBackoffScheduler {
42 private static final String TAG = "ExponentialBackoffScheduler";
43
44 private static final String PREFERENCE_DELAY = "delay";
45 private static final String PREFERENCE_FAILED_ATTEMPTS = "backoffFailedAttem pts";
46
47 private static Random sRandom = new Random();
48
49 private static final int MAX_EXPONENT = 10;
50
51 private final long mBaseMilliseconds;
52 private final long mMaxMilliseconds;
53 private final Context mContext;
54 private final String mPreferencePackage;
55
56 /**
57 * Creates a new scheduler.
58 * @param packageName The name under which to store its state in SharedPrefe rences.
59 * @param context The application's context.
60 * @param baseMilliseconds Used to calculate random backoff times.
61 * @param maxMilliseconds The absolute maximum delay allowed.
62 */
63 public ExponentialBackoffScheduler(String packageName, Context context, long baseMilliseconds,
64 long maxMilliseconds) {
65 mPreferencePackage = packageName;
66 mContext = context;
67 mBaseMilliseconds = baseMilliseconds;
68 mMaxMilliseconds = maxMilliseconds;
69 }
70
71 /**
72 * Creates an alarm to fire the specified intent after a random delay.
73 * @param intent The intent to fire.
74 * @return the timestamp of the scheduled intent
75 */
76 public long createAlarm(Intent intent) {
77 long delay = generateRandomDelay();
78 long timestamp = delay + getCurrentTime();
79 return createAlarm(intent, timestamp);
80 }
81
82 /**
83 * Creates an alarm to fire the specified intent at the specified time.
84 * @param intent The intent to fire.
85 * @return the timestamp of the scheduled intent
86 */
87 public long createAlarm(Intent intent, long timestamp) {
88 PendingIntent retryPIntent = PendingIntent.getService(mContext, 0, inten t, 0);
89 AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM _SERVICE);
90 setAlarm(am, timestamp, retryPIntent);
91 return timestamp;
92 }
93
94 /**
95 * Attempts to cancel any alarms set using the given Intent.
96 * @param scheduledIntent Intent that may have been previously scheduled.
97 * @return whether or not an alarm was canceled.
98 */
99 public boolean cancelAlarm(Intent scheduledIntent) {
100 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0, sche duledIntent,
101 PendingIntent.FLAG_NO_CREATE);
102 if (pendingIntent != null) {
103 AlarmManager am = (AlarmManager) mContext.getSystemService(Context.A LARM_SERVICE);
104 am.cancel(pendingIntent);
105 pendingIntent.cancel();
106 return true;
107 } else {
108 return false;
109 }
110 }
111
112 public int getNumFailedAttempts() {
113 SharedPreferences preferences = getSharedPreferences();
114 return preferences.getInt(PREFERENCE_FAILED_ATTEMPTS, 0);
115 }
116
117 public void increaseFailedAttempts() {
118 SharedPreferences preferences = getSharedPreferences();
119 int numFailedAttempts = getNumFailedAttempts() + 1;
120 preferences.edit()
121 .putInt(PREFERENCE_FAILED_ATTEMPTS, numFailedAttempts)
122 .apply();
123 }
124
125 public void resetFailedAttempts() {
126 SharedPreferences preferences = getSharedPreferences();
127 preferences.edit()
128 .putInt(PREFERENCE_FAILED_ATTEMPTS, 0)
129 .apply();
130 }
131
132 /**
133 * Returns a timestamp representing now, according to the backoff scheduler.
134 */
135 public long getCurrentTime() {
136 return System.currentTimeMillis();
137 }
138
139 /**
140 * Returns the delay used to generate the last alarm. If no previous alarm was generated,
141 * return the base delay.
142 */
143 public long getGeneratedDelay() {
144 SharedPreferences preferences = getSharedPreferences();
145 return preferences.getLong(PREFERENCE_DELAY, mBaseMilliseconds);
146 }
147
148 /**
149 * Sets an alarm in the alarm manager.
150 */
151 @VisibleForTesting
152 protected void setAlarm(AlarmManager am, long timestamp, PendingIntent retry PIntent) {
153 Log.v(TAG, "now(" + new Date(getCurrentTime()) + ") refiringAt("
154 + new Date(timestamp) + ")");
155 am.set(AlarmManager.RTC, timestamp, retryPIntent);
156 }
157
158 /**
159 * Determines the amount of time to wait for the current delay, then saves i t.
160 * @return the number of milliseconds to wait.
161 */
162 private long generateRandomDelay() {
163 long delay;
164 int numFailedAttempts = getNumFailedAttempts();
165 if (numFailedAttempts == 0) {
166 delay = Math.min(mBaseMilliseconds, mMaxMilliseconds);
167 } else {
168 int backoffCoefficient = computeConstrainedBackoffCoefficient(numFai ledAttempts);
169 delay = Math.min(backoffCoefficient * mBaseMilliseconds, mMaxMillise conds);
170 }
171
172 // Save the delay for sanity checks.
173 SharedPreferences preferences = getSharedPreferences();
174 preferences.edit()
175 .putLong(PREFERENCE_DELAY, delay)
176 .apply();
177 return delay;
178 }
179
180 /**
181 * Calculates a random coefficient based on the number of cumulative failed attempts.
182 * @param numFailedAttempts Number of cumulative failed attempts
183 * @return A random number between 1 and 2^N, where N is the smallest value of MAX_EXPONENT and
184 * numFailedAttempts
185 */
186 private int computeConstrainedBackoffCoefficient(int numFailedAttempts) {
187 int n = Math.min(MAX_EXPONENT, numFailedAttempts);
188 int twoToThePowerOfN = 1 << n;
189 return sRandom.nextInt(twoToThePowerOfN) + 1;
190 }
191
192 private SharedPreferences getSharedPreferences() {
193 SharedPreferences preferences =
194 mContext.getSharedPreferences(mPreferencePackage, Context.MODE_P RIVATE);
195 return preferences;
196 }
197 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698