blob: 4d2d2f999b0b1265cb7da206f672230006e0022d [file] [log] [blame]
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.AlarmManager;
20import android.app.Notification;
21import android.app.NotificationManager;
22import android.app.PendingIntent;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070023import android.content.BroadcastReceiver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -070024import android.content.ContentResolver;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070025import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.PackageManager;
29import android.content.res.Resources;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -070030import android.database.ContentObserver;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070031import android.net.IThrottleManager;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070032import android.net.SntpClient;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070033import android.net.ThrottleManager;
34import android.os.Binder;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070035import android.os.Environment;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070036import android.os.Handler;
37import android.os.HandlerThread;
38import android.os.IBinder;
39import android.os.INetworkManagementService;
40import android.os.Looper;
41import android.os.Message;
42import android.os.RemoteException;
43import android.os.ServiceManager;
44import android.os.SystemClock;
45import android.os.SystemProperties;
46import android.provider.Settings;
Robert Greenwalte6e98822010-04-15 08:27:14 -070047import android.telephony.TelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070048import android.util.Slog;
49
Robert Greenwalt7171ea82010-04-14 22:37:12 -070050import com.android.internal.R;
Robert Greenwalt5f996892010-04-08 16:19:24 -070051import com.android.internal.telephony.TelephonyProperties;
52
Robert Greenwaltb8912f52010-04-09 17:27:26 -070053import java.io.BufferedWriter;
54import java.io.File;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070055import java.io.FileDescriptor;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070056import java.io.FileInputStream;
57import java.io.FileWriter;
58import java.io.IOException;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070059import java.io.PrintWriter;
60import java.util.Calendar;
61import java.util.GregorianCalendar;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070062import java.util.Properties;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070063import java.util.Random;
64
65// TODO - add comments - reference the ThrottleManager for public API
66public class ThrottleService extends IThrottleManager.Stub {
67
68 private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
69
70 private static final String TAG = "ThrottleService";
71 private static boolean DBG = true;
72 private Handler mHandler;
73 private HandlerThread mThread;
74
75 private Context mContext;
76
Robert Greenwalt9e696c22010-04-01 14:45:18 -070077 private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070078 private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070079 private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070080
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070081 private int mPolicyPollPeriodSec;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070082 private long mPolicyThreshold;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070083 private int mPolicyThrottleValue;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070084 private int mPolicyResetDay; // 1-28
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070085 private int mPolicyNotificationsAllowedMask;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070086
87 private long mLastRead; // read byte count from last poll
88 private long mLastWrite; // write byte count from last poll
89
90 private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
91 private static int POLL_REQUEST = 0;
92 private PendingIntent mPendingPollIntent;
93 private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
94 private static int RESET_REQUEST = 1;
95 private PendingIntent mPendingResetIntent;
96
97 private INetworkManagementService mNMService;
98 private AlarmManager mAlarmManager;
99 private NotificationManager mNotificationManager;
100
101 private DataRecorder mRecorder;
102
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700103 private String mIface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700104
105 private static final int NOTIFICATION_WARNING = 2;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700106
107 private Notification mThrottlingNotification;
108 private boolean mWarningNotificationSent = false;
109
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700110 private SettingsObserver mSettingsObserver;
111
112 private int mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
113 private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
114 private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
115
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700116 private static final String PROPERTIES_FILE = "/etc/gps.conf";
117 private String mNtpServer;
118 private boolean mNtpActive;
119
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700120 public ThrottleService(Context context) {
121 if (DBG) Slog.d(TAG, "Starting ThrottleService");
122 mContext = context;
123
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700124 mNtpActive = false;
125
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700126 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
127 Intent pollIntent = new Intent(ACTION_POLL, null);
128 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
129 Intent resetIntent = new Intent(ACTION_RESET, null);
130 mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
131
132 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
133 mNMService = INetworkManagementService.Stub.asInterface(b);
134
135 mNotificationManager = (NotificationManager)mContext.getSystemService(
136 Context.NOTIFICATION_SERVICE);
137 }
138
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700139 private static class SettingsObserver extends ContentObserver {
140 private int mMsg;
141 private Handler mHandler;
142 SettingsObserver(Handler handler, int msg) {
143 super(handler);
144 mHandler = handler;
145 mMsg = msg;
146 }
147
148 void observe(Context context) {
149 ContentResolver resolver = context.getContentResolver();
150 resolver.registerContentObserver(Settings.Secure.getUriFor(
151 Settings.Secure.THROTTLE_POLLING_SEC), false, this);
152 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700153 Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700154 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700155 Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700156 resolver.registerContentObserver(Settings.Secure.getUriFor(
157 Settings.Secure.THROTTLE_RESET_DAY), false, this);
158 resolver.registerContentObserver(Settings.Secure.getUriFor(
159 Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
160 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700161 Settings.Secure.THROTTLE_HELP_URI), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700162 }
163
164 @Override
165 public void onChange(boolean selfChange) {
166 mHandler.obtainMessage(mMsg).sendToTarget();
167 }
168 }
169
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700170 private void enforceAccessPermission() {
171 mContext.enforceCallingOrSelfPermission(
172 android.Manifest.permission.ACCESS_NETWORK_STATE,
173 "ThrottleService");
174 }
175
Robert Greenwalt05d06732010-04-19 11:10:38 -0700176 private long ntpToWallTime(long ntpTime) {
177 long bestNow = getBestTime();
178 long localNow = System.currentTimeMillis();
179 return localNow + (ntpTime - bestNow);
180 }
181
Irfan Sheriffcf282362010-04-16 16:53:20 -0700182 // TODO - fetch for the iface
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700183 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt05d06732010-04-19 11:10:38 -0700184
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700185 public synchronized long getResetTime(String iface) {
186 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700187 long resetTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700188 if (mRecorder != null) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700189 resetTime = ntpToWallTime(mRecorder.getPeriodEnd());
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700190 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700191 return resetTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700192 }
Irfan Sheriffcf282362010-04-16 16:53:20 -0700193
194 // TODO - fetch for the iface
Robert Greenwalt05d06732010-04-19 11:10:38 -0700195 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700196 public synchronized long getPeriodStartTime(String iface) {
197 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700198 long startTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700199 if (mRecorder != null) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700200 startTime = ntpToWallTime(mRecorder.getPeriodStart());
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700201 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700202 return startTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700203 }
204 //TODO - a better name? getCliffByteCountThreshold?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700205 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700206 public synchronized long getCliffThreshold(String iface, int cliff) {
207 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700208 if (cliff == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700209 return mPolicyThreshold;
210 }
211 return 0;
212 }
213 // TODO - a better name? getThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700214 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700215 public synchronized int getCliffLevel(String iface, int cliff) {
216 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700217 if (cliff == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700218 return mPolicyThrottleValue;
219 }
220 return 0;
221 }
222
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700223 public String getHelpUri() {
224 enforceAccessPermission();
225 return Settings.Secure.getString(mContext.getContentResolver(),
226 Settings.Secure.THROTTLE_HELP_URI);
227 }
228
Irfan Sheriffcf282362010-04-16 16:53:20 -0700229 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700230 public synchronized long getByteCount(String iface, int dir, int period, int ago) {
231 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700232 if ((period == ThrottleManager.PERIOD_CYCLE) &&
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700233 (mRecorder != null)) {
234 if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
235 if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
236 }
237 return 0;
238 }
239
240 // TODO - a better name - getCurrentThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700241 // TODO - fetch for the iface
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700242 public synchronized int getThrottle(String iface) {
243 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700244 if (mThrottleIndex == 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700245 return mPolicyThrottleValue;
246 }
247 return 0;
248 }
249
250 void systemReady() {
251 if (DBG) Slog.d(TAG, "systemReady");
252 mContext.registerReceiver(
253 new BroadcastReceiver() {
254 @Override
255 public void onReceive(Context context, Intent intent) {
256 mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
257 }
258 }, new IntentFilter(ACTION_POLL));
259
260 mContext.registerReceiver(
261 new BroadcastReceiver() {
262 @Override
263 public void onReceive(Context context, Intent intent) {
264 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
265 }
266 }, new IntentFilter(ACTION_RESET));
267
268 // use a new thread as we don't want to stall the system for file writes
269 mThread = new HandlerThread(TAG);
270 mThread.start();
271 mHandler = new MyHandler(mThread.getLooper());
272 mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700273
274 mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
275 mSettingsObserver.observe(mContext);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700276
277 FileInputStream stream = null;
278 try {
279 Properties properties = new Properties();
280 File file = new File(PROPERTIES_FILE);
281 stream = new FileInputStream(file);
282 properties.load(stream);
283 mNtpServer = properties.getProperty("NTP_SERVER", null);
284 } catch (IOException e) {
285 Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
286 } finally {
287 if (stream != null) {
288 try {
289 stream.close();
290 } catch (Exception e) {}
291 }
292 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700293 }
294
295
296 private static final int EVENT_REBOOT_RECOVERY = 0;
297 private static final int EVENT_POLICY_CHANGED = 1;
298 private static final int EVENT_POLL_ALARM = 2;
299 private static final int EVENT_RESET_ALARM = 3;
300 private class MyHandler extends Handler {
301 public MyHandler(Looper l) {
302 super(l);
303 }
304
305 @Override
306 public void handleMessage(Message msg) {
307 switch (msg.what) {
308 case EVENT_REBOOT_RECOVERY:
309 onRebootRecovery();
310 break;
311 case EVENT_POLICY_CHANGED:
312 onPolicyChanged();
313 break;
314 case EVENT_POLL_ALARM:
315 onPollAlarm();
316 break;
317 case EVENT_RESET_ALARM:
318 onResetAlarm();
319 }
320 }
321
322 private void onRebootRecovery() {
323 if (DBG) Slog.d(TAG, "onRebootRecovery");
324 // check for sim change TODO
325 // reregister for notification of policy change
326
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700327 mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700328
329 mRecorder = new DataRecorder(mContext, ThrottleService.this);
330
331 // get policy
332 mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700333 }
334
335 // check for new policy info (threshold limit/value/etc)
336 private void onPolicyChanged() {
337 boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
338
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700339 int pollingPeriod = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700340 R.integer.config_datause_polling_period_sec);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700341 mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
342 Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
343
344 // TODO - remove testing stuff?
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700345 long defaultThreshold = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700346 R.integer.config_datause_threshold_bytes);
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700347 int defaultValue = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700348 R.integer.config_datause_throttle_kbitsps);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700349 synchronized (ThrottleService.this) {
350 mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700351 Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700352 mPolicyThrottleValue = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700353 Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
354 if (testing) {
355 mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
356 mPolicyThreshold = TESTING_THRESHOLD;
357 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700358 }
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700359
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700360 mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
361 Settings.Secure.THROTTLE_RESET_DAY, -1);
362 if (mPolicyResetDay == -1 ||
363 ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
364 Random g = new Random();
365 mPolicyResetDay = 1 + g.nextInt(28); // 1-28
366 Settings.Secure.putInt(mContext.getContentResolver(),
367 Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
368 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700369 mIface = mContext.getResources().getString(R.string.config_datause_iface);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700370 synchronized (ThrottleService.this) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700371 if (mIface == null) {
372 mPolicyThreshold = 0;
373 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700374 }
375
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700376 int defaultNotificationType = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700377 R.integer.config_datause_notification_type);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700378 mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700379 Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700380
381 Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" + mPolicyPollPeriodSec +
382 ", threshold=" + mPolicyThreshold + ", value=" + mPolicyThrottleValue +
383 ", resetDay=" + mPolicyResetDay + ", noteType=" +
384 mPolicyNotificationsAllowedMask);
385
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700386 onResetAlarm();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700387
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700388 onPollAlarm();
389
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700390 Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
391 mContext.sendBroadcast(broadcast);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700392 }
393
394 private void onPollAlarm() {
395 long now = SystemClock.elapsedRealtime();
396 long next = now + mPolicyPollPeriodSec*1000;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700397
398 checkForAuthoritativeTime();
399
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700400 long incRead = 0;
401 long incWrite = 0;
402 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700403 incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
404 incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700405 // handle iface resets - on some device the 3g iface comes and goes and gets
406 // totals reset to 0. Deal with it
407 if ((incRead < 0) || (incWrite < 0)) {
408 incRead += mLastRead;
409 incWrite += mLastWrite;
410 mLastRead = 0;
411 mLastWrite = 0;
412 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700413 } catch (RemoteException e) {
414 Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
415 }
Robert Greenwalt5f996892010-04-08 16:19:24 -0700416 // don't count this data if we're roaming.
417 boolean roaming = "true".equals(
418 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
419 if (!roaming) {
420 mRecorder.addData(incRead, incWrite);
421 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700422
423 long periodRx = mRecorder.getPeriodRx(0);
424 long periodTx = mRecorder.getPeriodTx(0);
425 long total = periodRx + periodTx;
426 if (DBG) {
Robert Greenwalt5f996892010-04-08 16:19:24 -0700427 Slog.d(TAG, "onPollAlarm - now =" + now + ", roaming =" + roaming +
428 ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700429 }
430 mLastRead += incRead;
431 mLastWrite += incWrite;
432
433 checkThrottleAndPostNotification(total);
434
435 Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
436 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
437 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700438 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
439 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700440 mContext.sendStickyBroadcast(broadcast);
441
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700442 mAlarmManager.cancel(mPendingPollIntent);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700443 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, next, mPendingPollIntent);
444 }
445
446 private void checkThrottleAndPostNotification(long currentTotal) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700447 // is throttling enabled?
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700448 if (mPolicyThreshold == 0) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700449 return;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700450 }
451
452 // have we spoken with an ntp server yet?
453 // this is controversial, but we'd rather err towards not throttling
454 if ((mNtpServer != null) && !mNtpActive) {
455 return;
456 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700457
458 // check if we need to throttle
459 if (currentTotal > mPolicyThreshold) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700460 if (mThrottleIndex != 1) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700461 synchronized (ThrottleService.this) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700462 mThrottleIndex = 1;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700463 }
464 if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
465 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700466 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700467 mPolicyThrottleValue, mPolicyThrottleValue);
468 } catch (Exception e) {
469 Slog.e(TAG, "error setting Throttle: " + e);
470 }
471
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700472 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700473
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700474 postNotification(R.string.throttled_notification_title,
475 R.string.throttled_notification_message,
476 R.drawable.stat_sys_throttled,
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700477 Notification.FLAG_ONGOING_EVENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700478
479 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
480 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, mPolicyThrottleValue);
481 mContext.sendStickyBroadcast(broadcast);
482
483 } // else already up!
484 } else {
485 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
486 // check if we should warn about throttle
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700487 // pretend we only have 1/2 the time remaining that we actually do
488 // if our burn rate in the period so far would have us exceed the limit
489 // in that 1/2 window, warn the user.
490 // this gets more generous in the early to middle period and converges back
491 // to the limit as we move toward the period end.
492
493 // adding another factor - it must be greater than the total cap/4
494 // else we may get false alarms very early in the period.. in the first
495 // tenth of a percent of the period if we used more than a tenth of a percent
496 // of the cap we'd get a warning and that's not desired.
497 long start = mRecorder.getPeriodStart();
498 long end = mRecorder.getPeriodEnd();
499 long periodLength = end - start;
500 long now = System.currentTimeMillis();
501 long timeUsed = now - start;
502 long warningThreshold = 2*mPolicyThreshold*timeUsed/(timeUsed+periodLength);
503 if ((currentTotal > warningThreshold) && (currentTotal > mPolicyThreshold/4)) {
504 if (mWarningNotificationSent == false) {
505 mWarningNotificationSent = true;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700506 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
507 postNotification(R.string.throttle_warning_notification_title,
508 R.string.throttle_warning_notification_message,
509 R.drawable.stat_sys_throttled,
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700510 0);
511 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700512 } else {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700513 if (mWarningNotificationSent == true) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700514 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700515 mWarningNotificationSent =false;
516 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700517 }
518 }
519 }
520 }
521
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700522 private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700523 Intent intent = new Intent();
524 // TODO - fix up intent
Robert Greenwalt2a7b7302010-04-12 14:56:31 -0700525 intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700526 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
527
528 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
529
530 Resources r = Resources.getSystem();
531 CharSequence title = r.getText(titleInt);
532 CharSequence message = r.getText(messageInt);
533 if (mThrottlingNotification == null) {
534 mThrottlingNotification = new Notification();
535 mThrottlingNotification.when = 0;
536 // TODO - fixup icon
537 mThrottlingNotification.icon = icon;
538 mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700539 }
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700540 mThrottlingNotification.flags = flags;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700541 mThrottlingNotification.tickerText = title;
542 mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
543
544 mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
545 }
546
547
548 private synchronized void clearThrottleAndNotification() {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700549 if (mThrottleIndex != THROTTLE_INDEX_UNTHROTTLED) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700550 synchronized (ThrottleService.this) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700551 mThrottleIndex = THROTTLE_INDEX_UNTHROTTLED;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700552 }
553 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700554 mNMService.setInterfaceThrottle(mIface, -1, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700555 } catch (Exception e) {
556 Slog.e(TAG, "error clearing Throttle: " + e);
557 }
558 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
559 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
560 mContext.sendStickyBroadcast(broadcast);
561 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700562 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700563 mWarningNotificationSent = false;
564 }
565
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700566 private Calendar calculatePeriodEnd(long now) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700567 Calendar end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700568 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700569 int day = end.get(Calendar.DAY_OF_MONTH);
570 end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
571 end.set(Calendar.HOUR_OF_DAY, 0);
572 end.set(Calendar.MINUTE, 0);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700573 end.set(Calendar.SECOND, 0);
574 end.set(Calendar.MILLISECOND, 0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700575 if (day >= mPolicyResetDay) {
576 int month = end.get(Calendar.MONTH);
577 if (month == Calendar.DECEMBER) {
578 end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
579 month = Calendar.JANUARY - 1;
580 }
581 end.set(Calendar.MONTH, month + 1);
582 }
583
584 // TODO - remove!
585 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
586 end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700587 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700588 end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
589 }
590 return end;
591 }
592 private Calendar calculatePeriodStart(Calendar end) {
593 Calendar start = (Calendar)end.clone();
594 int month = end.get(Calendar.MONTH);
595 if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
596 month = Calendar.DECEMBER + 1;
597 start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
598 }
599 start.set(Calendar.MONTH, month - 1);
600
601 // TODO - remove!!
602 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
603 start = (Calendar)end.clone();
604 start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
605 }
606 return start;
607 }
608
609 private void onResetAlarm() {
610 if (DBG) {
611 Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
612 " bytes read and " + mRecorder.getPeriodTx(0) + " written");
613 }
614
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700615 long now = getBestTime();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700616
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700617 if (mNtpActive || (mNtpServer == null)) {
618 Calendar end = calculatePeriodEnd(now);
619 Calendar start = calculatePeriodStart(end);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700620
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700621 if (mRecorder.setNextPeriod(start, end)) {
622 clearThrottleAndNotification();
Robert Greenwalt05d06732010-04-19 11:10:38 -0700623 onPollAlarm();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700624 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700625
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700626 mAlarmManager.cancel(mPendingResetIntent);
627 long offset = end.getTimeInMillis() - now;
628 // use Elapsed realtime so clock changes don't fool us.
629 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
630 SystemClock.elapsedRealtime() + offset,
631 mPendingResetIntent);
632 } else {
633 if (DBG) Slog.d(TAG, "no authoritative time - not resetting period");
634 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700635 }
636 }
637
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700638 private void checkForAuthoritativeTime() {
639 if (mNtpActive || (mNtpServer == null)) return;
640
Robert Greenwalt05d06732010-04-19 11:10:38 -0700641 // will try to get the ntp time and switch to it if found.
642 // will also cache the time so we don't fetch it repeatedly.
643 getBestTime();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700644 }
645
Robert Greenwalt05d06732010-04-19 11:10:38 -0700646 private static final int MAX_NTP_CACHE_AGE = 30 * 1000;
647 private static final int MAX_NTP_FETCH_WAIT = 10 * 1000;
648 private long cachedNtp;
649 private long cachedNtpTimestamp;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700650
Robert Greenwalt05d06732010-04-19 11:10:38 -0700651 private long getBestTime() {
652 if (mNtpServer != null) {
653 if (mNtpActive) {
654 long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
655 if (ntpAge < MAX_NTP_CACHE_AGE) {
656 return cachedNtp + ntpAge;
657 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700658 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700659 SntpClient client = new SntpClient();
660 if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT)) {
661 cachedNtp = client.getNtpTime();
662 cachedNtpTimestamp = SystemClock.elapsedRealtime();
663 if (!mNtpActive) {
664 mNtpActive = true;
665 if (DBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
666 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
667 }
668 if (DBG) Slog.d(TAG, "using Authoritative time: " + cachedNtp);
669 return cachedNtp;
670 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700671 }
Robert Greenwalt05d06732010-04-19 11:10:38 -0700672 long time = System.currentTimeMillis();
673 if (DBG) Slog.d(TAG, "using User time: " + time);
674 mNtpActive = false;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700675 return time;
676 }
677
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700678 // records bytecount data for a given time and accumulates it into larger time windows
679 // for logging and other purposes
680 //
681 // since time can be changed (user or network action) we will have to track the time of the
682 // last recording and deal with it.
683 private static class DataRecorder {
684 long[] mPeriodRxData;
685 long[] mPeriodTxData;
686 int mCurrentPeriod;
687 int mPeriodCount;
688
689 Calendar mPeriodStart;
690 Calendar mPeriodEnd;
691
692 ThrottleService mParent;
693 Context mContext;
Robert Greenwalte6e98822010-04-15 08:27:14 -0700694 String mImsi = null;
695
696 TelephonyManager mTelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700697
698 DataRecorder(Context context, ThrottleService parent) {
699 mContext = context;
700 mParent = parent;
701
Robert Greenwalte6e98822010-04-15 08:27:14 -0700702 mTelephonyManager = (TelephonyManager)mContext.getSystemService(
703 Context.TELEPHONY_SERVICE);
704
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700705 synchronized (mParent) {
706 mPeriodCount = 6;
707 mPeriodRxData = new long[mPeriodCount];
708 mPeriodTxData = new long[mPeriodCount];
709
710 mPeriodStart = Calendar.getInstance();
711 mPeriodEnd = Calendar.getInstance();
712
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700713 retrieve();
714 }
715 }
716
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700717 boolean setNextPeriod(Calendar start, Calendar end) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700718 // TODO - how would we deal with a dual-IMSI device?
719 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700720 boolean startNewPeriod = true;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700721 if (DBG) {
722 Slog.d(TAG, "setting next period to " + start.getTimeInMillis() +
723 " --until-- " + end.getTimeInMillis());
724 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700725 // if we rolled back in time, toss out
726 // if we rolled foward, advance to the next
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700727 if (end.before(mPeriodStart)) {
728 if (DBG) {
729 Slog.d(TAG, " old start was " + mPeriodStart.getTimeInMillis() + ", wiping");
730 }
731 synchronized (mParent) {
732 mPeriodRxData[mCurrentPeriod] = 0;
733 mPeriodTxData[mCurrentPeriod] = 0;
734 }
735 } else if(start.after(mPeriodEnd)) {
736 if (DBG) {
737 Slog.d(TAG, " old end was " + mPeriodEnd.getTimeInMillis() + ", following");
738 }
739 synchronized (mParent) {
740 ++mCurrentPeriod;
741 if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
742 mPeriodRxData[mCurrentPeriod] = 0;
743 mPeriodTxData[mCurrentPeriod] = 0;
744 }
745 } else {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700746 startNewPeriod = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700747 if (DBG) Slog.d(TAG, " we fit - ammending to last period");
748 }
749 setPeriodStart(start);
750 setPeriodEnd(end);
751 record();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700752 return startNewPeriod;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700753 }
754
755 public long getPeriodEnd() {
756 synchronized (mParent) {
757 return mPeriodEnd.getTimeInMillis();
758 }
759 }
760
761 private void setPeriodEnd(Calendar end) {
762 synchronized (mParent) {
763 mPeriodEnd = end;
764 }
765 }
766
767 public long getPeriodStart() {
768 synchronized (mParent) {
769 return mPeriodStart.getTimeInMillis();
770 }
771 }
772
773 private void setPeriodStart(Calendar start) {
774 synchronized (mParent) {
775 mPeriodStart = start;
776 }
777 }
778
779 public int getPeriodCount() {
780 synchronized (mParent) {
781 return mPeriodCount;
782 }
783 }
784
785 private void zeroData(int field) {
786 synchronized (mParent) {
787 for(int period = 0; period<mPeriodCount; period++) {
788 mPeriodRxData[period] = 0;
789 mPeriodTxData[period] = 0;
790 }
791 mCurrentPeriod = 0;
792 }
793
794 }
795
796 // if time moves backward accumulate all read/write that's lost into the now
797 // otherwise time moved forward.
798 void addData(long bytesRead, long bytesWritten) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700799 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700800
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700801 synchronized (mParent) {
802 mPeriodRxData[mCurrentPeriod] += bytesRead;
803 mPeriodTxData[mCurrentPeriod] += bytesWritten;
804 }
805 record();
806 }
807
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700808 private File getDataFile() {
809 File dataDir = Environment.getDataDirectory();
810 File throttleDir = new File(dataDir, "system/throttle");
811 throttleDir.mkdirs();
Robert Greenwalte6e98822010-04-15 08:27:14 -0700812 String mImsi = mTelephonyManager.getSubscriberId();
813 File dataFile;
814 if (mImsi == null) {
815 dataFile = useMRUFile(throttleDir);
816 Slog.d(TAG, "imsi not available yet, using " + dataFile);
817 } else {
818 String imsiHash = Integer.toString(mImsi.hashCode());
819 dataFile = new File(throttleDir, imsiHash);
820 }
821 // touch the file so it's not LRU
822 dataFile.setLastModified(System.currentTimeMillis());
823 checkAndDeleteLRUDataFile(throttleDir);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700824 return dataFile;
825 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700826
Robert Greenwalte6e98822010-04-15 08:27:14 -0700827 // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
828 private void checkForSubscriberId() {
829 if (mImsi != null) return;
830
831 mImsi = mTelephonyManager.getSubscriberId();
832 if (mImsi == null) return;
833
834 Slog.d(TAG, "finally have imsi - retreiving data");
835 retrieve();
836 }
837
838 private final static int MAX_SIMS_SUPPORTED = 3;
839
840 private void checkAndDeleteLRUDataFile(File dir) {
841 File[] files = dir.listFiles();
842
843 if (files.length <= MAX_SIMS_SUPPORTED) return;
844 Slog.d(TAG, "Too many data files");
845 do {
846 File oldest = null;
847 for (File f : files) {
848 if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
849 oldest = f;
850 }
851 }
852 if (oldest == null) return;
853 Slog.d(TAG, " deleting " + oldest);
854 oldest.delete();
855 files = dir.listFiles();
856 } while (files.length > MAX_SIMS_SUPPORTED);
857 }
858
859 private File useMRUFile(File dir) {
860 File newest = null;
861 File[] files = dir.listFiles();
862
863 for (File f : files) {
864 if ((newest == null) || (newest.lastModified() < f.lastModified())) {
865 newest = f;
866 }
867 }
868 if (newest == null) {
869 newest = new File(dir, "temp");
870 }
871 return newest;
872 }
873
874
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700875 private static final int DATA_FILE_VERSION = 1;
876
877 private void record() {
878 // 1 int version
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700879 // 1 int mPeriodCount
880 // 13*6 long[PERIOD_COUNT] mPeriodRxData
881 // 13*6 long[PERIOD_COUNT] mPeriodTxData
882 // 1 int mCurrentPeriod
883 // 13 long periodStartMS
884 // 13 long periodEndMS
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700885 // 200 chars max
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700886 StringBuilder builder = new StringBuilder();
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700887 builder.append(DATA_FILE_VERSION);
888 builder.append(":");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700889 builder.append(mPeriodCount);
890 builder.append(":");
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700891 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700892 builder.append(mPeriodRxData[i]);
893 builder.append(":");
894 }
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700895 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700896 builder.append(mPeriodTxData[i]);
897 builder.append(":");
898 }
899 builder.append(mCurrentPeriod);
900 builder.append(":");
901 builder.append(mPeriodStart.getTimeInMillis());
902 builder.append(":");
903 builder.append(mPeriodEnd.getTimeInMillis());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700904
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700905 BufferedWriter out = null;
906 try {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700907 out = new BufferedWriter(new FileWriter(getDataFile()), 256);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700908 out.write(builder.toString());
909 } catch (IOException e) {
910 Slog.e(TAG, "Error writing data file");
911 return;
912 } finally {
913 if (out != null) {
914 try {
915 out.close();
916 } catch (Exception e) {}
917 }
918 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700919 }
920
921 private void retrieve() {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700922 // clean out any old data first. If we fail to read we don't want old stuff
923 zeroData(0);
924
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700925 File f = getDataFile();
926 byte[] buffer;
927 FileInputStream s = null;
928 try {
929 buffer = new byte[(int)f.length()];
930 s = new FileInputStream(f);
931 s.read(buffer);
932 } catch (IOException e) {
933 Slog.e(TAG, "Error reading data file");
934 return;
935 } finally {
936 if (s != null) {
937 try {
938 s.close();
939 } catch (Exception e) {}
940 }
941 }
942 String data = new String(buffer);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700943 if (data == null || data.length() == 0) {
944 if (DBG) Slog.d(TAG, "data file empty");
945 return;
946 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700947 synchronized (mParent) {
948 String[] parsed = data.split(":");
949 int parsedUsed = 0;
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700950 if (parsed.length < 6) {
951 Slog.e(TAG, "reading data file with insufficient length - ignoring");
952 return;
953 }
954
955 if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
956 Slog.e(TAG, "reading data file with bad version - ignoring");
957 return;
958 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700959
960 mPeriodCount = Integer.parseInt(parsed[parsedUsed++]);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700961 if (parsed.length != 5 + (2 * mPeriodCount)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700962 Slog.e(TAG, "reading data file with bad length ("+parsed.length+" != "+(5 + (2*mPeriodCount))+") - ignoring");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700963 return;
964 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700965
966 mPeriodRxData = new long[mPeriodCount];
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700967 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700968 mPeriodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
969 }
970 mPeriodTxData = new long[mPeriodCount];
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700971 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700972 mPeriodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
973 }
974 mCurrentPeriod = Integer.parseInt(parsed[parsedUsed++]);
975 mPeriodStart = new GregorianCalendar();
976 mPeriodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
977 mPeriodEnd = new GregorianCalendar();
978 mPeriodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
979 }
980 }
981
982 long getPeriodRx(int which) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700983 synchronized (mParent) {
984 if (which > mPeriodCount) return 0;
985 which = mCurrentPeriod - which;
986 if (which < 0) which += mPeriodCount;
987 return mPeriodRxData[which];
988 }
989 }
990 long getPeriodTx(int which) {
991 synchronized (mParent) {
992 if (which > mPeriodCount) return 0;
993 which = mCurrentPeriod - which;
994 if (which < 0) which += mPeriodCount;
995 return mPeriodTxData[which];
996 }
997 }
998 }
999
1000 @Override
1001 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1002 if (mContext.checkCallingOrSelfPermission(
1003 android.Manifest.permission.DUMP)
1004 != PackageManager.PERMISSION_GRANTED) {
1005 pw.println("Permission Denial: can't dump ThrottleService " +
1006 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1007 Binder.getCallingUid());
1008 return;
1009 }
1010 pw.println();
1011
1012 pw.println("The threshold is " + mPolicyThreshold +
1013 ", after which you experince throttling to " +
1014 mPolicyThrottleValue + "kbps");
1015 pw.println("Current period is " +
1016 (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001017 "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001018 " seconds.");
1019 pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
Robert Greenwalt8c7e6092010-04-14 17:31:20 -07001020 pw.println("Current Throttle Index is " + mThrottleIndex);
1021
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001022 for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
1023 pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
1024 mRecorder.getPeriodTx(i));
1025 }
1026 }
1027}