blob: 2645e42f0edb0b286f65ac7f56dea525130ef2d5 [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;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070033import android.net.SntpClient;
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;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070050import android.util.Slog;
51
Robert Greenwalt7171ea82010-04-14 22:37:12 -070052import com.android.internal.R;
Robert Greenwalt5f996892010-04-08 16:19:24 -070053import com.android.internal.telephony.TelephonyProperties;
54
Robert Greenwaltb8912f52010-04-09 17:27:26 -070055import java.io.BufferedWriter;
56import java.io.File;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070057import java.io.FileDescriptor;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070058import java.io.FileInputStream;
59import java.io.FileWriter;
60import java.io.IOException;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070061import java.io.PrintWriter;
62import java.util.Calendar;
Robert Greenwalt39e163f2010-05-07 16:52:17 -070063import java.util.concurrent.atomic.AtomicInteger;
64import java.util.concurrent.atomic.AtomicLong;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070065import java.util.GregorianCalendar;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070066import java.util.Properties;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070067import java.util.Random;
68
69// TODO - add comments - reference the ThrottleManager for public API
70public class ThrottleService extends IThrottleManager.Stub {
71
72 private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
73
74 private static final String TAG = "ThrottleService";
Robert Greenwaltbf7de392010-04-21 17:09:38 -070075 private static final boolean DBG = true;
76 private static final boolean VDBG = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070077 private Handler mHandler;
78 private HandlerThread mThread;
79
80 private Context mContext;
81
Robert Greenwaltfb9896b2010-04-22 15:39:38 -070082 private static final int INITIAL_POLL_DELAY_SEC = 90;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070083 private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070084 private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070085 private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070086
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070087 private int mPolicyPollPeriodSec;
Robert Greenwalt39e163f2010-05-07 16:52:17 -070088 private AtomicLong mPolicyThreshold;
89 private AtomicInteger mPolicyThrottleValue;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070090 private int mPolicyResetDay; // 1-28
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070091 private int mPolicyNotificationsAllowedMask;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070092
93 private long mLastRead; // read byte count from last poll
94 private long mLastWrite; // write byte count from last poll
95
96 private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
97 private static int POLL_REQUEST = 0;
98 private PendingIntent mPendingPollIntent;
99 private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
100 private static int RESET_REQUEST = 1;
101 private PendingIntent mPendingResetIntent;
102
103 private INetworkManagementService mNMService;
104 private AlarmManager mAlarmManager;
105 private NotificationManager mNotificationManager;
106
107 private DataRecorder mRecorder;
108
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700109 private String mIface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700110
111 private static final int NOTIFICATION_WARNING = 2;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700112
113 private Notification mThrottlingNotification;
114 private boolean mWarningNotificationSent = false;
115
Robert Greenwaltfee46832010-05-06 12:25:13 -0700116 private InterfaceObserver mInterfaceObserver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700117 private SettingsObserver mSettingsObserver;
118
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700119 private AtomicInteger mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700120 private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
121 private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
122
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700123 private static final String PROPERTIES_FILE = "/etc/gps.conf";
124 private String mNtpServer;
125 private boolean mNtpActive;
126
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700127 public ThrottleService(Context context) {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700128 if (VDBG) Slog.v(TAG, "Starting ThrottleService");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700129 mContext = context;
130
Robert Greenwalt24488bd2010-05-10 16:56:43 -0700131 mPolicyThreshold = new AtomicLong();
132 mPolicyThrottleValue = new AtomicInteger();
133 mThrottleIndex = new AtomicInteger();
134
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700135 mNtpActive = false;
136
Robert Greenwaltfee46832010-05-06 12:25:13 -0700137 mIface = mContext.getResources().getString(R.string.config_datause_iface);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700138 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
139 Intent pollIntent = new Intent(ACTION_POLL, null);
140 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
141 Intent resetIntent = new Intent(ACTION_RESET, null);
142 mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
143
144 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
145 mNMService = INetworkManagementService.Stub.asInterface(b);
146
147 mNotificationManager = (NotificationManager)mContext.getSystemService(
148 Context.NOTIFICATION_SERVICE);
149 }
150
Robert Greenwaltfee46832010-05-06 12:25:13 -0700151 private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
152 private int mMsg;
153 private Handler mHandler;
154 private String mIface;
155
156 InterfaceObserver(Handler handler, int msg, String iface) {
157 super();
158 mHandler = handler;
159 mMsg = msg;
160 mIface = iface;
161 }
162
163 public void interfaceLinkStatusChanged(String iface, boolean link) {
164 if (link) {
165 if (TextUtils.equals(iface, mIface)) {
166 mHandler.obtainMessage(mMsg).sendToTarget();
167 }
168 }
169 }
170
171 public void interfaceAdded(String iface) {
172 // TODO - an interface added in the UP state should also trigger a StatusChanged
173 // notification..
174 if (TextUtils.equals(iface, mIface)) {
175 mHandler.obtainMessage(mMsg).sendToTarget();
176 }
177 }
178
179 public void interfaceRemoved(String iface) {}
180 }
181
182
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700183 private static class SettingsObserver extends ContentObserver {
184 private int mMsg;
185 private Handler mHandler;
186 SettingsObserver(Handler handler, int msg) {
187 super(handler);
188 mHandler = handler;
189 mMsg = msg;
190 }
191
192 void observe(Context context) {
193 ContentResolver resolver = context.getContentResolver();
194 resolver.registerContentObserver(Settings.Secure.getUriFor(
195 Settings.Secure.THROTTLE_POLLING_SEC), false, this);
196 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700197 Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700198 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700199 Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700200 resolver.registerContentObserver(Settings.Secure.getUriFor(
201 Settings.Secure.THROTTLE_RESET_DAY), false, this);
202 resolver.registerContentObserver(Settings.Secure.getUriFor(
203 Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
204 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700205 Settings.Secure.THROTTLE_HELP_URI), false, this);
Robert Greenwaltd1055a22010-05-25 15:54:52 -0700206 resolver.registerContentObserver(Settings.Secure.getUriFor(
207 Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700208 }
209
210 @Override
211 public void onChange(boolean selfChange) {
212 mHandler.obtainMessage(mMsg).sendToTarget();
213 }
214 }
215
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700216 private void enforceAccessPermission() {
217 mContext.enforceCallingOrSelfPermission(
218 android.Manifest.permission.ACCESS_NETWORK_STATE,
219 "ThrottleService");
220 }
221
Robert Greenwalt05d06732010-04-19 11:10:38 -0700222 private long ntpToWallTime(long ntpTime) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700223 long bestNow = getBestTime(true); // do it quickly
Robert Greenwalt05d06732010-04-19 11:10:38 -0700224 long localNow = System.currentTimeMillis();
225 return localNow + (ntpTime - bestNow);
226 }
227
Irfan Sheriffcf282362010-04-16 16:53:20 -0700228 // TODO - fetch for the iface
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700229 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt05d06732010-04-19 11:10:38 -0700230
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700231 public long getResetTime(String iface) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700232 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700233 long resetTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700234 if (mRecorder != null) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700235 resetTime = mRecorder.getPeriodEnd();
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700236 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700237 resetTime = ntpToWallTime(resetTime);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700238 return resetTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700239 }
Irfan Sheriffcf282362010-04-16 16:53:20 -0700240
241 // TODO - fetch for the iface
Robert Greenwalt05d06732010-04-19 11:10:38 -0700242 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700243 public long getPeriodStartTime(String iface) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700244 long startTime = 0;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700245 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700246 if (mRecorder != null) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700247 startTime = mRecorder.getPeriodStart();
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700248 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700249 startTime = ntpToWallTime(startTime);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700250 return startTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700251 }
252 //TODO - a better name? getCliffByteCountThreshold?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700253 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700254 public long getCliffThreshold(String iface, int cliff) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700255 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700256 if (cliff == 1) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700257 return mPolicyThreshold.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700258 }
259 return 0;
260 }
261 // TODO - a better name? getThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700262 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700263 public int getCliffLevel(String iface, int cliff) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700264 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700265 if (cliff == 1) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700266 return mPolicyThrottleValue.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700267 }
268 return 0;
269 }
270
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700271 public String getHelpUri() {
272 enforceAccessPermission();
273 return Settings.Secure.getString(mContext.getContentResolver(),
274 Settings.Secure.THROTTLE_HELP_URI);
275 }
276
Irfan Sheriffcf282362010-04-16 16:53:20 -0700277 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700278 public long getByteCount(String iface, int dir, int period, int ago) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700279 enforceAccessPermission();
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700280 if ((period == ThrottleManager.PERIOD_CYCLE) && (mRecorder != null)) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700281 if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
282 if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
283 }
284 return 0;
285 }
286
287 // TODO - a better name - getCurrentThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700288 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700289 public int getThrottle(String iface) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700290 enforceAccessPermission();
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700291 if (mThrottleIndex.get() == 1) {
292 return mPolicyThrottleValue.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700293 }
294 return 0;
295 }
296
297 void systemReady() {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700298 if (VDBG) Slog.v(TAG, "systemReady");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700299 mContext.registerReceiver(
300 new BroadcastReceiver() {
301 @Override
302 public void onReceive(Context context, Intent intent) {
303 mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
304 }
305 }, new IntentFilter(ACTION_POLL));
306
307 mContext.registerReceiver(
308 new BroadcastReceiver() {
309 @Override
310 public void onReceive(Context context, Intent intent) {
311 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
312 }
313 }, new IntentFilter(ACTION_RESET));
314
315 // use a new thread as we don't want to stall the system for file writes
316 mThread = new HandlerThread(TAG);
317 mThread.start();
318 mHandler = new MyHandler(mThread.getLooper());
319 mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700320
Robert Greenwaltfee46832010-05-06 12:25:13 -0700321 mInterfaceObserver = new InterfaceObserver(mHandler, EVENT_IFACE_UP, mIface);
322 try {
323 mNMService.registerObserver(mInterfaceObserver);
324 } catch (RemoteException e) {
325 Slog.e(TAG, "Could not register InterfaceObserver " + e);
326 }
327
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700328 mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
329 mSettingsObserver.observe(mContext);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700330
331 FileInputStream stream = null;
332 try {
333 Properties properties = new Properties();
334 File file = new File(PROPERTIES_FILE);
335 stream = new FileInputStream(file);
336 properties.load(stream);
337 mNtpServer = properties.getProperty("NTP_SERVER", null);
338 } catch (IOException e) {
339 Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
340 } finally {
341 if (stream != null) {
342 try {
343 stream.close();
344 } catch (Exception e) {}
345 }
346 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700347 }
348
349
350 private static final int EVENT_REBOOT_RECOVERY = 0;
351 private static final int EVENT_POLICY_CHANGED = 1;
352 private static final int EVENT_POLL_ALARM = 2;
353 private static final int EVENT_RESET_ALARM = 3;
Robert Greenwaltfee46832010-05-06 12:25:13 -0700354 private static final int EVENT_IFACE_UP = 4;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700355 private class MyHandler extends Handler {
356 public MyHandler(Looper l) {
357 super(l);
358 }
359
360 @Override
361 public void handleMessage(Message msg) {
362 switch (msg.what) {
363 case EVENT_REBOOT_RECOVERY:
364 onRebootRecovery();
365 break;
366 case EVENT_POLICY_CHANGED:
367 onPolicyChanged();
368 break;
369 case EVENT_POLL_ALARM:
370 onPollAlarm();
371 break;
372 case EVENT_RESET_ALARM:
373 onResetAlarm();
Robert Greenwaltfee46832010-05-06 12:25:13 -0700374 break;
375 case EVENT_IFACE_UP:
376 onIfaceUp();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700377 }
378 }
379
380 private void onRebootRecovery() {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700381 if (VDBG) Slog.v(TAG, "onRebootRecovery");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700382 // check for sim change TODO
383 // reregister for notification of policy change
384
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700385 mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700386
387 mRecorder = new DataRecorder(mContext, ThrottleService.this);
388
389 // get policy
390 mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
Robert Greenwaltfb9896b2010-04-22 15:39:38 -0700391
392 // if we poll now we won't have network connectivity or even imsi access
393 // queue up a poll to happen in a little while - after ntp and imsi are avail
394 // TODO - make this callback based (ie, listen for notificaitons)
395 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_POLL_ALARM),
396 INITIAL_POLL_DELAY_SEC * 1000);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700397 }
398
399 // check for new policy info (threshold limit/value/etc)
400 private void onPolicyChanged() {
401 boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
402
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700403 int pollingPeriod = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700404 R.integer.config_datause_polling_period_sec);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700405 mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
406 Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
407
408 // TODO - remove testing stuff?
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700409 long defaultThreshold = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700410 R.integer.config_datause_threshold_bytes);
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700411 int defaultValue = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700412 R.integer.config_datause_throttle_kbitsps);
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700413 long threshold = Settings.Secure.getLong(mContext.getContentResolver(),
414 Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
415 int value = Settings.Secure.getInt(mContext.getContentResolver(),
416 Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
417
418 mPolicyThreshold.set(threshold);
419 mPolicyThrottleValue.set(value);
420 if (testing) {
421 mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
422 mPolicyThreshold.set(TESTING_THRESHOLD);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700423 }
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700424
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700425 mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
426 Settings.Secure.THROTTLE_RESET_DAY, -1);
427 if (mPolicyResetDay == -1 ||
428 ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
429 Random g = new Random();
430 mPolicyResetDay = 1 + g.nextInt(28); // 1-28
431 Settings.Secure.putInt(mContext.getContentResolver(),
432 Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
433 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700434 if (mIface == null) {
435 mPolicyThreshold.set(0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700436 }
437
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700438 int defaultNotificationType = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700439 R.integer.config_datause_notification_type);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700440 mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700441 Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700442
Robert Greenwaltd1055a22010-05-25 15:54:52 -0700443 mMaxNtpCacheAgeSec = Settings.Secure.getInt(mContext.getContentResolver(),
444 Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC, MAX_NTP_CACHE_AGE_SEC);
445
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700446 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700447 Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" +
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700448 mPolicyPollPeriodSec + ", threshold=" + mPolicyThreshold.get() +
449 ", value=" + mPolicyThrottleValue.get() + ", resetDay=" + mPolicyResetDay +
450 ", noteType=" + mPolicyNotificationsAllowedMask + ", maxNtpCacheAge=" +
451 mMaxNtpCacheAgeSec);
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700452 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700453
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700454 // force updates
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700455 mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700456
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700457 onResetAlarm();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700458
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700459 onPollAlarm();
460
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700461 Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
462 mContext.sendBroadcast(broadcast);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700463 }
464
465 private void onPollAlarm() {
466 long now = SystemClock.elapsedRealtime();
467 long next = now + mPolicyPollPeriodSec*1000;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700468
469 checkForAuthoritativeTime();
470
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700471 long incRead = 0;
472 long incWrite = 0;
473 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700474 incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
475 incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700476 // handle iface resets - on some device the 3g iface comes and goes and gets
477 // totals reset to 0. Deal with it
478 if ((incRead < 0) || (incWrite < 0)) {
479 incRead += mLastRead;
480 incWrite += mLastWrite;
481 mLastRead = 0;
482 mLastWrite = 0;
483 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700484 } catch (RemoteException e) {
485 Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
486 }
Robert Greenwalt5f996892010-04-08 16:19:24 -0700487 // don't count this data if we're roaming.
488 boolean roaming = "true".equals(
489 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
490 if (!roaming) {
491 mRecorder.addData(incRead, incWrite);
492 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700493
494 long periodRx = mRecorder.getPeriodRx(0);
495 long periodTx = mRecorder.getPeriodTx(0);
496 long total = periodRx + periodTx;
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700497 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700498 Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
Robert Greenwalt5f996892010-04-08 16:19:24 -0700499 ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700500 }
501 mLastRead += incRead;
502 mLastWrite += incWrite;
503
504 checkThrottleAndPostNotification(total);
505
506 Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
507 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
508 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700509 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
510 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700511 mContext.sendStickyBroadcast(broadcast);
512
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700513 mAlarmManager.cancel(mPendingPollIntent);
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700514 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700515 }
516
Robert Greenwaltfee46832010-05-06 12:25:13 -0700517 private void onIfaceUp() {
518 // if we were throttled before, be sure and set it again - the iface went down
519 // (and may have disappeared all together) and these settings were lost
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700520 if (mThrottleIndex.get() == 1) {
Robert Greenwaltfee46832010-05-06 12:25:13 -0700521 try {
522 mNMService.setInterfaceThrottle(mIface, -1, -1);
523 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700524 mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
Robert Greenwaltfee46832010-05-06 12:25:13 -0700525 } catch (Exception e) {
526 Slog.e(TAG, "error setting Throttle: " + e);
527 }
528 }
529 }
530
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700531 private void checkThrottleAndPostNotification(long currentTotal) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700532 // is throttling enabled?
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700533 long threshold = mPolicyThreshold.get();
534 if (threshold == 0) {
Robert Greenwaltcce83372010-04-23 17:35:29 -0700535 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700536 return;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700537 }
538
539 // have we spoken with an ntp server yet?
540 // this is controversial, but we'd rather err towards not throttling
541 if ((mNtpServer != null) && !mNtpActive) {
542 return;
543 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700544
545 // check if we need to throttle
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700546 if (currentTotal > threshold) {
547 if (mThrottleIndex.get() != 1) {
548 mThrottleIndex.set(1);
549 if (DBG) Slog.d(TAG, "Threshold " + threshold + " exceeded!");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700550 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700551 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700552 mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700553 } catch (Exception e) {
554 Slog.e(TAG, "error setting Throttle: " + e);
555 }
556
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700557 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700558
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700559 postNotification(R.string.throttled_notification_title,
560 R.string.throttled_notification_message,
561 R.drawable.stat_sys_throttled,
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700562 Notification.FLAG_ONGOING_EVENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700563
564 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700565 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL,
566 mPolicyThrottleValue.get());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700567 mContext.sendStickyBroadcast(broadcast);
568
569 } // else already up!
570 } else {
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700571 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700572 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
573 // check if we should warn about throttle
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700574 // pretend we only have 1/2 the time remaining that we actually do
575 // if our burn rate in the period so far would have us exceed the limit
576 // in that 1/2 window, warn the user.
577 // this gets more generous in the early to middle period and converges back
578 // to the limit as we move toward the period end.
579
580 // adding another factor - it must be greater than the total cap/4
581 // else we may get false alarms very early in the period.. in the first
582 // tenth of a percent of the period if we used more than a tenth of a percent
583 // of the cap we'd get a warning and that's not desired.
584 long start = mRecorder.getPeriodStart();
585 long end = mRecorder.getPeriodEnd();
586 long periodLength = end - start;
587 long now = System.currentTimeMillis();
588 long timeUsed = now - start;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700589 long warningThreshold = 2*threshold*timeUsed/(timeUsed+periodLength);
590 if ((currentTotal > warningThreshold) && (currentTotal > threshold/4)) {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700591 if (mWarningNotificationSent == false) {
592 mWarningNotificationSent = true;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700593 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
594 postNotification(R.string.throttle_warning_notification_title,
595 R.string.throttle_warning_notification_message,
596 R.drawable.stat_sys_throttled,
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700597 0);
598 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700599 } else {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700600 if (mWarningNotificationSent == true) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700601 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700602 mWarningNotificationSent =false;
603 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700604 }
605 }
606 }
607 }
608
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700609 private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700610 Intent intent = new Intent();
611 // TODO - fix up intent
Robert Greenwalt2a7b7302010-04-12 14:56:31 -0700612 intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700613 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
614
615 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
616
617 Resources r = Resources.getSystem();
618 CharSequence title = r.getText(titleInt);
619 CharSequence message = r.getText(messageInt);
620 if (mThrottlingNotification == null) {
621 mThrottlingNotification = new Notification();
622 mThrottlingNotification.when = 0;
623 // TODO - fixup icon
624 mThrottlingNotification.icon = icon;
625 mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700626 }
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700627 mThrottlingNotification.flags = flags;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700628 mThrottlingNotification.tickerText = title;
629 mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
630
631 mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
632 }
633
634
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700635 private void clearThrottleAndNotification() {
636 if (mThrottleIndex.get() != THROTTLE_INDEX_UNTHROTTLED) {
637 mThrottleIndex.set(THROTTLE_INDEX_UNTHROTTLED);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700638 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700639 mNMService.setInterfaceThrottle(mIface, -1, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700640 } catch (Exception e) {
641 Slog.e(TAG, "error clearing Throttle: " + e);
642 }
643 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
644 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
645 mContext.sendStickyBroadcast(broadcast);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700646 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
647 mWarningNotificationSent = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700648 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700649 }
650
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700651 private Calendar calculatePeriodEnd(long now) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700652 Calendar end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700653 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700654 int day = end.get(Calendar.DAY_OF_MONTH);
655 end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
656 end.set(Calendar.HOUR_OF_DAY, 0);
657 end.set(Calendar.MINUTE, 0);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700658 end.set(Calendar.SECOND, 0);
659 end.set(Calendar.MILLISECOND, 0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700660 if (day >= mPolicyResetDay) {
661 int month = end.get(Calendar.MONTH);
662 if (month == Calendar.DECEMBER) {
663 end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
664 month = Calendar.JANUARY - 1;
665 }
666 end.set(Calendar.MONTH, month + 1);
667 }
668
669 // TODO - remove!
670 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
671 end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700672 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700673 end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
674 }
675 return end;
676 }
677 private Calendar calculatePeriodStart(Calendar end) {
678 Calendar start = (Calendar)end.clone();
679 int month = end.get(Calendar.MONTH);
680 if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
681 month = Calendar.DECEMBER + 1;
682 start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
683 }
684 start.set(Calendar.MONTH, month - 1);
685
686 // TODO - remove!!
687 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
688 start = (Calendar)end.clone();
689 start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
690 }
691 return start;
692 }
693
694 private void onResetAlarm() {
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700695 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700696 Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
697 " bytes read and " + mRecorder.getPeriodTx(0) + " written");
698 }
699
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700700 long now = getBestTime(false);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700701
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700702 if (mNtpActive || (mNtpServer == null)) {
703 Calendar end = calculatePeriodEnd(now);
704 Calendar start = calculatePeriodStart(end);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700705
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700706 if (mRecorder.setNextPeriod(start, end)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700707 onPollAlarm();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700708 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700709
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700710 mAlarmManager.cancel(mPendingResetIntent);
711 long offset = end.getTimeInMillis() - now;
712 // use Elapsed realtime so clock changes don't fool us.
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700713 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME,
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700714 SystemClock.elapsedRealtime() + offset,
715 mPendingResetIntent);
716 } else {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700717 if (VDBG) Slog.d(TAG, "no authoritative time - not resetting period");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700718 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700719 }
720 }
721
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700722 private void checkForAuthoritativeTime() {
723 if (mNtpActive || (mNtpServer == null)) return;
724
Robert Greenwalt05d06732010-04-19 11:10:38 -0700725 // will try to get the ntp time and switch to it if found.
726 // will also cache the time so we don't fetch it repeatedly.
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700727 getBestTime(false);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700728 }
729
Robert Greenwaltd1055a22010-05-25 15:54:52 -0700730 private static final int MAX_NTP_CACHE_AGE_SEC = 60 * 60 * 24; // 1 day
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700731 private static final int MAX_NTP_FETCH_WAIT = 20 * 1000;
Robert Greenwaltd1055a22010-05-25 15:54:52 -0700732 private int mMaxNtpCacheAgeSec = MAX_NTP_CACHE_AGE_SEC;
Robert Greenwalt05d06732010-04-19 11:10:38 -0700733 private long cachedNtp;
734 private long cachedNtpTimestamp;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700735
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700736 // if the request is tied to UI and ANR's are a danger, request a fast result
737 // the regular polling should have updated the cached time recently using the
738 // slower method (!fast)
739 private long getBestTime(boolean fast) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700740 if (mNtpServer != null) {
741 if (mNtpActive) {
742 long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
Robert Greenwaltd1c3ea62010-05-26 10:37:48 -0700743 if (ntpAge < mMaxNtpCacheAgeSec * 1000 || fast) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700744 if (VDBG) Slog.v(TAG, "using cached time");
Robert Greenwalt05d06732010-04-19 11:10:38 -0700745 return cachedNtp + ntpAge;
746 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700747 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700748 SntpClient client = new SntpClient();
749 if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT)) {
750 cachedNtp = client.getNtpTime();
751 cachedNtpTimestamp = SystemClock.elapsedRealtime();
752 if (!mNtpActive) {
753 mNtpActive = true;
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700754 if (VDBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
Robert Greenwalt05d06732010-04-19 11:10:38 -0700755 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
756 }
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700757 if (VDBG) Slog.v(TAG, "using Authoritative time: " + cachedNtp);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700758 return cachedNtp;
759 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700760 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700761 long time = System.currentTimeMillis();
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700762 if (VDBG) Slog.v(TAG, "using User time: " + time);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700763 mNtpActive = false;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700764 return time;
765 }
766
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700767 // records bytecount data for a given time and accumulates it into larger time windows
768 // for logging and other purposes
769 //
770 // since time can be changed (user or network action) we will have to track the time of the
771 // last recording and deal with it.
772 private static class DataRecorder {
773 long[] mPeriodRxData;
774 long[] mPeriodTxData;
775 int mCurrentPeriod;
776 int mPeriodCount;
777
778 Calendar mPeriodStart;
779 Calendar mPeriodEnd;
780
781 ThrottleService mParent;
782 Context mContext;
Robert Greenwalte6e98822010-04-15 08:27:14 -0700783 String mImsi = null;
784
785 TelephonyManager mTelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700786
787 DataRecorder(Context context, ThrottleService parent) {
788 mContext = context;
789 mParent = parent;
790
Robert Greenwalte6e98822010-04-15 08:27:14 -0700791 mTelephonyManager = (TelephonyManager)mContext.getSystemService(
792 Context.TELEPHONY_SERVICE);
793
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700794 synchronized (mParent) {
795 mPeriodCount = 6;
796 mPeriodRxData = new long[mPeriodCount];
797 mPeriodTxData = new long[mPeriodCount];
798
799 mPeriodStart = Calendar.getInstance();
800 mPeriodEnd = Calendar.getInstance();
801
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700802 retrieve();
803 }
804 }
805
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700806 boolean setNextPeriod(Calendar start, Calendar end) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700807 // TODO - how would we deal with a dual-IMSI device?
808 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700809 boolean startNewPeriod = true;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700810
Robert Greenwalt27fba672010-04-26 12:29:14 -0700811 if (start.equals(mPeriodStart) && end.equals(mPeriodEnd)) {
812 // same endpoints - keep collecting
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700813 if (VDBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700814 Slog.d(TAG, "same period (" + start.getTimeInMillis() + "," +
815 end.getTimeInMillis() +") - ammending data");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700816 }
Robert Greenwalt27fba672010-04-26 12:29:14 -0700817 startNewPeriod = false;
818 } else {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700819 if (VDBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700820 if(start.equals(mPeriodEnd) || start.after(mPeriodEnd)) {
821 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
822 end.getTimeInMillis() + ") - old end was " +
823 mPeriodEnd.getTimeInMillis() + ", following");
824 } else {
825 Slog.d(TAG, "new period (" + start.getTimeInMillis() + "," +
826 end.getTimeInMillis() + ") replacing old (" +
827 mPeriodStart.getTimeInMillis() + "," +
828 mPeriodEnd.getTimeInMillis() + ")");
829 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700830 }
831 synchronized (mParent) {
832 ++mCurrentPeriod;
833 if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
834 mPeriodRxData[mCurrentPeriod] = 0;
835 mPeriodTxData[mCurrentPeriod] = 0;
836 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700837 }
838 setPeriodStart(start);
839 setPeriodEnd(end);
840 record();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700841 return startNewPeriod;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700842 }
843
844 public long getPeriodEnd() {
845 synchronized (mParent) {
846 return mPeriodEnd.getTimeInMillis();
847 }
848 }
849
850 private void setPeriodEnd(Calendar end) {
851 synchronized (mParent) {
852 mPeriodEnd = end;
853 }
854 }
855
856 public long getPeriodStart() {
857 synchronized (mParent) {
858 return mPeriodStart.getTimeInMillis();
859 }
860 }
861
862 private void setPeriodStart(Calendar start) {
863 synchronized (mParent) {
864 mPeriodStart = start;
865 }
866 }
867
868 public int getPeriodCount() {
869 synchronized (mParent) {
870 return mPeriodCount;
871 }
872 }
873
874 private void zeroData(int field) {
875 synchronized (mParent) {
876 for(int period = 0; period<mPeriodCount; period++) {
877 mPeriodRxData[period] = 0;
878 mPeriodTxData[period] = 0;
879 }
880 mCurrentPeriod = 0;
881 }
882
883 }
884
885 // if time moves backward accumulate all read/write that's lost into the now
886 // otherwise time moved forward.
887 void addData(long bytesRead, long bytesWritten) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700888 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700889
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700890 synchronized (mParent) {
891 mPeriodRxData[mCurrentPeriod] += bytesRead;
892 mPeriodTxData[mCurrentPeriod] += bytesWritten;
893 }
894 record();
895 }
896
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700897 private File getDataFile() {
898 File dataDir = Environment.getDataDirectory();
899 File throttleDir = new File(dataDir, "system/throttle");
900 throttleDir.mkdirs();
Robert Greenwalte6e98822010-04-15 08:27:14 -0700901 String mImsi = mTelephonyManager.getSubscriberId();
902 File dataFile;
903 if (mImsi == null) {
904 dataFile = useMRUFile(throttleDir);
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700905 if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700906 } else {
907 String imsiHash = Integer.toString(mImsi.hashCode());
908 dataFile = new File(throttleDir, imsiHash);
909 }
910 // touch the file so it's not LRU
911 dataFile.setLastModified(System.currentTimeMillis());
912 checkAndDeleteLRUDataFile(throttleDir);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700913 return dataFile;
914 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700915
Robert Greenwalte6e98822010-04-15 08:27:14 -0700916 // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
917 private void checkForSubscriberId() {
918 if (mImsi != null) return;
919
920 mImsi = mTelephonyManager.getSubscriberId();
921 if (mImsi == null) return;
922
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700923 if (VDBG) Slog.d(TAG, "finally have imsi - retreiving data");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700924 retrieve();
925 }
926
927 private final static int MAX_SIMS_SUPPORTED = 3;
928
929 private void checkAndDeleteLRUDataFile(File dir) {
930 File[] files = dir.listFiles();
931
932 if (files.length <= MAX_SIMS_SUPPORTED) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700933 if (DBG) Slog.d(TAG, "Too many data files");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700934 do {
935 File oldest = null;
936 for (File f : files) {
937 if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
938 oldest = f;
939 }
940 }
941 if (oldest == null) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700942 if (DBG) Slog.d(TAG, " deleting " + oldest);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700943 oldest.delete();
944 files = dir.listFiles();
945 } while (files.length > MAX_SIMS_SUPPORTED);
946 }
947
948 private File useMRUFile(File dir) {
949 File newest = null;
950 File[] files = dir.listFiles();
951
952 for (File f : files) {
953 if ((newest == null) || (newest.lastModified() < f.lastModified())) {
954 newest = f;
955 }
956 }
957 if (newest == null) {
958 newest = new File(dir, "temp");
959 }
960 return newest;
961 }
962
963
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700964 private static final int DATA_FILE_VERSION = 1;
965
966 private void record() {
967 // 1 int version
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700968 // 1 int mPeriodCount
969 // 13*6 long[PERIOD_COUNT] mPeriodRxData
970 // 13*6 long[PERIOD_COUNT] mPeriodTxData
971 // 1 int mCurrentPeriod
972 // 13 long periodStartMS
973 // 13 long periodEndMS
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700974 // 200 chars max
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700975 StringBuilder builder = new StringBuilder();
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700976 builder.append(DATA_FILE_VERSION);
977 builder.append(":");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700978 builder.append(mPeriodCount);
979 builder.append(":");
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700980 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700981 builder.append(mPeriodRxData[i]);
982 builder.append(":");
983 }
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700984 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700985 builder.append(mPeriodTxData[i]);
986 builder.append(":");
987 }
988 builder.append(mCurrentPeriod);
989 builder.append(":");
990 builder.append(mPeriodStart.getTimeInMillis());
991 builder.append(":");
992 builder.append(mPeriodEnd.getTimeInMillis());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700993
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700994 BufferedWriter out = null;
995 try {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700996 out = new BufferedWriter(new FileWriter(getDataFile()), 256);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700997 out.write(builder.toString());
998 } catch (IOException e) {
999 Slog.e(TAG, "Error writing data file");
1000 return;
1001 } finally {
1002 if (out != null) {
1003 try {
1004 out.close();
1005 } catch (Exception e) {}
1006 }
1007 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001008 }
1009
1010 private void retrieve() {
Robert Greenwalt05d06732010-04-19 11:10:38 -07001011 // clean out any old data first. If we fail to read we don't want old stuff
1012 zeroData(0);
1013
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001014 File f = getDataFile();
1015 byte[] buffer;
1016 FileInputStream s = null;
1017 try {
1018 buffer = new byte[(int)f.length()];
1019 s = new FileInputStream(f);
1020 s.read(buffer);
1021 } catch (IOException e) {
1022 Slog.e(TAG, "Error reading data file");
1023 return;
1024 } finally {
1025 if (s != null) {
1026 try {
1027 s.close();
1028 } catch (Exception e) {}
1029 }
1030 }
1031 String data = new String(buffer);
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001032 if (data == null || data.length() == 0) {
1033 if (DBG) Slog.d(TAG, "data file empty");
1034 return;
1035 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001036 String[] parsed = data.split(":");
1037 int parsedUsed = 0;
1038 if (parsed.length < 6) {
1039 Slog.e(TAG, "reading data file with insufficient length - ignoring");
1040 return;
1041 }
1042
Robert Greenwalt9e3983f2010-05-11 07:06:13 -07001043 int periodCount;
1044 long[] periodRxData;
1045 long[] periodTxData;
1046 int currentPeriod;
1047 Calendar periodStart;
1048 Calendar periodEnd;
1049 try {
1050 if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
1051 Slog.e(TAG, "reading data file with bad version - ignoring");
1052 return;
1053 }
1054
1055 periodCount = Integer.parseInt(parsed[parsedUsed++]);
1056 if (parsed.length != 5 + (2 * periodCount)) {
1057 Slog.e(TAG, "reading data file with bad length (" + parsed.length +
1058 " != " + (5 + (2 * periodCount)) + ") - ignoring");
1059 return;
1060 }
1061 periodRxData = new long[periodCount];
1062 for (int i = 0; i < periodCount; i++) {
1063 periodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
1064 }
1065 periodTxData = new long[periodCount];
1066 for (int i = 0; i < periodCount; i++) {
1067 periodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
1068 }
1069
1070 currentPeriod = Integer.parseInt(parsed[parsedUsed++]);
1071
1072 periodStart = new GregorianCalendar();
1073 periodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1074 periodEnd = new GregorianCalendar();
1075 periodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1076 } catch (Exception e) {
1077 Slog.e(TAG, "Error parsing data file - ignoring");
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001078 return;
1079 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001080 synchronized (mParent) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001081 mPeriodCount = periodCount;
1082 mPeriodRxData = periodRxData;
1083 mPeriodTxData = periodTxData;
Robert Greenwalt9e3983f2010-05-11 07:06:13 -07001084 mCurrentPeriod = currentPeriod;
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001085 mPeriodStart = periodStart;
1086 mPeriodEnd = periodEnd;
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001087 }
1088 }
1089
1090 long getPeriodRx(int which) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001091 synchronized (mParent) {
1092 if (which > mPeriodCount) return 0;
1093 which = mCurrentPeriod - which;
1094 if (which < 0) which += mPeriodCount;
1095 return mPeriodRxData[which];
1096 }
1097 }
1098 long getPeriodTx(int which) {
1099 synchronized (mParent) {
1100 if (which > mPeriodCount) return 0;
1101 which = mCurrentPeriod - which;
1102 if (which < 0) which += mPeriodCount;
1103 return mPeriodTxData[which];
1104 }
1105 }
1106 }
1107
1108 @Override
1109 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1110 if (mContext.checkCallingOrSelfPermission(
1111 android.Manifest.permission.DUMP)
1112 != PackageManager.PERMISSION_GRANTED) {
1113 pw.println("Permission Denial: can't dump ThrottleService " +
1114 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1115 Binder.getCallingUid());
1116 return;
1117 }
1118 pw.println();
1119
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001120 pw.println("The threshold is " + mPolicyThreshold.get() +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001121 ", after which you experince throttling to " +
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001122 mPolicyThrottleValue.get() + "kbps");
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001123 pw.println("Current period is " +
1124 (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001125 "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001126 " seconds.");
1127 pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001128 pw.println("Current Throttle Index is " + mThrottleIndex.get());
Robert Greenwaltd1055a22010-05-25 15:54:52 -07001129 pw.println("Max NTP Cache Age is " + mMaxNtpCacheAgeSec);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -07001130
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001131 for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
1132 pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
1133 mRecorder.getPeriodTx(i));
1134 }
1135 }
1136}