blob: 75eb3c40d5b13a9da4644b85a17faa118625a781 [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;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070047import android.os.UserHandle;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070048import android.provider.Settings;
Robert Greenwalte6e98822010-04-15 08:27:14 -070049import android.telephony.TelephonyManager;
Robert Greenwaltfee46832010-05-06 12:25:13 -070050import android.text.TextUtils;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070051import android.util.NtpTrustedTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070052import android.util.Slog;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070053import android.util.TrustedTime;
Robert Greenwalt5f996892010-04-08 16:19:24 -070054
Jeff Sharkey104344e2011-07-10 14:20:41 -070055import com.android.internal.R;
56import com.android.internal.telephony.TelephonyProperties;
57
Robert Greenwaltb8912f52010-04-09 17:27:26 -070058import java.io.BufferedWriter;
59import java.io.File;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070060import java.io.FileDescriptor;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070061import java.io.FileInputStream;
62import java.io.FileWriter;
63import java.io.IOException;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070064import java.io.PrintWriter;
65import java.util.Calendar;
66import java.util.GregorianCalendar;
67import java.util.Random;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070068import java.util.concurrent.atomic.AtomicInteger;
69import java.util.concurrent.atomic.AtomicLong;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070070
71// TODO - add comments - reference the ThrottleManager for public API
72public class ThrottleService extends IThrottleManager.Stub {
73
74 private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
75
76 private static final String TAG = "ThrottleService";
Robert Greenwaltbf7de392010-04-21 17:09:38 -070077 private static final boolean DBG = true;
78 private static final boolean VDBG = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070079 private Handler mHandler;
80 private HandlerThread mThread;
81
82 private Context mContext;
83
Robert Greenwaltfb9896b2010-04-22 15:39:38 -070084 private static final int INITIAL_POLL_DELAY_SEC = 90;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070085 private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070086 private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070087 private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070088
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070089 private static final long MAX_NTP_CACHE_AGE = 24 * 60 * 60 * 1000;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070090
91 private long mMaxNtpCacheAge = MAX_NTP_CACHE_AGE;
92
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070093 private int mPolicyPollPeriodSec;
Robert Greenwalt39e163f2010-05-07 16:52:17 -070094 private AtomicLong mPolicyThreshold;
95 private AtomicInteger mPolicyThrottleValue;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070096 private int mPolicyResetDay; // 1-28
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070097 private int mPolicyNotificationsAllowedMask;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070098
99 private long mLastRead; // read byte count from last poll
100 private long mLastWrite; // write byte count from last poll
101
102 private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
103 private static int POLL_REQUEST = 0;
104 private PendingIntent mPendingPollIntent;
105 private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
106 private static int RESET_REQUEST = 1;
107 private PendingIntent mPendingResetIntent;
108
109 private INetworkManagementService mNMService;
110 private AlarmManager mAlarmManager;
111 private NotificationManager mNotificationManager;
112
113 private DataRecorder mRecorder;
114
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700115 private String mIface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700116
117 private static final int NOTIFICATION_WARNING = 2;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700118
119 private Notification mThrottlingNotification;
120 private boolean mWarningNotificationSent = false;
121
Robert Greenwaltfee46832010-05-06 12:25:13 -0700122 private InterfaceObserver mInterfaceObserver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700123 private SettingsObserver mSettingsObserver;
124
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700125 private AtomicInteger mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700126 private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
127 private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
128
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700129 private Intent mPollStickyBroadcast;
130
131 private TrustedTime mTime;
132
133 private static INetworkManagementService getNetworkManagementService() {
134 final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
135 return INetworkManagementService.Stub.asInterface(b);
136 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700137
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700138 public ThrottleService(Context context) {
Jeff Sharkey104344e2011-07-10 14:20:41 -0700139 this(context, getNetworkManagementService(), NtpTrustedTime.getInstance(context),
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700140 context.getResources().getString(R.string.config_datause_iface));
141 }
142
143 public ThrottleService(Context context, INetworkManagementService nmService, TrustedTime time,
144 String iface) {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700145 if (VDBG) Slog.v(TAG, "Starting ThrottleService");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700146 mContext = context;
147
Robert Greenwalt24488bd2010-05-10 16:56:43 -0700148 mPolicyThreshold = new AtomicLong();
149 mPolicyThrottleValue = new AtomicInteger();
150 mThrottleIndex = new AtomicInteger();
151
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700152 mIface = iface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700153 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
154 Intent pollIntent = new Intent(ACTION_POLL, null);
155 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
156 Intent resetIntent = new Intent(ACTION_RESET, null);
157 mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
158
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700159 mNMService = nmService;
160 mTime = time;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700161
162 mNotificationManager = (NotificationManager)mContext.getSystemService(
163 Context.NOTIFICATION_SERVICE);
164 }
165
Robert Greenwaltfee46832010-05-06 12:25:13 -0700166 private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
167 private int mMsg;
168 private Handler mHandler;
169 private String mIface;
170
171 InterfaceObserver(Handler handler, int msg, String iface) {
172 super();
173 mHandler = handler;
174 mMsg = msg;
175 mIface = iface;
176 }
177
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700178 public void interfaceStatusChanged(String iface, boolean up) {
179 if (up) {
Robert Greenwaltfee46832010-05-06 12:25:13 -0700180 if (TextUtils.equals(iface, mIface)) {
181 mHandler.obtainMessage(mMsg).sendToTarget();
182 }
183 }
184 }
185
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700186 public void interfaceLinkStateChanged(String iface, boolean up) {
187 }
188
Robert Greenwaltfee46832010-05-06 12:25:13 -0700189 public void interfaceAdded(String iface) {
190 // TODO - an interface added in the UP state should also trigger a StatusChanged
191 // notification..
192 if (TextUtils.equals(iface, mIface)) {
193 mHandler.obtainMessage(mMsg).sendToTarget();
194 }
195 }
196
197 public void interfaceRemoved(String iface) {}
JP Abgrall12b933d2011-07-14 18:09:22 -0700198 public void limitReached(String limitName, String iface) {}
Haoyu Baidb3c8672012-06-20 14:29:57 -0700199 public void interfaceClassDataActivityChanged(String label, boolean active) {}
Robert Greenwaltfee46832010-05-06 12:25:13 -0700200 }
201
202
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700203 private static class SettingsObserver extends ContentObserver {
204 private int mMsg;
205 private Handler mHandler;
206 SettingsObserver(Handler handler, int msg) {
207 super(handler);
208 mHandler = handler;
209 mMsg = msg;
210 }
211
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700212 void register(Context context) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700213 ContentResolver resolver = context.getContentResolver();
Jeff Sharkeybdfce2e2012-09-26 15:54:06 -0700214 resolver.registerContentObserver(Settings.Global.getUriFor(
215 Settings.Global.THROTTLE_POLLING_SEC), false, this);
216 resolver.registerContentObserver(Settings.Global.getUriFor(
217 Settings.Global.THROTTLE_THRESHOLD_BYTES), false, this);
218 resolver.registerContentObserver(Settings.Global.getUriFor(
219 Settings.Global.THROTTLE_VALUE_KBITSPS), false, this);
220 resolver.registerContentObserver(Settings.Global.getUriFor(
221 Settings.Global.THROTTLE_RESET_DAY), false, this);
222 resolver.registerContentObserver(Settings.Global.getUriFor(
223 Settings.Global.THROTTLE_NOTIFICATION_TYPE), false, this);
224 resolver.registerContentObserver(Settings.Global.getUriFor(
225 Settings.Global.THROTTLE_HELP_URI), false, this);
226 resolver.registerContentObserver(Settings.Global.getUriFor(
227 Settings.Global.THROTTLE_MAX_NTP_CACHE_AGE_SEC), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700228 }
229
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700230 void unregister(Context context) {
231 final ContentResolver resolver = context.getContentResolver();
232 resolver.unregisterContentObserver(this);
233 }
234
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700235 @Override
236 public void onChange(boolean selfChange) {
237 mHandler.obtainMessage(mMsg).sendToTarget();
238 }
239 }
240
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700241 private void enforceAccessPermission() {
242 mContext.enforceCallingOrSelfPermission(
243 android.Manifest.permission.ACCESS_NETWORK_STATE,
244 "ThrottleService");
245 }
246
Robert Greenwalt05d06732010-04-19 11:10:38 -0700247 private long ntpToWallTime(long ntpTime) {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700248 // get time quickly without worrying about trusted state
249 long bestNow = mTime.hasCache() ? mTime.currentTimeMillis()
250 : System.currentTimeMillis();
Robert Greenwalt05d06732010-04-19 11:10:38 -0700251 long localNow = System.currentTimeMillis();
252 return localNow + (ntpTime - bestNow);
253 }
254
Irfan Sheriffcf282362010-04-16 16:53:20 -0700255 // TODO - fetch for the iface
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700256 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt05d06732010-04-19 11:10:38 -0700257
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700258 public long getResetTime(String iface) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700259 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700260 long resetTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700261 if (mRecorder != null) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700262 resetTime = mRecorder.getPeriodEnd();
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700263 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700264 resetTime = ntpToWallTime(resetTime);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700265 return resetTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700266 }
Irfan Sheriffcf282362010-04-16 16:53:20 -0700267
268 // TODO - fetch for the iface
Robert Greenwalt05d06732010-04-19 11:10:38 -0700269 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700270 public long getPeriodStartTime(String iface) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700271 long startTime = 0;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700272 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700273 if (mRecorder != null) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700274 startTime = mRecorder.getPeriodStart();
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700275 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700276 startTime = ntpToWallTime(startTime);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700277 return startTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700278 }
279 //TODO - a better name? getCliffByteCountThreshold?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700280 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700281 public long getCliffThreshold(String iface, int cliff) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700282 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700283 if (cliff == 1) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700284 return mPolicyThreshold.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700285 }
286 return 0;
287 }
288 // TODO - a better name? getThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700289 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700290 public int getCliffLevel(String iface, int cliff) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700291 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700292 if (cliff == 1) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700293 return mPolicyThrottleValue.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700294 }
295 return 0;
296 }
297
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700298 public String getHelpUri() {
299 enforceAccessPermission();
Jeff Sharkeybdfce2e2012-09-26 15:54:06 -0700300 return Settings.Global.getString(mContext.getContentResolver(),
301 Settings.Global.THROTTLE_HELP_URI);
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700302 }
303
Irfan Sheriffcf282362010-04-16 16:53:20 -0700304 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700305 public long getByteCount(String iface, int dir, int period, int ago) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700306 enforceAccessPermission();
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700307 if ((period == ThrottleManager.PERIOD_CYCLE) && (mRecorder != null)) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700308 if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
309 if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
310 }
311 return 0;
312 }
313
314 // TODO - a better name - getCurrentThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700315 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700316 public int getThrottle(String iface) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700317 enforceAccessPermission();
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700318 if (mThrottleIndex.get() == 1) {
319 return mPolicyThrottleValue.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700320 }
321 return 0;
322 }
323
324 void systemReady() {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700325 if (VDBG) Slog.v(TAG, "systemReady");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700326 mContext.registerReceiver(
327 new BroadcastReceiver() {
328 @Override
329 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700330 dispatchPoll();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700331 }
332 }, new IntentFilter(ACTION_POLL));
333
334 mContext.registerReceiver(
335 new BroadcastReceiver() {
336 @Override
337 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700338 dispatchReset();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700339 }
340 }, new IntentFilter(ACTION_RESET));
341
Robert Greenwaltc76c15e2010-06-16 14:42:16 -0700342 // use a new thread as we don't want to stall the system for file writes
343 mThread = new HandlerThread(TAG);
344 mThread.start();
345 mHandler = new MyHandler(mThread.getLooper());
346 mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
347
348 mInterfaceObserver = new InterfaceObserver(mHandler, EVENT_IFACE_UP, mIface);
349 try {
350 mNMService.registerObserver(mInterfaceObserver);
351 } catch (RemoteException e) {
352 Slog.e(TAG, "Could not register InterfaceObserver " + e);
353 }
354
355 mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700356 mSettingsObserver.register(mContext);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700357 }
358
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700359 void shutdown() {
360 // TODO: eventually connect with ShutdownThread to persist stats during
361 // graceful shutdown.
362
363 if (mThread != null) {
364 mThread.quit();
365 }
366
367 if (mSettingsObserver != null) {
368 mSettingsObserver.unregister(mContext);
369 }
370
371 if (mPollStickyBroadcast != null) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700372 mContext.removeStickyBroadcastAsUser(mPollStickyBroadcast, UserHandle.ALL);
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700373 }
374 }
375
376 void dispatchPoll() {
377 mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
378 }
379
380 void dispatchReset() {
381 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
382 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700383
384 private static final int EVENT_REBOOT_RECOVERY = 0;
385 private static final int EVENT_POLICY_CHANGED = 1;
386 private static final int EVENT_POLL_ALARM = 2;
387 private static final int EVENT_RESET_ALARM = 3;
Robert Greenwaltfee46832010-05-06 12:25:13 -0700388 private static final int EVENT_IFACE_UP = 4;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700389 private class MyHandler extends Handler {
390 public MyHandler(Looper l) {
391 super(l);
392 }
393
394 @Override
395 public void handleMessage(Message msg) {
396 switch (msg.what) {
397 case EVENT_REBOOT_RECOVERY:
398 onRebootRecovery();
399 break;
400 case EVENT_POLICY_CHANGED:
401 onPolicyChanged();
402 break;
403 case EVENT_POLL_ALARM:
404 onPollAlarm();
405 break;
406 case EVENT_RESET_ALARM:
407 onResetAlarm();
Robert Greenwaltfee46832010-05-06 12:25:13 -0700408 break;
409 case EVENT_IFACE_UP:
410 onIfaceUp();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700411 }
412 }
413
414 private void onRebootRecovery() {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700415 if (VDBG) Slog.v(TAG, "onRebootRecovery");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700416 // check for sim change TODO
417 // reregister for notification of policy change
418
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700419 mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700420
421 mRecorder = new DataRecorder(mContext, ThrottleService.this);
422
423 // get policy
424 mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
Robert Greenwaltfb9896b2010-04-22 15:39:38 -0700425
426 // if we poll now we won't have network connectivity or even imsi access
427 // queue up a poll to happen in a little while - after ntp and imsi are avail
428 // TODO - make this callback based (ie, listen for notificaitons)
429 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_POLL_ALARM),
430 INITIAL_POLL_DELAY_SEC * 1000);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700431 }
432
433 // check for new policy info (threshold limit/value/etc)
434 private void onPolicyChanged() {
435 boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
436
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700437 int pollingPeriod = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700438 R.integer.config_datause_polling_period_sec);
Jeff Sharkeybdfce2e2012-09-26 15:54:06 -0700439 mPolicyPollPeriodSec = Settings.Global.getInt(mContext.getContentResolver(),
440 Settings.Global.THROTTLE_POLLING_SEC, pollingPeriod);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700441
442 // TODO - remove testing stuff?
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700443 long defaultThreshold = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700444 R.integer.config_datause_threshold_bytes);
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700445 int defaultValue = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700446 R.integer.config_datause_throttle_kbitsps);
Jeff Sharkeybdfce2e2012-09-26 15:54:06 -0700447 long threshold = Settings.Global.getLong(mContext.getContentResolver(),
448 Settings.Global.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
449 int value = Settings.Global.getInt(mContext.getContentResolver(),
450 Settings.Global.THROTTLE_VALUE_KBITSPS, defaultValue);
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700451
452 mPolicyThreshold.set(threshold);
453 mPolicyThrottleValue.set(value);
454 if (testing) {
455 mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
456 mPolicyThreshold.set(TESTING_THRESHOLD);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700457 }
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700458
Jeff Sharkeybdfce2e2012-09-26 15:54:06 -0700459 mPolicyResetDay = Settings.Global.getInt(mContext.getContentResolver(),
460 Settings.Global.THROTTLE_RESET_DAY, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700461 if (mPolicyResetDay == -1 ||
462 ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
463 Random g = new Random();
464 mPolicyResetDay = 1 + g.nextInt(28); // 1-28
Jeff Sharkeybdfce2e2012-09-26 15:54:06 -0700465 Settings.Global.putInt(mContext.getContentResolver(),
466 Settings.Global.THROTTLE_RESET_DAY, mPolicyResetDay);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700467 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700468 if (mIface == null) {
469 mPolicyThreshold.set(0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700470 }
471
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700472 int defaultNotificationType = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700473 R.integer.config_datause_notification_type);
Jeff Sharkeybdfce2e2012-09-26 15:54:06 -0700474 mPolicyNotificationsAllowedMask = Settings.Global.getInt(mContext.getContentResolver(),
475 Settings.Global.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700476
Jeff Sharkeybdfce2e2012-09-26 15:54:06 -0700477 final int maxNtpCacheAgeSec = Settings.Global.getInt(mContext.getContentResolver(),
478 Settings.Global.THROTTLE_MAX_NTP_CACHE_AGE_SEC,
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700479 (int) (MAX_NTP_CACHE_AGE / 1000));
480 mMaxNtpCacheAge = maxNtpCacheAgeSec * 1000;
Robert Greenwaltd1055a22010-05-25 15:54:52 -0700481
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700482 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700483 Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" +
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700484 mPolicyPollPeriodSec + ", threshold=" + mPolicyThreshold.get() +
485 ", value=" + mPolicyThrottleValue.get() + ", resetDay=" + mPolicyResetDay +
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700486 ", noteType=" + mPolicyNotificationsAllowedMask + ", mMaxNtpCacheAge=" +
487 mMaxNtpCacheAge);
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700488 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700489
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700490 // force updates
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700491 mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700492
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700493 onResetAlarm();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700494
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700495 onPollAlarm();
496
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700497 Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700498 mContext.sendBroadcastAsUser(broadcast, UserHandle.ALL);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700499 }
500
501 private void onPollAlarm() {
502 long now = SystemClock.elapsedRealtime();
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700503 long next = now + mPolicyPollPeriodSec * 1000;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700504
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700505 // when trusted cache outdated, try refreshing
506 if (mTime.getCacheAge() > mMaxNtpCacheAge) {
507 if (mTime.forceRefresh()) {
508 if (VDBG) Slog.d(TAG, "updated trusted time, reseting alarm");
509 dispatchReset();
510 }
511 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700512
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700513 long incRead = 0;
514 long incWrite = 0;
515 try {
Jeff Sharkeye8914c32012-05-01 16:26:09 -0700516 final NetworkStats stats = mNMService.getNetworkStatsSummaryDev();
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700517 final int index = stats.findIndex(mIface, NetworkStats.UID_ALL,
518 NetworkStats.SET_DEFAULT, NetworkStats.TAG_NONE);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700519
520 if (index != -1) {
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700521 final NetworkStats.Entry entry = stats.getValues(index, null);
522 incRead = entry.rxBytes - mLastRead;
523 incWrite = entry.txBytes - mLastWrite;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700524 } else {
525 // missing iface, assume stats are 0
526 Slog.w(TAG, "unable to find stats for iface " + mIface);
527 }
528
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700529 // handle iface resets - on some device the 3g iface comes and goes and gets
530 // totals reset to 0. Deal with it
531 if ((incRead < 0) || (incWrite < 0)) {
532 incRead += mLastRead;
533 incWrite += mLastWrite;
534 mLastRead = 0;
535 mLastWrite = 0;
536 }
Jeff Sharkey558a2322011-08-24 15:42:09 -0700537 } catch (IllegalStateException e) {
538 Slog.e(TAG, "problem during onPollAlarm: " + e);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700539 } catch (RemoteException e) {
Jeff Sharkey558a2322011-08-24 15:42:09 -0700540 Slog.e(TAG, "problem during onPollAlarm: " + e);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700541 }
Jeff Sharkey558a2322011-08-24 15:42:09 -0700542
Robert Greenwalt5f996892010-04-08 16:19:24 -0700543 // don't count this data if we're roaming.
544 boolean roaming = "true".equals(
545 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
546 if (!roaming) {
547 mRecorder.addData(incRead, incWrite);
548 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700549
550 long periodRx = mRecorder.getPeriodRx(0);
551 long periodTx = mRecorder.getPeriodTx(0);
552 long total = periodRx + periodTx;
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700553 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700554 Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
Robert Greenwalt5f996892010-04-08 16:19:24 -0700555 ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700556 }
557 mLastRead += incRead;
558 mLastWrite += incWrite;
559
560 checkThrottleAndPostNotification(total);
561
562 Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
563 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
564 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700565 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
566 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700567 mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700568 mPollStickyBroadcast = broadcast;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700569
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700570 mAlarmManager.cancel(mPendingPollIntent);
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700571 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700572 }
573
Robert Greenwaltfee46832010-05-06 12:25:13 -0700574 private void onIfaceUp() {
575 // if we were throttled before, be sure and set it again - the iface went down
576 // (and may have disappeared all together) and these settings were lost
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700577 if (mThrottleIndex.get() == 1) {
Robert Greenwaltfee46832010-05-06 12:25:13 -0700578 try {
579 mNMService.setInterfaceThrottle(mIface, -1, -1);
580 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700581 mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
Robert Greenwaltfee46832010-05-06 12:25:13 -0700582 } catch (Exception e) {
583 Slog.e(TAG, "error setting Throttle: " + e);
584 }
585 }
586 }
587
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700588 private void checkThrottleAndPostNotification(long currentTotal) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700589 // is throttling enabled?
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700590 long threshold = mPolicyThreshold.get();
591 if (threshold == 0) {
Robert Greenwaltcce83372010-04-23 17:35:29 -0700592 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700593 return;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700594 }
595
596 // have we spoken with an ntp server yet?
597 // this is controversial, but we'd rather err towards not throttling
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700598 if (!mTime.hasCache()) {
599 Slog.w(TAG, "missing trusted time, skipping throttle check");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700600 return;
601 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700602
603 // check if we need to throttle
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700604 if (currentTotal > threshold) {
605 if (mThrottleIndex.get() != 1) {
606 mThrottleIndex.set(1);
607 if (DBG) Slog.d(TAG, "Threshold " + threshold + " exceeded!");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700608 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700609 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700610 mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700611 } catch (Exception e) {
612 Slog.e(TAG, "error setting Throttle: " + e);
613 }
614
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700615 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700616
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700617 postNotification(R.string.throttled_notification_title,
618 R.string.throttled_notification_message,
619 R.drawable.stat_sys_throttled,
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700620 Notification.FLAG_ONGOING_EVENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700621
622 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700623 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL,
624 mPolicyThrottleValue.get());
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700625 mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700626
627 } // else already up!
628 } else {
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700629 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700630 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
631 // check if we should warn about throttle
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700632 // pretend we only have 1/2 the time remaining that we actually do
633 // if our burn rate in the period so far would have us exceed the limit
634 // in that 1/2 window, warn the user.
635 // this gets more generous in the early to middle period and converges back
636 // to the limit as we move toward the period end.
637
638 // adding another factor - it must be greater than the total cap/4
639 // else we may get false alarms very early in the period.. in the first
640 // tenth of a percent of the period if we used more than a tenth of a percent
641 // of the cap we'd get a warning and that's not desired.
642 long start = mRecorder.getPeriodStart();
643 long end = mRecorder.getPeriodEnd();
644 long periodLength = end - start;
645 long now = System.currentTimeMillis();
646 long timeUsed = now - start;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700647 long warningThreshold = 2*threshold*timeUsed/(timeUsed+periodLength);
648 if ((currentTotal > warningThreshold) && (currentTotal > threshold/4)) {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700649 if (mWarningNotificationSent == false) {
650 mWarningNotificationSent = true;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700651 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
652 postNotification(R.string.throttle_warning_notification_title,
653 R.string.throttle_warning_notification_message,
654 R.drawable.stat_sys_throttled,
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700655 0);
656 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700657 } else {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700658 if (mWarningNotificationSent == true) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700659 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700660 mWarningNotificationSent =false;
661 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700662 }
663 }
664 }
665 }
666
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700667 private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700668 Intent intent = new Intent();
669 // TODO - fix up intent
Robert Greenwalt2a7b7302010-04-12 14:56:31 -0700670 intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700671 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
672
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700673 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0,
674 null, UserHandle.CURRENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700675
676 Resources r = Resources.getSystem();
677 CharSequence title = r.getText(titleInt);
678 CharSequence message = r.getText(messageInt);
679 if (mThrottlingNotification == null) {
680 mThrottlingNotification = new Notification();
681 mThrottlingNotification.when = 0;
682 // TODO - fixup icon
683 mThrottlingNotification.icon = icon;
684 mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700685 }
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700686 mThrottlingNotification.flags = flags;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700687 mThrottlingNotification.tickerText = title;
688 mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
689
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700690 mNotificationManager.notifyAsUser(null, mThrottlingNotification.icon,
691 mThrottlingNotification, UserHandle.ALL);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700692 }
693
694
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700695 private void clearThrottleAndNotification() {
696 if (mThrottleIndex.get() != THROTTLE_INDEX_UNTHROTTLED) {
697 mThrottleIndex.set(THROTTLE_INDEX_UNTHROTTLED);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700698 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700699 mNMService.setInterfaceThrottle(mIface, -1, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700700 } catch (Exception e) {
701 Slog.e(TAG, "error clearing Throttle: " + e);
702 }
703 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
704 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700705 mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700706 mNotificationManager.cancelAsUser(null, R.drawable.stat_sys_throttled,
707 UserHandle.ALL);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700708 mWarningNotificationSent = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700709 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700710 }
711
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700712 private Calendar calculatePeriodEnd(long now) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700713 Calendar end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700714 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700715 int day = end.get(Calendar.DAY_OF_MONTH);
716 end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
717 end.set(Calendar.HOUR_OF_DAY, 0);
718 end.set(Calendar.MINUTE, 0);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700719 end.set(Calendar.SECOND, 0);
720 end.set(Calendar.MILLISECOND, 0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700721 if (day >= mPolicyResetDay) {
722 int month = end.get(Calendar.MONTH);
723 if (month == Calendar.DECEMBER) {
724 end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
725 month = Calendar.JANUARY - 1;
726 }
727 end.set(Calendar.MONTH, month + 1);
728 }
729
730 // TODO - remove!
731 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
732 end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700733 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700734 end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
735 }
736 return end;
737 }
738 private Calendar calculatePeriodStart(Calendar end) {
739 Calendar start = (Calendar)end.clone();
740 int month = end.get(Calendar.MONTH);
741 if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
742 month = Calendar.DECEMBER + 1;
743 start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
744 }
745 start.set(Calendar.MONTH, month - 1);
746
747 // TODO - remove!!
748 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
749 start = (Calendar)end.clone();
750 start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
751 }
752 return start;
753 }
754
755 private void onResetAlarm() {
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700756 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700757 Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
758 " bytes read and " + mRecorder.getPeriodTx(0) + " written");
759 }
760
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700761 // when trusted cache outdated, try refreshing
762 if (mTime.getCacheAge() > mMaxNtpCacheAge) {
763 mTime.forceRefresh();
764 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700765
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700766 // as long as we have a trusted time cache, we always reset alarms,
767 // even if the refresh above failed.
768 if (mTime.hasCache()) {
769 final long now = mTime.currentTimeMillis();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700770 Calendar end = calculatePeriodEnd(now);
771 Calendar start = calculatePeriodStart(end);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700772
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700773 if (mRecorder.setNextPeriod(start, end)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700774 onPollAlarm();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700775 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700776
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700777 mAlarmManager.cancel(mPendingResetIntent);
778 long offset = end.getTimeInMillis() - now;
779 // use Elapsed realtime so clock changes don't fool us.
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700780 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME,
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700781 SystemClock.elapsedRealtime() + offset,
782 mPendingResetIntent);
783 } else {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700784 if (VDBG) Slog.d(TAG, "no trusted time, not resetting period");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700785 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700786 }
787 }
788
789 // records bytecount data for a given time and accumulates it into larger time windows
790 // for logging and other purposes
791 //
792 // since time can be changed (user or network action) we will have to track the time of the
793 // last recording and deal with it.
794 private static class DataRecorder {
795 long[] mPeriodRxData;
796 long[] mPeriodTxData;
797 int mCurrentPeriod;
798 int mPeriodCount;
799
800 Calendar mPeriodStart;
801 Calendar mPeriodEnd;
802
803 ThrottleService mParent;
804 Context mContext;
Robert Greenwalte6e98822010-04-15 08:27:14 -0700805 String mImsi = null;
806
807 TelephonyManager mTelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700808
809 DataRecorder(Context context, ThrottleService parent) {
810 mContext = context;
811 mParent = parent;
812
Robert Greenwalte6e98822010-04-15 08:27:14 -0700813 mTelephonyManager = (TelephonyManager)mContext.getSystemService(
814 Context.TELEPHONY_SERVICE);
815
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700816 synchronized (mParent) {
817 mPeriodCount = 6;
818 mPeriodRxData = new long[mPeriodCount];
819 mPeriodTxData = new long[mPeriodCount];
820
821 mPeriodStart = Calendar.getInstance();
822 mPeriodEnd = Calendar.getInstance();
823
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700824 retrieve();
825 }
826 }
827
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700828 boolean setNextPeriod(Calendar start, Calendar end) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700829 // TODO - how would we deal with a dual-IMSI device?
830 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700831 boolean startNewPeriod = true;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700832
Robert Greenwalt27fba672010-04-26 12:29:14 -0700833 if (start.equals(mPeriodStart) && end.equals(mPeriodEnd)) {
834 // same endpoints - keep collecting
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700835 if (VDBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700836 Slog.d(TAG, "same period (" + start.getTimeInMillis() + "," +
837 end.getTimeInMillis() +") - ammending data");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700838 }
Robert Greenwalt27fba672010-04-26 12:29:14 -0700839 startNewPeriod = false;
840 } else {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700841 if (VDBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700842 if(start.equals(mPeriodEnd) || start.after(mPeriodEnd)) {
843 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
844 end.getTimeInMillis() + ") - old end was " +
845 mPeriodEnd.getTimeInMillis() + ", following");
846 } else {
847 Slog.d(TAG, "new period (" + start.getTimeInMillis() + "," +
848 end.getTimeInMillis() + ") replacing old (" +
849 mPeriodStart.getTimeInMillis() + "," +
850 mPeriodEnd.getTimeInMillis() + ")");
851 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700852 }
853 synchronized (mParent) {
854 ++mCurrentPeriod;
855 if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
856 mPeriodRxData[mCurrentPeriod] = 0;
857 mPeriodTxData[mCurrentPeriod] = 0;
858 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700859 }
860 setPeriodStart(start);
861 setPeriodEnd(end);
862 record();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700863 return startNewPeriod;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700864 }
865
866 public long getPeriodEnd() {
867 synchronized (mParent) {
868 return mPeriodEnd.getTimeInMillis();
869 }
870 }
871
872 private void setPeriodEnd(Calendar end) {
873 synchronized (mParent) {
874 mPeriodEnd = end;
875 }
876 }
877
878 public long getPeriodStart() {
879 synchronized (mParent) {
880 return mPeriodStart.getTimeInMillis();
881 }
882 }
883
884 private void setPeriodStart(Calendar start) {
885 synchronized (mParent) {
886 mPeriodStart = start;
887 }
888 }
889
890 public int getPeriodCount() {
891 synchronized (mParent) {
892 return mPeriodCount;
893 }
894 }
895
896 private void zeroData(int field) {
897 synchronized (mParent) {
898 for(int period = 0; period<mPeriodCount; period++) {
899 mPeriodRxData[period] = 0;
900 mPeriodTxData[period] = 0;
901 }
902 mCurrentPeriod = 0;
903 }
904
905 }
906
907 // if time moves backward accumulate all read/write that's lost into the now
908 // otherwise time moved forward.
909 void addData(long bytesRead, long bytesWritten) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700910 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700911
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700912 synchronized (mParent) {
913 mPeriodRxData[mCurrentPeriod] += bytesRead;
914 mPeriodTxData[mCurrentPeriod] += bytesWritten;
915 }
916 record();
917 }
918
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700919 private File getDataFile() {
920 File dataDir = Environment.getDataDirectory();
921 File throttleDir = new File(dataDir, "system/throttle");
922 throttleDir.mkdirs();
Robert Greenwalte6e98822010-04-15 08:27:14 -0700923 String mImsi = mTelephonyManager.getSubscriberId();
924 File dataFile;
925 if (mImsi == null) {
926 dataFile = useMRUFile(throttleDir);
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700927 if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700928 } else {
929 String imsiHash = Integer.toString(mImsi.hashCode());
930 dataFile = new File(throttleDir, imsiHash);
931 }
932 // touch the file so it's not LRU
933 dataFile.setLastModified(System.currentTimeMillis());
934 checkAndDeleteLRUDataFile(throttleDir);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700935 return dataFile;
936 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700937
Robert Greenwalte6e98822010-04-15 08:27:14 -0700938 // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
939 private void checkForSubscriberId() {
940 if (mImsi != null) return;
941
942 mImsi = mTelephonyManager.getSubscriberId();
943 if (mImsi == null) return;
944
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700945 if (VDBG) Slog.d(TAG, "finally have imsi - retreiving data");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700946 retrieve();
947 }
948
949 private final static int MAX_SIMS_SUPPORTED = 3;
950
951 private void checkAndDeleteLRUDataFile(File dir) {
952 File[] files = dir.listFiles();
953
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700954 if (files == null || files.length <= MAX_SIMS_SUPPORTED) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700955 if (DBG) Slog.d(TAG, "Too many data files");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700956 do {
957 File oldest = null;
958 for (File f : files) {
959 if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
960 oldest = f;
961 }
962 }
963 if (oldest == null) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700964 if (DBG) Slog.d(TAG, " deleting " + oldest);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700965 oldest.delete();
966 files = dir.listFiles();
967 } while (files.length > MAX_SIMS_SUPPORTED);
968 }
969
970 private File useMRUFile(File dir) {
971 File newest = null;
972 File[] files = dir.listFiles();
973
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700974 if (files != null) {
975 for (File f : files) {
976 if ((newest == null) || (newest.lastModified() < f.lastModified())) {
977 newest = f;
978 }
Robert Greenwalte6e98822010-04-15 08:27:14 -0700979 }
980 }
981 if (newest == null) {
982 newest = new File(dir, "temp");
983 }
984 return newest;
985 }
986
987
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700988 private static final int DATA_FILE_VERSION = 1;
989
990 private void record() {
991 // 1 int version
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700992 // 1 int mPeriodCount
993 // 13*6 long[PERIOD_COUNT] mPeriodRxData
994 // 13*6 long[PERIOD_COUNT] mPeriodTxData
995 // 1 int mCurrentPeriod
996 // 13 long periodStartMS
997 // 13 long periodEndMS
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700998 // 200 chars max
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700999 StringBuilder builder = new StringBuilder();
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001000 builder.append(DATA_FILE_VERSION);
1001 builder.append(":");
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001002 builder.append(mPeriodCount);
1003 builder.append(":");
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(mPeriodRxData[i]);
1006 builder.append(":");
1007 }
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001008 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001009 builder.append(mPeriodTxData[i]);
1010 builder.append(":");
1011 }
1012 builder.append(mCurrentPeriod);
1013 builder.append(":");
1014 builder.append(mPeriodStart.getTimeInMillis());
1015 builder.append(":");
1016 builder.append(mPeriodEnd.getTimeInMillis());
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001017
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001018 BufferedWriter out = null;
1019 try {
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001020 out = new BufferedWriter(new FileWriter(getDataFile()), 256);
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001021 out.write(builder.toString());
1022 } catch (IOException e) {
1023 Slog.e(TAG, "Error writing data file");
1024 return;
1025 } finally {
1026 if (out != null) {
1027 try {
1028 out.close();
1029 } catch (Exception e) {}
1030 }
1031 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001032 }
1033
1034 private void retrieve() {
Robert Greenwalt05d06732010-04-19 11:10:38 -07001035 // clean out any old data first. If we fail to read we don't want old stuff
1036 zeroData(0);
1037
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001038 File f = getDataFile();
1039 byte[] buffer;
1040 FileInputStream s = null;
1041 try {
1042 buffer = new byte[(int)f.length()];
1043 s = new FileInputStream(f);
1044 s.read(buffer);
1045 } catch (IOException e) {
1046 Slog.e(TAG, "Error reading data file");
1047 return;
1048 } finally {
1049 if (s != null) {
1050 try {
1051 s.close();
1052 } catch (Exception e) {}
1053 }
1054 }
1055 String data = new String(buffer);
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001056 if (data == null || data.length() == 0) {
1057 if (DBG) Slog.d(TAG, "data file empty");
1058 return;
1059 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001060 String[] parsed = data.split(":");
1061 int parsedUsed = 0;
1062 if (parsed.length < 6) {
1063 Slog.e(TAG, "reading data file with insufficient length - ignoring");
1064 return;
1065 }
1066
Robert Greenwalt9e3983f2010-05-11 07:06:13 -07001067 int periodCount;
1068 long[] periodRxData;
1069 long[] periodTxData;
1070 int currentPeriod;
1071 Calendar periodStart;
1072 Calendar periodEnd;
1073 try {
1074 if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
1075 Slog.e(TAG, "reading data file with bad version - ignoring");
1076 return;
1077 }
1078
1079 periodCount = Integer.parseInt(parsed[parsedUsed++]);
1080 if (parsed.length != 5 + (2 * periodCount)) {
1081 Slog.e(TAG, "reading data file with bad length (" + parsed.length +
1082 " != " + (5 + (2 * periodCount)) + ") - ignoring");
1083 return;
1084 }
1085 periodRxData = new long[periodCount];
1086 for (int i = 0; i < periodCount; i++) {
1087 periodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
1088 }
1089 periodTxData = new long[periodCount];
1090 for (int i = 0; i < periodCount; i++) {
1091 periodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
1092 }
1093
1094 currentPeriod = Integer.parseInt(parsed[parsedUsed++]);
1095
1096 periodStart = new GregorianCalendar();
1097 periodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1098 periodEnd = new GregorianCalendar();
1099 periodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1100 } catch (Exception e) {
1101 Slog.e(TAG, "Error parsing data file - ignoring");
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001102 return;
1103 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001104 synchronized (mParent) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001105 mPeriodCount = periodCount;
1106 mPeriodRxData = periodRxData;
1107 mPeriodTxData = periodTxData;
Robert Greenwalt9e3983f2010-05-11 07:06:13 -07001108 mCurrentPeriod = currentPeriod;
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001109 mPeriodStart = periodStart;
1110 mPeriodEnd = periodEnd;
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001111 }
1112 }
1113
1114 long getPeriodRx(int which) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001115 synchronized (mParent) {
1116 if (which > mPeriodCount) return 0;
1117 which = mCurrentPeriod - which;
1118 if (which < 0) which += mPeriodCount;
1119 return mPeriodRxData[which];
1120 }
1121 }
1122 long getPeriodTx(int which) {
1123 synchronized (mParent) {
1124 if (which > mPeriodCount) return 0;
1125 which = mCurrentPeriod - which;
1126 if (which < 0) which += mPeriodCount;
1127 return mPeriodTxData[which];
1128 }
1129 }
1130 }
1131
1132 @Override
1133 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1134 if (mContext.checkCallingOrSelfPermission(
1135 android.Manifest.permission.DUMP)
1136 != PackageManager.PERMISSION_GRANTED) {
1137 pw.println("Permission Denial: can't dump ThrottleService " +
1138 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1139 Binder.getCallingUid());
1140 return;
1141 }
1142 pw.println();
1143
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001144 pw.println("The threshold is " + mPolicyThreshold.get() +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001145 ", after which you experince throttling to " +
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001146 mPolicyThrottleValue.get() + "kbps");
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001147 pw.println("Current period is " +
1148 (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001149 "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001150 " seconds.");
1151 pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001152 pw.println("Current Throttle Index is " + mThrottleIndex.get());
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -07001153 pw.println("mMaxNtpCacheAge=" + mMaxNtpCacheAge);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -07001154
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001155 for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
1156 pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
1157 mRecorder.getPeriodTx(i));
1158 }
1159 }
1160}