blob: 2fe7420e3803e6faddd5ca464b8dd1c36daa69cf [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 Greenwalt9e696c22010-04-01 14:45:18 -0700460 return;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700461 }
462
463 // have we spoken with an ntp server yet?
464 // this is controversial, but we'd rather err towards not throttling
465 if ((mNtpServer != null) && !mNtpActive) {
466 return;
467 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700468
469 // check if we need to throttle
470 if (currentTotal > mPolicyThreshold) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700471 if (mThrottleIndex != 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700472 synchronized (ThrottleService.this) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700473 mThrottleIndex = 1;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700474 }
475 if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
476 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700477 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700478 mPolicyThrottleValue, mPolicyThrottleValue);
479 } catch (Exception e) {
480 Slog.e(TAG, "error setting Throttle: " + e);
481 }
482
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700483 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700484
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700485 postNotification(R.string.throttled_notification_title,
486 R.string.throttled_notification_message,
487 R.drawable.stat_sys_throttled,
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700488 Notification.FLAG_ONGOING_EVENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700489
490 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
491 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, mPolicyThrottleValue);
492 mContext.sendStickyBroadcast(broadcast);
493
494 } // else already up!
495 } else {
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700496 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700497 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
498 // check if we should warn about throttle
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700499 // pretend we only have 1/2 the time remaining that we actually do
500 // if our burn rate in the period so far would have us exceed the limit
501 // in that 1/2 window, warn the user.
502 // this gets more generous in the early to middle period and converges back
503 // to the limit as we move toward the period end.
504
505 // adding another factor - it must be greater than the total cap/4
506 // else we may get false alarms very early in the period.. in the first
507 // tenth of a percent of the period if we used more than a tenth of a percent
508 // of the cap we'd get a warning and that's not desired.
509 long start = mRecorder.getPeriodStart();
510 long end = mRecorder.getPeriodEnd();
511 long periodLength = end - start;
512 long now = System.currentTimeMillis();
513 long timeUsed = now - start;
514 long warningThreshold = 2*mPolicyThreshold*timeUsed/(timeUsed+periodLength);
515 if ((currentTotal > warningThreshold) && (currentTotal > mPolicyThreshold/4)) {
516 if (mWarningNotificationSent == false) {
517 mWarningNotificationSent = true;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700518 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
519 postNotification(R.string.throttle_warning_notification_title,
520 R.string.throttle_warning_notification_message,
521 R.drawable.stat_sys_throttled,
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700522 0);
523 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700524 } else {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700525 if (mWarningNotificationSent == true) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700526 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700527 mWarningNotificationSent =false;
528 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700529 }
530 }
531 }
532 }
533
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700534 private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700535 Intent intent = new Intent();
536 // TODO - fix up intent
Robert Greenwalt2a7b7302010-04-12 14:56:31 -0700537 intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700538 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
539
540 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
541
542 Resources r = Resources.getSystem();
543 CharSequence title = r.getText(titleInt);
544 CharSequence message = r.getText(messageInt);
545 if (mThrottlingNotification == null) {
546 mThrottlingNotification = new Notification();
547 mThrottlingNotification.when = 0;
548 // TODO - fixup icon
549 mThrottlingNotification.icon = icon;
550 mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700551 }
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700552 mThrottlingNotification.flags = flags;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700553 mThrottlingNotification.tickerText = title;
554 mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
555
556 mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
557 }
558
559
560 private synchronized void clearThrottleAndNotification() {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700561 if (mThrottleIndex != THROTTLE_INDEX_UNTHROTTLED) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700562 synchronized (ThrottleService.this) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700563 mThrottleIndex = THROTTLE_INDEX_UNTHROTTLED;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700564 }
565 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700566 mNMService.setInterfaceThrottle(mIface, -1, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700567 } catch (Exception e) {
568 Slog.e(TAG, "error clearing Throttle: " + e);
569 }
570 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
571 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
572 mContext.sendStickyBroadcast(broadcast);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700573 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
574 mWarningNotificationSent = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700575 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700576 }
577
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700578 private Calendar calculatePeriodEnd(long now) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700579 Calendar end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700580 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700581 int day = end.get(Calendar.DAY_OF_MONTH);
582 end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
583 end.set(Calendar.HOUR_OF_DAY, 0);
584 end.set(Calendar.MINUTE, 0);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700585 end.set(Calendar.SECOND, 0);
586 end.set(Calendar.MILLISECOND, 0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700587 if (day >= mPolicyResetDay) {
588 int month = end.get(Calendar.MONTH);
589 if (month == Calendar.DECEMBER) {
590 end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
591 month = Calendar.JANUARY - 1;
592 }
593 end.set(Calendar.MONTH, month + 1);
594 }
595
596 // TODO - remove!
597 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
598 end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700599 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700600 end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
601 }
602 return end;
603 }
604 private Calendar calculatePeriodStart(Calendar end) {
605 Calendar start = (Calendar)end.clone();
606 int month = end.get(Calendar.MONTH);
607 if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
608 month = Calendar.DECEMBER + 1;
609 start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
610 }
611 start.set(Calendar.MONTH, month - 1);
612
613 // TODO - remove!!
614 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
615 start = (Calendar)end.clone();
616 start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
617 }
618 return start;
619 }
620
621 private void onResetAlarm() {
622 if (DBG) {
623 Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
624 " bytes read and " + mRecorder.getPeriodTx(0) + " written");
625 }
626
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700627 long now = getBestTime();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700628
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700629 if (mNtpActive || (mNtpServer == null)) {
630 Calendar end = calculatePeriodEnd(now);
631 Calendar start = calculatePeriodStart(end);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700632
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700633 if (mRecorder.setNextPeriod(start, end)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700634 onPollAlarm();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700635 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700636
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700637 mAlarmManager.cancel(mPendingResetIntent);
638 long offset = end.getTimeInMillis() - now;
639 // use Elapsed realtime so clock changes don't fool us.
640 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
641 SystemClock.elapsedRealtime() + offset,
642 mPendingResetIntent);
643 } else {
644 if (DBG) Slog.d(TAG, "no authoritative time - not resetting period");
645 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700646 }
647 }
648
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700649 private void checkForAuthoritativeTime() {
650 if (mNtpActive || (mNtpServer == null)) return;
651
Robert Greenwalt05d06732010-04-19 11:10:38 -0700652 // will try to get the ntp time and switch to it if found.
653 // will also cache the time so we don't fetch it repeatedly.
654 getBestTime();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700655 }
656
Robert Greenwalt05d06732010-04-19 11:10:38 -0700657 private static final int MAX_NTP_CACHE_AGE = 30 * 1000;
658 private static final int MAX_NTP_FETCH_WAIT = 10 * 1000;
659 private long cachedNtp;
660 private long cachedNtpTimestamp;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700661
Robert Greenwalt05d06732010-04-19 11:10:38 -0700662 private long getBestTime() {
663 if (mNtpServer != null) {
664 if (mNtpActive) {
665 long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
666 if (ntpAge < MAX_NTP_CACHE_AGE) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700667 if (VDBG) Slog.v(TAG, "using cached time");
Robert Greenwalt05d06732010-04-19 11:10:38 -0700668 return cachedNtp + ntpAge;
669 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700670 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700671 SntpClient client = new SntpClient();
672 if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT)) {
673 cachedNtp = client.getNtpTime();
674 cachedNtpTimestamp = SystemClock.elapsedRealtime();
675 if (!mNtpActive) {
676 mNtpActive = true;
677 if (DBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
678 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
679 }
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700680 if (VDBG) Slog.v(TAG, "using Authoritative time: " + cachedNtp);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700681 return cachedNtp;
682 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700683 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700684 long time = System.currentTimeMillis();
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700685 if (VDBG) Slog.v(TAG, "using User time: " + time);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700686 mNtpActive = false;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700687 return time;
688 }
689
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700690 // records bytecount data for a given time and accumulates it into larger time windows
691 // for logging and other purposes
692 //
693 // since time can be changed (user or network action) we will have to track the time of the
694 // last recording and deal with it.
695 private static class DataRecorder {
696 long[] mPeriodRxData;
697 long[] mPeriodTxData;
698 int mCurrentPeriod;
699 int mPeriodCount;
700
701 Calendar mPeriodStart;
702 Calendar mPeriodEnd;
703
704 ThrottleService mParent;
705 Context mContext;
Robert Greenwalte6e98822010-04-15 08:27:14 -0700706 String mImsi = null;
707
708 TelephonyManager mTelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700709
710 DataRecorder(Context context, ThrottleService parent) {
711 mContext = context;
712 mParent = parent;
713
Robert Greenwalte6e98822010-04-15 08:27:14 -0700714 mTelephonyManager = (TelephonyManager)mContext.getSystemService(
715 Context.TELEPHONY_SERVICE);
716
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700717 synchronized (mParent) {
718 mPeriodCount = 6;
719 mPeriodRxData = new long[mPeriodCount];
720 mPeriodTxData = new long[mPeriodCount];
721
722 mPeriodStart = Calendar.getInstance();
723 mPeriodEnd = Calendar.getInstance();
724
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700725 retrieve();
726 }
727 }
728
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700729 boolean setNextPeriod(Calendar start, Calendar end) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700730 // TODO - how would we deal with a dual-IMSI device?
731 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700732 boolean startNewPeriod = true;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700733
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700734 // if we rolled back in time, toss out
735 // if we rolled foward, advance to the next
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700736 if (end.before(mPeriodStart)) {
737 if (DBG) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700738 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
739 end.getTimeInMillis() + ") - old start was " +
740 mPeriodStart.getTimeInMillis() + ", wiping");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700741 }
742 synchronized (mParent) {
743 mPeriodRxData[mCurrentPeriod] = 0;
744 mPeriodTxData[mCurrentPeriod] = 0;
745 }
746 } else if(start.after(mPeriodEnd)) {
747 if (DBG) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700748 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
749 end.getTimeInMillis() + ") - old end was " +
750 mPeriodEnd.getTimeInMillis() + ", following");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700751 }
752 synchronized (mParent) {
753 ++mCurrentPeriod;
754 if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
755 mPeriodRxData[mCurrentPeriod] = 0;
756 mPeriodTxData[mCurrentPeriod] = 0;
757 }
758 } else {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700759 startNewPeriod = false;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700760 if (DBG) {
761 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
762 end.getTimeInMillis() + ") - we fit - ammending to last period");
763 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700764 }
765 setPeriodStart(start);
766 setPeriodEnd(end);
767 record();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700768 return startNewPeriod;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700769 }
770
771 public long getPeriodEnd() {
772 synchronized (mParent) {
773 return mPeriodEnd.getTimeInMillis();
774 }
775 }
776
777 private void setPeriodEnd(Calendar end) {
778 synchronized (mParent) {
779 mPeriodEnd = end;
780 }
781 }
782
783 public long getPeriodStart() {
784 synchronized (mParent) {
785 return mPeriodStart.getTimeInMillis();
786 }
787 }
788
789 private void setPeriodStart(Calendar start) {
790 synchronized (mParent) {
791 mPeriodStart = start;
792 }
793 }
794
795 public int getPeriodCount() {
796 synchronized (mParent) {
797 return mPeriodCount;
798 }
799 }
800
801 private void zeroData(int field) {
802 synchronized (mParent) {
803 for(int period = 0; period<mPeriodCount; period++) {
804 mPeriodRxData[period] = 0;
805 mPeriodTxData[period] = 0;
806 }
807 mCurrentPeriod = 0;
808 }
809
810 }
811
812 // if time moves backward accumulate all read/write that's lost into the now
813 // otherwise time moved forward.
814 void addData(long bytesRead, long bytesWritten) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700815 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700816
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700817 synchronized (mParent) {
818 mPeriodRxData[mCurrentPeriod] += bytesRead;
819 mPeriodTxData[mCurrentPeriod] += bytesWritten;
820 }
821 record();
822 }
823
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700824 private File getDataFile() {
825 File dataDir = Environment.getDataDirectory();
826 File throttleDir = new File(dataDir, "system/throttle");
827 throttleDir.mkdirs();
Robert Greenwalte6e98822010-04-15 08:27:14 -0700828 String mImsi = mTelephonyManager.getSubscriberId();
829 File dataFile;
830 if (mImsi == null) {
831 dataFile = useMRUFile(throttleDir);
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700832 if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700833 } else {
834 String imsiHash = Integer.toString(mImsi.hashCode());
835 dataFile = new File(throttleDir, imsiHash);
836 }
837 // touch the file so it's not LRU
838 dataFile.setLastModified(System.currentTimeMillis());
839 checkAndDeleteLRUDataFile(throttleDir);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700840 return dataFile;
841 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700842
Robert Greenwalte6e98822010-04-15 08:27:14 -0700843 // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
844 private void checkForSubscriberId() {
845 if (mImsi != null) return;
846
847 mImsi = mTelephonyManager.getSubscriberId();
848 if (mImsi == null) return;
849
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700850 if (DBG) Slog.d(TAG, "finally have imsi - retreiving data");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700851 retrieve();
852 }
853
854 private final static int MAX_SIMS_SUPPORTED = 3;
855
856 private void checkAndDeleteLRUDataFile(File dir) {
857 File[] files = dir.listFiles();
858
859 if (files.length <= MAX_SIMS_SUPPORTED) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700860 if (DBG) Slog.d(TAG, "Too many data files");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700861 do {
862 File oldest = null;
863 for (File f : files) {
864 if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
865 oldest = f;
866 }
867 }
868 if (oldest == null) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700869 if (DBG) Slog.d(TAG, " deleting " + oldest);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700870 oldest.delete();
871 files = dir.listFiles();
872 } while (files.length > MAX_SIMS_SUPPORTED);
873 }
874
875 private File useMRUFile(File dir) {
876 File newest = null;
877 File[] files = dir.listFiles();
878
879 for (File f : files) {
880 if ((newest == null) || (newest.lastModified() < f.lastModified())) {
881 newest = f;
882 }
883 }
884 if (newest == null) {
885 newest = new File(dir, "temp");
886 }
887 return newest;
888 }
889
890
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700891 private static final int DATA_FILE_VERSION = 1;
892
893 private void record() {
894 // 1 int version
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700895 // 1 int mPeriodCount
896 // 13*6 long[PERIOD_COUNT] mPeriodRxData
897 // 13*6 long[PERIOD_COUNT] mPeriodTxData
898 // 1 int mCurrentPeriod
899 // 13 long periodStartMS
900 // 13 long periodEndMS
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700901 // 200 chars max
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700902 StringBuilder builder = new StringBuilder();
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700903 builder.append(DATA_FILE_VERSION);
904 builder.append(":");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700905 builder.append(mPeriodCount);
906 builder.append(":");
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700907 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700908 builder.append(mPeriodRxData[i]);
909 builder.append(":");
910 }
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700911 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700912 builder.append(mPeriodTxData[i]);
913 builder.append(":");
914 }
915 builder.append(mCurrentPeriod);
916 builder.append(":");
917 builder.append(mPeriodStart.getTimeInMillis());
918 builder.append(":");
919 builder.append(mPeriodEnd.getTimeInMillis());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700920
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700921 BufferedWriter out = null;
922 try {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700923 out = new BufferedWriter(new FileWriter(getDataFile()), 256);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700924 out.write(builder.toString());
925 } catch (IOException e) {
926 Slog.e(TAG, "Error writing data file");
927 return;
928 } finally {
929 if (out != null) {
930 try {
931 out.close();
932 } catch (Exception e) {}
933 }
934 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700935 }
936
937 private void retrieve() {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700938 // clean out any old data first. If we fail to read we don't want old stuff
939 zeroData(0);
940
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700941 File f = getDataFile();
942 byte[] buffer;
943 FileInputStream s = null;
944 try {
945 buffer = new byte[(int)f.length()];
946 s = new FileInputStream(f);
947 s.read(buffer);
948 } catch (IOException e) {
949 Slog.e(TAG, "Error reading data file");
950 return;
951 } finally {
952 if (s != null) {
953 try {
954 s.close();
955 } catch (Exception e) {}
956 }
957 }
958 String data = new String(buffer);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700959 if (data == null || data.length() == 0) {
960 if (DBG) Slog.d(TAG, "data file empty");
961 return;
962 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700963 synchronized (mParent) {
964 String[] parsed = data.split(":");
965 int parsedUsed = 0;
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700966 if (parsed.length < 6) {
967 Slog.e(TAG, "reading data file with insufficient length - ignoring");
968 return;
969 }
970
971 if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
972 Slog.e(TAG, "reading data file with bad version - ignoring");
973 return;
974 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700975
976 mPeriodCount = Integer.parseInt(parsed[parsedUsed++]);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700977 if (parsed.length != 5 + (2 * mPeriodCount)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700978 Slog.e(TAG, "reading data file with bad length ("+parsed.length+" != "+(5 + (2*mPeriodCount))+") - ignoring");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700979 return;
980 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700981
982 mPeriodRxData = new long[mPeriodCount];
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700983 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700984 mPeriodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
985 }
986 mPeriodTxData = new long[mPeriodCount];
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700987 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700988 mPeriodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
989 }
990 mCurrentPeriod = Integer.parseInt(parsed[parsedUsed++]);
991 mPeriodStart = new GregorianCalendar();
992 mPeriodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
993 mPeriodEnd = new GregorianCalendar();
994 mPeriodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
995 }
996 }
997
998 long getPeriodRx(int which) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700999 synchronized (mParent) {
1000 if (which > mPeriodCount) return 0;
1001 which = mCurrentPeriod - which;
1002 if (which < 0) which += mPeriodCount;
1003 return mPeriodRxData[which];
1004 }
1005 }
1006 long getPeriodTx(int which) {
1007 synchronized (mParent) {
1008 if (which > mPeriodCount) return 0;
1009 which = mCurrentPeriod - which;
1010 if (which < 0) which += mPeriodCount;
1011 return mPeriodTxData[which];
1012 }
1013 }
1014 }
1015
1016 @Override
1017 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1018 if (mContext.checkCallingOrSelfPermission(
1019 android.Manifest.permission.DUMP)
1020 != PackageManager.PERMISSION_GRANTED) {
1021 pw.println("Permission Denial: can't dump ThrottleService " +
1022 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1023 Binder.getCallingUid());
1024 return;
1025 }
1026 pw.println();
1027
1028 pw.println("The threshold is " + mPolicyThreshold +
1029 ", after which you experince throttling to " +
1030 mPolicyThrottleValue + "kbps");
1031 pw.println("Current period is " +
1032 (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001033 "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001034 " seconds.");
1035 pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
Robert Greenwalt8c7e6092010-04-14 17:31:20 -07001036 pw.println("Current Throttle Index is " + mThrottleIndex);
1037
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001038 for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
1039 pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
1040 mRecorder.getPeriodTx(i));
1041 }
1042 }
1043}