blob: 57e3918f7b71d049e585a9301deb80bc3113b721 [file] [log] [blame]
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.AlarmManager;
20import android.app.Notification;
21import android.app.NotificationManager;
22import android.app.PendingIntent;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070023import android.content.BroadcastReceiver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -070024import android.content.ContentResolver;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070025import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.PackageManager;
29import android.content.res.Resources;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -070030import android.database.ContentObserver;
Robert Greenwaltfee46832010-05-06 12:25:13 -070031import android.net.INetworkManagementEventObserver;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070032import android.net.IThrottleManager;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070033import android.net.SntpClient;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070034import android.net.ThrottleManager;
35import android.os.Binder;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070036import android.os.Environment;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070037import android.os.Handler;
38import android.os.HandlerThread;
39import android.os.IBinder;
40import android.os.INetworkManagementService;
41import android.os.Looper;
42import android.os.Message;
43import android.os.RemoteException;
44import android.os.ServiceManager;
45import android.os.SystemClock;
46import android.os.SystemProperties;
47import android.provider.Settings;
Robert Greenwalte6e98822010-04-15 08:27:14 -070048import android.telephony.TelephonyManager;
Robert Greenwaltfee46832010-05-06 12:25:13 -070049import android.text.TextUtils;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070050import android.util.Slog;
51
Robert Greenwalt7171ea82010-04-14 22:37:12 -070052import com.android.internal.R;
Robert Greenwalt5f996892010-04-08 16:19:24 -070053import com.android.internal.telephony.TelephonyProperties;
54
Robert Greenwaltb8912f52010-04-09 17:27:26 -070055import java.io.BufferedWriter;
56import java.io.File;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070057import java.io.FileDescriptor;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070058import java.io.FileInputStream;
59import java.io.FileWriter;
60import java.io.IOException;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070061import java.io.PrintWriter;
62import java.util.Calendar;
Robert Greenwalt39e163f2010-05-07 16:52:17 -070063import java.util.concurrent.atomic.AtomicInteger;
64import java.util.concurrent.atomic.AtomicLong;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070065import java.util.GregorianCalendar;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070066import java.util.Properties;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070067import java.util.Random;
68
69// TODO - add comments - reference the ThrottleManager for public API
70public class ThrottleService extends IThrottleManager.Stub {
71
72 private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
73
74 private static final String TAG = "ThrottleService";
Robert Greenwaltbf7de392010-04-21 17:09:38 -070075 private static final boolean DBG = true;
76 private static final boolean VDBG = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070077 private Handler mHandler;
78 private HandlerThread mThread;
79
80 private Context mContext;
81
Robert Greenwaltfb9896b2010-04-22 15:39:38 -070082 private static final int INITIAL_POLL_DELAY_SEC = 90;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070083 private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070084 private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070085 private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070086
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070087 private int mPolicyPollPeriodSec;
Robert Greenwalt39e163f2010-05-07 16:52:17 -070088 private AtomicLong mPolicyThreshold;
89 private AtomicInteger mPolicyThrottleValue;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070090 private int mPolicyResetDay; // 1-28
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070091 private int mPolicyNotificationsAllowedMask;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070092
93 private long mLastRead; // read byte count from last poll
94 private long mLastWrite; // write byte count from last poll
95
96 private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
97 private static int POLL_REQUEST = 0;
98 private PendingIntent mPendingPollIntent;
99 private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
100 private static int RESET_REQUEST = 1;
101 private PendingIntent mPendingResetIntent;
102
103 private INetworkManagementService mNMService;
104 private AlarmManager mAlarmManager;
105 private NotificationManager mNotificationManager;
106
107 private DataRecorder mRecorder;
108
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700109 private String mIface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700110
111 private static final int NOTIFICATION_WARNING = 2;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700112
113 private Notification mThrottlingNotification;
114 private boolean mWarningNotificationSent = false;
115
Robert Greenwaltfee46832010-05-06 12:25:13 -0700116 private InterfaceObserver mInterfaceObserver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700117 private SettingsObserver mSettingsObserver;
118
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700119 private AtomicInteger mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700120 private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
121 private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
122
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700123 private static final String PROPERTIES_FILE = "/etc/gps.conf";
124 private String mNtpServer;
125 private boolean mNtpActive;
126
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700127 public ThrottleService(Context context) {
128 if (DBG) Slog.d(TAG, "Starting ThrottleService");
129 mContext = context;
130
Robert Greenwalt24488bd2010-05-10 16:56:43 -0700131 mPolicyThreshold = new AtomicLong();
132 mPolicyThrottleValue = new AtomicInteger();
133 mThrottleIndex = new AtomicInteger();
134
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700135 mNtpActive = false;
136
Robert Greenwaltfee46832010-05-06 12:25:13 -0700137 mIface = mContext.getResources().getString(R.string.config_datause_iface);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700138 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
139 Intent pollIntent = new Intent(ACTION_POLL, null);
140 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
141 Intent resetIntent = new Intent(ACTION_RESET, null);
142 mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
143
144 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
145 mNMService = INetworkManagementService.Stub.asInterface(b);
146
147 mNotificationManager = (NotificationManager)mContext.getSystemService(
148 Context.NOTIFICATION_SERVICE);
149 }
150
Robert Greenwaltfee46832010-05-06 12:25:13 -0700151 private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
152 private int mMsg;
153 private Handler mHandler;
154 private String mIface;
155
156 InterfaceObserver(Handler handler, int msg, String iface) {
157 super();
158 mHandler = handler;
159 mMsg = msg;
160 mIface = iface;
161 }
162
163 public void interfaceLinkStatusChanged(String iface, boolean link) {
164 if (link) {
165 if (TextUtils.equals(iface, mIface)) {
166 mHandler.obtainMessage(mMsg).sendToTarget();
167 }
168 }
169 }
170
171 public void interfaceAdded(String iface) {
172 // TODO - an interface added in the UP state should also trigger a StatusChanged
173 // notification..
174 if (TextUtils.equals(iface, mIface)) {
175 mHandler.obtainMessage(mMsg).sendToTarget();
176 }
177 }
178
179 public void interfaceRemoved(String iface) {}
180 }
181
182
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700183 private static class SettingsObserver extends ContentObserver {
184 private int mMsg;
185 private Handler mHandler;
186 SettingsObserver(Handler handler, int msg) {
187 super(handler);
188 mHandler = handler;
189 mMsg = msg;
190 }
191
192 void observe(Context context) {
193 ContentResolver resolver = context.getContentResolver();
194 resolver.registerContentObserver(Settings.Secure.getUriFor(
195 Settings.Secure.THROTTLE_POLLING_SEC), false, this);
196 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700197 Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700198 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700199 Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700200 resolver.registerContentObserver(Settings.Secure.getUriFor(
201 Settings.Secure.THROTTLE_RESET_DAY), false, this);
202 resolver.registerContentObserver(Settings.Secure.getUriFor(
203 Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
204 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700205 Settings.Secure.THROTTLE_HELP_URI), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700206 }
207
208 @Override
209 public void onChange(boolean selfChange) {
210 mHandler.obtainMessage(mMsg).sendToTarget();
211 }
212 }
213
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700214 private void enforceAccessPermission() {
215 mContext.enforceCallingOrSelfPermission(
216 android.Manifest.permission.ACCESS_NETWORK_STATE,
217 "ThrottleService");
218 }
219
Robert Greenwalt05d06732010-04-19 11:10:38 -0700220 private long ntpToWallTime(long ntpTime) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700221 long bestNow = getBestTime(true); // do it quickly
Robert Greenwalt05d06732010-04-19 11:10:38 -0700222 long localNow = System.currentTimeMillis();
223 return localNow + (ntpTime - bestNow);
224 }
225
Irfan Sheriffcf282362010-04-16 16:53:20 -0700226 // TODO - fetch for the iface
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700227 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt05d06732010-04-19 11:10:38 -0700228
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700229 public long getResetTime(String iface) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700230 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700231 long resetTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700232 if (mRecorder != null) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700233 resetTime = mRecorder.getPeriodEnd();
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700234 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700235 resetTime = ntpToWallTime(resetTime);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700236 return resetTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700237 }
Irfan Sheriffcf282362010-04-16 16:53:20 -0700238
239 // TODO - fetch for the iface
Robert Greenwalt05d06732010-04-19 11:10:38 -0700240 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700241 public long getPeriodStartTime(String iface) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700242 long startTime = 0;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700243 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700244 if (mRecorder != null) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700245 startTime = mRecorder.getPeriodStart();
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700246 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700247 startTime = ntpToWallTime(startTime);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700248 return startTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700249 }
250 //TODO - a better name? getCliffByteCountThreshold?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700251 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700252 public long getCliffThreshold(String iface, int cliff) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700253 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700254 if (cliff == 1) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700255 return mPolicyThreshold.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700256 }
257 return 0;
258 }
259 // TODO - a better name? getThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700260 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700261 public int getCliffLevel(String iface, int cliff) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700262 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700263 if (cliff == 1) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700264 return mPolicyThrottleValue.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700265 }
266 return 0;
267 }
268
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700269 public String getHelpUri() {
270 enforceAccessPermission();
271 return Settings.Secure.getString(mContext.getContentResolver(),
272 Settings.Secure.THROTTLE_HELP_URI);
273 }
274
Irfan Sheriffcf282362010-04-16 16:53:20 -0700275 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700276 public long getByteCount(String iface, int dir, int period, int ago) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700277 enforceAccessPermission();
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700278 if ((period == ThrottleManager.PERIOD_CYCLE) && (mRecorder != null)) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700279 if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
280 if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
281 }
282 return 0;
283 }
284
285 // TODO - a better name - getCurrentThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700286 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700287 public int getThrottle(String iface) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700288 enforceAccessPermission();
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700289 if (mThrottleIndex.get() == 1) {
290 return mPolicyThrottleValue.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700291 }
292 return 0;
293 }
294
295 void systemReady() {
296 if (DBG) Slog.d(TAG, "systemReady");
297 mContext.registerReceiver(
298 new BroadcastReceiver() {
299 @Override
300 public void onReceive(Context context, Intent intent) {
301 mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
302 }
303 }, new IntentFilter(ACTION_POLL));
304
305 mContext.registerReceiver(
306 new BroadcastReceiver() {
307 @Override
308 public void onReceive(Context context, Intent intent) {
309 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
310 }
311 }, new IntentFilter(ACTION_RESET));
312
313 // use a new thread as we don't want to stall the system for file writes
314 mThread = new HandlerThread(TAG);
315 mThread.start();
316 mHandler = new MyHandler(mThread.getLooper());
317 mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700318
Robert Greenwaltfee46832010-05-06 12:25:13 -0700319 mInterfaceObserver = new InterfaceObserver(mHandler, EVENT_IFACE_UP, mIface);
320 try {
321 mNMService.registerObserver(mInterfaceObserver);
322 } catch (RemoteException e) {
323 Slog.e(TAG, "Could not register InterfaceObserver " + e);
324 }
325
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700326 mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
327 mSettingsObserver.observe(mContext);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700328
329 FileInputStream stream = null;
330 try {
331 Properties properties = new Properties();
332 File file = new File(PROPERTIES_FILE);
333 stream = new FileInputStream(file);
334 properties.load(stream);
335 mNtpServer = properties.getProperty("NTP_SERVER", null);
336 } catch (IOException e) {
337 Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
338 } finally {
339 if (stream != null) {
340 try {
341 stream.close();
342 } catch (Exception e) {}
343 }
344 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700345 }
346
347
348 private static final int EVENT_REBOOT_RECOVERY = 0;
349 private static final int EVENT_POLICY_CHANGED = 1;
350 private static final int EVENT_POLL_ALARM = 2;
351 private static final int EVENT_RESET_ALARM = 3;
Robert Greenwaltfee46832010-05-06 12:25:13 -0700352 private static final int EVENT_IFACE_UP = 4;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700353 private class MyHandler extends Handler {
354 public MyHandler(Looper l) {
355 super(l);
356 }
357
358 @Override
359 public void handleMessage(Message msg) {
360 switch (msg.what) {
361 case EVENT_REBOOT_RECOVERY:
362 onRebootRecovery();
363 break;
364 case EVENT_POLICY_CHANGED:
365 onPolicyChanged();
366 break;
367 case EVENT_POLL_ALARM:
368 onPollAlarm();
369 break;
370 case EVENT_RESET_ALARM:
371 onResetAlarm();
Robert Greenwaltfee46832010-05-06 12:25:13 -0700372 break;
373 case EVENT_IFACE_UP:
374 onIfaceUp();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700375 }
376 }
377
378 private void onRebootRecovery() {
379 if (DBG) Slog.d(TAG, "onRebootRecovery");
380 // check for sim change TODO
381 // reregister for notification of policy change
382
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700383 mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700384
385 mRecorder = new DataRecorder(mContext, ThrottleService.this);
386
387 // get policy
388 mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
Robert Greenwaltfb9896b2010-04-22 15:39:38 -0700389
390 // if we poll now we won't have network connectivity or even imsi access
391 // queue up a poll to happen in a little while - after ntp and imsi are avail
392 // TODO - make this callback based (ie, listen for notificaitons)
393 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_POLL_ALARM),
394 INITIAL_POLL_DELAY_SEC * 1000);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700395 }
396
397 // check for new policy info (threshold limit/value/etc)
398 private void onPolicyChanged() {
399 boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
400
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700401 int pollingPeriod = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700402 R.integer.config_datause_polling_period_sec);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700403 mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
404 Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
405
406 // TODO - remove testing stuff?
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700407 long defaultThreshold = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700408 R.integer.config_datause_threshold_bytes);
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700409 int defaultValue = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700410 R.integer.config_datause_throttle_kbitsps);
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700411 long threshold = Settings.Secure.getLong(mContext.getContentResolver(),
412 Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
413 int value = Settings.Secure.getInt(mContext.getContentResolver(),
414 Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
415
416 mPolicyThreshold.set(threshold);
417 mPolicyThrottleValue.set(value);
418 if (testing) {
419 mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
420 mPolicyThreshold.set(TESTING_THRESHOLD);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700421 }
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700422
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700423 mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
424 Settings.Secure.THROTTLE_RESET_DAY, -1);
425 if (mPolicyResetDay == -1 ||
426 ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
427 Random g = new Random();
428 mPolicyResetDay = 1 + g.nextInt(28); // 1-28
429 Settings.Secure.putInt(mContext.getContentResolver(),
430 Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
431 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700432 if (mIface == null) {
433 mPolicyThreshold.set(0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700434 }
435
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700436 int defaultNotificationType = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700437 R.integer.config_datause_notification_type);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700438 mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700439 Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700440
441 Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" + mPolicyPollPeriodSec +
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700442 ", threshold=" + mPolicyThreshold.get() + ", value=" +
443 mPolicyThrottleValue.get() + ", resetDay=" + mPolicyResetDay + ", noteType=" +
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700444 mPolicyNotificationsAllowedMask);
445
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700446 // force updates
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700447 mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700448
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700449 onResetAlarm();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700450
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700451 onPollAlarm();
452
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700453 Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
454 mContext.sendBroadcast(broadcast);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700455 }
456
457 private void onPollAlarm() {
458 long now = SystemClock.elapsedRealtime();
459 long next = now + mPolicyPollPeriodSec*1000;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700460
461 checkForAuthoritativeTime();
462
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700463 long incRead = 0;
464 long incWrite = 0;
465 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700466 incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
467 incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700468 // handle iface resets - on some device the 3g iface comes and goes and gets
469 // totals reset to 0. Deal with it
470 if ((incRead < 0) || (incWrite < 0)) {
471 incRead += mLastRead;
472 incWrite += mLastWrite;
473 mLastRead = 0;
474 mLastWrite = 0;
475 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700476 } catch (RemoteException e) {
477 Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
478 }
Robert Greenwalt5f996892010-04-08 16:19:24 -0700479 // don't count this data if we're roaming.
480 boolean roaming = "true".equals(
481 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
482 if (!roaming) {
483 mRecorder.addData(incRead, incWrite);
484 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700485
486 long periodRx = mRecorder.getPeriodRx(0);
487 long periodTx = mRecorder.getPeriodTx(0);
488 long total = periodRx + periodTx;
489 if (DBG) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700490 Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
Robert Greenwalt5f996892010-04-08 16:19:24 -0700491 ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700492 }
493 mLastRead += incRead;
494 mLastWrite += incWrite;
495
496 checkThrottleAndPostNotification(total);
497
498 Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
499 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
500 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700501 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
502 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700503 mContext.sendStickyBroadcast(broadcast);
504
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700505 mAlarmManager.cancel(mPendingPollIntent);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700506 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, next, mPendingPollIntent);
507 }
508
Robert Greenwaltfee46832010-05-06 12:25:13 -0700509 private void onIfaceUp() {
510 // if we were throttled before, be sure and set it again - the iface went down
511 // (and may have disappeared all together) and these settings were lost
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700512 if (mThrottleIndex.get() == 1) {
Robert Greenwaltfee46832010-05-06 12:25:13 -0700513 try {
514 mNMService.setInterfaceThrottle(mIface, -1, -1);
515 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700516 mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
Robert Greenwaltfee46832010-05-06 12:25:13 -0700517 } catch (Exception e) {
518 Slog.e(TAG, "error setting Throttle: " + e);
519 }
520 }
521 }
522
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700523 private void checkThrottleAndPostNotification(long currentTotal) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700524 // is throttling enabled?
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700525 long threshold = mPolicyThreshold.get();
526 if (threshold == 0) {
Robert Greenwaltcce83372010-04-23 17:35:29 -0700527 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700528 return;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700529 }
530
531 // have we spoken with an ntp server yet?
532 // this is controversial, but we'd rather err towards not throttling
533 if ((mNtpServer != null) && !mNtpActive) {
534 return;
535 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700536
537 // check if we need to throttle
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700538 if (currentTotal > threshold) {
539 if (mThrottleIndex.get() != 1) {
540 mThrottleIndex.set(1);
541 if (DBG) Slog.d(TAG, "Threshold " + threshold + " exceeded!");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700542 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700543 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700544 mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700545 } catch (Exception e) {
546 Slog.e(TAG, "error setting Throttle: " + e);
547 }
548
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700549 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700550
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700551 postNotification(R.string.throttled_notification_title,
552 R.string.throttled_notification_message,
553 R.drawable.stat_sys_throttled,
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700554 Notification.FLAG_ONGOING_EVENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700555
556 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700557 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL,
558 mPolicyThrottleValue.get());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700559 mContext.sendStickyBroadcast(broadcast);
560
561 } // else already up!
562 } else {
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700563 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700564 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
565 // check if we should warn about throttle
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700566 // pretend we only have 1/2 the time remaining that we actually do
567 // if our burn rate in the period so far would have us exceed the limit
568 // in that 1/2 window, warn the user.
569 // this gets more generous in the early to middle period and converges back
570 // to the limit as we move toward the period end.
571
572 // adding another factor - it must be greater than the total cap/4
573 // else we may get false alarms very early in the period.. in the first
574 // tenth of a percent of the period if we used more than a tenth of a percent
575 // of the cap we'd get a warning and that's not desired.
576 long start = mRecorder.getPeriodStart();
577 long end = mRecorder.getPeriodEnd();
578 long periodLength = end - start;
579 long now = System.currentTimeMillis();
580 long timeUsed = now - start;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700581 long warningThreshold = 2*threshold*timeUsed/(timeUsed+periodLength);
582 if ((currentTotal > warningThreshold) && (currentTotal > threshold/4)) {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700583 if (mWarningNotificationSent == false) {
584 mWarningNotificationSent = true;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700585 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
586 postNotification(R.string.throttle_warning_notification_title,
587 R.string.throttle_warning_notification_message,
588 R.drawable.stat_sys_throttled,
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700589 0);
590 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700591 } else {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700592 if (mWarningNotificationSent == true) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700593 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700594 mWarningNotificationSent =false;
595 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700596 }
597 }
598 }
599 }
600
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700601 private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700602 Intent intent = new Intent();
603 // TODO - fix up intent
Robert Greenwalt2a7b7302010-04-12 14:56:31 -0700604 intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700605 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
606
607 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
608
609 Resources r = Resources.getSystem();
610 CharSequence title = r.getText(titleInt);
611 CharSequence message = r.getText(messageInt);
612 if (mThrottlingNotification == null) {
613 mThrottlingNotification = new Notification();
614 mThrottlingNotification.when = 0;
615 // TODO - fixup icon
616 mThrottlingNotification.icon = icon;
617 mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700618 }
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700619 mThrottlingNotification.flags = flags;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700620 mThrottlingNotification.tickerText = title;
621 mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
622
623 mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
624 }
625
626
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700627 private void clearThrottleAndNotification() {
628 if (mThrottleIndex.get() != THROTTLE_INDEX_UNTHROTTLED) {
629 mThrottleIndex.set(THROTTLE_INDEX_UNTHROTTLED);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700630 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700631 mNMService.setInterfaceThrottle(mIface, -1, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700632 } catch (Exception e) {
633 Slog.e(TAG, "error clearing Throttle: " + e);
634 }
635 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
636 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
637 mContext.sendStickyBroadcast(broadcast);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700638 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
639 mWarningNotificationSent = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700640 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700641 }
642
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700643 private Calendar calculatePeriodEnd(long now) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700644 Calendar end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700645 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700646 int day = end.get(Calendar.DAY_OF_MONTH);
647 end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
648 end.set(Calendar.HOUR_OF_DAY, 0);
649 end.set(Calendar.MINUTE, 0);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700650 end.set(Calendar.SECOND, 0);
651 end.set(Calendar.MILLISECOND, 0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700652 if (day >= mPolicyResetDay) {
653 int month = end.get(Calendar.MONTH);
654 if (month == Calendar.DECEMBER) {
655 end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
656 month = Calendar.JANUARY - 1;
657 }
658 end.set(Calendar.MONTH, month + 1);
659 }
660
661 // TODO - remove!
662 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
663 end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700664 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700665 end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
666 }
667 return end;
668 }
669 private Calendar calculatePeriodStart(Calendar end) {
670 Calendar start = (Calendar)end.clone();
671 int month = end.get(Calendar.MONTH);
672 if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
673 month = Calendar.DECEMBER + 1;
674 start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
675 }
676 start.set(Calendar.MONTH, month - 1);
677
678 // TODO - remove!!
679 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
680 start = (Calendar)end.clone();
681 start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
682 }
683 return start;
684 }
685
686 private void onResetAlarm() {
687 if (DBG) {
688 Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
689 " bytes read and " + mRecorder.getPeriodTx(0) + " written");
690 }
691
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700692 long now = getBestTime(false);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700693
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700694 if (mNtpActive || (mNtpServer == null)) {
695 Calendar end = calculatePeriodEnd(now);
696 Calendar start = calculatePeriodStart(end);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700697
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700698 if (mRecorder.setNextPeriod(start, end)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700699 onPollAlarm();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700700 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700701
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700702 mAlarmManager.cancel(mPendingResetIntent);
703 long offset = end.getTimeInMillis() - now;
704 // use Elapsed realtime so clock changes don't fool us.
705 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
706 SystemClock.elapsedRealtime() + offset,
707 mPendingResetIntent);
708 } else {
709 if (DBG) Slog.d(TAG, "no authoritative time - not resetting period");
710 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700711 }
712 }
713
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700714 private void checkForAuthoritativeTime() {
715 if (mNtpActive || (mNtpServer == null)) return;
716
Robert Greenwalt05d06732010-04-19 11:10:38 -0700717 // will try to get the ntp time and switch to it if found.
718 // will also cache the time so we don't fetch it repeatedly.
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700719 getBestTime(false);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700720 }
721
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700722 private static final int MAX_NTP_CACHE_AGE = 60 * 1000;
723 private static final int MAX_NTP_FETCH_WAIT = 20 * 1000;
Robert Greenwalt05d06732010-04-19 11:10:38 -0700724 private long cachedNtp;
725 private long cachedNtpTimestamp;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700726
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700727 // if the request is tied to UI and ANR's are a danger, request a fast result
728 // the regular polling should have updated the cached time recently using the
729 // slower method (!fast)
730 private long getBestTime(boolean fast) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700731 if (mNtpServer != null) {
732 if (mNtpActive) {
733 long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700734 if (ntpAge < MAX_NTP_CACHE_AGE || fast) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700735 if (VDBG) Slog.v(TAG, "using cached time");
Robert Greenwalt05d06732010-04-19 11:10:38 -0700736 return cachedNtp + ntpAge;
737 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700738 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700739 SntpClient client = new SntpClient();
740 if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT)) {
741 cachedNtp = client.getNtpTime();
742 cachedNtpTimestamp = SystemClock.elapsedRealtime();
743 if (!mNtpActive) {
744 mNtpActive = true;
745 if (DBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
746 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
747 }
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700748 if (VDBG) Slog.v(TAG, "using Authoritative time: " + cachedNtp);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700749 return cachedNtp;
750 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700751 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700752 long time = System.currentTimeMillis();
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700753 if (VDBG) Slog.v(TAG, "using User time: " + time);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700754 mNtpActive = false;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700755 return time;
756 }
757
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700758 // records bytecount data for a given time and accumulates it into larger time windows
759 // for logging and other purposes
760 //
761 // since time can be changed (user or network action) we will have to track the time of the
762 // last recording and deal with it.
763 private static class DataRecorder {
764 long[] mPeriodRxData;
765 long[] mPeriodTxData;
766 int mCurrentPeriod;
767 int mPeriodCount;
768
769 Calendar mPeriodStart;
770 Calendar mPeriodEnd;
771
772 ThrottleService mParent;
773 Context mContext;
Robert Greenwalte6e98822010-04-15 08:27:14 -0700774 String mImsi = null;
775
776 TelephonyManager mTelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700777
778 DataRecorder(Context context, ThrottleService parent) {
779 mContext = context;
780 mParent = parent;
781
Robert Greenwalte6e98822010-04-15 08:27:14 -0700782 mTelephonyManager = (TelephonyManager)mContext.getSystemService(
783 Context.TELEPHONY_SERVICE);
784
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700785 synchronized (mParent) {
786 mPeriodCount = 6;
787 mPeriodRxData = new long[mPeriodCount];
788 mPeriodTxData = new long[mPeriodCount];
789
790 mPeriodStart = Calendar.getInstance();
791 mPeriodEnd = Calendar.getInstance();
792
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700793 retrieve();
794 }
795 }
796
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700797 boolean setNextPeriod(Calendar start, Calendar end) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700798 // TODO - how would we deal with a dual-IMSI device?
799 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700800 boolean startNewPeriod = true;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700801
Robert Greenwalt27fba672010-04-26 12:29:14 -0700802 if (start.equals(mPeriodStart) && end.equals(mPeriodEnd)) {
803 // same endpoints - keep collecting
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700804 if (DBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700805 Slog.d(TAG, "same period (" + start.getTimeInMillis() + "," +
806 end.getTimeInMillis() +") - ammending data");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700807 }
Robert Greenwalt27fba672010-04-26 12:29:14 -0700808 startNewPeriod = false;
809 } else {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700810 if (DBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700811 if(start.equals(mPeriodEnd) || start.after(mPeriodEnd)) {
812 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
813 end.getTimeInMillis() + ") - old end was " +
814 mPeriodEnd.getTimeInMillis() + ", following");
815 } else {
816 Slog.d(TAG, "new period (" + start.getTimeInMillis() + "," +
817 end.getTimeInMillis() + ") replacing old (" +
818 mPeriodStart.getTimeInMillis() + "," +
819 mPeriodEnd.getTimeInMillis() + ")");
820 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700821 }
822 synchronized (mParent) {
823 ++mCurrentPeriod;
824 if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
825 mPeriodRxData[mCurrentPeriod] = 0;
826 mPeriodTxData[mCurrentPeriod] = 0;
827 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700828 }
829 setPeriodStart(start);
830 setPeriodEnd(end);
831 record();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700832 return startNewPeriod;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700833 }
834
835 public long getPeriodEnd() {
836 synchronized (mParent) {
837 return mPeriodEnd.getTimeInMillis();
838 }
839 }
840
841 private void setPeriodEnd(Calendar end) {
842 synchronized (mParent) {
843 mPeriodEnd = end;
844 }
845 }
846
847 public long getPeriodStart() {
848 synchronized (mParent) {
849 return mPeriodStart.getTimeInMillis();
850 }
851 }
852
853 private void setPeriodStart(Calendar start) {
854 synchronized (mParent) {
855 mPeriodStart = start;
856 }
857 }
858
859 public int getPeriodCount() {
860 synchronized (mParent) {
861 return mPeriodCount;
862 }
863 }
864
865 private void zeroData(int field) {
866 synchronized (mParent) {
867 for(int period = 0; period<mPeriodCount; period++) {
868 mPeriodRxData[period] = 0;
869 mPeriodTxData[period] = 0;
870 }
871 mCurrentPeriod = 0;
872 }
873
874 }
875
876 // if time moves backward accumulate all read/write that's lost into the now
877 // otherwise time moved forward.
878 void addData(long bytesRead, long bytesWritten) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700879 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700880
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700881 synchronized (mParent) {
882 mPeriodRxData[mCurrentPeriod] += bytesRead;
883 mPeriodTxData[mCurrentPeriod] += bytesWritten;
884 }
885 record();
886 }
887
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700888 private File getDataFile() {
889 File dataDir = Environment.getDataDirectory();
890 File throttleDir = new File(dataDir, "system/throttle");
891 throttleDir.mkdirs();
Robert Greenwalte6e98822010-04-15 08:27:14 -0700892 String mImsi = mTelephonyManager.getSubscriberId();
893 File dataFile;
894 if (mImsi == null) {
895 dataFile = useMRUFile(throttleDir);
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700896 if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700897 } else {
898 String imsiHash = Integer.toString(mImsi.hashCode());
899 dataFile = new File(throttleDir, imsiHash);
900 }
901 // touch the file so it's not LRU
902 dataFile.setLastModified(System.currentTimeMillis());
903 checkAndDeleteLRUDataFile(throttleDir);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700904 return dataFile;
905 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700906
Robert Greenwalte6e98822010-04-15 08:27:14 -0700907 // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
908 private void checkForSubscriberId() {
909 if (mImsi != null) return;
910
911 mImsi = mTelephonyManager.getSubscriberId();
912 if (mImsi == null) return;
913
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700914 if (DBG) Slog.d(TAG, "finally have imsi - retreiving data");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700915 retrieve();
916 }
917
918 private final static int MAX_SIMS_SUPPORTED = 3;
919
920 private void checkAndDeleteLRUDataFile(File dir) {
921 File[] files = dir.listFiles();
922
923 if (files.length <= MAX_SIMS_SUPPORTED) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700924 if (DBG) Slog.d(TAG, "Too many data files");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700925 do {
926 File oldest = null;
927 for (File f : files) {
928 if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
929 oldest = f;
930 }
931 }
932 if (oldest == null) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700933 if (DBG) Slog.d(TAG, " deleting " + oldest);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700934 oldest.delete();
935 files = dir.listFiles();
936 } while (files.length > MAX_SIMS_SUPPORTED);
937 }
938
939 private File useMRUFile(File dir) {
940 File newest = null;
941 File[] files = dir.listFiles();
942
943 for (File f : files) {
944 if ((newest == null) || (newest.lastModified() < f.lastModified())) {
945 newest = f;
946 }
947 }
948 if (newest == null) {
949 newest = new File(dir, "temp");
950 }
951 return newest;
952 }
953
954
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700955 private static final int DATA_FILE_VERSION = 1;
956
957 private void record() {
958 // 1 int version
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700959 // 1 int mPeriodCount
960 // 13*6 long[PERIOD_COUNT] mPeriodRxData
961 // 13*6 long[PERIOD_COUNT] mPeriodTxData
962 // 1 int mCurrentPeriod
963 // 13 long periodStartMS
964 // 13 long periodEndMS
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700965 // 200 chars max
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700966 StringBuilder builder = new StringBuilder();
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700967 builder.append(DATA_FILE_VERSION);
968 builder.append(":");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700969 builder.append(mPeriodCount);
970 builder.append(":");
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700971 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700972 builder.append(mPeriodRxData[i]);
973 builder.append(":");
974 }
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700975 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700976 builder.append(mPeriodTxData[i]);
977 builder.append(":");
978 }
979 builder.append(mCurrentPeriod);
980 builder.append(":");
981 builder.append(mPeriodStart.getTimeInMillis());
982 builder.append(":");
983 builder.append(mPeriodEnd.getTimeInMillis());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700984
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700985 BufferedWriter out = null;
986 try {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700987 out = new BufferedWriter(new FileWriter(getDataFile()), 256);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700988 out.write(builder.toString());
989 } catch (IOException e) {
990 Slog.e(TAG, "Error writing data file");
991 return;
992 } finally {
993 if (out != null) {
994 try {
995 out.close();
996 } catch (Exception e) {}
997 }
998 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700999 }
1000
1001 private void retrieve() {
Robert Greenwalt05d06732010-04-19 11:10:38 -07001002 // clean out any old data first. If we fail to read we don't want old stuff
1003 zeroData(0);
1004
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001005 File f = getDataFile();
1006 byte[] buffer;
1007 FileInputStream s = null;
1008 try {
1009 buffer = new byte[(int)f.length()];
1010 s = new FileInputStream(f);
1011 s.read(buffer);
1012 } catch (IOException e) {
1013 Slog.e(TAG, "Error reading data file");
1014 return;
1015 } finally {
1016 if (s != null) {
1017 try {
1018 s.close();
1019 } catch (Exception e) {}
1020 }
1021 }
1022 String data = new String(buffer);
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001023 if (data == null || data.length() == 0) {
1024 if (DBG) Slog.d(TAG, "data file empty");
1025 return;
1026 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001027 String[] parsed = data.split(":");
1028 int parsedUsed = 0;
1029 if (parsed.length < 6) {
1030 Slog.e(TAG, "reading data file with insufficient length - ignoring");
1031 return;
1032 }
1033
1034 if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
1035 Slog.e(TAG, "reading data file with bad version - ignoring");
1036 return;
1037 }
1038
1039 int periodCount = Integer.parseInt(parsed[parsedUsed++]);
1040 if (parsed.length != 5 + (2 * periodCount)) {
1041 Slog.e(TAG, "reading data file with bad length (" + parsed.length +
1042 " != " + (5 + (2 * periodCount)) + ") - ignoring");
1043 return;
1044 }
1045 long[] periodRxData = new long[periodCount];
1046 for (int i = 0; i < periodCount; i++) {
1047 periodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
1048 }
1049 long[] periodTxData = new long[periodCount];
1050 for (int i = 0; i < periodCount; i++) {
1051 periodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
1052 }
1053
1054 Calendar periodStart = new GregorianCalendar();
1055 periodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1056 Calendar periodEnd = new GregorianCalendar();
1057 periodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001058 synchronized (mParent) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001059 mPeriodCount = periodCount;
1060 mPeriodRxData = periodRxData;
1061 mPeriodTxData = periodTxData;
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001062 mCurrentPeriod = Integer.parseInt(parsed[parsedUsed++]);
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001063 mPeriodStart = periodStart;
1064 mPeriodEnd = periodEnd;
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001065 }
1066 }
1067
1068 long getPeriodRx(int which) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001069 synchronized (mParent) {
1070 if (which > mPeriodCount) return 0;
1071 which = mCurrentPeriod - which;
1072 if (which < 0) which += mPeriodCount;
1073 return mPeriodRxData[which];
1074 }
1075 }
1076 long getPeriodTx(int which) {
1077 synchronized (mParent) {
1078 if (which > mPeriodCount) return 0;
1079 which = mCurrentPeriod - which;
1080 if (which < 0) which += mPeriodCount;
1081 return mPeriodTxData[which];
1082 }
1083 }
1084 }
1085
1086 @Override
1087 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1088 if (mContext.checkCallingOrSelfPermission(
1089 android.Manifest.permission.DUMP)
1090 != PackageManager.PERMISSION_GRANTED) {
1091 pw.println("Permission Denial: can't dump ThrottleService " +
1092 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1093 Binder.getCallingUid());
1094 return;
1095 }
1096 pw.println();
1097
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001098 pw.println("The threshold is " + mPolicyThreshold.get() +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001099 ", after which you experince throttling to " +
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001100 mPolicyThrottleValue.get() + "kbps");
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001101 pw.println("Current period is " +
1102 (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001103 "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001104 " seconds.");
1105 pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001106 pw.println("Current Throttle Index is " + mThrottleIndex.get());
Robert Greenwalt8c7e6092010-04-14 17:31:20 -07001107
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001108 for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
1109 pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
1110 mRecorder.getPeriodTx(i));
1111 }
1112 }
1113}