Loading Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,7 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/ISensorService.aidl \ core/java/android/net/IConnectivityManager.aidl \ core/java/android/net/INetworkManagementEventObserver.aidl \ core/java/android/net/IThrottleManager.aidl \ core/java/android/os/IMessenger.aidl \ core/java/android/os/storage/IMountService.aidl \ core/java/android/os/storage/IMountServiceListener.aidl \ Loading api/current.xml +56 −64 Original line number Diff line number Diff line Loading @@ -34,17 +34,6 @@ visibility="public" > </constructor> <field name="ACCESS_CACHE_FILESYSTEM" type="java.lang.String" transient="false" volatile="false" value=""android.permission.ACCESS_CACHE_FILESYSTEM"" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="ACCESS_CHECKIN_PROPERTIES" type="java.lang.String" transient="false" Loading Loading @@ -716,17 +705,6 @@ visibility="public" > </field> <field name="MOVE_PACKAGE" type="java.lang.String" transient="false" volatile="false" value=""android.permission.MOVE_PACKAGE"" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="PERSISTENT_ACTIVITY" type="java.lang.String" transient="false" Loading Loading @@ -25450,6 +25428,17 @@ visibility="public" > </field> <field name="ENABLE_CAR_MODE_GO_CAR_HOME" type="int" transient="false" volatile="false" value="1" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="MODE_NIGHT_AUTO" type="int" transient="false" Loading Loading @@ -72887,6 +72876,17 @@ visibility="public" > </field> <field name="FOCUS_MODE_EDOF" type="java.lang.String" transient="false" volatile="false" value=""edof"" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="FOCUS_MODE_FIXED" type="java.lang.String" transient="false" Loading Loading @@ -72942,6 +72942,17 @@ visibility="public" > </field> <field name="SCENE_MODE_BARCODE" type="java.lang.String" transient="false" volatile="false" value=""barcode"" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="SCENE_MODE_BEACH" type="java.lang.String" transient="false" Loading Loading @@ -89051,7 +89062,7 @@ <method name="getMobileRxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89062,7 +89073,7 @@ <method name="getMobileRxPackets" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89073,7 +89084,7 @@ <method name="getMobileTxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89084,7 +89095,7 @@ <method name="getMobileTxPackets" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89095,7 +89106,7 @@ <method name="getTotalRxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89106,7 +89117,7 @@ <method name="getTotalRxPackets" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89117,7 +89128,7 @@ <method name="getTotalTxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89128,7 +89139,7 @@ <method name="getTotalTxPackets" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89139,7 +89150,7 @@ <method name="getUidRxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89152,7 +89163,7 @@ <method name="getUidTxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading Loading @@ -90881,35 +90892,8 @@ <parameter name="userAgent" type="java.lang.String"> </parameter> </method> <field name="DEFAULT_SYNC_MIN_GZIP_BYTES" type="long" transient="false" volatile="false" static="true" final="false" deprecated="not deprecated" visibility="public" > </field> </class> <class name="HttpDateTime" extends="java.lang.Object" abstract="false" static="false" final="true" deprecated="not deprecated" visibility="public" > <constructor name="HttpDateTime" type="android.net.http.HttpDateTime" static="false" final="false" deprecated="not deprecated" visibility="public" > </constructor> <method name="parse" return="java.lang.Long" <method name="parseDate" return="long" abstract="false" native="false" synchronized="false" Loading @@ -90918,11 +90902,19 @@ deprecated="not deprecated" visibility="public" > <parameter name="timeString" type="java.lang.String"> <parameter name="dateString" type="java.lang.String"> </parameter> <exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> </exception> </method> <field name="DEFAULT_SYNC_MIN_GZIP_BYTES" type="long" transient="false" volatile="false" static="true" final="false" deprecated="not deprecated" visibility="public" > </field> </class> <class name="SslCertificate" extends="java.lang.Object" common/java/com/android/common/OperationScheduler.java +24 −17 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ package com.android.common; import android.content.SharedPreferences; import android.net.http.HttpDateTime; import android.net.http.AndroidHttpClient; import android.text.format.Time; import java.util.Map; Loading Loading @@ -124,7 +124,8 @@ public class OperationScheduler { } /** * Compute the time of the next operation. Does not modify any state. * Compute the time of the next operation. Does not modify any state * (unless the clock rolls backwards, in which case timers are reset). * * @param options to use for this computation. * @return the wall clock time ({@link System#currentTimeMillis()}) when the Loading @@ -143,11 +144,11 @@ public class OperationScheduler { // clipped to the current time so we don't languish forever. int errorCount = mStorage.getInt(PREFIX + "errorCount", 0); long now = System.currentTimeMillis(); long now = currentTimeMillis(); long lastSuccessTimeMillis = getTimeBefore(PREFIX + "lastSuccessTimeMillis", now); long lastErrorTimeMillis = getTimeBefore(PREFIX + "lastErrorTimeMillis", now); long triggerTimeMillis = mStorage.getLong(PREFIX + "triggerTimeMillis", Long.MAX_VALUE); long moratoriumSetMillis = mStorage.getLong(PREFIX + "moratoriumSetTimeMillis", 0); long moratoriumSetMillis = getTimeBefore(PREFIX + "moratoriumSetTimeMillis", now); long moratoriumTimeMillis = getTimeBefore(PREFIX + "moratoriumTimeMillis", moratoriumSetMillis + options.maxMoratoriumMillis); Loading @@ -155,9 +156,8 @@ public class OperationScheduler { if (options.periodicIntervalMillis > 0) { time = Math.min(time, lastSuccessTimeMillis + options.periodicIntervalMillis); } if (time >= moratoriumTimeMillis - options.maxMoratoriumMillis) { time = Math.max(time, moratoriumTimeMillis); } time = Math.max(time, lastSuccessTimeMillis + options.minTriggerMillis); if (errorCount > 0) { time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis + Loading Loading @@ -205,7 +205,7 @@ public class OperationScheduler { /** * Request an operation to be performed at a certain time. The actual * scheduled time may be affected by error backoff logic and defined * minimum intervals. * minimum intervals. Use {@link Long#MAX_VALUE} to disable triggering. * * @param millis wall clock time ({@link System#currentTimeMillis()}) to * trigger another operation; 0 to trigger immediately Loading @@ -218,13 +218,13 @@ public class OperationScheduler { * Forbid any operations until after a certain (absolute) time. * Limited by {@link #Options.maxMoratoriumMillis}. * * @param millis wall clock time ({@link System#currentTimeMillis()}) to * wait before attempting any more operations; 0 to remove moratorium * @param millis wall clock time ({@link System#currentTimeMillis()}) * when operations should be allowed again; 0 to remove moratorium */ public void setMoratoriumTimeMillis(long millis) { mStorage.edit() .putLong(PREFIX + "moratoriumTimeMillis", millis) .putLong(PREFIX + "moratoriumSetTimeMillis", System.currentTimeMillis()) .putLong(PREFIX + "moratoriumSetTimeMillis", currentTimeMillis()) .commit(); } Loading @@ -239,11 +239,11 @@ public class OperationScheduler { public boolean setMoratoriumTimeHttp(String retryAfter) { try { long ms = Long.valueOf(retryAfter) * 1000; setMoratoriumTimeMillis(ms + System.currentTimeMillis()); setMoratoriumTimeMillis(ms + currentTimeMillis()); return true; } catch (NumberFormatException nfe) { try { setMoratoriumTimeMillis(HttpDateTime.parse(retryAfter)); setMoratoriumTimeMillis(AndroidHttpClient.parseDate(retryAfter)); return true; } catch (IllegalArgumentException iae) { return false; Loading @@ -269,13 +269,12 @@ public class OperationScheduler { public void onSuccess() { resetTransientError(); resetPermanentError(); long now = System.currentTimeMillis(); mStorage.edit() .remove(PREFIX + "errorCount") .remove(PREFIX + "lastErrorTimeMillis") .remove(PREFIX + "permanentError") .remove(PREFIX + "triggerTimeMillis") .putLong(PREFIX + "lastSuccessTimeMillis", now).commit(); .putLong(PREFIX + "lastSuccessTimeMillis", currentTimeMillis()).commit(); } /** Loading @@ -284,8 +283,7 @@ public class OperationScheduler { * purposes. */ public void onTransientError() { long now = System.currentTimeMillis(); mStorage.edit().putLong(PREFIX + "lastErrorTimeMillis", now).commit(); mStorage.edit().putLong(PREFIX + "lastErrorTimeMillis", currentTimeMillis()).commit(); mStorage.edit().putInt(PREFIX + "errorCount", mStorage.getInt(PREFIX + "errorCount", 0) + 1).commit(); } Loading Loading @@ -338,4 +336,13 @@ public class OperationScheduler { } return out.append("]").toString(); } /** * Gets the current time. Can be overridden for unit testing. * * @return {@link System#currentTimeMillis()} */ protected long currentTimeMillis() { return System.currentTimeMillis(); } } common/tests/src/com/android/common/OperationSchedulerTest.java +92 −40 Original line number Diff line number Diff line Loading @@ -22,19 +22,34 @@ import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; public class OperationSchedulerTest extends AndroidTestCase { /** * OperationScheduler subclass which uses an artificial time. * Set {@link #timeMillis} to whatever value you like. */ private class TimeTravelScheduler extends OperationScheduler { static final long DEFAULT_TIME = 1250146800000L; // 13-Aug-2009, 12:00:00 am public long timeMillis = DEFAULT_TIME; @Override protected long currentTimeMillis() { return timeMillis; } public TimeTravelScheduler() { super(getFreshStorage()); } } private SharedPreferences getFreshStorage() { SharedPreferences sp = getContext().getSharedPreferences("OperationSchedulerTest", 0); sp.edit().clear().commit(); return sp; } @MediumTest public void testScheduler() throws Exception { String name = "OperationSchedulerTest.testScheduler"; SharedPreferences storage = getContext().getSharedPreferences(name, 0); storage.edit().clear().commit(); OperationScheduler scheduler = new OperationScheduler(storage); TimeTravelScheduler scheduler = new TimeTravelScheduler(); OperationScheduler.Options options = new OperationScheduler.Options(); assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options)); assertEquals(0, scheduler.getLastSuccessTimeMillis()); assertEquals(0, scheduler.getLastAttemptTimeMillis()); long beforeTrigger = System.currentTimeMillis(); long beforeTrigger = scheduler.timeMillis; scheduler.setTriggerTimeMillis(beforeTrigger + 1000000); assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); Loading @@ -51,33 +66,26 @@ public class OperationSchedulerTest extends AndroidTestCase { assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); // Backoff interval after an error long beforeError = System.currentTimeMillis(); long beforeError = (scheduler.timeMillis += 100); scheduler.onTransientError(); long afterError = System.currentTimeMillis(); assertEquals(0, scheduler.getLastSuccessTimeMillis()); assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis()); assertTrue(afterError >= scheduler.getLastAttemptTimeMillis()); assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); options.backoffFixedMillis = 1000000; options.backoffIncrementalMillis = 500000; assertTrue(beforeError + 1500000 <= scheduler.getNextTimeMillis(options)); assertTrue(afterError + 1500000 >= scheduler.getNextTimeMillis(options)); assertEquals(beforeError + 1500000, scheduler.getNextTimeMillis(options)); // Two errors: backoff interval increases beforeError = System.currentTimeMillis(); beforeError = (scheduler.timeMillis += 100); scheduler.onTransientError(); afterError = System.currentTimeMillis(); assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis()); assertTrue(afterError >= scheduler.getLastAttemptTimeMillis()); assertTrue(beforeError + 2000000 <= scheduler.getNextTimeMillis(options)); assertTrue(afterError + 2000000 >= scheduler.getNextTimeMillis(options)); assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeError + 2000000, scheduler.getNextTimeMillis(options)); // Reset transient error: no backoff interval scheduler.resetTransientError(); assertEquals(0, scheduler.getLastSuccessTimeMillis()); assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis()); assertTrue(afterError >= scheduler.getLastAttemptTimeMillis()); assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); // Permanent error holds true even if transient errors are reset // However, we remember that the transient error was reset... Loading @@ -89,30 +97,26 @@ public class OperationSchedulerTest extends AndroidTestCase { assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); // Success resets the trigger long beforeSuccess = System.currentTimeMillis(); long beforeSuccess = (scheduler.timeMillis += 100); scheduler.onSuccess(); long afterSuccess = System.currentTimeMillis(); assertTrue(beforeSuccess <= scheduler.getLastAttemptTimeMillis()); assertTrue(afterSuccess >= scheduler.getLastAttemptTimeMillis()); assertTrue(beforeSuccess <= scheduler.getLastSuccessTimeMillis()); assertTrue(afterSuccess >= scheduler.getLastSuccessTimeMillis()); assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeSuccess, scheduler.getLastSuccessTimeMillis()); assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options)); // The moratorium is not reset by success! scheduler.setTriggerTimeMillis(beforeSuccess + 500000); scheduler.setTriggerTimeMillis(0); assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); scheduler.setMoratoriumTimeMillis(0); assertEquals(beforeSuccess + 500000, scheduler.getNextTimeMillis(options)); assertEquals(beforeSuccess, scheduler.getNextTimeMillis(options)); // Periodic interval after success options.periodicIntervalMillis = 250000; assertTrue(beforeSuccess + 250000 <= scheduler.getNextTimeMillis(options)); assertTrue(afterSuccess + 250000 >= scheduler.getNextTimeMillis(options)); scheduler.setTriggerTimeMillis(Long.MAX_VALUE); assertEquals(beforeSuccess + 250000, scheduler.getNextTimeMillis(options)); // Trigger minimum is also since the last success options.minTriggerMillis = 1000000; assertTrue(beforeSuccess + 1000000 <= scheduler.getNextTimeMillis(options)); assertTrue(afterSuccess + 1000000 >= scheduler.getNextTimeMillis(options)); assertEquals(beforeSuccess + 1000000, scheduler.getNextTimeMillis(options)); } @SmallTest Loading @@ -138,23 +142,19 @@ public class OperationSchedulerTest extends AndroidTestCase { @SmallTest public void testMoratoriumWithHttpDate() throws Exception { String name = "OperationSchedulerTest.testMoratoriumWithHttpDate"; SharedPreferences storage = getContext().getSharedPreferences(name, 0); storage.edit().clear().commit(); OperationScheduler scheduler = new OperationScheduler(storage); TimeTravelScheduler scheduler = new TimeTravelScheduler(); OperationScheduler.Options options = new OperationScheduler.Options(); long beforeTrigger = System.currentTimeMillis(); long beforeTrigger = scheduler.timeMillis; scheduler.setTriggerTimeMillis(beforeTrigger + 1000000); assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); scheduler.setMoratoriumTimeMillis(beforeTrigger + 2000000); assertEquals(beforeTrigger + 2000000, scheduler.getNextTimeMillis(options)); long beforeMoratorium = System.currentTimeMillis(); long beforeMoratorium = scheduler.timeMillis; assertTrue(scheduler.setMoratoriumTimeHttp("3000")); long afterMoratorium = System.currentTimeMillis(); long afterMoratorium = scheduler.timeMillis; assertTrue(beforeMoratorium + 3000000 <= scheduler.getNextTimeMillis(options)); assertTrue(afterMoratorium + 3000000 >= scheduler.getNextTimeMillis(options)); Loading @@ -164,4 +164,56 @@ public class OperationSchedulerTest extends AndroidTestCase { assertFalse(scheduler.setMoratoriumTimeHttp("not actually a date")); } @SmallTest public void testClockRollbackScenario() throws Exception { TimeTravelScheduler scheduler = new TimeTravelScheduler(); OperationScheduler.Options options = new OperationScheduler.Options(); options.minTriggerMillis = 2000; // First, set up a scheduler with reasons to wait: a transient // error with backoff and a moratorium for a few minutes. long beforeTrigger = scheduler.timeMillis; long triggerTime = beforeTrigger - 10000000; scheduler.setTriggerTimeMillis(triggerTime); assertEquals(triggerTime, scheduler.getNextTimeMillis(options)); assertEquals(0, scheduler.getLastAttemptTimeMillis()); long beforeSuccess = (scheduler.timeMillis += 100); scheduler.onSuccess(); scheduler.setTriggerTimeMillis(triggerTime); assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeSuccess + 2000, scheduler.getNextTimeMillis(options)); long beforeError = (scheduler.timeMillis += 100); scheduler.onTransientError(); assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeError + 5000, scheduler.getNextTimeMillis(options)); long beforeMoratorium = (scheduler.timeMillis += 100); scheduler.setMoratoriumTimeMillis(beforeTrigger + 1000000); assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); // Now set the time back a few seconds. // The moratorium time should still be honored. long beforeRollback = (scheduler.timeMillis = beforeTrigger - 10000); assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); // The rollback also moved the last-attempt clock back to the rollback time. assertEquals(scheduler.timeMillis, scheduler.getLastAttemptTimeMillis()); // But if we set the time back more than a day, the moratorium // resets to the maximum moratorium (a day, by default), exposing // the original trigger time. beforeRollback = (scheduler.timeMillis = beforeTrigger - 100000000); assertEquals(triggerTime, scheduler.getNextTimeMillis(options)); assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis()); // If we roll forward until after the re-set moratorium, then it expires. scheduler.timeMillis = triggerTime + 5000000; assertEquals(triggerTime, scheduler.getNextTimeMillis(options)); assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeRollback, scheduler.getLastSuccessTimeMillis()); } } core/java/android/app/ContextImpl.java +17 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,8 @@ import android.location.LocationManager; import android.media.AudioManager; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.ThrottleManager; import android.net.IThrottleManager; import android.net.Uri; import android.net.wifi.IWifiManager; import android.net.wifi.WifiManager; Loading Loading @@ -164,6 +166,7 @@ class ContextImpl extends Context { private static AlarmManager sAlarmManager; private static PowerManager sPowerManager; private static ConnectivityManager sConnectivityManager; private static ThrottleManager sThrottleManager; private static WifiManager sWifiManager; private static LocationManager sLocationManager; private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs = Loading Loading @@ -929,6 +932,8 @@ class ContextImpl extends Context { return getPowerManager(); } else if (CONNECTIVITY_SERVICE.equals(name)) { return getConnectivityManager(); } else if (THROTTLE_SERVICE.equals(name)) { return getThrottleManager(); } else if (WIFI_SERVICE.equals(name)) { return getWifiManager(); } else if (NOTIFICATION_SERVICE.equals(name)) { Loading Loading @@ -1028,6 +1033,18 @@ class ContextImpl extends Context { return sConnectivityManager; } private ThrottleManager getThrottleManager() { synchronized (sSync) { if (sThrottleManager == null) { IBinder b = ServiceManager.getService(THROTTLE_SERVICE); IThrottleManager service = IThrottleManager.Stub.asInterface(b); sThrottleManager = new ThrottleManager(service); } } return sThrottleManager; } private WifiManager getWifiManager() { synchronized (sSync) { Loading Loading
Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,7 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/ISensorService.aidl \ core/java/android/net/IConnectivityManager.aidl \ core/java/android/net/INetworkManagementEventObserver.aidl \ core/java/android/net/IThrottleManager.aidl \ core/java/android/os/IMessenger.aidl \ core/java/android/os/storage/IMountService.aidl \ core/java/android/os/storage/IMountServiceListener.aidl \ Loading
api/current.xml +56 −64 Original line number Diff line number Diff line Loading @@ -34,17 +34,6 @@ visibility="public" > </constructor> <field name="ACCESS_CACHE_FILESYSTEM" type="java.lang.String" transient="false" volatile="false" value=""android.permission.ACCESS_CACHE_FILESYSTEM"" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="ACCESS_CHECKIN_PROPERTIES" type="java.lang.String" transient="false" Loading Loading @@ -716,17 +705,6 @@ visibility="public" > </field> <field name="MOVE_PACKAGE" type="java.lang.String" transient="false" volatile="false" value=""android.permission.MOVE_PACKAGE"" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="PERSISTENT_ACTIVITY" type="java.lang.String" transient="false" Loading Loading @@ -25450,6 +25428,17 @@ visibility="public" > </field> <field name="ENABLE_CAR_MODE_GO_CAR_HOME" type="int" transient="false" volatile="false" value="1" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="MODE_NIGHT_AUTO" type="int" transient="false" Loading Loading @@ -72887,6 +72876,17 @@ visibility="public" > </field> <field name="FOCUS_MODE_EDOF" type="java.lang.String" transient="false" volatile="false" value=""edof"" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="FOCUS_MODE_FIXED" type="java.lang.String" transient="false" Loading Loading @@ -72942,6 +72942,17 @@ visibility="public" > </field> <field name="SCENE_MODE_BARCODE" type="java.lang.String" transient="false" volatile="false" value=""barcode"" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="SCENE_MODE_BEACH" type="java.lang.String" transient="false" Loading Loading @@ -89051,7 +89062,7 @@ <method name="getMobileRxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89062,7 +89073,7 @@ <method name="getMobileRxPackets" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89073,7 +89084,7 @@ <method name="getMobileTxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89084,7 +89095,7 @@ <method name="getMobileTxPackets" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89095,7 +89106,7 @@ <method name="getTotalRxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89106,7 +89117,7 @@ <method name="getTotalRxPackets" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89117,7 +89128,7 @@ <method name="getTotalTxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89128,7 +89139,7 @@ <method name="getTotalTxPackets" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89139,7 +89150,7 @@ <method name="getUidRxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading @@ -89152,7 +89163,7 @@ <method name="getUidTxBytes" return="long" abstract="false" native="false" native="true" synchronized="false" static="true" final="false" Loading Loading @@ -90881,35 +90892,8 @@ <parameter name="userAgent" type="java.lang.String"> </parameter> </method> <field name="DEFAULT_SYNC_MIN_GZIP_BYTES" type="long" transient="false" volatile="false" static="true" final="false" deprecated="not deprecated" visibility="public" > </field> </class> <class name="HttpDateTime" extends="java.lang.Object" abstract="false" static="false" final="true" deprecated="not deprecated" visibility="public" > <constructor name="HttpDateTime" type="android.net.http.HttpDateTime" static="false" final="false" deprecated="not deprecated" visibility="public" > </constructor> <method name="parse" return="java.lang.Long" <method name="parseDate" return="long" abstract="false" native="false" synchronized="false" Loading @@ -90918,11 +90902,19 @@ deprecated="not deprecated" visibility="public" > <parameter name="timeString" type="java.lang.String"> <parameter name="dateString" type="java.lang.String"> </parameter> <exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> </exception> </method> <field name="DEFAULT_SYNC_MIN_GZIP_BYTES" type="long" transient="false" volatile="false" static="true" final="false" deprecated="not deprecated" visibility="public" > </field> </class> <class name="SslCertificate" extends="java.lang.Object"
common/java/com/android/common/OperationScheduler.java +24 −17 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ package com.android.common; import android.content.SharedPreferences; import android.net.http.HttpDateTime; import android.net.http.AndroidHttpClient; import android.text.format.Time; import java.util.Map; Loading Loading @@ -124,7 +124,8 @@ public class OperationScheduler { } /** * Compute the time of the next operation. Does not modify any state. * Compute the time of the next operation. Does not modify any state * (unless the clock rolls backwards, in which case timers are reset). * * @param options to use for this computation. * @return the wall clock time ({@link System#currentTimeMillis()}) when the Loading @@ -143,11 +144,11 @@ public class OperationScheduler { // clipped to the current time so we don't languish forever. int errorCount = mStorage.getInt(PREFIX + "errorCount", 0); long now = System.currentTimeMillis(); long now = currentTimeMillis(); long lastSuccessTimeMillis = getTimeBefore(PREFIX + "lastSuccessTimeMillis", now); long lastErrorTimeMillis = getTimeBefore(PREFIX + "lastErrorTimeMillis", now); long triggerTimeMillis = mStorage.getLong(PREFIX + "triggerTimeMillis", Long.MAX_VALUE); long moratoriumSetMillis = mStorage.getLong(PREFIX + "moratoriumSetTimeMillis", 0); long moratoriumSetMillis = getTimeBefore(PREFIX + "moratoriumSetTimeMillis", now); long moratoriumTimeMillis = getTimeBefore(PREFIX + "moratoriumTimeMillis", moratoriumSetMillis + options.maxMoratoriumMillis); Loading @@ -155,9 +156,8 @@ public class OperationScheduler { if (options.periodicIntervalMillis > 0) { time = Math.min(time, lastSuccessTimeMillis + options.periodicIntervalMillis); } if (time >= moratoriumTimeMillis - options.maxMoratoriumMillis) { time = Math.max(time, moratoriumTimeMillis); } time = Math.max(time, lastSuccessTimeMillis + options.minTriggerMillis); if (errorCount > 0) { time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis + Loading Loading @@ -205,7 +205,7 @@ public class OperationScheduler { /** * Request an operation to be performed at a certain time. The actual * scheduled time may be affected by error backoff logic and defined * minimum intervals. * minimum intervals. Use {@link Long#MAX_VALUE} to disable triggering. * * @param millis wall clock time ({@link System#currentTimeMillis()}) to * trigger another operation; 0 to trigger immediately Loading @@ -218,13 +218,13 @@ public class OperationScheduler { * Forbid any operations until after a certain (absolute) time. * Limited by {@link #Options.maxMoratoriumMillis}. * * @param millis wall clock time ({@link System#currentTimeMillis()}) to * wait before attempting any more operations; 0 to remove moratorium * @param millis wall clock time ({@link System#currentTimeMillis()}) * when operations should be allowed again; 0 to remove moratorium */ public void setMoratoriumTimeMillis(long millis) { mStorage.edit() .putLong(PREFIX + "moratoriumTimeMillis", millis) .putLong(PREFIX + "moratoriumSetTimeMillis", System.currentTimeMillis()) .putLong(PREFIX + "moratoriumSetTimeMillis", currentTimeMillis()) .commit(); } Loading @@ -239,11 +239,11 @@ public class OperationScheduler { public boolean setMoratoriumTimeHttp(String retryAfter) { try { long ms = Long.valueOf(retryAfter) * 1000; setMoratoriumTimeMillis(ms + System.currentTimeMillis()); setMoratoriumTimeMillis(ms + currentTimeMillis()); return true; } catch (NumberFormatException nfe) { try { setMoratoriumTimeMillis(HttpDateTime.parse(retryAfter)); setMoratoriumTimeMillis(AndroidHttpClient.parseDate(retryAfter)); return true; } catch (IllegalArgumentException iae) { return false; Loading @@ -269,13 +269,12 @@ public class OperationScheduler { public void onSuccess() { resetTransientError(); resetPermanentError(); long now = System.currentTimeMillis(); mStorage.edit() .remove(PREFIX + "errorCount") .remove(PREFIX + "lastErrorTimeMillis") .remove(PREFIX + "permanentError") .remove(PREFIX + "triggerTimeMillis") .putLong(PREFIX + "lastSuccessTimeMillis", now).commit(); .putLong(PREFIX + "lastSuccessTimeMillis", currentTimeMillis()).commit(); } /** Loading @@ -284,8 +283,7 @@ public class OperationScheduler { * purposes. */ public void onTransientError() { long now = System.currentTimeMillis(); mStorage.edit().putLong(PREFIX + "lastErrorTimeMillis", now).commit(); mStorage.edit().putLong(PREFIX + "lastErrorTimeMillis", currentTimeMillis()).commit(); mStorage.edit().putInt(PREFIX + "errorCount", mStorage.getInt(PREFIX + "errorCount", 0) + 1).commit(); } Loading Loading @@ -338,4 +336,13 @@ public class OperationScheduler { } return out.append("]").toString(); } /** * Gets the current time. Can be overridden for unit testing. * * @return {@link System#currentTimeMillis()} */ protected long currentTimeMillis() { return System.currentTimeMillis(); } }
common/tests/src/com/android/common/OperationSchedulerTest.java +92 −40 Original line number Diff line number Diff line Loading @@ -22,19 +22,34 @@ import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; public class OperationSchedulerTest extends AndroidTestCase { /** * OperationScheduler subclass which uses an artificial time. * Set {@link #timeMillis} to whatever value you like. */ private class TimeTravelScheduler extends OperationScheduler { static final long DEFAULT_TIME = 1250146800000L; // 13-Aug-2009, 12:00:00 am public long timeMillis = DEFAULT_TIME; @Override protected long currentTimeMillis() { return timeMillis; } public TimeTravelScheduler() { super(getFreshStorage()); } } private SharedPreferences getFreshStorage() { SharedPreferences sp = getContext().getSharedPreferences("OperationSchedulerTest", 0); sp.edit().clear().commit(); return sp; } @MediumTest public void testScheduler() throws Exception { String name = "OperationSchedulerTest.testScheduler"; SharedPreferences storage = getContext().getSharedPreferences(name, 0); storage.edit().clear().commit(); OperationScheduler scheduler = new OperationScheduler(storage); TimeTravelScheduler scheduler = new TimeTravelScheduler(); OperationScheduler.Options options = new OperationScheduler.Options(); assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options)); assertEquals(0, scheduler.getLastSuccessTimeMillis()); assertEquals(0, scheduler.getLastAttemptTimeMillis()); long beforeTrigger = System.currentTimeMillis(); long beforeTrigger = scheduler.timeMillis; scheduler.setTriggerTimeMillis(beforeTrigger + 1000000); assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); Loading @@ -51,33 +66,26 @@ public class OperationSchedulerTest extends AndroidTestCase { assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); // Backoff interval after an error long beforeError = System.currentTimeMillis(); long beforeError = (scheduler.timeMillis += 100); scheduler.onTransientError(); long afterError = System.currentTimeMillis(); assertEquals(0, scheduler.getLastSuccessTimeMillis()); assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis()); assertTrue(afterError >= scheduler.getLastAttemptTimeMillis()); assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); options.backoffFixedMillis = 1000000; options.backoffIncrementalMillis = 500000; assertTrue(beforeError + 1500000 <= scheduler.getNextTimeMillis(options)); assertTrue(afterError + 1500000 >= scheduler.getNextTimeMillis(options)); assertEquals(beforeError + 1500000, scheduler.getNextTimeMillis(options)); // Two errors: backoff interval increases beforeError = System.currentTimeMillis(); beforeError = (scheduler.timeMillis += 100); scheduler.onTransientError(); afterError = System.currentTimeMillis(); assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis()); assertTrue(afterError >= scheduler.getLastAttemptTimeMillis()); assertTrue(beforeError + 2000000 <= scheduler.getNextTimeMillis(options)); assertTrue(afterError + 2000000 >= scheduler.getNextTimeMillis(options)); assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeError + 2000000, scheduler.getNextTimeMillis(options)); // Reset transient error: no backoff interval scheduler.resetTransientError(); assertEquals(0, scheduler.getLastSuccessTimeMillis()); assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis()); assertTrue(afterError >= scheduler.getLastAttemptTimeMillis()); assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); // Permanent error holds true even if transient errors are reset // However, we remember that the transient error was reset... Loading @@ -89,30 +97,26 @@ public class OperationSchedulerTest extends AndroidTestCase { assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); // Success resets the trigger long beforeSuccess = System.currentTimeMillis(); long beforeSuccess = (scheduler.timeMillis += 100); scheduler.onSuccess(); long afterSuccess = System.currentTimeMillis(); assertTrue(beforeSuccess <= scheduler.getLastAttemptTimeMillis()); assertTrue(afterSuccess >= scheduler.getLastAttemptTimeMillis()); assertTrue(beforeSuccess <= scheduler.getLastSuccessTimeMillis()); assertTrue(afterSuccess >= scheduler.getLastSuccessTimeMillis()); assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeSuccess, scheduler.getLastSuccessTimeMillis()); assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options)); // The moratorium is not reset by success! scheduler.setTriggerTimeMillis(beforeSuccess + 500000); scheduler.setTriggerTimeMillis(0); assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); scheduler.setMoratoriumTimeMillis(0); assertEquals(beforeSuccess + 500000, scheduler.getNextTimeMillis(options)); assertEquals(beforeSuccess, scheduler.getNextTimeMillis(options)); // Periodic interval after success options.periodicIntervalMillis = 250000; assertTrue(beforeSuccess + 250000 <= scheduler.getNextTimeMillis(options)); assertTrue(afterSuccess + 250000 >= scheduler.getNextTimeMillis(options)); scheduler.setTriggerTimeMillis(Long.MAX_VALUE); assertEquals(beforeSuccess + 250000, scheduler.getNextTimeMillis(options)); // Trigger minimum is also since the last success options.minTriggerMillis = 1000000; assertTrue(beforeSuccess + 1000000 <= scheduler.getNextTimeMillis(options)); assertTrue(afterSuccess + 1000000 >= scheduler.getNextTimeMillis(options)); assertEquals(beforeSuccess + 1000000, scheduler.getNextTimeMillis(options)); } @SmallTest Loading @@ -138,23 +142,19 @@ public class OperationSchedulerTest extends AndroidTestCase { @SmallTest public void testMoratoriumWithHttpDate() throws Exception { String name = "OperationSchedulerTest.testMoratoriumWithHttpDate"; SharedPreferences storage = getContext().getSharedPreferences(name, 0); storage.edit().clear().commit(); OperationScheduler scheduler = new OperationScheduler(storage); TimeTravelScheduler scheduler = new TimeTravelScheduler(); OperationScheduler.Options options = new OperationScheduler.Options(); long beforeTrigger = System.currentTimeMillis(); long beforeTrigger = scheduler.timeMillis; scheduler.setTriggerTimeMillis(beforeTrigger + 1000000); assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); scheduler.setMoratoriumTimeMillis(beforeTrigger + 2000000); assertEquals(beforeTrigger + 2000000, scheduler.getNextTimeMillis(options)); long beforeMoratorium = System.currentTimeMillis(); long beforeMoratorium = scheduler.timeMillis; assertTrue(scheduler.setMoratoriumTimeHttp("3000")); long afterMoratorium = System.currentTimeMillis(); long afterMoratorium = scheduler.timeMillis; assertTrue(beforeMoratorium + 3000000 <= scheduler.getNextTimeMillis(options)); assertTrue(afterMoratorium + 3000000 >= scheduler.getNextTimeMillis(options)); Loading @@ -164,4 +164,56 @@ public class OperationSchedulerTest extends AndroidTestCase { assertFalse(scheduler.setMoratoriumTimeHttp("not actually a date")); } @SmallTest public void testClockRollbackScenario() throws Exception { TimeTravelScheduler scheduler = new TimeTravelScheduler(); OperationScheduler.Options options = new OperationScheduler.Options(); options.minTriggerMillis = 2000; // First, set up a scheduler with reasons to wait: a transient // error with backoff and a moratorium for a few minutes. long beforeTrigger = scheduler.timeMillis; long triggerTime = beforeTrigger - 10000000; scheduler.setTriggerTimeMillis(triggerTime); assertEquals(triggerTime, scheduler.getNextTimeMillis(options)); assertEquals(0, scheduler.getLastAttemptTimeMillis()); long beforeSuccess = (scheduler.timeMillis += 100); scheduler.onSuccess(); scheduler.setTriggerTimeMillis(triggerTime); assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeSuccess + 2000, scheduler.getNextTimeMillis(options)); long beforeError = (scheduler.timeMillis += 100); scheduler.onTransientError(); assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeError + 5000, scheduler.getNextTimeMillis(options)); long beforeMoratorium = (scheduler.timeMillis += 100); scheduler.setMoratoriumTimeMillis(beforeTrigger + 1000000); assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); // Now set the time back a few seconds. // The moratorium time should still be honored. long beforeRollback = (scheduler.timeMillis = beforeTrigger - 10000); assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); // The rollback also moved the last-attempt clock back to the rollback time. assertEquals(scheduler.timeMillis, scheduler.getLastAttemptTimeMillis()); // But if we set the time back more than a day, the moratorium // resets to the maximum moratorium (a day, by default), exposing // the original trigger time. beforeRollback = (scheduler.timeMillis = beforeTrigger - 100000000); assertEquals(triggerTime, scheduler.getNextTimeMillis(options)); assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis()); // If we roll forward until after the re-set moratorium, then it expires. scheduler.timeMillis = triggerTime + 5000000; assertEquals(triggerTime, scheduler.getNextTimeMillis(options)); assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis()); assertEquals(beforeRollback, scheduler.getLastSuccessTimeMillis()); } }
core/java/android/app/ContextImpl.java +17 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,8 @@ import android.location.LocationManager; import android.media.AudioManager; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.ThrottleManager; import android.net.IThrottleManager; import android.net.Uri; import android.net.wifi.IWifiManager; import android.net.wifi.WifiManager; Loading Loading @@ -164,6 +166,7 @@ class ContextImpl extends Context { private static AlarmManager sAlarmManager; private static PowerManager sPowerManager; private static ConnectivityManager sConnectivityManager; private static ThrottleManager sThrottleManager; private static WifiManager sWifiManager; private static LocationManager sLocationManager; private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs = Loading Loading @@ -929,6 +932,8 @@ class ContextImpl extends Context { return getPowerManager(); } else if (CONNECTIVITY_SERVICE.equals(name)) { return getConnectivityManager(); } else if (THROTTLE_SERVICE.equals(name)) { return getThrottleManager(); } else if (WIFI_SERVICE.equals(name)) { return getWifiManager(); } else if (NOTIFICATION_SERVICE.equals(name)) { Loading Loading @@ -1028,6 +1033,18 @@ class ContextImpl extends Context { return sConnectivityManager; } private ThrottleManager getThrottleManager() { synchronized (sSync) { if (sThrottleManager == null) { IBinder b = ServiceManager.getService(THROTTLE_SERVICE); IThrottleManager service = IThrottleManager.Stub.asInterface(b); sThrottleManager = new ThrottleManager(service); } } return sThrottleManager; } private WifiManager getWifiManager() { synchronized (sSync) { Loading