blob: 23c1adcc288c0c7673a5058545845cab4993edff [file] [log] [blame]
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.AlarmManager;
20import android.app.Notification;
21import android.app.NotificationManager;
22import android.app.PendingIntent;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070023import android.content.BroadcastReceiver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -070024import android.content.ContentResolver;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070025import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.PackageManager;
29import android.content.res.Resources;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -070030import android.database.ContentObserver;
Robert Greenwaltfee46832010-05-06 12:25:13 -070031import android.net.INetworkManagementEventObserver;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070032import android.net.IThrottleManager;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070033import android.net.SntpClient;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070034import android.net.ThrottleManager;
35import android.os.Binder;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070036import android.os.Environment;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070037import android.os.Handler;
38import android.os.HandlerThread;
39import android.os.IBinder;
40import android.os.INetworkManagementService;
41import android.os.Looper;
42import android.os.Message;
43import android.os.RemoteException;
44import android.os.ServiceManager;
45import android.os.SystemClock;
46import android.os.SystemProperties;
47import android.provider.Settings;
Robert Greenwalte6e98822010-04-15 08:27:14 -070048import android.telephony.TelephonyManager;
Robert Greenwaltfee46832010-05-06 12:25:13 -070049import android.text.TextUtils;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070050import android.util.Slog;
51
Robert Greenwalt7171ea82010-04-14 22:37:12 -070052import com.android.internal.R;
Robert Greenwalt5f996892010-04-08 16:19:24 -070053import com.android.internal.telephony.TelephonyProperties;
54
Robert Greenwaltb8912f52010-04-09 17:27:26 -070055import java.io.BufferedWriter;
56import java.io.File;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070057import java.io.FileDescriptor;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070058import java.io.FileInputStream;
59import java.io.FileWriter;
60import java.io.IOException;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070061import java.io.PrintWriter;
62import java.util.Calendar;
63import java.util.GregorianCalendar;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070064import java.util.Properties;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070065import java.util.Random;
66
67// TODO - add comments - reference the ThrottleManager for public API
68public class ThrottleService extends IThrottleManager.Stub {
69
70 private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
71
72 private static final String TAG = "ThrottleService";
Robert Greenwaltbf7de392010-04-21 17:09:38 -070073 private static final boolean DBG = true;
74 private static final boolean VDBG = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070075 private Handler mHandler;
76 private HandlerThread mThread;
77
78 private Context mContext;
79
Robert Greenwaltfb9896b2010-04-22 15:39:38 -070080 private static final int INITIAL_POLL_DELAY_SEC = 90;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070081 private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070082 private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070083 private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070084
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070085 private int mPolicyPollPeriodSec;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070086 private long mPolicyThreshold;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070087 private int mPolicyThrottleValue;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070088 private int mPolicyResetDay; // 1-28
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070089 private int mPolicyNotificationsAllowedMask;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070090
91 private long mLastRead; // read byte count from last poll
92 private long mLastWrite; // write byte count from last poll
93
94 private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
95 private static int POLL_REQUEST = 0;
96 private PendingIntent mPendingPollIntent;
97 private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
98 private static int RESET_REQUEST = 1;
99 private PendingIntent mPendingResetIntent;
100
101 private INetworkManagementService mNMService;
102 private AlarmManager mAlarmManager;
103 private NotificationManager mNotificationManager;
104
105 private DataRecorder mRecorder;
106
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700107 private String mIface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700108
109 private static final int NOTIFICATION_WARNING = 2;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700110
111 private Notification mThrottlingNotification;
112 private boolean mWarningNotificationSent = false;
113
Robert Greenwaltfee46832010-05-06 12:25:13 -0700114 private InterfaceObserver mInterfaceObserver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700115 private SettingsObserver mSettingsObserver;
116
117 private int mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
118 private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
119 private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
120
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700121 private static final String PROPERTIES_FILE = "/etc/gps.conf";
122 private String mNtpServer;
123 private boolean mNtpActive;
124
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700125 public ThrottleService(Context context) {
126 if (DBG) Slog.d(TAG, "Starting ThrottleService");
127 mContext = context;
128
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700129 mNtpActive = false;
130
Robert Greenwaltfee46832010-05-06 12:25:13 -0700131 mIface = mContext.getResources().getString(R.string.config_datause_iface);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700132 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
133 Intent pollIntent = new Intent(ACTION_POLL, null);
134 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
135 Intent resetIntent = new Intent(ACTION_RESET, null);
136 mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
137
138 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
139 mNMService = INetworkManagementService.Stub.asInterface(b);
140
141 mNotificationManager = (NotificationManager)mContext.getSystemService(
142 Context.NOTIFICATION_SERVICE);
143 }
144
Robert Greenwaltfee46832010-05-06 12:25:13 -0700145 private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
146 private int mMsg;
147 private Handler mHandler;
148 private String mIface;
149
150 InterfaceObserver(Handler handler, int msg, String iface) {
151 super();
152 mHandler = handler;
153 mMsg = msg;
154 mIface = iface;
155 }
156
157 public void interfaceLinkStatusChanged(String iface, boolean link) {
158 if (link) {
159 if (TextUtils.equals(iface, mIface)) {
160 mHandler.obtainMessage(mMsg).sendToTarget();
161 }
162 }
163 }
164
165 public void interfaceAdded(String iface) {
166 // TODO - an interface added in the UP state should also trigger a StatusChanged
167 // notification..
168 if (TextUtils.equals(iface, mIface)) {
169 mHandler.obtainMessage(mMsg).sendToTarget();
170 }
171 }
172
173 public void interfaceRemoved(String iface) {}
174 }
175
176
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700177 private static class SettingsObserver extends ContentObserver {
178 private int mMsg;
179 private Handler mHandler;
180 SettingsObserver(Handler handler, int msg) {
181 super(handler);
182 mHandler = handler;
183 mMsg = msg;
184 }
185
186 void observe(Context context) {
187 ContentResolver resolver = context.getContentResolver();
188 resolver.registerContentObserver(Settings.Secure.getUriFor(
189 Settings.Secure.THROTTLE_POLLING_SEC), false, this);
190 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700191 Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700192 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700193 Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700194 resolver.registerContentObserver(Settings.Secure.getUriFor(
195 Settings.Secure.THROTTLE_RESET_DAY), false, this);
196 resolver.registerContentObserver(Settings.Secure.getUriFor(
197 Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
198 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700199 Settings.Secure.THROTTLE_HELP_URI), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700200 }
201
202 @Override
203 public void onChange(boolean selfChange) {
204 mHandler.obtainMessage(mMsg).sendToTarget();
205 }
206 }
207
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700208 private void enforceAccessPermission() {
209 mContext.enforceCallingOrSelfPermission(
210 android.Manifest.permission.ACCESS_NETWORK_STATE,
211 "ThrottleService");
212 }
213
Robert Greenwalt05d06732010-04-19 11:10:38 -0700214 private long ntpToWallTime(long ntpTime) {
215 long bestNow = getBestTime();
216 long localNow = System.currentTimeMillis();
217 return localNow + (ntpTime - bestNow);
218 }
219
Irfan Sheriffcf282362010-04-16 16:53:20 -0700220 // TODO - fetch for the iface
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700221 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt05d06732010-04-19 11:10:38 -0700222
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700223 public synchronized long getResetTime(String iface) {
224 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700225 long resetTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700226 if (mRecorder != null) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700227 resetTime = ntpToWallTime(mRecorder.getPeriodEnd());
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700228 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700229 return resetTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700230 }
Irfan Sheriffcf282362010-04-16 16:53:20 -0700231
232 // TODO - fetch for the iface
Robert Greenwalt05d06732010-04-19 11:10:38 -0700233 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700234 public synchronized long getPeriodStartTime(String iface) {
235 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700236 long startTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700237 if (mRecorder != null) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700238 startTime = ntpToWallTime(mRecorder.getPeriodStart());
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700239 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700240 return startTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700241 }
242 //TODO - a better name? getCliffByteCountThreshold?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700243 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700244 public synchronized long getCliffThreshold(String iface, int cliff) {
245 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700246 if (cliff == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700247 return mPolicyThreshold;
248 }
249 return 0;
250 }
251 // TODO - a better name? getThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700252 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700253 public synchronized int getCliffLevel(String iface, int cliff) {
254 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700255 if (cliff == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700256 return mPolicyThrottleValue;
257 }
258 return 0;
259 }
260
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700261 public String getHelpUri() {
262 enforceAccessPermission();
263 return Settings.Secure.getString(mContext.getContentResolver(),
264 Settings.Secure.THROTTLE_HELP_URI);
265 }
266
Irfan Sheriffcf282362010-04-16 16:53:20 -0700267 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700268 public synchronized long getByteCount(String iface, int dir, int period, int ago) {
269 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700270 if ((period == ThrottleManager.PERIOD_CYCLE) &&
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700271 (mRecorder != null)) {
272 if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
273 if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
274 }
275 return 0;
276 }
277
278 // TODO - a better name - getCurrentThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700279 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700280 public synchronized int getThrottle(String iface) {
281 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700282 if (mThrottleIndex == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700283 return mPolicyThrottleValue;
284 }
285 return 0;
286 }
287
288 void systemReady() {
289 if (DBG) Slog.d(TAG, "systemReady");
290 mContext.registerReceiver(
291 new BroadcastReceiver() {
292 @Override
293 public void onReceive(Context context, Intent intent) {
294 mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
295 }
296 }, new IntentFilter(ACTION_POLL));
297
298 mContext.registerReceiver(
299 new BroadcastReceiver() {
300 @Override
301 public void onReceive(Context context, Intent intent) {
302 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
303 }
304 }, new IntentFilter(ACTION_RESET));
305
306 // use a new thread as we don't want to stall the system for file writes
307 mThread = new HandlerThread(TAG);
308 mThread.start();
309 mHandler = new MyHandler(mThread.getLooper());
310 mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700311
Robert Greenwaltfee46832010-05-06 12:25:13 -0700312 mInterfaceObserver = new InterfaceObserver(mHandler, EVENT_IFACE_UP, mIface);
313 try {
314 mNMService.registerObserver(mInterfaceObserver);
315 } catch (RemoteException e) {
316 Slog.e(TAG, "Could not register InterfaceObserver " + e);
317 }
318
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700319 mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
320 mSettingsObserver.observe(mContext);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700321
322 FileInputStream stream = null;
323 try {
324 Properties properties = new Properties();
325 File file = new File(PROPERTIES_FILE);
326 stream = new FileInputStream(file);
327 properties.load(stream);
328 mNtpServer = properties.getProperty("NTP_SERVER", null);
329 } catch (IOException e) {
330 Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
331 } finally {
332 if (stream != null) {
333 try {
334 stream.close();
335 } catch (Exception e) {}
336 }
337 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700338 }
339
340
341 private static final int EVENT_REBOOT_RECOVERY = 0;
342 private static final int EVENT_POLICY_CHANGED = 1;
343 private static final int EVENT_POLL_ALARM = 2;
344 private static final int EVENT_RESET_ALARM = 3;
Robert Greenwaltfee46832010-05-06 12:25:13 -0700345 private static final int EVENT_IFACE_UP = 4;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700346 private class MyHandler extends Handler {
347 public MyHandler(Looper l) {
348 super(l);
349 }
350
351 @Override
352 public void handleMessage(Message msg) {
353 switch (msg.what) {
354 case EVENT_REBOOT_RECOVERY:
355 onRebootRecovery();
356 break;
357 case EVENT_POLICY_CHANGED:
358 onPolicyChanged();
359 break;
360 case EVENT_POLL_ALARM:
361 onPollAlarm();
362 break;
363 case EVENT_RESET_ALARM:
364 onResetAlarm();
Robert Greenwaltfee46832010-05-06 12:25:13 -0700365 break;
366 case EVENT_IFACE_UP:
367 onIfaceUp();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700368 }
369 }
370
371 private void onRebootRecovery() {
372 if (DBG) Slog.d(TAG, "onRebootRecovery");
373 // check for sim change TODO
374 // reregister for notification of policy change
375
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700376 mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700377
378 mRecorder = new DataRecorder(mContext, ThrottleService.this);
379
380 // get policy
381 mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
Robert Greenwaltfb9896b2010-04-22 15:39:38 -0700382
383 // if we poll now we won't have network connectivity or even imsi access
384 // queue up a poll to happen in a little while - after ntp and imsi are avail
385 // TODO - make this callback based (ie, listen for notificaitons)
386 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_POLL_ALARM),
387 INITIAL_POLL_DELAY_SEC * 1000);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700388 }
389
390 // check for new policy info (threshold limit/value/etc)
391 private void onPolicyChanged() {
392 boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
393
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700394 int pollingPeriod = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700395 R.integer.config_datause_polling_period_sec);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700396 mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
397 Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
398
399 // TODO - remove testing stuff?
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700400 long defaultThreshold = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700401 R.integer.config_datause_threshold_bytes);
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700402 int defaultValue = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700403 R.integer.config_datause_throttle_kbitsps);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700404 synchronized (ThrottleService.this) {
405 mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700406 Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700407 mPolicyThrottleValue = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700408 Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
409 if (testing) {
410 mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
411 mPolicyThreshold = TESTING_THRESHOLD;
412 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700413 }
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700414
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700415 mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
416 Settings.Secure.THROTTLE_RESET_DAY, -1);
417 if (mPolicyResetDay == -1 ||
418 ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
419 Random g = new Random();
420 mPolicyResetDay = 1 + g.nextInt(28); // 1-28
421 Settings.Secure.putInt(mContext.getContentResolver(),
422 Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
423 }
424 synchronized (ThrottleService.this) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700425 if (mIface == null) {
426 mPolicyThreshold = 0;
427 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700428 }
429
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700430 int defaultNotificationType = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700431 R.integer.config_datause_notification_type);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700432 mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700433 Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700434
435 Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" + mPolicyPollPeriodSec +
436 ", threshold=" + mPolicyThreshold + ", value=" + mPolicyThrottleValue +
437 ", resetDay=" + mPolicyResetDay + ", noteType=" +
438 mPolicyNotificationsAllowedMask);
439
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700440 // force updates
441 mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
442
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700443 onResetAlarm();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700444
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700445 onPollAlarm();
446
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700447 Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
448 mContext.sendBroadcast(broadcast);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700449 }
450
451 private void onPollAlarm() {
452 long now = SystemClock.elapsedRealtime();
453 long next = now + mPolicyPollPeriodSec*1000;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700454
455 checkForAuthoritativeTime();
456
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700457 long incRead = 0;
458 long incWrite = 0;
459 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700460 incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
461 incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700462 // handle iface resets - on some device the 3g iface comes and goes and gets
463 // totals reset to 0. Deal with it
464 if ((incRead < 0) || (incWrite < 0)) {
465 incRead += mLastRead;
466 incWrite += mLastWrite;
467 mLastRead = 0;
468 mLastWrite = 0;
469 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700470 } catch (RemoteException e) {
471 Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
472 }
Robert Greenwalt5f996892010-04-08 16:19:24 -0700473 // don't count this data if we're roaming.
474 boolean roaming = "true".equals(
475 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
476 if (!roaming) {
477 mRecorder.addData(incRead, incWrite);
478 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700479
480 long periodRx = mRecorder.getPeriodRx(0);
481 long periodTx = mRecorder.getPeriodTx(0);
482 long total = periodRx + periodTx;
483 if (DBG) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700484 Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
Robert Greenwalt5f996892010-04-08 16:19:24 -0700485 ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700486 }
487 mLastRead += incRead;
488 mLastWrite += incWrite;
489
490 checkThrottleAndPostNotification(total);
491
492 Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
493 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
494 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700495 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
496 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700497 mContext.sendStickyBroadcast(broadcast);
498
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700499 mAlarmManager.cancel(mPendingPollIntent);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700500 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, next, mPendingPollIntent);
501 }
502
Robert Greenwaltfee46832010-05-06 12:25:13 -0700503 private void onIfaceUp() {
504 // if we were throttled before, be sure and set it again - the iface went down
505 // (and may have disappeared all together) and these settings were lost
506 if (mThrottleIndex == 1) {
507 try {
508 mNMService.setInterfaceThrottle(mIface, -1, -1);
509 mNMService.setInterfaceThrottle(mIface,
510 mPolicyThrottleValue, mPolicyThrottleValue);
511 } catch (Exception e) {
512 Slog.e(TAG, "error setting Throttle: " + e);
513 }
514 }
515 }
516
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700517 private void checkThrottleAndPostNotification(long currentTotal) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700518 // is throttling enabled?
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700519 if (mPolicyThreshold == 0) {
Robert Greenwaltcce83372010-04-23 17:35:29 -0700520 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700521 return;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700522 }
523
524 // have we spoken with an ntp server yet?
525 // this is controversial, but we'd rather err towards not throttling
526 if ((mNtpServer != null) && !mNtpActive) {
527 return;
528 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700529
530 // check if we need to throttle
531 if (currentTotal > mPolicyThreshold) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700532 if (mThrottleIndex != 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700533 synchronized (ThrottleService.this) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700534 mThrottleIndex = 1;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700535 }
536 if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
537 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700538 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700539 mPolicyThrottleValue, mPolicyThrottleValue);
540 } catch (Exception e) {
541 Slog.e(TAG, "error setting Throttle: " + e);
542 }
543
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700544 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700545
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700546 postNotification(R.string.throttled_notification_title,
547 R.string.throttled_notification_message,
548 R.drawable.stat_sys_throttled,
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700549 Notification.FLAG_ONGOING_EVENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700550
551 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
552 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, mPolicyThrottleValue);
553 mContext.sendStickyBroadcast(broadcast);
554
555 } // else already up!
556 } else {
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700557 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700558 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
559 // check if we should warn about throttle
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700560 // pretend we only have 1/2 the time remaining that we actually do
561 // if our burn rate in the period so far would have us exceed the limit
562 // in that 1/2 window, warn the user.
563 // this gets more generous in the early to middle period and converges back
564 // to the limit as we move toward the period end.
565
566 // adding another factor - it must be greater than the total cap/4
567 // else we may get false alarms very early in the period.. in the first
568 // tenth of a percent of the period if we used more than a tenth of a percent
569 // of the cap we'd get a warning and that's not desired.
570 long start = mRecorder.getPeriodStart();
571 long end = mRecorder.getPeriodEnd();
572 long periodLength = end - start;
573 long now = System.currentTimeMillis();
574 long timeUsed = now - start;
575 long warningThreshold = 2*mPolicyThreshold*timeUsed/(timeUsed+periodLength);
576 if ((currentTotal > warningThreshold) && (currentTotal > mPolicyThreshold/4)) {
577 if (mWarningNotificationSent == false) {
578 mWarningNotificationSent = true;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700579 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
580 postNotification(R.string.throttle_warning_notification_title,
581 R.string.throttle_warning_notification_message,
582 R.drawable.stat_sys_throttled,
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700583 0);
584 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700585 } else {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700586 if (mWarningNotificationSent == true) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700587 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700588 mWarningNotificationSent =false;
589 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700590 }
591 }
592 }
593 }
594
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700595 private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700596 Intent intent = new Intent();
597 // TODO - fix up intent
Robert Greenwalt2a7b7302010-04-12 14:56:31 -0700598 intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700599 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
600
601 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
602
603 Resources r = Resources.getSystem();
604 CharSequence title = r.getText(titleInt);
605 CharSequence message = r.getText(messageInt);
606 if (mThrottlingNotification == null) {
607 mThrottlingNotification = new Notification();
608 mThrottlingNotification.when = 0;
609 // TODO - fixup icon
610 mThrottlingNotification.icon = icon;
611 mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700612 }
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700613 mThrottlingNotification.flags = flags;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700614 mThrottlingNotification.tickerText = title;
615 mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
616
617 mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
618 }
619
620
621 private synchronized void clearThrottleAndNotification() {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700622 if (mThrottleIndex != THROTTLE_INDEX_UNTHROTTLED) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700623 synchronized (ThrottleService.this) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700624 mThrottleIndex = THROTTLE_INDEX_UNTHROTTLED;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700625 }
626 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700627 mNMService.setInterfaceThrottle(mIface, -1, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700628 } catch (Exception e) {
629 Slog.e(TAG, "error clearing Throttle: " + e);
630 }
631 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
632 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
633 mContext.sendStickyBroadcast(broadcast);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700634 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
635 mWarningNotificationSent = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700636 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700637 }
638
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700639 private Calendar calculatePeriodEnd(long now) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700640 Calendar end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700641 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700642 int day = end.get(Calendar.DAY_OF_MONTH);
643 end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
644 end.set(Calendar.HOUR_OF_DAY, 0);
645 end.set(Calendar.MINUTE, 0);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700646 end.set(Calendar.SECOND, 0);
647 end.set(Calendar.MILLISECOND, 0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700648 if (day >= mPolicyResetDay) {
649 int month = end.get(Calendar.MONTH);
650 if (month == Calendar.DECEMBER) {
651 end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
652 month = Calendar.JANUARY - 1;
653 }
654 end.set(Calendar.MONTH, month + 1);
655 }
656
657 // TODO - remove!
658 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
659 end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700660 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700661 end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
662 }
663 return end;
664 }
665 private Calendar calculatePeriodStart(Calendar end) {
666 Calendar start = (Calendar)end.clone();
667 int month = end.get(Calendar.MONTH);
668 if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
669 month = Calendar.DECEMBER + 1;
670 start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
671 }
672 start.set(Calendar.MONTH, month - 1);
673
674 // TODO - remove!!
675 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
676 start = (Calendar)end.clone();
677 start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
678 }
679 return start;
680 }
681
682 private void onResetAlarm() {
683 if (DBG) {
684 Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
685 " bytes read and " + mRecorder.getPeriodTx(0) + " written");
686 }
687
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700688 long now = getBestTime();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700689
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700690 if (mNtpActive || (mNtpServer == null)) {
691 Calendar end = calculatePeriodEnd(now);
692 Calendar start = calculatePeriodStart(end);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700693
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700694 if (mRecorder.setNextPeriod(start, end)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700695 onPollAlarm();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700696 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700697
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700698 mAlarmManager.cancel(mPendingResetIntent);
699 long offset = end.getTimeInMillis() - now;
700 // use Elapsed realtime so clock changes don't fool us.
701 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
702 SystemClock.elapsedRealtime() + offset,
703 mPendingResetIntent);
704 } else {
705 if (DBG) Slog.d(TAG, "no authoritative time - not resetting period");
706 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700707 }
708 }
709
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700710 private void checkForAuthoritativeTime() {
711 if (mNtpActive || (mNtpServer == null)) return;
712
Robert Greenwalt05d06732010-04-19 11:10:38 -0700713 // will try to get the ntp time and switch to it if found.
714 // will also cache the time so we don't fetch it repeatedly.
715 getBestTime();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700716 }
717
Robert Greenwalt05d06732010-04-19 11:10:38 -0700718 private static final int MAX_NTP_CACHE_AGE = 30 * 1000;
719 private static final int MAX_NTP_FETCH_WAIT = 10 * 1000;
720 private long cachedNtp;
721 private long cachedNtpTimestamp;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700722
Robert Greenwalt05d06732010-04-19 11:10:38 -0700723 private long getBestTime() {
724 if (mNtpServer != null) {
725 if (mNtpActive) {
726 long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
727 if (ntpAge < MAX_NTP_CACHE_AGE) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700728 if (VDBG) Slog.v(TAG, "using cached time");
Robert Greenwalt05d06732010-04-19 11:10:38 -0700729 return cachedNtp + ntpAge;
730 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700731 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700732 SntpClient client = new SntpClient();
733 if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT)) {
734 cachedNtp = client.getNtpTime();
735 cachedNtpTimestamp = SystemClock.elapsedRealtime();
736 if (!mNtpActive) {
737 mNtpActive = true;
738 if (DBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
739 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
740 }
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700741 if (VDBG) Slog.v(TAG, "using Authoritative time: " + cachedNtp);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700742 return cachedNtp;
743 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700744 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700745 long time = System.currentTimeMillis();
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700746 if (VDBG) Slog.v(TAG, "using User time: " + time);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700747 mNtpActive = false;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700748 return time;
749 }
750
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700751 // records bytecount data for a given time and accumulates it into larger time windows
752 // for logging and other purposes
753 //
754 // since time can be changed (user or network action) we will have to track the time of the
755 // last recording and deal with it.
756 private static class DataRecorder {
757 long[] mPeriodRxData;
758 long[] mPeriodTxData;
759 int mCurrentPeriod;
760 int mPeriodCount;
761
762 Calendar mPeriodStart;
763 Calendar mPeriodEnd;
764
765 ThrottleService mParent;
766 Context mContext;
Robert Greenwalte6e98822010-04-15 08:27:14 -0700767 String mImsi = null;
768
769 TelephonyManager mTelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700770
771 DataRecorder(Context context, ThrottleService parent) {
772 mContext = context;
773 mParent = parent;
774
Robert Greenwalte6e98822010-04-15 08:27:14 -0700775 mTelephonyManager = (TelephonyManager)mContext.getSystemService(
776 Context.TELEPHONY_SERVICE);
777
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700778 synchronized (mParent) {
779 mPeriodCount = 6;
780 mPeriodRxData = new long[mPeriodCount];
781 mPeriodTxData = new long[mPeriodCount];
782
783 mPeriodStart = Calendar.getInstance();
784 mPeriodEnd = Calendar.getInstance();
785
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700786 retrieve();
787 }
788 }
789
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700790 boolean setNextPeriod(Calendar start, Calendar end) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700791 // TODO - how would we deal with a dual-IMSI device?
792 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700793 boolean startNewPeriod = true;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700794
Robert Greenwalt27fba672010-04-26 12:29:14 -0700795 if (start.equals(mPeriodStart) && end.equals(mPeriodEnd)) {
796 // same endpoints - keep collecting
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700797 if (DBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700798 Slog.d(TAG, "same period (" + start.getTimeInMillis() + "," +
799 end.getTimeInMillis() +") - ammending data");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700800 }
Robert Greenwalt27fba672010-04-26 12:29:14 -0700801 startNewPeriod = false;
802 } else {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700803 if (DBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700804 if(start.equals(mPeriodEnd) || start.after(mPeriodEnd)) {
805 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
806 end.getTimeInMillis() + ") - old end was " +
807 mPeriodEnd.getTimeInMillis() + ", following");
808 } else {
809 Slog.d(TAG, "new period (" + start.getTimeInMillis() + "," +
810 end.getTimeInMillis() + ") replacing old (" +
811 mPeriodStart.getTimeInMillis() + "," +
812 mPeriodEnd.getTimeInMillis() + ")");
813 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700814 }
815 synchronized (mParent) {
816 ++mCurrentPeriod;
817 if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
818 mPeriodRxData[mCurrentPeriod] = 0;
819 mPeriodTxData[mCurrentPeriod] = 0;
820 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700821 }
822 setPeriodStart(start);
823 setPeriodEnd(end);
824 record();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700825 return startNewPeriod;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700826 }
827
828 public long getPeriodEnd() {
829 synchronized (mParent) {
830 return mPeriodEnd.getTimeInMillis();
831 }
832 }
833
834 private void setPeriodEnd(Calendar end) {
835 synchronized (mParent) {
836 mPeriodEnd = end;
837 }
838 }
839
840 public long getPeriodStart() {
841 synchronized (mParent) {
842 return mPeriodStart.getTimeInMillis();
843 }
844 }
845
846 private void setPeriodStart(Calendar start) {
847 synchronized (mParent) {
848 mPeriodStart = start;
849 }
850 }
851
852 public int getPeriodCount() {
853 synchronized (mParent) {
854 return mPeriodCount;
855 }
856 }
857
858 private void zeroData(int field) {
859 synchronized (mParent) {
860 for(int period = 0; period<mPeriodCount; period++) {
861 mPeriodRxData[period] = 0;
862 mPeriodTxData[period] = 0;
863 }
864 mCurrentPeriod = 0;
865 }
866
867 }
868
869 // if time moves backward accumulate all read/write that's lost into the now
870 // otherwise time moved forward.
871 void addData(long bytesRead, long bytesWritten) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700872 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700873
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700874 synchronized (mParent) {
875 mPeriodRxData[mCurrentPeriod] += bytesRead;
876 mPeriodTxData[mCurrentPeriod] += bytesWritten;
877 }
878 record();
879 }
880
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700881 private File getDataFile() {
882 File dataDir = Environment.getDataDirectory();
883 File throttleDir = new File(dataDir, "system/throttle");
884 throttleDir.mkdirs();
Robert Greenwalte6e98822010-04-15 08:27:14 -0700885 String mImsi = mTelephonyManager.getSubscriberId();
886 File dataFile;
887 if (mImsi == null) {
888 dataFile = useMRUFile(throttleDir);
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700889 if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700890 } else {
891 String imsiHash = Integer.toString(mImsi.hashCode());
892 dataFile = new File(throttleDir, imsiHash);
893 }
894 // touch the file so it's not LRU
895 dataFile.setLastModified(System.currentTimeMillis());
896 checkAndDeleteLRUDataFile(throttleDir);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700897 return dataFile;
898 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700899
Robert Greenwalte6e98822010-04-15 08:27:14 -0700900 // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
901 private void checkForSubscriberId() {
902 if (mImsi != null) return;
903
904 mImsi = mTelephonyManager.getSubscriberId();
905 if (mImsi == null) return;
906
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700907 if (DBG) Slog.d(TAG, "finally have imsi - retreiving data");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700908 retrieve();
909 }
910
911 private final static int MAX_SIMS_SUPPORTED = 3;
912
913 private void checkAndDeleteLRUDataFile(File dir) {
914 File[] files = dir.listFiles();
915
916 if (files.length <= MAX_SIMS_SUPPORTED) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700917 if (DBG) Slog.d(TAG, "Too many data files");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700918 do {
919 File oldest = null;
920 for (File f : files) {
921 if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
922 oldest = f;
923 }
924 }
925 if (oldest == null) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700926 if (DBG) Slog.d(TAG, " deleting " + oldest);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700927 oldest.delete();
928 files = dir.listFiles();
929 } while (files.length > MAX_SIMS_SUPPORTED);
930 }
931
932 private File useMRUFile(File dir) {
933 File newest = null;
934 File[] files = dir.listFiles();
935
936 for (File f : files) {
937 if ((newest == null) || (newest.lastModified() < f.lastModified())) {
938 newest = f;
939 }
940 }
941 if (newest == null) {
942 newest = new File(dir, "temp");
943 }
944 return newest;
945 }
946
947
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700948 private static final int DATA_FILE_VERSION = 1;
949
950 private void record() {
951 // 1 int version
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700952 // 1 int mPeriodCount
953 // 13*6 long[PERIOD_COUNT] mPeriodRxData
954 // 13*6 long[PERIOD_COUNT] mPeriodTxData
955 // 1 int mCurrentPeriod
956 // 13 long periodStartMS
957 // 13 long periodEndMS
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700958 // 200 chars max
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700959 StringBuilder builder = new StringBuilder();
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700960 builder.append(DATA_FILE_VERSION);
961 builder.append(":");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700962 builder.append(mPeriodCount);
963 builder.append(":");
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700964 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700965 builder.append(mPeriodRxData[i]);
966 builder.append(":");
967 }
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700968 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700969 builder.append(mPeriodTxData[i]);
970 builder.append(":");
971 }
972 builder.append(mCurrentPeriod);
973 builder.append(":");
974 builder.append(mPeriodStart.getTimeInMillis());
975 builder.append(":");
976 builder.append(mPeriodEnd.getTimeInMillis());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700977
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700978 BufferedWriter out = null;
979 try {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700980 out = new BufferedWriter(new FileWriter(getDataFile()), 256);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700981 out.write(builder.toString());
982 } catch (IOException e) {
983 Slog.e(TAG, "Error writing data file");
984 return;
985 } finally {
986 if (out != null) {
987 try {
988 out.close();
989 } catch (Exception e) {}
990 }
991 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700992 }
993
994 private void retrieve() {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700995 // clean out any old data first. If we fail to read we don't want old stuff
996 zeroData(0);
997
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700998 File f = getDataFile();
999 byte[] buffer;
1000 FileInputStream s = null;
1001 try {
1002 buffer = new byte[(int)f.length()];
1003 s = new FileInputStream(f);
1004 s.read(buffer);
1005 } catch (IOException e) {
1006 Slog.e(TAG, "Error reading data file");
1007 return;
1008 } finally {
1009 if (s != null) {
1010 try {
1011 s.close();
1012 } catch (Exception e) {}
1013 }
1014 }
1015 String data = new String(buffer);
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001016 if (data == null || data.length() == 0) {
1017 if (DBG) Slog.d(TAG, "data file empty");
1018 return;
1019 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001020 synchronized (mParent) {
1021 String[] parsed = data.split(":");
1022 int parsedUsed = 0;
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001023 if (parsed.length < 6) {
1024 Slog.e(TAG, "reading data file with insufficient length - ignoring");
1025 return;
1026 }
1027
1028 if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
1029 Slog.e(TAG, "reading data file with bad version - ignoring");
1030 return;
1031 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001032
1033 mPeriodCount = Integer.parseInt(parsed[parsedUsed++]);
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001034 if (parsed.length != 5 + (2 * mPeriodCount)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -07001035 Slog.e(TAG, "reading data file with bad length ("+parsed.length+" != "+(5 + (2*mPeriodCount))+") - ignoring");
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001036 return;
1037 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001038
1039 mPeriodRxData = new long[mPeriodCount];
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001040 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001041 mPeriodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
1042 }
1043 mPeriodTxData = new long[mPeriodCount];
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001044 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001045 mPeriodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
1046 }
1047 mCurrentPeriod = Integer.parseInt(parsed[parsedUsed++]);
1048 mPeriodStart = new GregorianCalendar();
1049 mPeriodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1050 mPeriodEnd = new GregorianCalendar();
1051 mPeriodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1052 }
1053 }
1054
1055 long getPeriodRx(int which) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001056 synchronized (mParent) {
1057 if (which > mPeriodCount) return 0;
1058 which = mCurrentPeriod - which;
1059 if (which < 0) which += mPeriodCount;
1060 return mPeriodRxData[which];
1061 }
1062 }
1063 long getPeriodTx(int which) {
1064 synchronized (mParent) {
1065 if (which > mPeriodCount) return 0;
1066 which = mCurrentPeriod - which;
1067 if (which < 0) which += mPeriodCount;
1068 return mPeriodTxData[which];
1069 }
1070 }
1071 }
1072
1073 @Override
1074 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1075 if (mContext.checkCallingOrSelfPermission(
1076 android.Manifest.permission.DUMP)
1077 != PackageManager.PERMISSION_GRANTED) {
1078 pw.println("Permission Denial: can't dump ThrottleService " +
1079 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1080 Binder.getCallingUid());
1081 return;
1082 }
1083 pw.println();
1084
1085 pw.println("The threshold is " + mPolicyThreshold +
1086 ", after which you experince throttling to " +
1087 mPolicyThrottleValue + "kbps");
1088 pw.println("Current period is " +
1089 (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001090 "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001091 " seconds.");
1092 pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
Robert Greenwalt8c7e6092010-04-14 17:31:20 -07001093 pw.println("Current Throttle Index is " + mThrottleIndex);
1094
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001095 for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
1096 pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
1097 mRecorder.getPeriodTx(i));
1098 }
1099 }
1100}