blob: 4ff0fb9833f3c10ab2e0d5b92d4bc4006d067a70 [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 Greenwalt9e696c22010-04-01 14:45:18 -070078 private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070079 private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070080 private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070081
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070082 private int mPolicyPollPeriodSec;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070083 private long mPolicyThreshold;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070084 private int mPolicyThrottleValue;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070085 private int mPolicyResetDay; // 1-28
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070086 private int mPolicyNotificationsAllowedMask;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070087
88 private long mLastRead; // read byte count from last poll
89 private long mLastWrite; // write byte count from last poll
90
91 private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
92 private static int POLL_REQUEST = 0;
93 private PendingIntent mPendingPollIntent;
94 private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
95 private static int RESET_REQUEST = 1;
96 private PendingIntent mPendingResetIntent;
97
98 private INetworkManagementService mNMService;
99 private AlarmManager mAlarmManager;
100 private NotificationManager mNotificationManager;
101
102 private DataRecorder mRecorder;
103
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700104 private String mIface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700105
106 private static final int NOTIFICATION_WARNING = 2;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700107
108 private Notification mThrottlingNotification;
109 private boolean mWarningNotificationSent = false;
110
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700111 private SettingsObserver mSettingsObserver;
112
113 private int mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
114 private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
115 private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
116
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700117 private static final String PROPERTIES_FILE = "/etc/gps.conf";
118 private String mNtpServer;
119 private boolean mNtpActive;
120
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700121 public ThrottleService(Context context) {
122 if (DBG) Slog.d(TAG, "Starting ThrottleService");
123 mContext = context;
124
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700125 mNtpActive = false;
126
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700127 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
128 Intent pollIntent = new Intent(ACTION_POLL, null);
129 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
130 Intent resetIntent = new Intent(ACTION_RESET, null);
131 mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
132
133 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
134 mNMService = INetworkManagementService.Stub.asInterface(b);
135
136 mNotificationManager = (NotificationManager)mContext.getSystemService(
137 Context.NOTIFICATION_SERVICE);
138 }
139
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700140 private static class SettingsObserver extends ContentObserver {
141 private int mMsg;
142 private Handler mHandler;
143 SettingsObserver(Handler handler, int msg) {
144 super(handler);
145 mHandler = handler;
146 mMsg = msg;
147 }
148
149 void observe(Context context) {
150 ContentResolver resolver = context.getContentResolver();
151 resolver.registerContentObserver(Settings.Secure.getUriFor(
152 Settings.Secure.THROTTLE_POLLING_SEC), false, this);
153 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700154 Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700155 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700156 Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700157 resolver.registerContentObserver(Settings.Secure.getUriFor(
158 Settings.Secure.THROTTLE_RESET_DAY), false, this);
159 resolver.registerContentObserver(Settings.Secure.getUriFor(
160 Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
161 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700162 Settings.Secure.THROTTLE_HELP_URI), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700163 }
164
165 @Override
166 public void onChange(boolean selfChange) {
167 mHandler.obtainMessage(mMsg).sendToTarget();
168 }
169 }
170
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700171 private void enforceAccessPermission() {
172 mContext.enforceCallingOrSelfPermission(
173 android.Manifest.permission.ACCESS_NETWORK_STATE,
174 "ThrottleService");
175 }
176
Robert Greenwalt05d06732010-04-19 11:10:38 -0700177 private long ntpToWallTime(long ntpTime) {
178 long bestNow = getBestTime();
179 long localNow = System.currentTimeMillis();
180 return localNow + (ntpTime - bestNow);
181 }
182
Irfan Sheriffcf282362010-04-16 16:53:20 -0700183 // TODO - fetch for the iface
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700184 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt05d06732010-04-19 11:10:38 -0700185
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700186 public synchronized long getResetTime(String iface) {
187 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700188 long resetTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700189 if (mRecorder != null) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700190 resetTime = ntpToWallTime(mRecorder.getPeriodEnd());
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700191 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700192 return resetTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700193 }
Irfan Sheriffcf282362010-04-16 16:53:20 -0700194
195 // TODO - fetch for the iface
Robert Greenwalt05d06732010-04-19 11:10:38 -0700196 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700197 public synchronized long getPeriodStartTime(String iface) {
198 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700199 long startTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700200 if (mRecorder != null) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700201 startTime = ntpToWallTime(mRecorder.getPeriodStart());
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700202 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700203 return startTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700204 }
205 //TODO - a better name? getCliffByteCountThreshold?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700206 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700207 public synchronized long getCliffThreshold(String iface, int cliff) {
208 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700209 if (cliff == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700210 return mPolicyThreshold;
211 }
212 return 0;
213 }
214 // TODO - a better name? getThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700215 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700216 public synchronized int getCliffLevel(String iface, int cliff) {
217 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700218 if (cliff == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700219 return mPolicyThrottleValue;
220 }
221 return 0;
222 }
223
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700224 public String getHelpUri() {
225 enforceAccessPermission();
226 return Settings.Secure.getString(mContext.getContentResolver(),
227 Settings.Secure.THROTTLE_HELP_URI);
228 }
229
Irfan Sheriffcf282362010-04-16 16:53:20 -0700230 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700231 public synchronized long getByteCount(String iface, int dir, int period, int ago) {
232 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700233 if ((period == ThrottleManager.PERIOD_CYCLE) &&
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700234 (mRecorder != null)) {
235 if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
236 if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
237 }
238 return 0;
239 }
240
241 // TODO - a better name - getCurrentThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700242 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700243 public synchronized int getThrottle(String iface) {
244 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700245 if (mThrottleIndex == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700246 return mPolicyThrottleValue;
247 }
248 return 0;
249 }
250
251 void systemReady() {
252 if (DBG) Slog.d(TAG, "systemReady");
253 mContext.registerReceiver(
254 new BroadcastReceiver() {
255 @Override
256 public void onReceive(Context context, Intent intent) {
257 mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
258 }
259 }, new IntentFilter(ACTION_POLL));
260
261 mContext.registerReceiver(
262 new BroadcastReceiver() {
263 @Override
264 public void onReceive(Context context, Intent intent) {
265 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
266 }
267 }, new IntentFilter(ACTION_RESET));
268
269 // use a new thread as we don't want to stall the system for file writes
270 mThread = new HandlerThread(TAG);
271 mThread.start();
272 mHandler = new MyHandler(mThread.getLooper());
273 mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700274
275 mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
276 mSettingsObserver.observe(mContext);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700277
278 FileInputStream stream = null;
279 try {
280 Properties properties = new Properties();
281 File file = new File(PROPERTIES_FILE);
282 stream = new FileInputStream(file);
283 properties.load(stream);
284 mNtpServer = properties.getProperty("NTP_SERVER", null);
285 } catch (IOException e) {
286 Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
287 } finally {
288 if (stream != null) {
289 try {
290 stream.close();
291 } catch (Exception e) {}
292 }
293 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700294 }
295
296
297 private static final int EVENT_REBOOT_RECOVERY = 0;
298 private static final int EVENT_POLICY_CHANGED = 1;
299 private static final int EVENT_POLL_ALARM = 2;
300 private static final int EVENT_RESET_ALARM = 3;
301 private class MyHandler extends Handler {
302 public MyHandler(Looper l) {
303 super(l);
304 }
305
306 @Override
307 public void handleMessage(Message msg) {
308 switch (msg.what) {
309 case EVENT_REBOOT_RECOVERY:
310 onRebootRecovery();
311 break;
312 case EVENT_POLICY_CHANGED:
313 onPolicyChanged();
314 break;
315 case EVENT_POLL_ALARM:
316 onPollAlarm();
317 break;
318 case EVENT_RESET_ALARM:
319 onResetAlarm();
320 }
321 }
322
323 private void onRebootRecovery() {
324 if (DBG) Slog.d(TAG, "onRebootRecovery");
325 // check for sim change TODO
326 // reregister for notification of policy change
327
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700328 mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700329
330 mRecorder = new DataRecorder(mContext, ThrottleService.this);
331
332 // get policy
333 mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700334 }
335
336 // check for new policy info (threshold limit/value/etc)
337 private void onPolicyChanged() {
338 boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
339
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700340 int pollingPeriod = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700341 R.integer.config_datause_polling_period_sec);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700342 mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
343 Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
344
345 // TODO - remove testing stuff?
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700346 long defaultThreshold = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700347 R.integer.config_datause_threshold_bytes);
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700348 int defaultValue = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700349 R.integer.config_datause_throttle_kbitsps);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700350 synchronized (ThrottleService.this) {
351 mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700352 Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700353 mPolicyThrottleValue = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700354 Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
355 if (testing) {
356 mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
357 mPolicyThreshold = TESTING_THRESHOLD;
358 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700359 }
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700360
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700361 mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
362 Settings.Secure.THROTTLE_RESET_DAY, -1);
363 if (mPolicyResetDay == -1 ||
364 ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
365 Random g = new Random();
366 mPolicyResetDay = 1 + g.nextInt(28); // 1-28
367 Settings.Secure.putInt(mContext.getContentResolver(),
368 Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
369 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700370 mIface = mContext.getResources().getString(R.string.config_datause_iface);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700371 synchronized (ThrottleService.this) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700372 if (mIface == null) {
373 mPolicyThreshold = 0;
374 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700375 }
376
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700377 int defaultNotificationType = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700378 R.integer.config_datause_notification_type);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700379 mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700380 Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700381
382 Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" + mPolicyPollPeriodSec +
383 ", threshold=" + mPolicyThreshold + ", value=" + mPolicyThrottleValue +
384 ", resetDay=" + mPolicyResetDay + ", noteType=" +
385 mPolicyNotificationsAllowedMask);
386
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700387 onResetAlarm();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700388
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700389 onPollAlarm();
390
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700391 Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
392 mContext.sendBroadcast(broadcast);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700393 }
394
395 private void onPollAlarm() {
396 long now = SystemClock.elapsedRealtime();
397 long next = now + mPolicyPollPeriodSec*1000;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700398
399 checkForAuthoritativeTime();
400
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700401 long incRead = 0;
402 long incWrite = 0;
403 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700404 incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
405 incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700406 // handle iface resets - on some device the 3g iface comes and goes and gets
407 // totals reset to 0. Deal with it
408 if ((incRead < 0) || (incWrite < 0)) {
409 incRead += mLastRead;
410 incWrite += mLastWrite;
411 mLastRead = 0;
412 mLastWrite = 0;
413 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700414 } catch (RemoteException e) {
415 Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
416 }
Robert Greenwalt5f996892010-04-08 16:19:24 -0700417 // don't count this data if we're roaming.
418 boolean roaming = "true".equals(
419 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
420 if (!roaming) {
421 mRecorder.addData(incRead, incWrite);
422 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700423
424 long periodRx = mRecorder.getPeriodRx(0);
425 long periodTx = mRecorder.getPeriodTx(0);
426 long total = periodRx + periodTx;
427 if (DBG) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700428 Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
Robert Greenwalt5f996892010-04-08 16:19:24 -0700429 ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700430 }
431 mLastRead += incRead;
432 mLastWrite += incWrite;
433
434 checkThrottleAndPostNotification(total);
435
436 Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
437 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
438 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700439 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
440 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700441 mContext.sendStickyBroadcast(broadcast);
442
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700443 mAlarmManager.cancel(mPendingPollIntent);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700444 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, next, mPendingPollIntent);
445 }
446
447 private void checkThrottleAndPostNotification(long currentTotal) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700448 // is throttling enabled?
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700449 if (mPolicyThreshold == 0) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700450 return;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700451 }
452
453 // have we spoken with an ntp server yet?
454 // this is controversial, but we'd rather err towards not throttling
455 if ((mNtpServer != null) && !mNtpActive) {
456 return;
457 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700458
459 // check if we need to throttle
460 if (currentTotal > mPolicyThreshold) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700461 if (mThrottleIndex != 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700462 synchronized (ThrottleService.this) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700463 mThrottleIndex = 1;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700464 }
465 if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
466 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700467 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700468 mPolicyThrottleValue, mPolicyThrottleValue);
469 } catch (Exception e) {
470 Slog.e(TAG, "error setting Throttle: " + e);
471 }
472
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700473 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700474
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700475 postNotification(R.string.throttled_notification_title,
476 R.string.throttled_notification_message,
477 R.drawable.stat_sys_throttled,
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700478 Notification.FLAG_ONGOING_EVENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700479
480 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
481 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, mPolicyThrottleValue);
482 mContext.sendStickyBroadcast(broadcast);
483
484 } // else already up!
485 } else {
486 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
487 // check if we should warn about throttle
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700488 // pretend we only have 1/2 the time remaining that we actually do
489 // if our burn rate in the period so far would have us exceed the limit
490 // in that 1/2 window, warn the user.
491 // this gets more generous in the early to middle period and converges back
492 // to the limit as we move toward the period end.
493
494 // adding another factor - it must be greater than the total cap/4
495 // else we may get false alarms very early in the period.. in the first
496 // tenth of a percent of the period if we used more than a tenth of a percent
497 // of the cap we'd get a warning and that's not desired.
498 long start = mRecorder.getPeriodStart();
499 long end = mRecorder.getPeriodEnd();
500 long periodLength = end - start;
501 long now = System.currentTimeMillis();
502 long timeUsed = now - start;
503 long warningThreshold = 2*mPolicyThreshold*timeUsed/(timeUsed+periodLength);
504 if ((currentTotal > warningThreshold) && (currentTotal > mPolicyThreshold/4)) {
505 if (mWarningNotificationSent == false) {
506 mWarningNotificationSent = true;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700507 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
508 postNotification(R.string.throttle_warning_notification_title,
509 R.string.throttle_warning_notification_message,
510 R.drawable.stat_sys_throttled,
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700511 0);
512 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700513 } else {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700514 if (mWarningNotificationSent == true) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700515 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700516 mWarningNotificationSent =false;
517 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700518 }
519 }
520 }
521 }
522
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700523 private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700524 Intent intent = new Intent();
525 // TODO - fix up intent
Robert Greenwalt2a7b7302010-04-12 14:56:31 -0700526 intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700527 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
528
529 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
530
531 Resources r = Resources.getSystem();
532 CharSequence title = r.getText(titleInt);
533 CharSequence message = r.getText(messageInt);
534 if (mThrottlingNotification == null) {
535 mThrottlingNotification = new Notification();
536 mThrottlingNotification.when = 0;
537 // TODO - fixup icon
538 mThrottlingNotification.icon = icon;
539 mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700540 }
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700541 mThrottlingNotification.flags = flags;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700542 mThrottlingNotification.tickerText = title;
543 mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
544
545 mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
546 }
547
548
549 private synchronized void clearThrottleAndNotification() {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700550 if (mThrottleIndex != THROTTLE_INDEX_UNTHROTTLED) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700551 synchronized (ThrottleService.this) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700552 mThrottleIndex = THROTTLE_INDEX_UNTHROTTLED;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700553 }
554 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700555 mNMService.setInterfaceThrottle(mIface, -1, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700556 } catch (Exception e) {
557 Slog.e(TAG, "error clearing Throttle: " + e);
558 }
559 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
560 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
561 mContext.sendStickyBroadcast(broadcast);
562 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700563 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700564 mWarningNotificationSent = false;
565 }
566
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700567 private Calendar calculatePeriodEnd(long now) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700568 Calendar end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700569 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700570 int day = end.get(Calendar.DAY_OF_MONTH);
571 end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
572 end.set(Calendar.HOUR_OF_DAY, 0);
573 end.set(Calendar.MINUTE, 0);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700574 end.set(Calendar.SECOND, 0);
575 end.set(Calendar.MILLISECOND, 0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700576 if (day >= mPolicyResetDay) {
577 int month = end.get(Calendar.MONTH);
578 if (month == Calendar.DECEMBER) {
579 end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
580 month = Calendar.JANUARY - 1;
581 }
582 end.set(Calendar.MONTH, month + 1);
583 }
584
585 // TODO - remove!
586 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
587 end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700588 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700589 end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
590 }
591 return end;
592 }
593 private Calendar calculatePeriodStart(Calendar end) {
594 Calendar start = (Calendar)end.clone();
595 int month = end.get(Calendar.MONTH);
596 if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
597 month = Calendar.DECEMBER + 1;
598 start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
599 }
600 start.set(Calendar.MONTH, month - 1);
601
602 // TODO - remove!!
603 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
604 start = (Calendar)end.clone();
605 start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
606 }
607 return start;
608 }
609
610 private void onResetAlarm() {
611 if (DBG) {
612 Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
613 " bytes read and " + mRecorder.getPeriodTx(0) + " written");
614 }
615
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700616 long now = getBestTime();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700617
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700618 if (mNtpActive || (mNtpServer == null)) {
619 Calendar end = calculatePeriodEnd(now);
620 Calendar start = calculatePeriodStart(end);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700621
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700622 if (mRecorder.setNextPeriod(start, end)) {
623 clearThrottleAndNotification();
Robert Greenwalt05d06732010-04-19 11:10:38 -0700624 onPollAlarm();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700625 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700626
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700627 mAlarmManager.cancel(mPendingResetIntent);
628 long offset = end.getTimeInMillis() - now;
629 // use Elapsed realtime so clock changes don't fool us.
630 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
631 SystemClock.elapsedRealtime() + offset,
632 mPendingResetIntent);
633 } else {
634 if (DBG) Slog.d(TAG, "no authoritative time - not resetting period");
635 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700636 }
637 }
638
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700639 private void checkForAuthoritativeTime() {
640 if (mNtpActive || (mNtpServer == null)) return;
641
Robert Greenwalt05d06732010-04-19 11:10:38 -0700642 // will try to get the ntp time and switch to it if found.
643 // will also cache the time so we don't fetch it repeatedly.
644 getBestTime();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700645 }
646
Robert Greenwalt05d06732010-04-19 11:10:38 -0700647 private static final int MAX_NTP_CACHE_AGE = 30 * 1000;
648 private static final int MAX_NTP_FETCH_WAIT = 10 * 1000;
649 private long cachedNtp;
650 private long cachedNtpTimestamp;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700651
Robert Greenwalt05d06732010-04-19 11:10:38 -0700652 private long getBestTime() {
653 if (mNtpServer != null) {
654 if (mNtpActive) {
655 long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
656 if (ntpAge < MAX_NTP_CACHE_AGE) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700657 if (VDBG) Slog.v(TAG, "using cached time");
Robert Greenwalt05d06732010-04-19 11:10:38 -0700658 return cachedNtp + ntpAge;
659 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700660 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700661 SntpClient client = new SntpClient();
662 if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT)) {
663 cachedNtp = client.getNtpTime();
664 cachedNtpTimestamp = SystemClock.elapsedRealtime();
665 if (!mNtpActive) {
666 mNtpActive = true;
667 if (DBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
668 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
669 }
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700670 if (VDBG) Slog.v(TAG, "using Authoritative time: " + cachedNtp);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700671 return cachedNtp;
672 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700673 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700674 long time = System.currentTimeMillis();
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700675 if (VDBG) Slog.v(TAG, "using User time: " + time);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700676 mNtpActive = false;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700677 return time;
678 }
679
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700680 // records bytecount data for a given time and accumulates it into larger time windows
681 // for logging and other purposes
682 //
683 // since time can be changed (user or network action) we will have to track the time of the
684 // last recording and deal with it.
685 private static class DataRecorder {
686 long[] mPeriodRxData;
687 long[] mPeriodTxData;
688 int mCurrentPeriod;
689 int mPeriodCount;
690
691 Calendar mPeriodStart;
692 Calendar mPeriodEnd;
693
694 ThrottleService mParent;
695 Context mContext;
Robert Greenwalte6e98822010-04-15 08:27:14 -0700696 String mImsi = null;
697
698 TelephonyManager mTelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700699
700 DataRecorder(Context context, ThrottleService parent) {
701 mContext = context;
702 mParent = parent;
703
Robert Greenwalte6e98822010-04-15 08:27:14 -0700704 mTelephonyManager = (TelephonyManager)mContext.getSystemService(
705 Context.TELEPHONY_SERVICE);
706
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700707 synchronized (mParent) {
708 mPeriodCount = 6;
709 mPeriodRxData = new long[mPeriodCount];
710 mPeriodTxData = new long[mPeriodCount];
711
712 mPeriodStart = Calendar.getInstance();
713 mPeriodEnd = Calendar.getInstance();
714
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700715 retrieve();
716 }
717 }
718
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700719 boolean setNextPeriod(Calendar start, Calendar end) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700720 // TODO - how would we deal with a dual-IMSI device?
721 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700722 boolean startNewPeriod = true;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700723
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700724 // if we rolled back in time, toss out
725 // if we rolled foward, advance to the next
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700726 if (end.before(mPeriodStart)) {
727 if (DBG) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700728 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
729 end.getTimeInMillis() + ") - old start was " +
730 mPeriodStart.getTimeInMillis() + ", wiping");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700731 }
732 synchronized (mParent) {
733 mPeriodRxData[mCurrentPeriod] = 0;
734 mPeriodTxData[mCurrentPeriod] = 0;
735 }
736 } else if(start.after(mPeriodEnd)) {
737 if (DBG) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700738 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
739 end.getTimeInMillis() + ") - old end was " +
740 mPeriodEnd.getTimeInMillis() + ", following");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700741 }
742 synchronized (mParent) {
743 ++mCurrentPeriod;
744 if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
745 mPeriodRxData[mCurrentPeriod] = 0;
746 mPeriodTxData[mCurrentPeriod] = 0;
747 }
748 } else {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700749 startNewPeriod = false;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700750 if (DBG) {
751 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
752 end.getTimeInMillis() + ") - we fit - ammending to last period");
753 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700754 }
755 setPeriodStart(start);
756 setPeriodEnd(end);
757 record();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700758 return startNewPeriod;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700759 }
760
761 public long getPeriodEnd() {
762 synchronized (mParent) {
763 return mPeriodEnd.getTimeInMillis();
764 }
765 }
766
767 private void setPeriodEnd(Calendar end) {
768 synchronized (mParent) {
769 mPeriodEnd = end;
770 }
771 }
772
773 public long getPeriodStart() {
774 synchronized (mParent) {
775 return mPeriodStart.getTimeInMillis();
776 }
777 }
778
779 private void setPeriodStart(Calendar start) {
780 synchronized (mParent) {
781 mPeriodStart = start;
782 }
783 }
784
785 public int getPeriodCount() {
786 synchronized (mParent) {
787 return mPeriodCount;
788 }
789 }
790
791 private void zeroData(int field) {
792 synchronized (mParent) {
793 for(int period = 0; period<mPeriodCount; period++) {
794 mPeriodRxData[period] = 0;
795 mPeriodTxData[period] = 0;
796 }
797 mCurrentPeriod = 0;
798 }
799
800 }
801
802 // if time moves backward accumulate all read/write that's lost into the now
803 // otherwise time moved forward.
804 void addData(long bytesRead, long bytesWritten) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700805 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700806
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700807 synchronized (mParent) {
808 mPeriodRxData[mCurrentPeriod] += bytesRead;
809 mPeriodTxData[mCurrentPeriod] += bytesWritten;
810 }
811 record();
812 }
813
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700814 private File getDataFile() {
815 File dataDir = Environment.getDataDirectory();
816 File throttleDir = new File(dataDir, "system/throttle");
817 throttleDir.mkdirs();
Robert Greenwalte6e98822010-04-15 08:27:14 -0700818 String mImsi = mTelephonyManager.getSubscriberId();
819 File dataFile;
820 if (mImsi == null) {
821 dataFile = useMRUFile(throttleDir);
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700822 if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700823 } else {
824 String imsiHash = Integer.toString(mImsi.hashCode());
825 dataFile = new File(throttleDir, imsiHash);
826 }
827 // touch the file so it's not LRU
828 dataFile.setLastModified(System.currentTimeMillis());
829 checkAndDeleteLRUDataFile(throttleDir);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700830 return dataFile;
831 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700832
Robert Greenwalte6e98822010-04-15 08:27:14 -0700833 // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
834 private void checkForSubscriberId() {
835 if (mImsi != null) return;
836
837 mImsi = mTelephonyManager.getSubscriberId();
838 if (mImsi == null) return;
839
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700840 if (DBG) Slog.d(TAG, "finally have imsi - retreiving data");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700841 retrieve();
842 }
843
844 private final static int MAX_SIMS_SUPPORTED = 3;
845
846 private void checkAndDeleteLRUDataFile(File dir) {
847 File[] files = dir.listFiles();
848
849 if (files.length <= MAX_SIMS_SUPPORTED) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700850 if (DBG) Slog.d(TAG, "Too many data files");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700851 do {
852 File oldest = null;
853 for (File f : files) {
854 if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
855 oldest = f;
856 }
857 }
858 if (oldest == null) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700859 if (DBG) Slog.d(TAG, " deleting " + oldest);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700860 oldest.delete();
861 files = dir.listFiles();
862 } while (files.length > MAX_SIMS_SUPPORTED);
863 }
864
865 private File useMRUFile(File dir) {
866 File newest = null;
867 File[] files = dir.listFiles();
868
869 for (File f : files) {
870 if ((newest == null) || (newest.lastModified() < f.lastModified())) {
871 newest = f;
872 }
873 }
874 if (newest == null) {
875 newest = new File(dir, "temp");
876 }
877 return newest;
878 }
879
880
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700881 private static final int DATA_FILE_VERSION = 1;
882
883 private void record() {
884 // 1 int version
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700885 // 1 int mPeriodCount
886 // 13*6 long[PERIOD_COUNT] mPeriodRxData
887 // 13*6 long[PERIOD_COUNT] mPeriodTxData
888 // 1 int mCurrentPeriod
889 // 13 long periodStartMS
890 // 13 long periodEndMS
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700891 // 200 chars max
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700892 StringBuilder builder = new StringBuilder();
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700893 builder.append(DATA_FILE_VERSION);
894 builder.append(":");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700895 builder.append(mPeriodCount);
896 builder.append(":");
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700897 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700898 builder.append(mPeriodRxData[i]);
899 builder.append(":");
900 }
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700901 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700902 builder.append(mPeriodTxData[i]);
903 builder.append(":");
904 }
905 builder.append(mCurrentPeriod);
906 builder.append(":");
907 builder.append(mPeriodStart.getTimeInMillis());
908 builder.append(":");
909 builder.append(mPeriodEnd.getTimeInMillis());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700910
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700911 BufferedWriter out = null;
912 try {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700913 out = new BufferedWriter(new FileWriter(getDataFile()), 256);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700914 out.write(builder.toString());
915 } catch (IOException e) {
916 Slog.e(TAG, "Error writing data file");
917 return;
918 } finally {
919 if (out != null) {
920 try {
921 out.close();
922 } catch (Exception e) {}
923 }
924 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700925 }
926
927 private void retrieve() {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700928 // clean out any old data first. If we fail to read we don't want old stuff
929 zeroData(0);
930
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700931 File f = getDataFile();
932 byte[] buffer;
933 FileInputStream s = null;
934 try {
935 buffer = new byte[(int)f.length()];
936 s = new FileInputStream(f);
937 s.read(buffer);
938 } catch (IOException e) {
939 Slog.e(TAG, "Error reading data file");
940 return;
941 } finally {
942 if (s != null) {
943 try {
944 s.close();
945 } catch (Exception e) {}
946 }
947 }
948 String data = new String(buffer);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700949 if (data == null || data.length() == 0) {
950 if (DBG) Slog.d(TAG, "data file empty");
951 return;
952 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700953 synchronized (mParent) {
954 String[] parsed = data.split(":");
955 int parsedUsed = 0;
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700956 if (parsed.length < 6) {
957 Slog.e(TAG, "reading data file with insufficient length - ignoring");
958 return;
959 }
960
961 if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
962 Slog.e(TAG, "reading data file with bad version - ignoring");
963 return;
964 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700965
966 mPeriodCount = Integer.parseInt(parsed[parsedUsed++]);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700967 if (parsed.length != 5 + (2 * mPeriodCount)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700968 Slog.e(TAG, "reading data file with bad length ("+parsed.length+" != "+(5 + (2*mPeriodCount))+") - ignoring");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700969 return;
970 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700971
972 mPeriodRxData = new long[mPeriodCount];
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700973 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700974 mPeriodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
975 }
976 mPeriodTxData = new long[mPeriodCount];
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700977 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700978 mPeriodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
979 }
980 mCurrentPeriod = Integer.parseInt(parsed[parsedUsed++]);
981 mPeriodStart = new GregorianCalendar();
982 mPeriodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
983 mPeriodEnd = new GregorianCalendar();
984 mPeriodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
985 }
986 }
987
988 long getPeriodRx(int which) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700989 synchronized (mParent) {
990 if (which > mPeriodCount) return 0;
991 which = mCurrentPeriod - which;
992 if (which < 0) which += mPeriodCount;
993 return mPeriodRxData[which];
994 }
995 }
996 long getPeriodTx(int which) {
997 synchronized (mParent) {
998 if (which > mPeriodCount) return 0;
999 which = mCurrentPeriod - which;
1000 if (which < 0) which += mPeriodCount;
1001 return mPeriodTxData[which];
1002 }
1003 }
1004 }
1005
1006 @Override
1007 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1008 if (mContext.checkCallingOrSelfPermission(
1009 android.Manifest.permission.DUMP)
1010 != PackageManager.PERMISSION_GRANTED) {
1011 pw.println("Permission Denial: can't dump ThrottleService " +
1012 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1013 Binder.getCallingUid());
1014 return;
1015 }
1016 pw.println();
1017
1018 pw.println("The threshold is " + mPolicyThreshold +
1019 ", after which you experince throttling to " +
1020 mPolicyThrottleValue + "kbps");
1021 pw.println("Current period is " +
1022 (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001023 "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001024 " seconds.");
1025 pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
Robert Greenwalt8c7e6092010-04-14 17:31:20 -07001026 pw.println("Current Throttle Index is " + mThrottleIndex);
1027
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001028 for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
1029 pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
1030 mRecorder.getPeriodTx(i));
1031 }
1032 }
1033}