diff options
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 8 | ||||
-rw-r--r-- | core/java/android/content/Context.java | 11 | ||||
-rw-r--r-- | core/java/android/net/IThrottleManager.aidl | 40 | ||||
-rw-r--r-- | core/java/android/net/ThrottleManager.java | 214 | ||||
-rw-r--r-- | core/java/android/os/INetworkManagementService.aidl | 17 | ||||
-rw-r--r-- | services/java/com/android/server/NetworkManagementService.java | 43 | ||||
-rw-r--r-- | services/java/com/android/server/SystemServer.java | 16 | ||||
-rw-r--r-- | services/java/com/android/server/ThrottleService.java | 1160 | ||||
-rw-r--r-- | services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java | 353 |
10 files changed, 0 insertions, 1863 deletions
@@ -123,7 +123,6 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/usb/IUsbManager.aidl \ core/java/android/net/IConnectivityManager.aidl \ core/java/android/net/INetworkManagementEventObserver.aidl \ - core/java/android/net/IThrottleManager.aidl \ core/java/android/net/INetworkPolicyListener.aidl \ core/java/android/net/INetworkPolicyManager.aidl \ core/java/android/net/INetworkStatsService.aidl \ diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 8ef708c..99ac0d6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -63,8 +63,6 @@ import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.INetworkPolicyManager; import android.net.NetworkPolicyManager; -import android.net.ThrottleManager; -import android.net.IThrottleManager; import android.net.Uri; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; @@ -474,12 +472,6 @@ class ContextImpl extends Context { return new TelephonyManager(ctx.getOuterContext()); }}); - registerService(THROTTLE_SERVICE, new StaticServiceFetcher() { - public Object createStaticService() { - IBinder b = ServiceManager.getService(THROTTLE_SERVICE); - return new ThrottleManager(IThrottleManager.Stub.asInterface(b)); - }}); - registerService(UI_MODE_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new UiModeManager(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 41d470b..9510257 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1993,17 +1993,6 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a {@link - * android.net.ThrottleManager} for handling management of - * throttling. - * - * @hide - * @see #getSystemService - * @see android.net.ThrottleManager - */ - public static final String THROTTLE_SERVICE = "throttle"; - - /** - * Use with {@link #getSystemService} to retrieve a {@link * android.os.IUpdateLock} for managing runtime sequences that * must not be interrupted by headless OTA application or similar. * diff --git a/core/java/android/net/IThrottleManager.aidl b/core/java/android/net/IThrottleManager.aidl deleted file mode 100644 index a12469d..0000000 --- a/core/java/android/net/IThrottleManager.aidl +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2010, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.IBinder; - -/** - * Interface that answers queries about data transfer amounts and throttling - */ -/** {@hide} */ -interface IThrottleManager -{ - long getByteCount(String iface, int dir, int period, int ago); - - int getThrottle(String iface); - - long getResetTime(String iface); - - long getPeriodStartTime(String iface); - - long getCliffThreshold(String iface, int cliff); - - int getCliffLevel(String iface, int cliff); - - String getHelpUri(); -} diff --git a/core/java/android/net/ThrottleManager.java b/core/java/android/net/ThrottleManager.java deleted file mode 100644 index 5fdac58..0000000 --- a/core/java/android/net/ThrottleManager.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.os.Binder; -import android.os.RemoteException; - -/** - * Class that handles throttling. It provides read/write numbers per interface - * and methods to apply throttled rates. - * {@hide} - */ -public class ThrottleManager -{ - /** - * Broadcast each polling period to indicate new data counts. - * - * Includes four extras: - * EXTRA_CYCLE_READ - a long of the read bytecount for the current cycle - * EXTRA_CYCLE_WRITE -a long of the write bytecount for the current cycle - * EXTRA_CYLCE_START -a long of MS for the cycle start time - * EXTRA_CYCLE_END -a long of MS for the cycle stop time - * {@hide} - */ - public static final String THROTTLE_POLL_ACTION = "android.net.thrott.POLL_ACTION"; - /** - * The lookup key for a long for the read bytecount for this period. Retrieve with - * {@link android.content.Intent#getLongExtra(String)}. - * {@hide} - */ - public static final String EXTRA_CYCLE_READ = "cycleRead"; - /** - * contains a long of the number of bytes written in the cycle - * {@hide} - */ - public static final String EXTRA_CYCLE_WRITE = "cycleWrite"; - /** - * contains a long of the number of bytes read in the cycle - * {@hide} - */ - public static final String EXTRA_CYCLE_START = "cycleStart"; - /** - * contains a long of the ms since 1970 used to init a calendar, etc for the end - * of the cycle - * {@hide} - */ - public static final String EXTRA_CYCLE_END = "cycleEnd"; - - /** - * Broadcast when the thottle level changes. - * {@hide} - */ - public static final String THROTTLE_ACTION = "android.net.thrott.THROTTLE_ACTION"; - /** - * int of the current bandwidth in TODO - * {@hide} - */ - public static final String EXTRA_THROTTLE_LEVEL = "level"; - - /** - * Broadcast on boot and whenever the settings change. - * {@hide} - */ - public static final String POLICY_CHANGED_ACTION = "android.net.thrott.POLICY_CHANGED_ACTION"; - - // {@hide} - public static final int DIRECTION_TX = 0; - // {@hide} - public static final int DIRECTION_RX = 1; - - // {@hide} - public static final int PERIOD_CYCLE = 0; - // {@hide} - public static final int PERIOD_YEAR = 1; - // {@hide} - public static final int PERIOD_MONTH = 2; - // {@hide} - public static final int PERIOD_WEEK = 3; - // @hide - public static final int PERIOD_7DAY = 4; - // @hide - public static final int PERIOD_DAY = 5; - // @hide - public static final int PERIOD_24HOUR = 6; - // @hide - public static final int PERIOD_HOUR = 7; - // @hide - public static final int PERIOD_60MIN = 8; - // @hide - public static final int PERIOD_MINUTE = 9; - // @hide - public static final int PERIOD_60SEC = 10; - // @hide - public static final int PERIOD_SECOND = 11; - - - - /** - * returns a long of the ms from the epoch to the time the current cycle ends for the - * named interface - * {@hide} - */ - public long getResetTime(String iface) { - try { - return mService.getResetTime(iface); - } catch (RemoteException e) { - return -1; - } - } - - /** - * returns a long of the ms from the epoch to the time the current cycle started for the - * named interface - * {@hide} - */ - public long getPeriodStartTime(String iface) { - try { - return mService.getPeriodStartTime(iface); - } catch (RemoteException e) { - return -1; - } - } - - /** - * returns a long of the byte count either read or written on the named interface - * for the period described. Direction is either DIRECTION_RX or DIRECTION_TX and - * period may only be PERIOD_CYCLE for the current cycle (other periods may be supported - * in the future). Ago indicates the number of periods in the past to lookup - 0 means - * the current period, 1 is the last one, 2 was two periods ago.. - * {@hide} - */ - public long getByteCount(String iface, int direction, int period, int ago) { - try { - return mService.getByteCount(iface, direction, period, ago); - } catch (RemoteException e) { - return -1; - } - } - - /** - * returns the number of bytes read+written after which a particular cliff - * takes effect on the named iface. Currently only cliff #1 is supported (1 step) - * {@hide} - */ - public long getCliffThreshold(String iface, int cliff) { - try { - return mService.getCliffThreshold(iface, cliff); - } catch (RemoteException e) { - return -1; - } - } - - /** - * returns the thottling bandwidth (bps) for a given cliff # on the named iface. - * only cliff #1 is currently supported. - * {@hide} - */ - public int getCliffLevel(String iface, int cliff) { - try { - return mService.getCliffLevel(iface, cliff); - } catch (RemoteException e) { - return -1; - } - } - - /** - * returns the help URI for throttling - * {@hide} - */ - public String getHelpUri() { - try { - return mService.getHelpUri(); - } catch (RemoteException e) { - return null; - } - } - - - private IThrottleManager mService; - - /** - * Don't allow use of default constructor. - */ - @SuppressWarnings({"UnusedDeclaration"}) - private ThrottleManager() { - } - - /** - * {@hide} - */ - public ThrottleManager(IThrottleManager service) { - if (service == null) { - throw new IllegalArgumentException( - "ThrottleManager() cannot be constructed with null service"); - } - mService = service; - } -} diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 80abd0f..d0e5019 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -306,23 +306,6 @@ interface INetworkManagementService boolean isBandwidthControlEnabled(); /** - * Configures bandwidth throttling on an interface. - */ - void setInterfaceThrottle(String iface, int rxKbps, int txKbps); - - /** - * Returns the currently configured RX throttle values - * for the specified interface - */ - int getInterfaceRxThrottle(String iface); - - /** - * Returns the currently configured TX throttle values - * for the specified interface - */ - int getInterfaceTxThrottle(String iface); - - /** * Sets idletimer for an interface. * * This either initializes a new idletimer or increases its diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 9ce02e3..0a54593 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -1345,49 +1345,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub } @Override - public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) { - mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); - try { - mConnector.execute("interface", "setthrottle", iface, rxKbps, txKbps); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); - } - } - - private int getInterfaceThrottle(String iface, boolean rx) { - final NativeDaemonEvent event; - try { - event = mConnector.execute("interface", "getthrottle", iface, rx ? "rx" : "tx"); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); - } - - if (rx) { - event.checkCode(InterfaceRxThrottleResult); - } else { - event.checkCode(InterfaceTxThrottleResult); - } - - try { - return Integer.parseInt(event.getMessage()); - } catch (NumberFormatException e) { - throw new IllegalStateException("unexpected response:" + event); - } - } - - @Override - public int getInterfaceRxThrottle(String iface) { - mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); - return getInterfaceThrottle(iface, true); - } - - @Override - public int getInterfaceTxThrottle(String iface) { - mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); - return getInterfaceThrottle(iface, false); - } - - @Override public void setDefaultInterfaceForDns(String iface) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index c33eb2b..39ee47e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -146,7 +146,6 @@ class ServerThread extends Thread { TwilightService twilight = null; UiModeManagerService uiMode = null; RecognitionManagerService recognition = null; - ThrottleService throttle = null; NetworkTimeUpdateService networkTimeUpdater = null; CommonTimeManagementService commonTimeMgmtService = null; InputManagerService inputManager = null; @@ -511,15 +510,6 @@ class ServerThread extends Thread { } try { - Slog.i(TAG, "Throttle Service"); - throttle = new ThrottleService(context); - ServiceManager.addService( - Context.THROTTLE_SERVICE, throttle); - } catch (Throwable e) { - reportWtf("starting ThrottleService", e); - } - - try { Slog.i(TAG, "UpdateLock Service"); ServiceManager.addService(Context.UPDATE_LOCK_SERVICE, new UpdateLockService(context)); @@ -839,7 +829,6 @@ class ServerThread extends Thread { final ConnectivityService connectivityF = connectivity; final DockObserver dockF = dock; final UsbService usbF = usb; - final ThrottleService throttleF = throttle; final TwilightService twilightF = twilight; final UiModeManagerService uiModeF = uiMode; final AppWidgetService appWidgetF = appWidget; @@ -952,11 +941,6 @@ class ServerThread extends Thread { reportWtf("making Country Detector Service ready", e); } try { - if (throttleF != null) throttleF.systemReady(); - } catch (Throwable e) { - reportWtf("making Throttle Service ready", e); - } - try { if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady(); } catch (Throwable e) { reportWtf("making Network Time Service ready", e); diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java deleted file mode 100644 index 75eb3c4..0000000 --- a/services/java/com/android/server/ThrottleService.java +++ /dev/null @@ -1,1160 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.app.AlarmManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.database.ContentObserver; -import android.net.INetworkManagementEventObserver; -import android.net.IThrottleManager; -import android.net.NetworkStats; -import android.net.ThrottleManager; -import android.os.Binder; -import android.os.Environment; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.INetworkManagementService; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.provider.Settings; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.NtpTrustedTime; -import android.util.Slog; -import android.util.TrustedTime; - -import com.android.internal.R; -import com.android.internal.telephony.TelephonyProperties; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.Random; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -// TODO - add comments - reference the ThrottleManager for public API -public class ThrottleService extends IThrottleManager.Stub { - - private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing"; - - private static final String TAG = "ThrottleService"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - private Handler mHandler; - private HandlerThread mThread; - - private Context mContext; - - private static final int INITIAL_POLL_DELAY_SEC = 90; - private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1; - private static final int TESTING_RESET_PERIOD_SEC = 60 * 10; - private static final long TESTING_THRESHOLD = 1 * 1024 * 1024; - - private static final long MAX_NTP_CACHE_AGE = 24 * 60 * 60 * 1000; - - private long mMaxNtpCacheAge = MAX_NTP_CACHE_AGE; - - private int mPolicyPollPeriodSec; - private AtomicLong mPolicyThreshold; - private AtomicInteger mPolicyThrottleValue; - private int mPolicyResetDay; // 1-28 - private int mPolicyNotificationsAllowedMask; - - private long mLastRead; // read byte count from last poll - private long mLastWrite; // write byte count from last poll - - private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL"; - private static int POLL_REQUEST = 0; - private PendingIntent mPendingPollIntent; - private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET"; - private static int RESET_REQUEST = 1; - private PendingIntent mPendingResetIntent; - - private INetworkManagementService mNMService; - private AlarmManager mAlarmManager; - private NotificationManager mNotificationManager; - - private DataRecorder mRecorder; - - private String mIface; - - private static final int NOTIFICATION_WARNING = 2; - - private Notification mThrottlingNotification; - private boolean mWarningNotificationSent = false; - - private InterfaceObserver mInterfaceObserver; - private SettingsObserver mSettingsObserver; - - private AtomicInteger mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc - private static final int THROTTLE_INDEX_UNINITIALIZED = -1; - private static final int THROTTLE_INDEX_UNTHROTTLED = 0; - - private Intent mPollStickyBroadcast; - - private TrustedTime mTime; - - private static INetworkManagementService getNetworkManagementService() { - final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - return INetworkManagementService.Stub.asInterface(b); - } - - public ThrottleService(Context context) { - this(context, getNetworkManagementService(), NtpTrustedTime.getInstance(context), - context.getResources().getString(R.string.config_datause_iface)); - } - - public ThrottleService(Context context, INetworkManagementService nmService, TrustedTime time, - String iface) { - if (VDBG) Slog.v(TAG, "Starting ThrottleService"); - mContext = context; - - mPolicyThreshold = new AtomicLong(); - mPolicyThrottleValue = new AtomicInteger(); - mThrottleIndex = new AtomicInteger(); - - mIface = iface; - mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - Intent pollIntent = new Intent(ACTION_POLL, null); - mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0); - Intent resetIntent = new Intent(ACTION_RESET, null); - mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0); - - mNMService = nmService; - mTime = time; - - mNotificationManager = (NotificationManager)mContext.getSystemService( - Context.NOTIFICATION_SERVICE); - } - - private static class InterfaceObserver extends INetworkManagementEventObserver.Stub { - private int mMsg; - private Handler mHandler; - private String mIface; - - InterfaceObserver(Handler handler, int msg, String iface) { - super(); - mHandler = handler; - mMsg = msg; - mIface = iface; - } - - public void interfaceStatusChanged(String iface, boolean up) { - if (up) { - if (TextUtils.equals(iface, mIface)) { - mHandler.obtainMessage(mMsg).sendToTarget(); - } - } - } - - public void interfaceLinkStateChanged(String iface, boolean up) { - } - - public void interfaceAdded(String iface) { - // TODO - an interface added in the UP state should also trigger a StatusChanged - // notification.. - if (TextUtils.equals(iface, mIface)) { - mHandler.obtainMessage(mMsg).sendToTarget(); - } - } - - public void interfaceRemoved(String iface) {} - public void limitReached(String limitName, String iface) {} - public void interfaceClassDataActivityChanged(String label, boolean active) {} - } - - - private static class SettingsObserver extends ContentObserver { - private int mMsg; - private Handler mHandler; - SettingsObserver(Handler handler, int msg) { - super(handler); - mHandler = handler; - mMsg = msg; - } - - void register(Context context) { - ContentResolver resolver = context.getContentResolver(); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.THROTTLE_POLLING_SEC), false, this); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.THROTTLE_THRESHOLD_BYTES), false, this); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.THROTTLE_VALUE_KBITSPS), false, this); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.THROTTLE_RESET_DAY), false, this); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.THROTTLE_NOTIFICATION_TYPE), false, this); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.THROTTLE_HELP_URI), false, this); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.THROTTLE_MAX_NTP_CACHE_AGE_SEC), false, this); - } - - void unregister(Context context) { - final ContentResolver resolver = context.getContentResolver(); - resolver.unregisterContentObserver(this); - } - - @Override - public void onChange(boolean selfChange) { - mHandler.obtainMessage(mMsg).sendToTarget(); - } - } - - private void enforceAccessPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.ACCESS_NETWORK_STATE, - "ThrottleService"); - } - - private long ntpToWallTime(long ntpTime) { - // get time quickly without worrying about trusted state - long bestNow = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); - long localNow = System.currentTimeMillis(); - return localNow + (ntpTime - bestNow); - } - - // TODO - fetch for the iface - // return time in the local, system wall time, correcting for the use of ntp - - public long getResetTime(String iface) { - enforceAccessPermission(); - long resetTime = 0; - if (mRecorder != null) { - resetTime = mRecorder.getPeriodEnd(); - } - resetTime = ntpToWallTime(resetTime); - return resetTime; - } - - // TODO - fetch for the iface - // return time in the local, system wall time, correcting for the use of ntp - public long getPeriodStartTime(String iface) { - long startTime = 0; - enforceAccessPermission(); - if (mRecorder != null) { - startTime = mRecorder.getPeriodStart(); - } - startTime = ntpToWallTime(startTime); - return startTime; - } - //TODO - a better name? getCliffByteCountThreshold? - // TODO - fetch for the iface - public long getCliffThreshold(String iface, int cliff) { - enforceAccessPermission(); - if (cliff == 1) { - return mPolicyThreshold.get(); - } - return 0; - } - // TODO - a better name? getThrottleRate? - // TODO - fetch for the iface - public int getCliffLevel(String iface, int cliff) { - enforceAccessPermission(); - if (cliff == 1) { - return mPolicyThrottleValue.get(); - } - return 0; - } - - public String getHelpUri() { - enforceAccessPermission(); - return Settings.Global.getString(mContext.getContentResolver(), - Settings.Global.THROTTLE_HELP_URI); - } - - // TODO - fetch for the iface - public long getByteCount(String iface, int dir, int period, int ago) { - enforceAccessPermission(); - if ((period == ThrottleManager.PERIOD_CYCLE) && (mRecorder != null)) { - if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago); - if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago); - } - return 0; - } - - // TODO - a better name - getCurrentThrottleRate? - // TODO - fetch for the iface - public int getThrottle(String iface) { - enforceAccessPermission(); - if (mThrottleIndex.get() == 1) { - return mPolicyThrottleValue.get(); - } - return 0; - } - - void systemReady() { - if (VDBG) Slog.v(TAG, "systemReady"); - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - dispatchPoll(); - } - }, new IntentFilter(ACTION_POLL)); - - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - dispatchReset(); - } - }, new IntentFilter(ACTION_RESET)); - - // use a new thread as we don't want to stall the system for file writes - mThread = new HandlerThread(TAG); - mThread.start(); - mHandler = new MyHandler(mThread.getLooper()); - mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget(); - - mInterfaceObserver = new InterfaceObserver(mHandler, EVENT_IFACE_UP, mIface); - try { - mNMService.registerObserver(mInterfaceObserver); - } catch (RemoteException e) { - Slog.e(TAG, "Could not register InterfaceObserver " + e); - } - - mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED); - mSettingsObserver.register(mContext); - } - - void shutdown() { - // TODO: eventually connect with ShutdownThread to persist stats during - // graceful shutdown. - - if (mThread != null) { - mThread.quit(); - } - - if (mSettingsObserver != null) { - mSettingsObserver.unregister(mContext); - } - - if (mPollStickyBroadcast != null) { - mContext.removeStickyBroadcastAsUser(mPollStickyBroadcast, UserHandle.ALL); - } - } - - void dispatchPoll() { - mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget(); - } - - void dispatchReset() { - mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget(); - } - - private static final int EVENT_REBOOT_RECOVERY = 0; - private static final int EVENT_POLICY_CHANGED = 1; - private static final int EVENT_POLL_ALARM = 2; - private static final int EVENT_RESET_ALARM = 3; - private static final int EVENT_IFACE_UP = 4; - private class MyHandler extends Handler { - public MyHandler(Looper l) { - super(l); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_REBOOT_RECOVERY: - onRebootRecovery(); - break; - case EVENT_POLICY_CHANGED: - onPolicyChanged(); - break; - case EVENT_POLL_ALARM: - onPollAlarm(); - break; - case EVENT_RESET_ALARM: - onResetAlarm(); - break; - case EVENT_IFACE_UP: - onIfaceUp(); - } - } - - private void onRebootRecovery() { - if (VDBG) Slog.v(TAG, "onRebootRecovery"); - // check for sim change TODO - // reregister for notification of policy change - - mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED); - - mRecorder = new DataRecorder(mContext, ThrottleService.this); - - // get policy - mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget(); - - // if we poll now we won't have network connectivity or even imsi access - // queue up a poll to happen in a little while - after ntp and imsi are avail - // TODO - make this callback based (ie, listen for notificaitons) - mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_POLL_ALARM), - INITIAL_POLL_DELAY_SEC * 1000); - } - - // check for new policy info (threshold limit/value/etc) - private void onPolicyChanged() { - boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true"); - - int pollingPeriod = mContext.getResources().getInteger( - R.integer.config_datause_polling_period_sec); - mPolicyPollPeriodSec = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.THROTTLE_POLLING_SEC, pollingPeriod); - - // TODO - remove testing stuff? - long defaultThreshold = mContext.getResources().getInteger( - R.integer.config_datause_threshold_bytes); - int defaultValue = mContext.getResources().getInteger( - R.integer.config_datause_throttle_kbitsps); - long threshold = Settings.Global.getLong(mContext.getContentResolver(), - Settings.Global.THROTTLE_THRESHOLD_BYTES, defaultThreshold); - int value = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.THROTTLE_VALUE_KBITSPS, defaultValue); - - mPolicyThreshold.set(threshold); - mPolicyThrottleValue.set(value); - if (testing) { - mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC; - mPolicyThreshold.set(TESTING_THRESHOLD); - } - - mPolicyResetDay = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.THROTTLE_RESET_DAY, -1); - if (mPolicyResetDay == -1 || - ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) { - Random g = new Random(); - mPolicyResetDay = 1 + g.nextInt(28); // 1-28 - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.THROTTLE_RESET_DAY, mPolicyResetDay); - } - if (mIface == null) { - mPolicyThreshold.set(0); - } - - int defaultNotificationType = mContext.getResources().getInteger( - R.integer.config_datause_notification_type); - mPolicyNotificationsAllowedMask = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType); - - final int maxNtpCacheAgeSec = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.THROTTLE_MAX_NTP_CACHE_AGE_SEC, - (int) (MAX_NTP_CACHE_AGE / 1000)); - mMaxNtpCacheAge = maxNtpCacheAgeSec * 1000; - - if (VDBG || (mPolicyThreshold.get() != 0)) { - Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" + - mPolicyPollPeriodSec + ", threshold=" + mPolicyThreshold.get() + - ", value=" + mPolicyThrottleValue.get() + ", resetDay=" + mPolicyResetDay + - ", noteType=" + mPolicyNotificationsAllowedMask + ", mMaxNtpCacheAge=" + - mMaxNtpCacheAge); - } - - // force updates - mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED); - - onResetAlarm(); - - onPollAlarm(); - - Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION); - mContext.sendBroadcastAsUser(broadcast, UserHandle.ALL); - } - - private void onPollAlarm() { - long now = SystemClock.elapsedRealtime(); - long next = now + mPolicyPollPeriodSec * 1000; - - // when trusted cache outdated, try refreshing - if (mTime.getCacheAge() > mMaxNtpCacheAge) { - if (mTime.forceRefresh()) { - if (VDBG) Slog.d(TAG, "updated trusted time, reseting alarm"); - dispatchReset(); - } - } - - long incRead = 0; - long incWrite = 0; - try { - final NetworkStats stats = mNMService.getNetworkStatsSummaryDev(); - final int index = stats.findIndex(mIface, NetworkStats.UID_ALL, - NetworkStats.SET_DEFAULT, NetworkStats.TAG_NONE); - - if (index != -1) { - final NetworkStats.Entry entry = stats.getValues(index, null); - incRead = entry.rxBytes - mLastRead; - incWrite = entry.txBytes - mLastWrite; - } else { - // missing iface, assume stats are 0 - Slog.w(TAG, "unable to find stats for iface " + mIface); - } - - // handle iface resets - on some device the 3g iface comes and goes and gets - // totals reset to 0. Deal with it - if ((incRead < 0) || (incWrite < 0)) { - incRead += mLastRead; - incWrite += mLastWrite; - mLastRead = 0; - mLastWrite = 0; - } - } catch (IllegalStateException e) { - Slog.e(TAG, "problem during onPollAlarm: " + e); - } catch (RemoteException e) { - Slog.e(TAG, "problem during onPollAlarm: " + e); - } - - // don't count this data if we're roaming. - boolean roaming = "true".equals( - SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING)); - if (!roaming) { - mRecorder.addData(incRead, incWrite); - } - - long periodRx = mRecorder.getPeriodRx(0); - long periodTx = mRecorder.getPeriodTx(0); - long total = periodRx + periodTx; - if (VDBG || (mPolicyThreshold.get() != 0)) { - Slog.d(TAG, "onPollAlarm - roaming =" + roaming + - ", read =" + incRead + ", written =" + incWrite + ", new total =" + total); - } - mLastRead += incRead; - mLastWrite += incWrite; - - checkThrottleAndPostNotification(total); - - Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION); - broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx); - broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx); - broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface)); - broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface)); - mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL); - mPollStickyBroadcast = broadcast; - - mAlarmManager.cancel(mPendingPollIntent); - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent); - } - - private void onIfaceUp() { - // if we were throttled before, be sure and set it again - the iface went down - // (and may have disappeared all together) and these settings were lost - if (mThrottleIndex.get() == 1) { - try { - mNMService.setInterfaceThrottle(mIface, -1, -1); - mNMService.setInterfaceThrottle(mIface, - mPolicyThrottleValue.get(), mPolicyThrottleValue.get()); - } catch (Exception e) { - Slog.e(TAG, "error setting Throttle: " + e); - } - } - } - - private void checkThrottleAndPostNotification(long currentTotal) { - // is throttling enabled? - long threshold = mPolicyThreshold.get(); - if (threshold == 0) { - clearThrottleAndNotification(); - return; - } - - // have we spoken with an ntp server yet? - // this is controversial, but we'd rather err towards not throttling - if (!mTime.hasCache()) { - Slog.w(TAG, "missing trusted time, skipping throttle check"); - return; - } - - // check if we need to throttle - if (currentTotal > threshold) { - if (mThrottleIndex.get() != 1) { - mThrottleIndex.set(1); - if (DBG) Slog.d(TAG, "Threshold " + threshold + " exceeded!"); - try { - mNMService.setInterfaceThrottle(mIface, - mPolicyThrottleValue.get(), mPolicyThrottleValue.get()); - } catch (Exception e) { - Slog.e(TAG, "error setting Throttle: " + e); - } - - mNotificationManager.cancel(R.drawable.stat_sys_throttled); - - postNotification(R.string.throttled_notification_title, - R.string.throttled_notification_message, - R.drawable.stat_sys_throttled, - Notification.FLAG_ONGOING_EVENT); - - Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION); - broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, - mPolicyThrottleValue.get()); - mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL); - - } // else already up! - } else { - clearThrottleAndNotification(); - if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) { - // check if we should warn about throttle - // pretend we only have 1/2 the time remaining that we actually do - // if our burn rate in the period so far would have us exceed the limit - // in that 1/2 window, warn the user. - // this gets more generous in the early to middle period and converges back - // to the limit as we move toward the period end. - - // adding another factor - it must be greater than the total cap/4 - // else we may get false alarms very early in the period.. in the first - // tenth of a percent of the period if we used more than a tenth of a percent - // of the cap we'd get a warning and that's not desired. - long start = mRecorder.getPeriodStart(); - long end = mRecorder.getPeriodEnd(); - long periodLength = end - start; - long now = System.currentTimeMillis(); - long timeUsed = now - start; - long warningThreshold = 2*threshold*timeUsed/(timeUsed+periodLength); - if ((currentTotal > warningThreshold) && (currentTotal > threshold/4)) { - if (mWarningNotificationSent == false) { - mWarningNotificationSent = true; - mNotificationManager.cancel(R.drawable.stat_sys_throttled); - postNotification(R.string.throttle_warning_notification_title, - R.string.throttle_warning_notification_message, - R.drawable.stat_sys_throttled, - 0); - } - } else { - if (mWarningNotificationSent == true) { - mNotificationManager.cancel(R.drawable.stat_sys_throttled); - mWarningNotificationSent =false; - } - } - } - } - } - - private void postNotification(int titleInt, int messageInt, int icon, int flags) { - Intent intent = new Intent(); - // TODO - fix up intent - intent.setClassName("com.android.phone", "com.android.phone.DataUsage"); - intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - - PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0, - null, UserHandle.CURRENT); - - Resources r = Resources.getSystem(); - CharSequence title = r.getText(titleInt); - CharSequence message = r.getText(messageInt); - if (mThrottlingNotification == null) { - mThrottlingNotification = new Notification(); - mThrottlingNotification.when = 0; - // TODO - fixup icon - mThrottlingNotification.icon = icon; - mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND; - } - mThrottlingNotification.flags = flags; - mThrottlingNotification.tickerText = title; - mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi); - - mNotificationManager.notifyAsUser(null, mThrottlingNotification.icon, - mThrottlingNotification, UserHandle.ALL); - } - - - private void clearThrottleAndNotification() { - if (mThrottleIndex.get() != THROTTLE_INDEX_UNTHROTTLED) { - mThrottleIndex.set(THROTTLE_INDEX_UNTHROTTLED); - try { - mNMService.setInterfaceThrottle(mIface, -1, -1); - } catch (Exception e) { - Slog.e(TAG, "error clearing Throttle: " + e); - } - Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION); - broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1); - mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL); - mNotificationManager.cancelAsUser(null, R.drawable.stat_sys_throttled, - UserHandle.ALL); - mWarningNotificationSent = false; - } - } - - private Calendar calculatePeriodEnd(long now) { - Calendar end = GregorianCalendar.getInstance(); - end.setTimeInMillis(now); - int day = end.get(Calendar.DAY_OF_MONTH); - end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay); - end.set(Calendar.HOUR_OF_DAY, 0); - end.set(Calendar.MINUTE, 0); - end.set(Calendar.SECOND, 0); - end.set(Calendar.MILLISECOND, 0); - if (day >= mPolicyResetDay) { - int month = end.get(Calendar.MONTH); - if (month == Calendar.DECEMBER) { - end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1); - month = Calendar.JANUARY - 1; - } - end.set(Calendar.MONTH, month + 1); - } - - // TODO - remove! - if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) { - end = GregorianCalendar.getInstance(); - end.setTimeInMillis(now); - end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC); - } - return end; - } - private Calendar calculatePeriodStart(Calendar end) { - Calendar start = (Calendar)end.clone(); - int month = end.get(Calendar.MONTH); - if (end.get(Calendar.MONTH) == Calendar.JANUARY) { - month = Calendar.DECEMBER + 1; - start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1); - } - start.set(Calendar.MONTH, month - 1); - - // TODO - remove!! - if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) { - start = (Calendar)end.clone(); - start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC); - } - return start; - } - - private void onResetAlarm() { - if (VDBG || (mPolicyThreshold.get() != 0)) { - Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) + - " bytes read and " + mRecorder.getPeriodTx(0) + " written"); - } - - // when trusted cache outdated, try refreshing - if (mTime.getCacheAge() > mMaxNtpCacheAge) { - mTime.forceRefresh(); - } - - // as long as we have a trusted time cache, we always reset alarms, - // even if the refresh above failed. - if (mTime.hasCache()) { - final long now = mTime.currentTimeMillis(); - Calendar end = calculatePeriodEnd(now); - Calendar start = calculatePeriodStart(end); - - if (mRecorder.setNextPeriod(start, end)) { - onPollAlarm(); - } - - mAlarmManager.cancel(mPendingResetIntent); - long offset = end.getTimeInMillis() - now; - // use Elapsed realtime so clock changes don't fool us. - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, - SystemClock.elapsedRealtime() + offset, - mPendingResetIntent); - } else { - if (VDBG) Slog.d(TAG, "no trusted time, not resetting period"); - } - } - } - - // records bytecount data for a given time and accumulates it into larger time windows - // for logging and other purposes - // - // since time can be changed (user or network action) we will have to track the time of the - // last recording and deal with it. - private static class DataRecorder { - long[] mPeriodRxData; - long[] mPeriodTxData; - int mCurrentPeriod; - int mPeriodCount; - - Calendar mPeriodStart; - Calendar mPeriodEnd; - - ThrottleService mParent; - Context mContext; - String mImsi = null; - - TelephonyManager mTelephonyManager; - - DataRecorder(Context context, ThrottleService parent) { - mContext = context; - mParent = parent; - - mTelephonyManager = (TelephonyManager)mContext.getSystemService( - Context.TELEPHONY_SERVICE); - - synchronized (mParent) { - mPeriodCount = 6; - mPeriodRxData = new long[mPeriodCount]; - mPeriodTxData = new long[mPeriodCount]; - - mPeriodStart = Calendar.getInstance(); - mPeriodEnd = Calendar.getInstance(); - - retrieve(); - } - } - - boolean setNextPeriod(Calendar start, Calendar end) { - // TODO - how would we deal with a dual-IMSI device? - checkForSubscriberId(); - boolean startNewPeriod = true; - - if (start.equals(mPeriodStart) && end.equals(mPeriodEnd)) { - // same endpoints - keep collecting - if (VDBG) { - Slog.d(TAG, "same period (" + start.getTimeInMillis() + "," + - end.getTimeInMillis() +") - ammending data"); - } - startNewPeriod = false; - } else { - if (VDBG) { - if(start.equals(mPeriodEnd) || start.after(mPeriodEnd)) { - Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," + - end.getTimeInMillis() + ") - old end was " + - mPeriodEnd.getTimeInMillis() + ", following"); - } else { - Slog.d(TAG, "new period (" + start.getTimeInMillis() + "," + - end.getTimeInMillis() + ") replacing old (" + - mPeriodStart.getTimeInMillis() + "," + - mPeriodEnd.getTimeInMillis() + ")"); - } - } - synchronized (mParent) { - ++mCurrentPeriod; - if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0; - mPeriodRxData[mCurrentPeriod] = 0; - mPeriodTxData[mCurrentPeriod] = 0; - } - } - setPeriodStart(start); - setPeriodEnd(end); - record(); - return startNewPeriod; - } - - public long getPeriodEnd() { - synchronized (mParent) { - return mPeriodEnd.getTimeInMillis(); - } - } - - private void setPeriodEnd(Calendar end) { - synchronized (mParent) { - mPeriodEnd = end; - } - } - - public long getPeriodStart() { - synchronized (mParent) { - return mPeriodStart.getTimeInMillis(); - } - } - - private void setPeriodStart(Calendar start) { - synchronized (mParent) { - mPeriodStart = start; - } - } - - public int getPeriodCount() { - synchronized (mParent) { - return mPeriodCount; - } - } - - private void zeroData(int field) { - synchronized (mParent) { - for(int period = 0; period<mPeriodCount; period++) { - mPeriodRxData[period] = 0; - mPeriodTxData[period] = 0; - } - mCurrentPeriod = 0; - } - - } - - // if time moves backward accumulate all read/write that's lost into the now - // otherwise time moved forward. - void addData(long bytesRead, long bytesWritten) { - checkForSubscriberId(); - - synchronized (mParent) { - mPeriodRxData[mCurrentPeriod] += bytesRead; - mPeriodTxData[mCurrentPeriod] += bytesWritten; - } - record(); - } - - private File getDataFile() { - File dataDir = Environment.getDataDirectory(); - File throttleDir = new File(dataDir, "system/throttle"); - throttleDir.mkdirs(); - String mImsi = mTelephonyManager.getSubscriberId(); - File dataFile; - if (mImsi == null) { - dataFile = useMRUFile(throttleDir); - if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile); - } else { - String imsiHash = Integer.toString(mImsi.hashCode()); - dataFile = new File(throttleDir, imsiHash); - } - // touch the file so it's not LRU - dataFile.setLastModified(System.currentTimeMillis()); - checkAndDeleteLRUDataFile(throttleDir); - return dataFile; - } - - // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling - private void checkForSubscriberId() { - if (mImsi != null) return; - - mImsi = mTelephonyManager.getSubscriberId(); - if (mImsi == null) return; - - if (VDBG) Slog.d(TAG, "finally have imsi - retreiving data"); - retrieve(); - } - - private final static int MAX_SIMS_SUPPORTED = 3; - - private void checkAndDeleteLRUDataFile(File dir) { - File[] files = dir.listFiles(); - - if (files == null || files.length <= MAX_SIMS_SUPPORTED) return; - if (DBG) Slog.d(TAG, "Too many data files"); - do { - File oldest = null; - for (File f : files) { - if ((oldest == null) || (oldest.lastModified() > f.lastModified())) { - oldest = f; - } - } - if (oldest == null) return; - if (DBG) Slog.d(TAG, " deleting " + oldest); - oldest.delete(); - files = dir.listFiles(); - } while (files.length > MAX_SIMS_SUPPORTED); - } - - private File useMRUFile(File dir) { - File newest = null; - File[] files = dir.listFiles(); - - if (files != null) { - for (File f : files) { - if ((newest == null) || (newest.lastModified() < f.lastModified())) { - newest = f; - } - } - } - if (newest == null) { - newest = new File(dir, "temp"); - } - return newest; - } - - - private static final int DATA_FILE_VERSION = 1; - - private void record() { - // 1 int version - // 1 int mPeriodCount - // 13*6 long[PERIOD_COUNT] mPeriodRxData - // 13*6 long[PERIOD_COUNT] mPeriodTxData - // 1 int mCurrentPeriod - // 13 long periodStartMS - // 13 long periodEndMS - // 200 chars max - StringBuilder builder = new StringBuilder(); - builder.append(DATA_FILE_VERSION); - builder.append(":"); - builder.append(mPeriodCount); - builder.append(":"); - for(int i = 0; i < mPeriodCount; i++) { - builder.append(mPeriodRxData[i]); - builder.append(":"); - } - for(int i = 0; i < mPeriodCount; i++) { - builder.append(mPeriodTxData[i]); - builder.append(":"); - } - builder.append(mCurrentPeriod); - builder.append(":"); - builder.append(mPeriodStart.getTimeInMillis()); - builder.append(":"); - builder.append(mPeriodEnd.getTimeInMillis()); - - BufferedWriter out = null; - try { - out = new BufferedWriter(new FileWriter(getDataFile()), 256); - out.write(builder.toString()); - } catch (IOException e) { - Slog.e(TAG, "Error writing data file"); - return; - } finally { - if (out != null) { - try { - out.close(); - } catch (Exception e) {} - } - } - } - - private void retrieve() { - // clean out any old data first. If we fail to read we don't want old stuff - zeroData(0); - - File f = getDataFile(); - byte[] buffer; - FileInputStream s = null; - try { - buffer = new byte[(int)f.length()]; - s = new FileInputStream(f); - s.read(buffer); - } catch (IOException e) { - Slog.e(TAG, "Error reading data file"); - return; - } finally { - if (s != null) { - try { - s.close(); - } catch (Exception e) {} - } - } - String data = new String(buffer); - if (data == null || data.length() == 0) { - if (DBG) Slog.d(TAG, "data file empty"); - return; - } - String[] parsed = data.split(":"); - int parsedUsed = 0; - if (parsed.length < 6) { - Slog.e(TAG, "reading data file with insufficient length - ignoring"); - return; - } - - int periodCount; - long[] periodRxData; - long[] periodTxData; - int currentPeriod; - Calendar periodStart; - Calendar periodEnd; - try { - if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) { - Slog.e(TAG, "reading data file with bad version - ignoring"); - return; - } - - periodCount = Integer.parseInt(parsed[parsedUsed++]); - if (parsed.length != 5 + (2 * periodCount)) { - Slog.e(TAG, "reading data file with bad length (" + parsed.length + - " != " + (5 + (2 * periodCount)) + ") - ignoring"); - return; - } - periodRxData = new long[periodCount]; - for (int i = 0; i < periodCount; i++) { - periodRxData[i] = Long.parseLong(parsed[parsedUsed++]); - } - periodTxData = new long[periodCount]; - for (int i = 0; i < periodCount; i++) { - periodTxData[i] = Long.parseLong(parsed[parsedUsed++]); - } - - currentPeriod = Integer.parseInt(parsed[parsedUsed++]); - - periodStart = new GregorianCalendar(); - periodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++])); - periodEnd = new GregorianCalendar(); - periodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++])); - } catch (Exception e) { - Slog.e(TAG, "Error parsing data file - ignoring"); - return; - } - synchronized (mParent) { - mPeriodCount = periodCount; - mPeriodRxData = periodRxData; - mPeriodTxData = periodTxData; - mCurrentPeriod = currentPeriod; - mPeriodStart = periodStart; - mPeriodEnd = periodEnd; - } - } - - long getPeriodRx(int which) { - synchronized (mParent) { - if (which > mPeriodCount) return 0; - which = mCurrentPeriod - which; - if (which < 0) which += mPeriodCount; - return mPeriodRxData[which]; - } - } - long getPeriodTx(int which) { - synchronized (mParent) { - if (which > mPeriodCount) return 0; - which = mCurrentPeriod - which; - if (which < 0) which += mPeriodCount; - return mPeriodTxData[which]; - } - } - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump ThrottleService " + - "from from pid=" + Binder.getCallingPid() + ", uid=" + - Binder.getCallingUid()); - return; - } - pw.println(); - - pw.println("The threshold is " + mPolicyThreshold.get() + - ", after which you experince throttling to " + - mPolicyThrottleValue.get() + "kbps"); - pw.println("Current period is " + - (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " + - "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 + - " seconds."); - pw.println("Polling every " + mPolicyPollPeriodSec + " seconds"); - pw.println("Current Throttle Index is " + mThrottleIndex.get()); - pw.println("mMaxNtpCacheAge=" + mMaxNtpCacheAge); - - for (int i = 0; i < mRecorder.getPeriodCount(); i++) { - pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" + - mRecorder.getPeriodTx(i)); - } - } -} diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java deleted file mode 100644 index 569acee..0000000 --- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.eq; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.isA; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.reset; -import static org.easymock.EasyMock.verify; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.net.INetworkManagementEventObserver; -import android.net.NetworkStats; -import android.net.ThrottleManager; -import android.os.IBinder; -import android.os.INetworkManagementService; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.provider.Settings; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.Suppress; -import android.text.format.DateUtils; -import android.util.Log; -import android.util.TrustedTime; - -import java.util.concurrent.Future; - -/** - * Tests for {@link ThrottleService}. - */ -@LargeTest -public class ThrottleServiceTest extends AndroidTestCase { - private static final String TAG = "ThrottleServiceTest"; - - private static final long MB_IN_BYTES = 1024 * 1024; - - private static final int TEST_KBITPS = 222; - private static final int TEST_RESET_DAY = 11; - - private static final String TEST_IFACE = "test0"; - - private BroadcastInterceptingContext mWatchingContext; - private INetworkManagementService mMockNMService; - private TrustedTime mMockTime; - - private ThrottleService mThrottleService; - - @Override - public void setUp() throws Exception { - super.setUp(); - - mWatchingContext = new BroadcastInterceptingContext(getContext()); - - mMockNMService = createMock(INetworkManagementService.class); - mMockTime = createMock(TrustedTime.class); - - mThrottleService = new ThrottleService( - mWatchingContext, mMockNMService, mMockTime, TEST_IFACE); - } - - @Override - public void tearDown() throws Exception { - mWatchingContext = null; - mMockNMService = null; - - mThrottleService.shutdown(); - mThrottleService = null; - - clearThrottlePolicy(); - - super.tearDown(); - } - - public void testNoPolicyNotThrottled() throws Exception { - expectTimeCurrent(); - expectSystemReady(); - - // provide stats without policy, verify not throttled - expectGetInterfaceCounter(1 * MB_IN_BYTES, 2 * MB_IN_BYTES); - expectSetInterfaceThrottle(-1, -1); - - replay(mMockTime, mMockNMService); - systemReady(); - verify(mMockTime, mMockNMService); - } - - public void testUnderLimitNotThrottled() throws Exception { - setThrottlePolicy(200 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); - - expectTimeCurrent(); - expectSystemReady(); - - // provide stats under limits, and verify not throttled - expectGetInterfaceCounter(1 * MB_IN_BYTES, 2 * MB_IN_BYTES); - expectSetInterfaceThrottle(-1, -1); - - replay(mMockTime, mMockNMService); - systemReady(); - verify(mMockTime, mMockNMService); - } - - public void testOverLimitThrottled() throws Exception { - setThrottlePolicy(200 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); - - expectTimeCurrent(); - expectSystemReady(); - - // provide stats over limits, and verify throttled - expectGetInterfaceCounter(500 * MB_IN_BYTES, 600 * MB_IN_BYTES); - expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS); - - replay(mMockTime, mMockNMService); - systemReady(); - verify(mMockTime, mMockNMService); - } - - public void testUnderThenOverLimitThrottled() throws Exception { - setThrottlePolicy(201 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); - - expectTimeCurrent(); - expectSystemReady(); - - // provide stats right under 201MB limit, verify not throttled - expectGetInterfaceCounter(100 * MB_IN_BYTES, 100 * MB_IN_BYTES); - expectSetInterfaceThrottle(-1, -1); - - replay(mMockTime, mMockNMService); - systemReady(); - verify(mMockTime, mMockNMService); - reset(mMockTime, mMockNMService); - - expectTimeCurrent(); - - // adjust usage to bump over limit, verify throttle kicks in - expectGetInterfaceCounter(105 * MB_IN_BYTES, 100 * MB_IN_BYTES); - expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS); - - // and kick poll event which should throttle - replay(mMockTime, mMockNMService); - forceServicePoll(); - verify(mMockTime, mMockNMService); - } - - public void testUpdatedPolicyThrottled() throws Exception { - setThrottlePolicy(500 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); - - expectTimeCurrent(); - expectSystemReady(); - - // provide stats under limit, verify not throttled - expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES); - expectSetInterfaceThrottle(-1, -1); - - replay(mMockTime, mMockNMService); - systemReady(); - verify(mMockTime, mMockNMService); - reset(mMockTime, mMockNMService); - - expectTimeCurrent(); - - // provide same stats, but verify that modified policy will throttle - expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES); - expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS); - - replay(mMockTime, mMockNMService); - - // now adjust policy to bump usage over limit - setThrottlePolicy(5 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); - - // and wait for policy updated broadcast - mWatchingContext.nextBroadcastIntent(ThrottleManager.POLICY_CHANGED_ACTION).get(); - - verify(mMockTime, mMockNMService); - } - - public void testWithPolicyOverLimitThrottledAndRemovedAfterCycle() throws Exception { - setThrottlePolicy(90 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); - - final long baseTime = System.currentTimeMillis(); - - expectTime(baseTime); - expectSystemReady(); - - // provide stats over limit, verify throttle kicks in - expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES); - expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS); - - replay(mMockTime, mMockNMService); - systemReady(); - verify(mMockTime, mMockNMService); - reset(mMockTime, mMockNMService); - - // pretend that time has jumped forward two months - expectTime(baseTime + DateUtils.WEEK_IN_MILLIS * 8); - - // provide slightly updated stats, but verify throttle is removed - expectGetInterfaceCounter(60 * MB_IN_BYTES, 60 * MB_IN_BYTES); - expectSetInterfaceThrottle(-1, -1); - - // and kick poll event which should throttle - replay(mMockTime, mMockNMService); - forceServiceReset(); - verify(mMockTime, mMockNMService); - } - - @Suppress - public void testReturnStats() throws Exception { - final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - final INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b); - - // test is currently no-op, just exercises stats apis - Log.d(TAG, nmService.getNetworkStatsSummaryDev().toString()); - Log.d(TAG, nmService.getNetworkStatsSummaryXt().toString()); - Log.d(TAG, nmService.getNetworkStatsDetail().toString()); - } - - /** - * Persist the given {@link ThrottleService} policy into {@link Settings}. - */ - public void setThrottlePolicy(long thresholdBytes, int valueKbitps, int resetDay) { - final ContentResolver resolver = getContext().getContentResolver(); - Settings.Global.putLong(resolver, Settings.Global.THROTTLE_THRESHOLD_BYTES, thresholdBytes); - Settings.Global.putInt(resolver, Settings.Global.THROTTLE_VALUE_KBITSPS, valueKbitps); - Settings.Global.putInt(resolver, Settings.Global.THROTTLE_RESET_DAY, resetDay); - } - - /** - * Clear any {@link ThrottleService} policy from {@link Settings}. - */ - public void clearThrottlePolicy() { - final ContentResolver resolver = getContext().getContentResolver(); - Settings.Global.putString(resolver, Settings.Global.THROTTLE_THRESHOLD_BYTES, null); - Settings.Global.putString(resolver, Settings.Global.THROTTLE_VALUE_KBITSPS, null); - Settings.Global.putString(resolver, Settings.Global.THROTTLE_RESET_DAY, null); - } - - /** - * Expect any {@link TrustedTime} mock calls, and respond with - * {@link System#currentTimeMillis()}. - */ - public void expectTimeCurrent() throws Exception { - expectTime(System.currentTimeMillis()); - } - - /** - * Expect any {@link TrustedTime} mock calls, and respond with the given - * time in response to {@link TrustedTime#currentTimeMillis()}. - */ - public void expectTime(long currentTime) throws Exception { - expect(mMockTime.forceRefresh()).andReturn(false).anyTimes(); - expect(mMockTime.hasCache()).andReturn(true).anyTimes(); - expect(mMockTime.currentTimeMillis()).andReturn(currentTime).anyTimes(); - expect(mMockTime.getCacheAge()).andReturn(0L).anyTimes(); - expect(mMockTime.getCacheCertainty()).andReturn(0L).anyTimes(); - } - - /** - * Expect {@link ThrottleService#systemReady()} generated calls, such as - * connecting with {@link NetworkManagementService} mock. - */ - public void expectSystemReady() throws Exception { - mMockNMService.registerObserver(isA(INetworkManagementEventObserver.class)); - expectLastCall().atLeastOnce(); - } - - /** - * Expect {@link NetworkManagementService#getNetworkStatsSummaryDev()} mock - * calls, responding with the given counter values. - */ - public void expectGetInterfaceCounter(long rx, long tx) throws Exception { - // TODO: provide elapsedRealtime mock to match TimeAuthority - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); - stats.addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, rx, 0L, tx, 0L, 0); - - expect(mMockNMService.getNetworkStatsSummaryDev()).andReturn(stats).atLeastOnce(); - } - - /** - * Expect {@link NetworkManagementService#setInterfaceThrottle} mock call - * with the specified parameters. - */ - public void expectSetInterfaceThrottle(int rx, int tx) throws Exception { - mMockNMService.setInterfaceThrottle(isA(String.class), eq(rx), eq(tx)); - expectLastCall().atLeastOnce(); - } - - /** - * Dispatch {@link ThrottleService#systemReady()} and block until finished. - */ - public void systemReady() throws Exception { - final Future<Intent> policyChanged = mWatchingContext.nextBroadcastIntent( - ThrottleManager.POLICY_CHANGED_ACTION); - final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent( - ThrottleManager.THROTTLE_POLL_ACTION); - - mThrottleService.systemReady(); - - // wait for everything to settle; for policy to update and for first poll - policyChanged.get(); - pollAction.get(); - } - - /** - * Dispatch {@link ThrottleService#dispatchPoll()} and block until finished. - */ - public void forceServicePoll() throws Exception { - // during systemReady() service already pushed a sticky broadcast, so we - // need to skip the immediate and wait for the updated sticky. - final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent( - ThrottleManager.THROTTLE_POLL_ACTION); - - mThrottleService.dispatchPoll(); - - pollAction.get(); - } - - /** - * Dispatch {@link ThrottleService#dispatchReset()} and block until finished. - */ - public void forceServiceReset() throws Exception { - // during systemReady() service already pushed a sticky broadcast, so we - // need to skip the immediate and wait for the updated sticky. - final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent( - ThrottleManager.THROTTLE_POLL_ACTION); - - mThrottleService.dispatchReset(); - - pollAction.get(); - } -} |