blob: 6a5bbd2bee8cb7c14c0066938e161924f9e512eb [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 Greenwalt9e696c22010-04-01 14:45:18 -070031import android.net.IThrottleManager;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070032import android.net.SntpClient;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070033import android.net.ThrottleManager;
34import android.os.Binder;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070035import android.os.Environment;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070036import android.os.Handler;
37import android.os.HandlerThread;
38import android.os.IBinder;
39import android.os.INetworkManagementService;
40import android.os.Looper;
41import android.os.Message;
42import android.os.RemoteException;
43import android.os.ServiceManager;
44import android.os.SystemClock;
45import android.os.SystemProperties;
46import android.provider.Settings;
Robert Greenwalte6e98822010-04-15 08:27:14 -070047import android.telephony.TelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070048import android.util.Slog;
49
Robert Greenwalt7171ea82010-04-14 22:37:12 -070050import com.android.internal.R;
Robert Greenwalt5f996892010-04-08 16:19:24 -070051import com.android.internal.telephony.TelephonyProperties;
52
Robert Greenwaltb8912f52010-04-09 17:27:26 -070053import java.io.BufferedWriter;
54import java.io.File;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070055import java.io.FileDescriptor;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070056import java.io.FileInputStream;
57import java.io.FileWriter;
58import java.io.IOException;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070059import java.io.PrintWriter;
60import java.util.Calendar;
61import java.util.GregorianCalendar;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070062import java.util.Properties;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070063import java.util.Random;
64
65// TODO - add comments - reference the ThrottleManager for public API
66public class ThrottleService extends IThrottleManager.Stub {
67
68 private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
69
70 private static final String TAG = "ThrottleService";
Robert Greenwaltbf7de392010-04-21 17:09:38 -070071 private static final boolean DBG = true;
72 private static final boolean VDBG = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070073 private Handler mHandler;
74 private HandlerThread mThread;
75
76 private Context mContext;
77
Robert Greenwaltfb9896b2010-04-22 15:39:38 -070078 private static final int INITIAL_POLL_DELAY_SEC = 90;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070079 private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070080 private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070081 private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070082
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070083 private int mPolicyPollPeriodSec;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070084 private long mPolicyThreshold;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070085 private int mPolicyThrottleValue;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070086 private int mPolicyResetDay; // 1-28
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070087 private int mPolicyNotificationsAllowedMask;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070088
89 private long mLastRead; // read byte count from last poll
90 private long mLastWrite; // write byte count from last poll
91
92 private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
93 private static int POLL_REQUEST = 0;
94 private PendingIntent mPendingPollIntent;
95 private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
96 private static int RESET_REQUEST = 1;
97 private PendingIntent mPendingResetIntent;
98
99 private INetworkManagementService mNMService;
100 private AlarmManager mAlarmManager;
101 private NotificationManager mNotificationManager;
102
103 private DataRecorder mRecorder;
104
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700105 private String mIface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700106
107 private static final int NOTIFICATION_WARNING = 2;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700108
109 private Notification mThrottlingNotification;
110 private boolean mWarningNotificationSent = false;
111
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700112 private SettingsObserver mSettingsObserver;
113
114 private int mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
115 private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
116 private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
117
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700118 private static final String PROPERTIES_FILE = "/etc/gps.conf";
119 private String mNtpServer;
120 private boolean mNtpActive;
121
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700122 public ThrottleService(Context context) {
123 if (DBG) Slog.d(TAG, "Starting ThrottleService");
124 mContext = context;
125
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700126 mNtpActive = false;
127
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700128 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
129 Intent pollIntent = new Intent(ACTION_POLL, null);
130 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
131 Intent resetIntent = new Intent(ACTION_RESET, null);
132 mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
133
134 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
135 mNMService = INetworkManagementService.Stub.asInterface(b);
136
137 mNotificationManager = (NotificationManager)mContext.getSystemService(
138 Context.NOTIFICATION_SERVICE);
139 }
140
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700141 private static class SettingsObserver extends ContentObserver {
142 private int mMsg;
143 private Handler mHandler;
144 SettingsObserver(Handler handler, int msg) {
145 super(handler);
146 mHandler = handler;
147 mMsg = msg;
148 }
149
150 void observe(Context context) {
151 ContentResolver resolver = context.getContentResolver();
152 resolver.registerContentObserver(Settings.Secure.getUriFor(
153 Settings.Secure.THROTTLE_POLLING_SEC), false, this);
154 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700155 Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700156 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700157 Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700158 resolver.registerContentObserver(Settings.Secure.getUriFor(
159 Settings.Secure.THROTTLE_RESET_DAY), false, this);
160 resolver.registerContentObserver(Settings.Secure.getUriFor(
161 Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
162 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700163 Settings.Secure.THROTTLE_HELP_URI), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700164 }
165
166 @Override
167 public void onChange(boolean selfChange) {
168 mHandler.obtainMessage(mMsg).sendToTarget();
169 }
170 }
171
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700172 private void enforceAccessPermission() {
173 mContext.enforceCallingOrSelfPermission(
174 android.Manifest.permission.ACCESS_NETWORK_STATE,
175 "ThrottleService");
176 }
177
Robert Greenwalt05d06732010-04-19 11:10:38 -0700178 private long ntpToWallTime(long ntpTime) {
179 long bestNow = getBestTime();
180 long localNow = System.currentTimeMillis();
181 return localNow + (ntpTime - bestNow);
182 }
183
Irfan Sheriffcf282362010-04-16 16:53:20 -0700184 // TODO - fetch for the iface
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700185 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt05d06732010-04-19 11:10:38 -0700186
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700187 public synchronized long getResetTime(String iface) {
188 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700189 long resetTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700190 if (mRecorder != null) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700191 resetTime = ntpToWallTime(mRecorder.getPeriodEnd());
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700192 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700193 return resetTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700194 }
Irfan Sheriffcf282362010-04-16 16:53:20 -0700195
196 // TODO - fetch for the iface
Robert Greenwalt05d06732010-04-19 11:10:38 -0700197 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700198 public synchronized long getPeriodStartTime(String iface) {
199 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700200 long startTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700201 if (mRecorder != null) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700202 startTime = ntpToWallTime(mRecorder.getPeriodStart());
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700203 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700204 return startTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700205 }
206 //TODO - a better name? getCliffByteCountThreshold?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700207 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700208 public synchronized long getCliffThreshold(String iface, int cliff) {
209 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700210 if (cliff == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700211 return mPolicyThreshold;
212 }
213 return 0;
214 }
215 // TODO - a better name? getThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700216 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700217 public synchronized int getCliffLevel(String iface, int cliff) {
218 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700219 if (cliff == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700220 return mPolicyThrottleValue;
221 }
222 return 0;
223 }
224
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700225 public String getHelpUri() {
226 enforceAccessPermission();
227 return Settings.Secure.getString(mContext.getContentResolver(),
228 Settings.Secure.THROTTLE_HELP_URI);
229 }
230
Irfan Sheriffcf282362010-04-16 16:53:20 -0700231 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700232 public synchronized long getByteCount(String iface, int dir, int period, int ago) {
233 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700234 if ((period == ThrottleManager.PERIOD_CYCLE) &&
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700235 (mRecorder != null)) {
236 if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
237 if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
238 }
239 return 0;
240 }
241
242 // TODO - a better name - getCurrentThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700243 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700244 public synchronized int getThrottle(String iface) {
245 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700246 if (mThrottleIndex == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700247 return mPolicyThrottleValue;
248 }
249 return 0;
250 }
251
252 void systemReady() {
253 if (DBG) Slog.d(TAG, "systemReady");
254 mContext.registerReceiver(
255 new BroadcastReceiver() {
256 @Override
257 public void onReceive(Context context, Intent intent) {
258 mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
259 }
260 }, new IntentFilter(ACTION_POLL));
261
262 mContext.registerReceiver(
263 new BroadcastReceiver() {
264 @Override
265 public void onReceive(Context context, Intent intent) {
266 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
267 }
268 }, new IntentFilter(ACTION_RESET));
269
270 // use a new thread as we don't want to stall the system for file writes
271 mThread = new HandlerThread(TAG);
272 mThread.start();
273 mHandler = new MyHandler(mThread.getLooper());
274 mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700275
276 mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
277 mSettingsObserver.observe(mContext);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700278
279 FileInputStream stream = null;
280 try {
281 Properties properties = new Properties();
282 File file = new File(PROPERTIES_FILE);
283 stream = new FileInputStream(file);
284 properties.load(stream);
285 mNtpServer = properties.getProperty("NTP_SERVER", null);
286 } catch (IOException e) {
287 Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
288 } finally {
289 if (stream != null) {
290 try {
291 stream.close();
292 } catch (Exception e) {}
293 }
294 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700295 }
296
297
298 private static final int EVENT_REBOOT_RECOVERY = 0;
299 private static final int EVENT_POLICY_CHANGED = 1;
300 private static final int EVENT_POLL_ALARM = 2;
301 private static final int EVENT_RESET_ALARM = 3;
302 private class MyHandler extends Handler {
303 public MyHandler(Looper l) {
304 super(l);
305 }
306
307 @Override
308 public void handleMessage(Message msg) {
309 switch (msg.what) {
310 case EVENT_REBOOT_RECOVERY:
311 onRebootRecovery();
312 break;
313 case EVENT_POLICY_CHANGED:
314 onPolicyChanged();
315 break;
316 case EVENT_POLL_ALARM:
317 onPollAlarm();
318 break;
319 case EVENT_RESET_ALARM:
320 onResetAlarm();
321 }
322 }
323
324 private void onRebootRecovery() {
325 if (DBG) Slog.d(TAG, "onRebootRecovery");
326 // check for sim change TODO
327 // reregister for notification of policy change
328
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700329 mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700330
331 mRecorder = new DataRecorder(mContext, ThrottleService.this);
332
333 // get policy
334 mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
Robert Greenwaltfb9896b2010-04-22 15:39:38 -0700335
336 // if we poll now we won't have network connectivity or even imsi access
337 // queue up a poll to happen in a little while - after ntp and imsi are avail
338 // TODO - make this callback based (ie, listen for notificaitons)
339 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_POLL_ALARM),
340 INITIAL_POLL_DELAY_SEC * 1000);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700341 }
342
343 // check for new policy info (threshold limit/value/etc)
344 private void onPolicyChanged() {
345 boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
346
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700347 int pollingPeriod = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700348 R.integer.config_datause_polling_period_sec);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700349 mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
350 Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
351
352 // TODO - remove testing stuff?
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700353 long defaultThreshold = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700354 R.integer.config_datause_threshold_bytes);
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700355 int defaultValue = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700356 R.integer.config_datause_throttle_kbitsps);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700357 synchronized (ThrottleService.this) {
358 mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700359 Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700360 mPolicyThrottleValue = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700361 Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
362 if (testing) {
363 mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
364 mPolicyThreshold = TESTING_THRESHOLD;
365 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700366 }
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700367
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700368 mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
369 Settings.Secure.THROTTLE_RESET_DAY, -1);
370 if (mPolicyResetDay == -1 ||
371 ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
372 Random g = new Random();
373 mPolicyResetDay = 1 + g.nextInt(28); // 1-28
374 Settings.Secure.putInt(mContext.getContentResolver(),
375 Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
376 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700377 mIface = mContext.getResources().getString(R.string.config_datause_iface);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700378 synchronized (ThrottleService.this) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700379 if (mIface == null) {
380 mPolicyThreshold = 0;
381 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700382 }
383
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700384 int defaultNotificationType = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700385 R.integer.config_datause_notification_type);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700386 mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700387 Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700388
389 Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" + mPolicyPollPeriodSec +
390 ", threshold=" + mPolicyThreshold + ", value=" + mPolicyThrottleValue +
391 ", resetDay=" + mPolicyResetDay + ", noteType=" +
392 mPolicyNotificationsAllowedMask);
393
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700394 // force updates
395 mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
396
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700397 onResetAlarm();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700398
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700399 onPollAlarm();
400
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700401 Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
402 mContext.sendBroadcast(broadcast);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700403 }
404
405 private void onPollAlarm() {
406 long now = SystemClock.elapsedRealtime();
407 long next = now + mPolicyPollPeriodSec*1000;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700408
409 checkForAuthoritativeTime();
410
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700411 long incRead = 0;
412 long incWrite = 0;
413 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700414 incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
415 incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700416 // handle iface resets - on some device the 3g iface comes and goes and gets
417 // totals reset to 0. Deal with it
418 if ((incRead < 0) || (incWrite < 0)) {
419 incRead += mLastRead;
420 incWrite += mLastWrite;
421 mLastRead = 0;
422 mLastWrite = 0;
423 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700424 } catch (RemoteException e) {
425 Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
426 }
Robert Greenwalt5f996892010-04-08 16:19:24 -0700427 // don't count this data if we're roaming.
428 boolean roaming = "true".equals(
429 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
430 if (!roaming) {
431 mRecorder.addData(incRead, incWrite);
432 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700433
434 long periodRx = mRecorder.getPeriodRx(0);
435 long periodTx = mRecorder.getPeriodTx(0);
436 long total = periodRx + periodTx;
437 if (DBG) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700438 Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
Robert Greenwalt5f996892010-04-08 16:19:24 -0700439 ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700440 }
441 mLastRead += incRead;
442 mLastWrite += incWrite;
443
444 checkThrottleAndPostNotification(total);
445
446 Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
447 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
448 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700449 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
450 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700451 mContext.sendStickyBroadcast(broadcast);
452
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700453 mAlarmManager.cancel(mPendingPollIntent);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700454 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, next, mPendingPollIntent);
455 }
456
457 private void checkThrottleAndPostNotification(long currentTotal) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700458 // is throttling enabled?
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700459 if (mPolicyThreshold == 0) {
Robert Greenwaltcce83372010-04-23 17:35:29 -0700460 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700461 return;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700462 }
463
464 // have we spoken with an ntp server yet?
465 // this is controversial, but we'd rather err towards not throttling
466 if ((mNtpServer != null) && !mNtpActive) {
467 return;
468 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700469
470 // check if we need to throttle
471 if (currentTotal > mPolicyThreshold) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700472 if (mThrottleIndex != 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700473 synchronized (ThrottleService.this) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700474 mThrottleIndex = 1;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700475 }
476 if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
477 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700478 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700479 mPolicyThrottleValue, mPolicyThrottleValue);
480 } catch (Exception e) {
481 Slog.e(TAG, "error setting Throttle: " + e);
482 }
483
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700484 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700485
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700486 postNotification(R.string.throttled_notification_title,
487 R.string.throttled_notification_message,
488 R.drawable.stat_sys_throttled,
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700489 Notification.FLAG_ONGOING_EVENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700490
491 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
492 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, mPolicyThrottleValue);
493 mContext.sendStickyBroadcast(broadcast);
494
495 } // else already up!
496 } else {
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700497 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700498 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
499 // check if we should warn about throttle
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700500 // pretend we only have 1/2 the time remaining that we actually do
501 // if our burn rate in the period so far would have us exceed the limit
502 // in that 1/2 window, warn the user.
503 // this gets more generous in the early to middle period and converges back
504 // to the limit as we move toward the period end.
505
506 // adding another factor - it must be greater than the total cap/4
507 // else we may get false alarms very early in the period.. in the first
508 // tenth of a percent of the period if we used more than a tenth of a percent
509 // of the cap we'd get a warning and that's not desired.
510 long start = mRecorder.getPeriodStart();
511 long end = mRecorder.getPeriodEnd();
512 long periodLength = end - start;
513 long now = System.currentTimeMillis();
514 long timeUsed = now - start;
515 long warningThreshold = 2*mPolicyThreshold*timeUsed/(timeUsed+periodLength);
516 if ((currentTotal > warningThreshold) && (currentTotal > mPolicyThreshold/4)) {
517 if (mWarningNotificationSent == false) {
518 mWarningNotificationSent = true;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700519 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
520 postNotification(R.string.throttle_warning_notification_title,
521 R.string.throttle_warning_notification_message,
522 R.drawable.stat_sys_throttled,
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700523 0);
524 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700525 } else {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700526 if (mWarningNotificationSent == true) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700527 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700528 mWarningNotificationSent =false;
529 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700530 }
531 }
532 }
533 }
534
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700535 private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700536 Intent intent = new Intent();
537 // TODO - fix up intent
Robert Greenwalt2a7b7302010-04-12 14:56:31 -0700538 intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700539 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
540
541 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
542
543 Resources r = Resources.getSystem();
544 CharSequence title = r.getText(titleInt);
545 CharSequence message = r.getText(messageInt);
546 if (mThrottlingNotification == null) {
547 mThrottlingNotification = new Notification();
548 mThrottlingNotification.when = 0;
549 // TODO - fixup icon
550 mThrottlingNotification.icon = icon;
551 mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700552 }
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700553 mThrottlingNotification.flags = flags;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700554 mThrottlingNotification.tickerText = title;
555 mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
556
557 mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
558 }
559
560
561 private synchronized void clearThrottleAndNotification() {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700562 if (mThrottleIndex != THROTTLE_INDEX_UNTHROTTLED) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700563 synchronized (ThrottleService.this) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700564 mThrottleIndex = THROTTLE_INDEX_UNTHROTTLED;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700565 }
566 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700567 mNMService.setInterfaceThrottle(mIface, -1, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700568 } catch (Exception e) {
569 Slog.e(TAG, "error clearing Throttle: " + e);
570 }
571 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
572 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
573 mContext.sendStickyBroadcast(broadcast);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700574 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
575 mWarningNotificationSent = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700576 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700577 }
578
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700579 private Calendar calculatePeriodEnd(long now) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700580 Calendar end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700581 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700582 int day = end.get(Calendar.DAY_OF_MONTH);
583 end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
584 end.set(Calendar.HOUR_OF_DAY, 0);
585 end.set(Calendar.MINUTE, 0);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700586 end.set(Calendar.SECOND, 0);
587 end.set(Calendar.MILLISECOND, 0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700588 if (day >= mPolicyResetDay) {
589 int month = end.get(Calendar.MONTH);
590 if (month == Calendar.DECEMBER) {
591 end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
592 month = Calendar.JANUARY - 1;
593 }
594 end.set(Calendar.MONTH, month + 1);
595 }
596
597 // TODO - remove!
598 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
599 end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700600 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700601 end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
602 }
603 return end;
604 }
605 private Calendar calculatePeriodStart(Calendar end) {
606 Calendar start = (Calendar)end.clone();
607 int month = end.get(Calendar.MONTH);
608 if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
609 month = Calendar.DECEMBER + 1;
610 start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
611 }
612 start.set(Calendar.MONTH, month - 1);
613
614 // TODO - remove!!
615 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
616 start = (Calendar)end.clone();
617 start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
618 }
619 return start;
620 }
621
622 private void onResetAlarm() {
623 if (DBG) {
624 Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
625 " bytes read and " + mRecorder.getPeriodTx(0) + " written");
626 }
627
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700628 long now = getBestTime();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700629
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700630 if (mNtpActive || (mNtpServer == null)) {
631 Calendar end = calculatePeriodEnd(now);
632 Calendar start = calculatePeriodStart(end);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700633
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700634 if (mRecorder.setNextPeriod(start, end)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700635 onPollAlarm();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700636 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700637
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700638 mAlarmManager.cancel(mPendingResetIntent);
639 long offset = end.getTimeInMillis() - now;
640 // use Elapsed realtime so clock changes don't fool us.
641 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
642 SystemClock.elapsedRealtime() + offset,
643 mPendingResetIntent);
644 } else {
645 if (DBG) Slog.d(TAG, "no authoritative time - not resetting period");
646 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700647 }
648 }
649
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700650 private void checkForAuthoritativeTime() {
651 if (mNtpActive || (mNtpServer == null)) return;
652
Robert Greenwalt05d06732010-04-19 11:10:38 -0700653 // will try to get the ntp time and switch to it if found.
654 // will also cache the time so we don't fetch it repeatedly.
655 getBestTime();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700656 }
657
Robert Greenwalt05d06732010-04-19 11:10:38 -0700658 private static final int MAX_NTP_CACHE_AGE = 30 * 1000;
659 private static final int MAX_NTP_FETCH_WAIT = 10 * 1000;
660 private long cachedNtp;
661 private long cachedNtpTimestamp;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700662
Robert Greenwalt05d06732010-04-19 11:10:38 -0700663 private long getBestTime() {
664 if (mNtpServer != null) {
665 if (mNtpActive) {
666 long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
667 if (ntpAge < MAX_NTP_CACHE_AGE) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700668 if (VDBG) Slog.v(TAG, "using cached time");
Robert Greenwalt05d06732010-04-19 11:10:38 -0700669 return cachedNtp + ntpAge;
670 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700671 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700672 SntpClient client = new SntpClient();
673 if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT)) {
674 cachedNtp = client.getNtpTime();
675 cachedNtpTimestamp = SystemClock.elapsedRealtime();
676 if (!mNtpActive) {
677 mNtpActive = true;
678 if (DBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
679 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
680 }
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700681 if (VDBG) Slog.v(TAG, "using Authoritative time: " + cachedNtp);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700682 return cachedNtp;
683 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700684 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700685 long time = System.currentTimeMillis();
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700686 if (VDBG) Slog.v(TAG, "using User time: " + time);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700687 mNtpActive = false;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700688 return time;
689 }
690
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700691 // records bytecount data for a given time and accumulates it into larger time windows
692 // for logging and other purposes
693 //
694 // since time can be changed (user or network action) we will have to track the time of the
695 // last recording and deal with it.
696 private static class DataRecorder {
697 long[] mPeriodRxData;
698 long[] mPeriodTxData;
699 int mCurrentPeriod;
700 int mPeriodCount;
701
702 Calendar mPeriodStart;
703 Calendar mPeriodEnd;
704
705 ThrottleService mParent;
706 Context mContext;
Robert Greenwalte6e98822010-04-15 08:27:14 -0700707 String mImsi = null;
708
709 TelephonyManager mTelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700710
711 DataRecorder(Context context, ThrottleService parent) {
712 mContext = context;
713 mParent = parent;
714
Robert Greenwalte6e98822010-04-15 08:27:14 -0700715 mTelephonyManager = (TelephonyManager)mContext.getSystemService(
716 Context.TELEPHONY_SERVICE);
717
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700718 synchronized (mParent) {
719 mPeriodCount = 6;
720 mPeriodRxData = new long[mPeriodCount];
721 mPeriodTxData = new long[mPeriodCount];
722
723 mPeriodStart = Calendar.getInstance();
724 mPeriodEnd = Calendar.getInstance();
725
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700726 retrieve();
727 }
728 }
729
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700730 boolean setNextPeriod(Calendar start, Calendar end) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700731 // TODO - how would we deal with a dual-IMSI device?
732 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700733 boolean startNewPeriod = true;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700734
Robert Greenwalt27fba672010-04-26 12:29:14 -0700735 if (start.equals(mPeriodStart) && end.equals(mPeriodEnd)) {
736 // same endpoints - keep collecting
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700737 if (DBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700738 Slog.d(TAG, "same period (" + start.getTimeInMillis() + "," +
739 end.getTimeInMillis() +") - ammending data");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700740 }
Robert Greenwalt27fba672010-04-26 12:29:14 -0700741 startNewPeriod = false;
742 } else {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700743 if (DBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700744 if(start.equals(mPeriodEnd) || start.after(mPeriodEnd)) {
745 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
746 end.getTimeInMillis() + ") - old end was " +
747 mPeriodEnd.getTimeInMillis() + ", following");
748 } else {
749 Slog.d(TAG, "new period (" + start.getTimeInMillis() + "," +
750 end.getTimeInMillis() + ") replacing old (" +
751 mPeriodStart.getTimeInMillis() + "," +
752 mPeriodEnd.getTimeInMillis() + ")");
753 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700754 }
755 synchronized (mParent) {
756 ++mCurrentPeriod;
757 if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
758 mPeriodRxData[mCurrentPeriod] = 0;
759 mPeriodTxData[mCurrentPeriod] = 0;
760 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700761 }
762 setPeriodStart(start);
763 setPeriodEnd(end);
764 record();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700765 return startNewPeriod;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700766 }
767
768 public long getPeriodEnd() {
769 synchronized (mParent) {
770 return mPeriodEnd.getTimeInMillis();
771 }
772 }
773
774 private void setPeriodEnd(Calendar end) {
775 synchronized (mParent) {
776 mPeriodEnd = end;
777 }
778 }
779
780 public long getPeriodStart() {
781 synchronized (mParent) {
782 return mPeriodStart.getTimeInMillis();
783 }
784 }
785
786 private void setPeriodStart(Calendar start) {
787 synchronized (mParent) {
788 mPeriodStart = start;
789 }
790 }
791
792 public int getPeriodCount() {
793 synchronized (mParent) {
794 return mPeriodCount;
795 }
796 }
797
798 private void zeroData(int field) {
799 synchronized (mParent) {
800 for(int period = 0; period<mPeriodCount; period++) {
801 mPeriodRxData[period] = 0;
802 mPeriodTxData[period] = 0;
803 }
804 mCurrentPeriod = 0;
805 }
806
807 }
808
809 // if time moves backward accumulate all read/write that's lost into the now
810 // otherwise time moved forward.
811 void addData(long bytesRead, long bytesWritten) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700812 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700813
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700814 synchronized (mParent) {
815 mPeriodRxData[mCurrentPeriod] += bytesRead;
816 mPeriodTxData[mCurrentPeriod] += bytesWritten;
817 }
818 record();
819 }
820
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700821 private File getDataFile() {
822 File dataDir = Environment.getDataDirectory();
823 File throttleDir = new File(dataDir, "system/throttle");
824 throttleDir.mkdirs();
Robert Greenwalte6e98822010-04-15 08:27:14 -0700825 String mImsi = mTelephonyManager.getSubscriberId();
826 File dataFile;
827 if (mImsi == null) {
828 dataFile = useMRUFile(throttleDir);
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700829 if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700830 } else {
831 String imsiHash = Integer.toString(mImsi.hashCode());
832 dataFile = new File(throttleDir, imsiHash);
833 }
834 // touch the file so it's not LRU
835 dataFile.setLastModified(System.currentTimeMillis());
836 checkAndDeleteLRUDataFile(throttleDir);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700837 return dataFile;
838 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700839
Robert Greenwalte6e98822010-04-15 08:27:14 -0700840 // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
841 private void checkForSubscriberId() {
842 if (mImsi != null) return;
843
844 mImsi = mTelephonyManager.getSubscriberId();
845 if (mImsi == null) return;
846
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700847 if (DBG) Slog.d(TAG, "finally have imsi - retreiving data");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700848 retrieve();
849 }
850
851 private final static int MAX_SIMS_SUPPORTED = 3;
852
853 private void checkAndDeleteLRUDataFile(File dir) {
854 File[] files = dir.listFiles();
855
856 if (files.length <= MAX_SIMS_SUPPORTED) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700857 if (DBG) Slog.d(TAG, "Too many data files");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700858 do {
859 File oldest = null;
860 for (File f : files) {
861 if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
862 oldest = f;
863 }
864 }
865 if (oldest == null) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700866 if (DBG) Slog.d(TAG, " deleting " + oldest);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700867 oldest.delete();
868 files = dir.listFiles();
869 } while (files.length > MAX_SIMS_SUPPORTED);
870 }
871
872 private File useMRUFile(File dir) {
873 File newest = null;
874 File[] files = dir.listFiles();
875
876 for (File f : files) {
877 if ((newest == null) || (newest.lastModified() < f.lastModified())) {
878 newest = f;
879 }
880 }
881 if (newest == null) {
882 newest = new File(dir, "temp");
883 }
884 return newest;
885 }
886
887
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700888 private static final int DATA_FILE_VERSION = 1;
889
890 private void record() {
891 // 1 int version
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700892 // 1 int mPeriodCount
893 // 13*6 long[PERIOD_COUNT] mPeriodRxData
894 // 13*6 long[PERIOD_COUNT] mPeriodTxData
895 // 1 int mCurrentPeriod
896 // 13 long periodStartMS
897 // 13 long periodEndMS
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700898 // 200 chars max
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700899 StringBuilder builder = new StringBuilder();
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700900 builder.append(DATA_FILE_VERSION);
901 builder.append(":");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700902 builder.append(mPeriodCount);
903 builder.append(":");
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700904 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700905 builder.append(mPeriodRxData[i]);
906 builder.append(":");
907 }
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700908 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700909 builder.append(mPeriodTxData[i]);
910 builder.append(":");
911 }
912 builder.append(mCurrentPeriod);
913 builder.append(":");
914 builder.append(mPeriodStart.getTimeInMillis());
915 builder.append(":");
916 builder.append(mPeriodEnd.getTimeInMillis());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700917
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700918 BufferedWriter out = null;
919 try {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700920 out = new BufferedWriter(new FileWriter(getDataFile()), 256);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700921 out.write(builder.toString());
922 } catch (IOException e) {
923 Slog.e(TAG, "Error writing data file");
924 return;
925 } finally {
926 if (out != null) {
927 try {
928 out.close();
929 } catch (Exception e) {}
930 }
931 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700932 }
933
934 private void retrieve() {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700935 // clean out any old data first. If we fail to read we don't want old stuff
936 zeroData(0);
937
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700938 File f = getDataFile();
939 byte[] buffer;
940 FileInputStream s = null;
941 try {
942 buffer = new byte[(int)f.length()];
943 s = new FileInputStream(f);
944 s.read(buffer);
945 } catch (IOException e) {
946 Slog.e(TAG, "Error reading data file");
947 return;
948 } finally {
949 if (s != null) {
950 try {
951 s.close();
952 } catch (Exception e) {}
953 }
954 }
955 String data = new String(buffer);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700956 if (data == null || data.length() == 0) {
957 if (DBG) Slog.d(TAG, "data file empty");
958 return;
959 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700960 synchronized (mParent) {
961 String[] parsed = data.split(":");
962 int parsedUsed = 0;
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700963 if (parsed.length < 6) {
964 Slog.e(TAG, "reading data file with insufficient length - ignoring");
965 return;
966 }
967
968 if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
969 Slog.e(TAG, "reading data file with bad version - ignoring");
970 return;
971 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700972
973 mPeriodCount = Integer.parseInt(parsed[parsedUsed++]);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700974 if (parsed.length != 5 + (2 * mPeriodCount)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700975 Slog.e(TAG, "reading data file with bad length ("+parsed.length+" != "+(5 + (2*mPeriodCount))+") - ignoring");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700976 return;
977 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700978
979 mPeriodRxData = new long[mPeriodCount];
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700980 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700981 mPeriodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
982 }
983 mPeriodTxData = new long[mPeriodCount];
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700984 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700985 mPeriodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
986 }
987 mCurrentPeriod = Integer.parseInt(parsed[parsedUsed++]);
988 mPeriodStart = new GregorianCalendar();
989 mPeriodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
990 mPeriodEnd = new GregorianCalendar();
991 mPeriodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
992 }
993 }
994
995 long getPeriodRx(int which) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700996 synchronized (mParent) {
997 if (which > mPeriodCount) return 0;
998 which = mCurrentPeriod - which;
999 if (which < 0) which += mPeriodCount;
1000 return mPeriodRxData[which];
1001 }
1002 }
1003 long getPeriodTx(int which) {
1004 synchronized (mParent) {
1005 if (which > mPeriodCount) return 0;
1006 which = mCurrentPeriod - which;
1007 if (which < 0) which += mPeriodCount;
1008 return mPeriodTxData[which];
1009 }
1010 }
1011 }
1012
1013 @Override
1014 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1015 if (mContext.checkCallingOrSelfPermission(
1016 android.Manifest.permission.DUMP)
1017 != PackageManager.PERMISSION_GRANTED) {
1018 pw.println("Permission Denial: can't dump ThrottleService " +
1019 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1020 Binder.getCallingUid());
1021 return;
1022 }
1023 pw.println();
1024
1025 pw.println("The threshold is " + mPolicyThreshold +
1026 ", after which you experince throttling to " +
1027 mPolicyThrottleValue + "kbps");
1028 pw.println("Current period is " +
1029 (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001030 "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001031 " seconds.");
1032 pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
Robert Greenwalt8c7e6092010-04-14 17:31:20 -07001033 pw.println("Current Throttle Index is " + mThrottleIndex);
1034
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001035 for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
1036 pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
1037 mRecorder.getPeriodTx(i));
1038 }
1039 }
1040}