blob: 98e6dc0212c7aa02e07a4bd2403d00030324d865 [file] [log] [blame]
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.AlarmManager;
20import android.app.Notification;
21import android.app.NotificationManager;
22import android.app.PendingIntent;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070023import android.content.BroadcastReceiver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -070024import android.content.ContentResolver;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070025import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.PackageManager;
29import android.content.res.Resources;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -070030import android.database.ContentObserver;
Robert Greenwaltfee46832010-05-06 12:25:13 -070031import android.net.INetworkManagementEventObserver;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070032import android.net.IThrottleManager;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070033import android.net.NetworkStats;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070034import android.net.ThrottleManager;
35import android.os.Binder;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070036import android.os.Environment;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070037import android.os.Handler;
38import android.os.HandlerThread;
39import android.os.IBinder;
40import android.os.INetworkManagementService;
41import android.os.Looper;
42import android.os.Message;
43import android.os.RemoteException;
44import android.os.ServiceManager;
45import android.os.SystemClock;
46import android.os.SystemProperties;
47import android.provider.Settings;
Robert Greenwalte6e98822010-04-15 08:27:14 -070048import android.telephony.TelephonyManager;
Robert Greenwaltfee46832010-05-06 12:25:13 -070049import android.text.TextUtils;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070050import android.util.NtpTrustedTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070051import android.util.Slog;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070052import android.util.TrustedTime;
Robert Greenwalt5f996892010-04-08 16:19:24 -070053
Jeff Sharkey104344e2011-07-10 14:20:41 -070054import com.android.internal.R;
55import com.android.internal.telephony.TelephonyProperties;
56
Robert Greenwaltb8912f52010-04-09 17:27:26 -070057import java.io.BufferedWriter;
58import java.io.File;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070059import java.io.FileDescriptor;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070060import java.io.FileInputStream;
61import java.io.FileWriter;
62import java.io.IOException;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070063import java.io.PrintWriter;
64import java.util.Calendar;
65import java.util.GregorianCalendar;
66import java.util.Random;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070067import java.util.concurrent.atomic.AtomicInteger;
68import java.util.concurrent.atomic.AtomicLong;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070069
70// TODO - add comments - reference the ThrottleManager for public API
71public class ThrottleService extends IThrottleManager.Stub {
72
73 private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
74
75 private static final String TAG = "ThrottleService";
Robert Greenwaltbf7de392010-04-21 17:09:38 -070076 private static final boolean DBG = true;
77 private static final boolean VDBG = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070078 private Handler mHandler;
79 private HandlerThread mThread;
80
81 private Context mContext;
82
Robert Greenwaltfb9896b2010-04-22 15:39:38 -070083 private static final int INITIAL_POLL_DELAY_SEC = 90;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070084 private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070085 private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070086 private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070087
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070088 private static final long MAX_NTP_CACHE_AGE = 24 * 60 * 60 * 1000;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070089
90 private long mMaxNtpCacheAge = MAX_NTP_CACHE_AGE;
91
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070092 private int mPolicyPollPeriodSec;
Robert Greenwalt39e163f2010-05-07 16:52:17 -070093 private AtomicLong mPolicyThreshold;
94 private AtomicInteger mPolicyThrottleValue;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070095 private int mPolicyResetDay; // 1-28
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070096 private int mPolicyNotificationsAllowedMask;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070097
98 private long mLastRead; // read byte count from last poll
99 private long mLastWrite; // write byte count from last poll
100
101 private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
102 private static int POLL_REQUEST = 0;
103 private PendingIntent mPendingPollIntent;
104 private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
105 private static int RESET_REQUEST = 1;
106 private PendingIntent mPendingResetIntent;
107
108 private INetworkManagementService mNMService;
109 private AlarmManager mAlarmManager;
110 private NotificationManager mNotificationManager;
111
112 private DataRecorder mRecorder;
113
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700114 private String mIface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700115
116 private static final int NOTIFICATION_WARNING = 2;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700117
118 private Notification mThrottlingNotification;
119 private boolean mWarningNotificationSent = false;
120
Robert Greenwaltfee46832010-05-06 12:25:13 -0700121 private InterfaceObserver mInterfaceObserver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700122 private SettingsObserver mSettingsObserver;
123
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700124 private AtomicInteger mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700125 private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
126 private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
127
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700128 private Intent mPollStickyBroadcast;
129
130 private TrustedTime mTime;
131
132 private static INetworkManagementService getNetworkManagementService() {
133 final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
134 return INetworkManagementService.Stub.asInterface(b);
135 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700136
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700137 public ThrottleService(Context context) {
Jeff Sharkey104344e2011-07-10 14:20:41 -0700138 this(context, getNetworkManagementService(), NtpTrustedTime.getInstance(context),
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700139 context.getResources().getString(R.string.config_datause_iface));
140 }
141
142 public ThrottleService(Context context, INetworkManagementService nmService, TrustedTime time,
143 String iface) {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700144 if (VDBG) Slog.v(TAG, "Starting ThrottleService");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700145 mContext = context;
146
Robert Greenwalt24488bd2010-05-10 16:56:43 -0700147 mPolicyThreshold = new AtomicLong();
148 mPolicyThrottleValue = new AtomicInteger();
149 mThrottleIndex = new AtomicInteger();
150
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700151 mIface = iface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700152 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
153 Intent pollIntent = new Intent(ACTION_POLL, null);
154 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
155 Intent resetIntent = new Intent(ACTION_RESET, null);
156 mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
157
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700158 mNMService = nmService;
159 mTime = time;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700160
161 mNotificationManager = (NotificationManager)mContext.getSystemService(
162 Context.NOTIFICATION_SERVICE);
163 }
164
Robert Greenwaltfee46832010-05-06 12:25:13 -0700165 private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
166 private int mMsg;
167 private Handler mHandler;
168 private String mIface;
169
170 InterfaceObserver(Handler handler, int msg, String iface) {
171 super();
172 mHandler = handler;
173 mMsg = msg;
174 mIface = iface;
175 }
176
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700177 public void interfaceStatusChanged(String iface, boolean up) {
178 if (up) {
Robert Greenwaltfee46832010-05-06 12:25:13 -0700179 if (TextUtils.equals(iface, mIface)) {
180 mHandler.obtainMessage(mMsg).sendToTarget();
181 }
182 }
183 }
184
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700185 public void interfaceLinkStateChanged(String iface, boolean up) {
186 }
187
Robert Greenwaltfee46832010-05-06 12:25:13 -0700188 public void interfaceAdded(String iface) {
189 // TODO - an interface added in the UP state should also trigger a StatusChanged
190 // notification..
191 if (TextUtils.equals(iface, mIface)) {
192 mHandler.obtainMessage(mMsg).sendToTarget();
193 }
194 }
195
196 public void interfaceRemoved(String iface) {}
JP Abgrall12b933d2011-07-14 18:09:22 -0700197 public void limitReached(String limitName, String iface) {}
Haoyu Baidb3c8672012-06-20 14:29:57 -0700198 public void interfaceClassDataActivityChanged(String label, boolean active) {}
Robert Greenwaltfee46832010-05-06 12:25:13 -0700199 }
200
201
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700202 private static class SettingsObserver extends ContentObserver {
203 private int mMsg;
204 private Handler mHandler;
205 SettingsObserver(Handler handler, int msg) {
206 super(handler);
207 mHandler = handler;
208 mMsg = msg;
209 }
210
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700211 void register(Context context) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700212 ContentResolver resolver = context.getContentResolver();
213 resolver.registerContentObserver(Settings.Secure.getUriFor(
214 Settings.Secure.THROTTLE_POLLING_SEC), false, this);
215 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700216 Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700217 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700218 Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700219 resolver.registerContentObserver(Settings.Secure.getUriFor(
220 Settings.Secure.THROTTLE_RESET_DAY), false, this);
221 resolver.registerContentObserver(Settings.Secure.getUriFor(
222 Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
223 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700224 Settings.Secure.THROTTLE_HELP_URI), false, this);
Robert Greenwaltd1055a22010-05-25 15:54:52 -0700225 resolver.registerContentObserver(Settings.Secure.getUriFor(
226 Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700227 }
228
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700229 void unregister(Context context) {
230 final ContentResolver resolver = context.getContentResolver();
231 resolver.unregisterContentObserver(this);
232 }
233
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700234 @Override
235 public void onChange(boolean selfChange) {
236 mHandler.obtainMessage(mMsg).sendToTarget();
237 }
238 }
239
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700240 private void enforceAccessPermission() {
241 mContext.enforceCallingOrSelfPermission(
242 android.Manifest.permission.ACCESS_NETWORK_STATE,
243 "ThrottleService");
244 }
245
Robert Greenwalt05d06732010-04-19 11:10:38 -0700246 private long ntpToWallTime(long ntpTime) {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700247 // get time quickly without worrying about trusted state
248 long bestNow = mTime.hasCache() ? mTime.currentTimeMillis()
249 : System.currentTimeMillis();
Robert Greenwalt05d06732010-04-19 11:10:38 -0700250 long localNow = System.currentTimeMillis();
251 return localNow + (ntpTime - bestNow);
252 }
253
Irfan Sheriffcf282362010-04-16 16:53:20 -0700254 // TODO - fetch for the iface
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700255 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt05d06732010-04-19 11:10:38 -0700256
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700257 public long getResetTime(String iface) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700258 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700259 long resetTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700260 if (mRecorder != null) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700261 resetTime = mRecorder.getPeriodEnd();
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700262 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700263 resetTime = ntpToWallTime(resetTime);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700264 return resetTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700265 }
Irfan Sheriffcf282362010-04-16 16:53:20 -0700266
267 // TODO - fetch for the iface
Robert Greenwalt05d06732010-04-19 11:10:38 -0700268 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700269 public long getPeriodStartTime(String iface) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700270 long startTime = 0;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700271 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700272 if (mRecorder != null) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700273 startTime = mRecorder.getPeriodStart();
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700274 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700275 startTime = ntpToWallTime(startTime);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700276 return startTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700277 }
278 //TODO - a better name? getCliffByteCountThreshold?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700279 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700280 public long getCliffThreshold(String iface, int cliff) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700281 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700282 if (cliff == 1) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700283 return mPolicyThreshold.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700284 }
285 return 0;
286 }
287 // TODO - a better name? getThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700288 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700289 public int getCliffLevel(String iface, int cliff) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700290 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700291 if (cliff == 1) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700292 return mPolicyThrottleValue.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700293 }
294 return 0;
295 }
296
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700297 public String getHelpUri() {
298 enforceAccessPermission();
299 return Settings.Secure.getString(mContext.getContentResolver(),
300 Settings.Secure.THROTTLE_HELP_URI);
301 }
302
Irfan Sheriffcf282362010-04-16 16:53:20 -0700303 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700304 public long getByteCount(String iface, int dir, int period, int ago) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700305 enforceAccessPermission();
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700306 if ((period == ThrottleManager.PERIOD_CYCLE) && (mRecorder != null)) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700307 if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
308 if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
309 }
310 return 0;
311 }
312
313 // TODO - a better name - getCurrentThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700314 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700315 public int getThrottle(String iface) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700316 enforceAccessPermission();
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700317 if (mThrottleIndex.get() == 1) {
318 return mPolicyThrottleValue.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700319 }
320 return 0;
321 }
322
323 void systemReady() {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700324 if (VDBG) Slog.v(TAG, "systemReady");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700325 mContext.registerReceiver(
326 new BroadcastReceiver() {
327 @Override
328 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700329 dispatchPoll();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700330 }
331 }, new IntentFilter(ACTION_POLL));
332
333 mContext.registerReceiver(
334 new BroadcastReceiver() {
335 @Override
336 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700337 dispatchReset();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700338 }
339 }, new IntentFilter(ACTION_RESET));
340
Robert Greenwaltc76c15e2010-06-16 14:42:16 -0700341 // use a new thread as we don't want to stall the system for file writes
342 mThread = new HandlerThread(TAG);
343 mThread.start();
344 mHandler = new MyHandler(mThread.getLooper());
345 mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
346
347 mInterfaceObserver = new InterfaceObserver(mHandler, EVENT_IFACE_UP, mIface);
348 try {
349 mNMService.registerObserver(mInterfaceObserver);
350 } catch (RemoteException e) {
351 Slog.e(TAG, "Could not register InterfaceObserver " + e);
352 }
353
354 mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700355 mSettingsObserver.register(mContext);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700356 }
357
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700358 void shutdown() {
359 // TODO: eventually connect with ShutdownThread to persist stats during
360 // graceful shutdown.
361
362 if (mThread != null) {
363 mThread.quit();
364 }
365
366 if (mSettingsObserver != null) {
367 mSettingsObserver.unregister(mContext);
368 }
369
370 if (mPollStickyBroadcast != null) {
371 mContext.removeStickyBroadcast(mPollStickyBroadcast);
372 }
373 }
374
375 void dispatchPoll() {
376 mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
377 }
378
379 void dispatchReset() {
380 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
381 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700382
383 private static final int EVENT_REBOOT_RECOVERY = 0;
384 private static final int EVENT_POLICY_CHANGED = 1;
385 private static final int EVENT_POLL_ALARM = 2;
386 private static final int EVENT_RESET_ALARM = 3;
Robert Greenwaltfee46832010-05-06 12:25:13 -0700387 private static final int EVENT_IFACE_UP = 4;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700388 private class MyHandler extends Handler {
389 public MyHandler(Looper l) {
390 super(l);
391 }
392
393 @Override
394 public void handleMessage(Message msg) {
395 switch (msg.what) {
396 case EVENT_REBOOT_RECOVERY:
397 onRebootRecovery();
398 break;
399 case EVENT_POLICY_CHANGED:
400 onPolicyChanged();
401 break;
402 case EVENT_POLL_ALARM:
403 onPollAlarm();
404 break;
405 case EVENT_RESET_ALARM:
406 onResetAlarm();
Robert Greenwaltfee46832010-05-06 12:25:13 -0700407 break;
408 case EVENT_IFACE_UP:
409 onIfaceUp();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700410 }
411 }
412
413 private void onRebootRecovery() {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700414 if (VDBG) Slog.v(TAG, "onRebootRecovery");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700415 // check for sim change TODO
416 // reregister for notification of policy change
417
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700418 mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700419
420 mRecorder = new DataRecorder(mContext, ThrottleService.this);
421
422 // get policy
423 mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
Robert Greenwaltfb9896b2010-04-22 15:39:38 -0700424
425 // if we poll now we won't have network connectivity or even imsi access
426 // queue up a poll to happen in a little while - after ntp and imsi are avail
427 // TODO - make this callback based (ie, listen for notificaitons)
428 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_POLL_ALARM),
429 INITIAL_POLL_DELAY_SEC * 1000);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700430 }
431
432 // check for new policy info (threshold limit/value/etc)
433 private void onPolicyChanged() {
434 boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
435
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700436 int pollingPeriod = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700437 R.integer.config_datause_polling_period_sec);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700438 mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
439 Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
440
441 // TODO - remove testing stuff?
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700442 long defaultThreshold = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700443 R.integer.config_datause_threshold_bytes);
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700444 int defaultValue = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700445 R.integer.config_datause_throttle_kbitsps);
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700446 long threshold = Settings.Secure.getLong(mContext.getContentResolver(),
447 Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
448 int value = Settings.Secure.getInt(mContext.getContentResolver(),
449 Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
450
451 mPolicyThreshold.set(threshold);
452 mPolicyThrottleValue.set(value);
453 if (testing) {
454 mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
455 mPolicyThreshold.set(TESTING_THRESHOLD);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700456 }
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700457
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700458 mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
459 Settings.Secure.THROTTLE_RESET_DAY, -1);
460 if (mPolicyResetDay == -1 ||
461 ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
462 Random g = new Random();
463 mPolicyResetDay = 1 + g.nextInt(28); // 1-28
464 Settings.Secure.putInt(mContext.getContentResolver(),
465 Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
466 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700467 if (mIface == null) {
468 mPolicyThreshold.set(0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700469 }
470
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700471 int defaultNotificationType = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700472 R.integer.config_datause_notification_type);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700473 mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700474 Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700475
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700476 final int maxNtpCacheAgeSec = Settings.Secure.getInt(mContext.getContentResolver(),
477 Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC,
478 (int) (MAX_NTP_CACHE_AGE / 1000));
479 mMaxNtpCacheAge = maxNtpCacheAgeSec * 1000;
Robert Greenwaltd1055a22010-05-25 15:54:52 -0700480
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700481 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700482 Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" +
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700483 mPolicyPollPeriodSec + ", threshold=" + mPolicyThreshold.get() +
484 ", value=" + mPolicyThrottleValue.get() + ", resetDay=" + mPolicyResetDay +
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700485 ", noteType=" + mPolicyNotificationsAllowedMask + ", mMaxNtpCacheAge=" +
486 mMaxNtpCacheAge);
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700487 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700488
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700489 // force updates
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700490 mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700491
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700492 onResetAlarm();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700493
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700494 onPollAlarm();
495
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700496 Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
497 mContext.sendBroadcast(broadcast);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700498 }
499
500 private void onPollAlarm() {
501 long now = SystemClock.elapsedRealtime();
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700502 long next = now + mPolicyPollPeriodSec * 1000;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700503
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700504 // when trusted cache outdated, try refreshing
505 if (mTime.getCacheAge() > mMaxNtpCacheAge) {
506 if (mTime.forceRefresh()) {
507 if (VDBG) Slog.d(TAG, "updated trusted time, reseting alarm");
508 dispatchReset();
509 }
510 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700511
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700512 long incRead = 0;
513 long incWrite = 0;
514 try {
Jeff Sharkeye8914c32012-05-01 16:26:09 -0700515 final NetworkStats stats = mNMService.getNetworkStatsSummaryDev();
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700516 final int index = stats.findIndex(mIface, NetworkStats.UID_ALL,
517 NetworkStats.SET_DEFAULT, NetworkStats.TAG_NONE);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700518
519 if (index != -1) {
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700520 final NetworkStats.Entry entry = stats.getValues(index, null);
521 incRead = entry.rxBytes - mLastRead;
522 incWrite = entry.txBytes - mLastWrite;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700523 } else {
524 // missing iface, assume stats are 0
525 Slog.w(TAG, "unable to find stats for iface " + mIface);
526 }
527
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700528 // handle iface resets - on some device the 3g iface comes and goes and gets
529 // totals reset to 0. Deal with it
530 if ((incRead < 0) || (incWrite < 0)) {
531 incRead += mLastRead;
532 incWrite += mLastWrite;
533 mLastRead = 0;
534 mLastWrite = 0;
535 }
Jeff Sharkey558a2322011-08-24 15:42:09 -0700536 } catch (IllegalStateException e) {
537 Slog.e(TAG, "problem during onPollAlarm: " + e);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700538 } catch (RemoteException e) {
Jeff Sharkey558a2322011-08-24 15:42:09 -0700539 Slog.e(TAG, "problem during onPollAlarm: " + e);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700540 }
Jeff Sharkey558a2322011-08-24 15:42:09 -0700541
Robert Greenwalt5f996892010-04-08 16:19:24 -0700542 // don't count this data if we're roaming.
543 boolean roaming = "true".equals(
544 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
545 if (!roaming) {
546 mRecorder.addData(incRead, incWrite);
547 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700548
549 long periodRx = mRecorder.getPeriodRx(0);
550 long periodTx = mRecorder.getPeriodTx(0);
551 long total = periodRx + periodTx;
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700552 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700553 Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
Robert Greenwalt5f996892010-04-08 16:19:24 -0700554 ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700555 }
556 mLastRead += incRead;
557 mLastWrite += incWrite;
558
559 checkThrottleAndPostNotification(total);
560
561 Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
562 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
563 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700564 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
565 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700566 mContext.sendStickyBroadcast(broadcast);
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700567 mPollStickyBroadcast = broadcast;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700568
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700569 mAlarmManager.cancel(mPendingPollIntent);
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700570 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700571 }
572
Robert Greenwaltfee46832010-05-06 12:25:13 -0700573 private void onIfaceUp() {
574 // if we were throttled before, be sure and set it again - the iface went down
575 // (and may have disappeared all together) and these settings were lost
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700576 if (mThrottleIndex.get() == 1) {
Robert Greenwaltfee46832010-05-06 12:25:13 -0700577 try {
578 mNMService.setInterfaceThrottle(mIface, -1, -1);
579 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700580 mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
Robert Greenwaltfee46832010-05-06 12:25:13 -0700581 } catch (Exception e) {
582 Slog.e(TAG, "error setting Throttle: " + e);
583 }
584 }
585 }
586
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700587 private void checkThrottleAndPostNotification(long currentTotal) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700588 // is throttling enabled?
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700589 long threshold = mPolicyThreshold.get();
590 if (threshold == 0) {
Robert Greenwaltcce83372010-04-23 17:35:29 -0700591 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700592 return;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700593 }
594
595 // have we spoken with an ntp server yet?
596 // this is controversial, but we'd rather err towards not throttling
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700597 if (!mTime.hasCache()) {
598 Slog.w(TAG, "missing trusted time, skipping throttle check");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700599 return;
600 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700601
602 // check if we need to throttle
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700603 if (currentTotal > threshold) {
604 if (mThrottleIndex.get() != 1) {
605 mThrottleIndex.set(1);
606 if (DBG) Slog.d(TAG, "Threshold " + threshold + " exceeded!");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700607 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700608 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700609 mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700610 } catch (Exception e) {
611 Slog.e(TAG, "error setting Throttle: " + e);
612 }
613
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700614 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700615
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700616 postNotification(R.string.throttled_notification_title,
617 R.string.throttled_notification_message,
618 R.drawable.stat_sys_throttled,
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700619 Notification.FLAG_ONGOING_EVENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700620
621 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700622 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL,
623 mPolicyThrottleValue.get());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700624 mContext.sendStickyBroadcast(broadcast);
625
626 } // else already up!
627 } else {
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700628 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700629 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
630 // check if we should warn about throttle
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700631 // pretend we only have 1/2 the time remaining that we actually do
632 // if our burn rate in the period so far would have us exceed the limit
633 // in that 1/2 window, warn the user.
634 // this gets more generous in the early to middle period and converges back
635 // to the limit as we move toward the period end.
636
637 // adding another factor - it must be greater than the total cap/4
638 // else we may get false alarms very early in the period.. in the first
639 // tenth of a percent of the period if we used more than a tenth of a percent
640 // of the cap we'd get a warning and that's not desired.
641 long start = mRecorder.getPeriodStart();
642 long end = mRecorder.getPeriodEnd();
643 long periodLength = end - start;
644 long now = System.currentTimeMillis();
645 long timeUsed = now - start;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700646 long warningThreshold = 2*threshold*timeUsed/(timeUsed+periodLength);
647 if ((currentTotal > warningThreshold) && (currentTotal > threshold/4)) {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700648 if (mWarningNotificationSent == false) {
649 mWarningNotificationSent = true;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700650 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
651 postNotification(R.string.throttle_warning_notification_title,
652 R.string.throttle_warning_notification_message,
653 R.drawable.stat_sys_throttled,
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700654 0);
655 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700656 } else {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700657 if (mWarningNotificationSent == true) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700658 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700659 mWarningNotificationSent =false;
660 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700661 }
662 }
663 }
664 }
665
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700666 private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700667 Intent intent = new Intent();
668 // TODO - fix up intent
Robert Greenwalt2a7b7302010-04-12 14:56:31 -0700669 intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700670 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
671
672 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
673
674 Resources r = Resources.getSystem();
675 CharSequence title = r.getText(titleInt);
676 CharSequence message = r.getText(messageInt);
677 if (mThrottlingNotification == null) {
678 mThrottlingNotification = new Notification();
679 mThrottlingNotification.when = 0;
680 // TODO - fixup icon
681 mThrottlingNotification.icon = icon;
682 mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700683 }
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700684 mThrottlingNotification.flags = flags;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700685 mThrottlingNotification.tickerText = title;
686 mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
687
688 mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
689 }
690
691
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700692 private void clearThrottleAndNotification() {
693 if (mThrottleIndex.get() != THROTTLE_INDEX_UNTHROTTLED) {
694 mThrottleIndex.set(THROTTLE_INDEX_UNTHROTTLED);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700695 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700696 mNMService.setInterfaceThrottle(mIface, -1, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700697 } catch (Exception e) {
698 Slog.e(TAG, "error clearing Throttle: " + e);
699 }
700 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
701 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
702 mContext.sendStickyBroadcast(broadcast);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700703 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
704 mWarningNotificationSent = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700705 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700706 }
707
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700708 private Calendar calculatePeriodEnd(long now) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700709 Calendar end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700710 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700711 int day = end.get(Calendar.DAY_OF_MONTH);
712 end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
713 end.set(Calendar.HOUR_OF_DAY, 0);
714 end.set(Calendar.MINUTE, 0);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700715 end.set(Calendar.SECOND, 0);
716 end.set(Calendar.MILLISECOND, 0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700717 if (day >= mPolicyResetDay) {
718 int month = end.get(Calendar.MONTH);
719 if (month == Calendar.DECEMBER) {
720 end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
721 month = Calendar.JANUARY - 1;
722 }
723 end.set(Calendar.MONTH, month + 1);
724 }
725
726 // TODO - remove!
727 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
728 end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700729 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700730 end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
731 }
732 return end;
733 }
734 private Calendar calculatePeriodStart(Calendar end) {
735 Calendar start = (Calendar)end.clone();
736 int month = end.get(Calendar.MONTH);
737 if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
738 month = Calendar.DECEMBER + 1;
739 start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
740 }
741 start.set(Calendar.MONTH, month - 1);
742
743 // TODO - remove!!
744 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
745 start = (Calendar)end.clone();
746 start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
747 }
748 return start;
749 }
750
751 private void onResetAlarm() {
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700752 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700753 Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
754 " bytes read and " + mRecorder.getPeriodTx(0) + " written");
755 }
756
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700757 // when trusted cache outdated, try refreshing
758 if (mTime.getCacheAge() > mMaxNtpCacheAge) {
759 mTime.forceRefresh();
760 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700761
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700762 // as long as we have a trusted time cache, we always reset alarms,
763 // even if the refresh above failed.
764 if (mTime.hasCache()) {
765 final long now = mTime.currentTimeMillis();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700766 Calendar end = calculatePeriodEnd(now);
767 Calendar start = calculatePeriodStart(end);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700768
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700769 if (mRecorder.setNextPeriod(start, end)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700770 onPollAlarm();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700771 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700772
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700773 mAlarmManager.cancel(mPendingResetIntent);
774 long offset = end.getTimeInMillis() - now;
775 // use Elapsed realtime so clock changes don't fool us.
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700776 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME,
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700777 SystemClock.elapsedRealtime() + offset,
778 mPendingResetIntent);
779 } else {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700780 if (VDBG) Slog.d(TAG, "no trusted time, not resetting period");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700781 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700782 }
783 }
784
785 // records bytecount data for a given time and accumulates it into larger time windows
786 // for logging and other purposes
787 //
788 // since time can be changed (user or network action) we will have to track the time of the
789 // last recording and deal with it.
790 private static class DataRecorder {
791 long[] mPeriodRxData;
792 long[] mPeriodTxData;
793 int mCurrentPeriod;
794 int mPeriodCount;
795
796 Calendar mPeriodStart;
797 Calendar mPeriodEnd;
798
799 ThrottleService mParent;
800 Context mContext;
Robert Greenwalte6e98822010-04-15 08:27:14 -0700801 String mImsi = null;
802
803 TelephonyManager mTelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700804
805 DataRecorder(Context context, ThrottleService parent) {
806 mContext = context;
807 mParent = parent;
808
Robert Greenwalte6e98822010-04-15 08:27:14 -0700809 mTelephonyManager = (TelephonyManager)mContext.getSystemService(
810 Context.TELEPHONY_SERVICE);
811
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700812 synchronized (mParent) {
813 mPeriodCount = 6;
814 mPeriodRxData = new long[mPeriodCount];
815 mPeriodTxData = new long[mPeriodCount];
816
817 mPeriodStart = Calendar.getInstance();
818 mPeriodEnd = Calendar.getInstance();
819
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700820 retrieve();
821 }
822 }
823
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700824 boolean setNextPeriod(Calendar start, Calendar end) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700825 // TODO - how would we deal with a dual-IMSI device?
826 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700827 boolean startNewPeriod = true;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700828
Robert Greenwalt27fba672010-04-26 12:29:14 -0700829 if (start.equals(mPeriodStart) && end.equals(mPeriodEnd)) {
830 // same endpoints - keep collecting
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700831 if (VDBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700832 Slog.d(TAG, "same period (" + start.getTimeInMillis() + "," +
833 end.getTimeInMillis() +") - ammending data");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700834 }
Robert Greenwalt27fba672010-04-26 12:29:14 -0700835 startNewPeriod = false;
836 } else {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700837 if (VDBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700838 if(start.equals(mPeriodEnd) || start.after(mPeriodEnd)) {
839 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
840 end.getTimeInMillis() + ") - old end was " +
841 mPeriodEnd.getTimeInMillis() + ", following");
842 } else {
843 Slog.d(TAG, "new period (" + start.getTimeInMillis() + "," +
844 end.getTimeInMillis() + ") replacing old (" +
845 mPeriodStart.getTimeInMillis() + "," +
846 mPeriodEnd.getTimeInMillis() + ")");
847 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700848 }
849 synchronized (mParent) {
850 ++mCurrentPeriod;
851 if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
852 mPeriodRxData[mCurrentPeriod] = 0;
853 mPeriodTxData[mCurrentPeriod] = 0;
854 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700855 }
856 setPeriodStart(start);
857 setPeriodEnd(end);
858 record();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700859 return startNewPeriod;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700860 }
861
862 public long getPeriodEnd() {
863 synchronized (mParent) {
864 return mPeriodEnd.getTimeInMillis();
865 }
866 }
867
868 private void setPeriodEnd(Calendar end) {
869 synchronized (mParent) {
870 mPeriodEnd = end;
871 }
872 }
873
874 public long getPeriodStart() {
875 synchronized (mParent) {
876 return mPeriodStart.getTimeInMillis();
877 }
878 }
879
880 private void setPeriodStart(Calendar start) {
881 synchronized (mParent) {
882 mPeriodStart = start;
883 }
884 }
885
886 public int getPeriodCount() {
887 synchronized (mParent) {
888 return mPeriodCount;
889 }
890 }
891
892 private void zeroData(int field) {
893 synchronized (mParent) {
894 for(int period = 0; period<mPeriodCount; period++) {
895 mPeriodRxData[period] = 0;
896 mPeriodTxData[period] = 0;
897 }
898 mCurrentPeriod = 0;
899 }
900
901 }
902
903 // if time moves backward accumulate all read/write that's lost into the now
904 // otherwise time moved forward.
905 void addData(long bytesRead, long bytesWritten) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700906 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700907
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700908 synchronized (mParent) {
909 mPeriodRxData[mCurrentPeriod] += bytesRead;
910 mPeriodTxData[mCurrentPeriod] += bytesWritten;
911 }
912 record();
913 }
914
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700915 private File getDataFile() {
916 File dataDir = Environment.getDataDirectory();
917 File throttleDir = new File(dataDir, "system/throttle");
918 throttleDir.mkdirs();
Robert Greenwalte6e98822010-04-15 08:27:14 -0700919 String mImsi = mTelephonyManager.getSubscriberId();
920 File dataFile;
921 if (mImsi == null) {
922 dataFile = useMRUFile(throttleDir);
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700923 if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700924 } else {
925 String imsiHash = Integer.toString(mImsi.hashCode());
926 dataFile = new File(throttleDir, imsiHash);
927 }
928 // touch the file so it's not LRU
929 dataFile.setLastModified(System.currentTimeMillis());
930 checkAndDeleteLRUDataFile(throttleDir);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700931 return dataFile;
932 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700933
Robert Greenwalte6e98822010-04-15 08:27:14 -0700934 // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
935 private void checkForSubscriberId() {
936 if (mImsi != null) return;
937
938 mImsi = mTelephonyManager.getSubscriberId();
939 if (mImsi == null) return;
940
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700941 if (VDBG) Slog.d(TAG, "finally have imsi - retreiving data");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700942 retrieve();
943 }
944
945 private final static int MAX_SIMS_SUPPORTED = 3;
946
947 private void checkAndDeleteLRUDataFile(File dir) {
948 File[] files = dir.listFiles();
949
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700950 if (files == null || files.length <= MAX_SIMS_SUPPORTED) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700951 if (DBG) Slog.d(TAG, "Too many data files");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700952 do {
953 File oldest = null;
954 for (File f : files) {
955 if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
956 oldest = f;
957 }
958 }
959 if (oldest == null) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700960 if (DBG) Slog.d(TAG, " deleting " + oldest);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700961 oldest.delete();
962 files = dir.listFiles();
963 } while (files.length > MAX_SIMS_SUPPORTED);
964 }
965
966 private File useMRUFile(File dir) {
967 File newest = null;
968 File[] files = dir.listFiles();
969
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700970 if (files != null) {
971 for (File f : files) {
972 if ((newest == null) || (newest.lastModified() < f.lastModified())) {
973 newest = f;
974 }
Robert Greenwalte6e98822010-04-15 08:27:14 -0700975 }
976 }
977 if (newest == null) {
978 newest = new File(dir, "temp");
979 }
980 return newest;
981 }
982
983
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700984 private static final int DATA_FILE_VERSION = 1;
985
986 private void record() {
987 // 1 int version
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700988 // 1 int mPeriodCount
989 // 13*6 long[PERIOD_COUNT] mPeriodRxData
990 // 13*6 long[PERIOD_COUNT] mPeriodTxData
991 // 1 int mCurrentPeriod
992 // 13 long periodStartMS
993 // 13 long periodEndMS
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700994 // 200 chars max
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700995 StringBuilder builder = new StringBuilder();
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700996 builder.append(DATA_FILE_VERSION);
997 builder.append(":");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700998 builder.append(mPeriodCount);
999 builder.append(":");
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001000 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001001 builder.append(mPeriodRxData[i]);
1002 builder.append(":");
1003 }
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001004 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001005 builder.append(mPeriodTxData[i]);
1006 builder.append(":");
1007 }
1008 builder.append(mCurrentPeriod);
1009 builder.append(":");
1010 builder.append(mPeriodStart.getTimeInMillis());
1011 builder.append(":");
1012 builder.append(mPeriodEnd.getTimeInMillis());
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001013
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001014 BufferedWriter out = null;
1015 try {
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001016 out = new BufferedWriter(new FileWriter(getDataFile()), 256);
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001017 out.write(builder.toString());
1018 } catch (IOException e) {
1019 Slog.e(TAG, "Error writing data file");
1020 return;
1021 } finally {
1022 if (out != null) {
1023 try {
1024 out.close();
1025 } catch (Exception e) {}
1026 }
1027 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001028 }
1029
1030 private void retrieve() {
Robert Greenwalt05d06732010-04-19 11:10:38 -07001031 // clean out any old data first. If we fail to read we don't want old stuff
1032 zeroData(0);
1033
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001034 File f = getDataFile();
1035 byte[] buffer;
1036 FileInputStream s = null;
1037 try {
1038 buffer = new byte[(int)f.length()];
1039 s = new FileInputStream(f);
1040 s.read(buffer);
1041 } catch (IOException e) {
1042 Slog.e(TAG, "Error reading data file");
1043 return;
1044 } finally {
1045 if (s != null) {
1046 try {
1047 s.close();
1048 } catch (Exception e) {}
1049 }
1050 }
1051 String data = new String(buffer);
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001052 if (data == null || data.length() == 0) {
1053 if (DBG) Slog.d(TAG, "data file empty");
1054 return;
1055 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001056 String[] parsed = data.split(":");
1057 int parsedUsed = 0;
1058 if (parsed.length < 6) {
1059 Slog.e(TAG, "reading data file with insufficient length - ignoring");
1060 return;
1061 }
1062
Robert Greenwalt9e3983f2010-05-11 07:06:13 -07001063 int periodCount;
1064 long[] periodRxData;
1065 long[] periodTxData;
1066 int currentPeriod;
1067 Calendar periodStart;
1068 Calendar periodEnd;
1069 try {
1070 if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
1071 Slog.e(TAG, "reading data file with bad version - ignoring");
1072 return;
1073 }
1074
1075 periodCount = Integer.parseInt(parsed[parsedUsed++]);
1076 if (parsed.length != 5 + (2 * periodCount)) {
1077 Slog.e(TAG, "reading data file with bad length (" + parsed.length +
1078 " != " + (5 + (2 * periodCount)) + ") - ignoring");
1079 return;
1080 }
1081 periodRxData = new long[periodCount];
1082 for (int i = 0; i < periodCount; i++) {
1083 periodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
1084 }
1085 periodTxData = new long[periodCount];
1086 for (int i = 0; i < periodCount; i++) {
1087 periodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
1088 }
1089
1090 currentPeriod = Integer.parseInt(parsed[parsedUsed++]);
1091
1092 periodStart = new GregorianCalendar();
1093 periodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1094 periodEnd = new GregorianCalendar();
1095 periodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1096 } catch (Exception e) {
1097 Slog.e(TAG, "Error parsing data file - ignoring");
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001098 return;
1099 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001100 synchronized (mParent) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001101 mPeriodCount = periodCount;
1102 mPeriodRxData = periodRxData;
1103 mPeriodTxData = periodTxData;
Robert Greenwalt9e3983f2010-05-11 07:06:13 -07001104 mCurrentPeriod = currentPeriod;
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001105 mPeriodStart = periodStart;
1106 mPeriodEnd = periodEnd;
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001107 }
1108 }
1109
1110 long getPeriodRx(int which) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001111 synchronized (mParent) {
1112 if (which > mPeriodCount) return 0;
1113 which = mCurrentPeriod - which;
1114 if (which < 0) which += mPeriodCount;
1115 return mPeriodRxData[which];
1116 }
1117 }
1118 long getPeriodTx(int which) {
1119 synchronized (mParent) {
1120 if (which > mPeriodCount) return 0;
1121 which = mCurrentPeriod - which;
1122 if (which < 0) which += mPeriodCount;
1123 return mPeriodTxData[which];
1124 }
1125 }
1126 }
1127
1128 @Override
1129 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1130 if (mContext.checkCallingOrSelfPermission(
1131 android.Manifest.permission.DUMP)
1132 != PackageManager.PERMISSION_GRANTED) {
1133 pw.println("Permission Denial: can't dump ThrottleService " +
1134 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1135 Binder.getCallingUid());
1136 return;
1137 }
1138 pw.println();
1139
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001140 pw.println("The threshold is " + mPolicyThreshold.get() +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001141 ", after which you experince throttling to " +
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001142 mPolicyThrottleValue.get() + "kbps");
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001143 pw.println("Current period is " +
1144 (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001145 "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001146 " seconds.");
1147 pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001148 pw.println("Current Throttle Index is " + mThrottleIndex.get());
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -07001149 pw.println("mMaxNtpCacheAge=" + mMaxNtpCacheAge);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -07001150
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001151 for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
1152 pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
1153 mRecorder.getPeriodTx(i));
1154 }
1155 }
1156}