blob: 8658f3d6347fc3c40eb8b29fc76a8a87c9c28cee [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
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070019import com.android.internal.R;
20import com.android.internal.telephony.TelephonyProperties;
21
Robert Greenwalt9e696c22010-04-01 14:45:18 -070022import android.app.AlarmManager;
23import android.app.Notification;
24import android.app.NotificationManager;
25import android.app.PendingIntent;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070026import android.content.BroadcastReceiver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -070027import android.content.ContentResolver;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070028import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.pm.PackageManager;
32import android.content.res.Resources;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -070033import android.database.ContentObserver;
Robert Greenwaltfee46832010-05-06 12:25:13 -070034import android.net.INetworkManagementEventObserver;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070035import android.net.IThrottleManager;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070036import android.net.NetworkStats;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070037import android.net.ThrottleManager;
38import android.os.Binder;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070039import android.os.Environment;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070040import android.os.Handler;
41import android.os.HandlerThread;
42import android.os.IBinder;
43import android.os.INetworkManagementService;
44import android.os.Looper;
45import android.os.Message;
46import android.os.RemoteException;
47import android.os.ServiceManager;
48import android.os.SystemClock;
49import android.os.SystemProperties;
50import android.provider.Settings;
Robert Greenwalte6e98822010-04-15 08:27:14 -070051import android.telephony.TelephonyManager;
Robert Greenwaltfee46832010-05-06 12:25:13 -070052import android.text.TextUtils;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070053import android.util.NtpTrustedTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070054import android.util.Slog;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070055import android.util.TrustedTime;
Robert Greenwalt5f996892010-04-08 16:19:24 -070056
Robert Greenwaltb8912f52010-04-09 17:27:26 -070057import java.io.BufferedWriter;
58import java.io.File;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070059import java.io.FileDescriptor;
Robert Greenwaltb8912f52010-04-09 17:27:26 -070060import java.io.FileInputStream;
61import java.io.FileWriter;
62import java.io.IOException;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070063import java.io.PrintWriter;
64import java.util.Calendar;
65import 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;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070068import java.util.concurrent.atomic.AtomicInteger;
69import java.util.concurrent.atomic.AtomicLong;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070070
71// TODO - add comments - reference the ThrottleManager for public API
72public class ThrottleService extends IThrottleManager.Stub {
73
74 private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
75
76 private static final String TAG = "ThrottleService";
Robert Greenwaltbf7de392010-04-21 17:09:38 -070077 private static final boolean DBG = true;
78 private static final boolean VDBG = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070079 private Handler mHandler;
80 private HandlerThread mThread;
81
82 private Context mContext;
83
Robert Greenwaltfb9896b2010-04-22 15:39:38 -070084 private static final int INITIAL_POLL_DELAY_SEC = 90;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070085 private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
Robert Greenwalt7171ea82010-04-14 22:37:12 -070086 private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070087 private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070088
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070089 private static final long MAX_NTP_CACHE_AGE = 24 * 60 * 60 * 1000;
90 private static final long MAX_NTP_FETCH_WAIT = 20 * 1000;
91
92 private long mMaxNtpCacheAge = MAX_NTP_CACHE_AGE;
93
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070094 private int mPolicyPollPeriodSec;
Robert Greenwalt39e163f2010-05-07 16:52:17 -070095 private AtomicLong mPolicyThreshold;
96 private AtomicInteger mPolicyThrottleValue;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070097 private int mPolicyResetDay; // 1-28
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -070098 private int mPolicyNotificationsAllowedMask;
Robert Greenwalt9e696c22010-04-01 14:45:18 -070099
100 private long mLastRead; // read byte count from last poll
101 private long mLastWrite; // write byte count from last poll
102
103 private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
104 private static int POLL_REQUEST = 0;
105 private PendingIntent mPendingPollIntent;
106 private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
107 private static int RESET_REQUEST = 1;
108 private PendingIntent mPendingResetIntent;
109
110 private INetworkManagementService mNMService;
111 private AlarmManager mAlarmManager;
112 private NotificationManager mNotificationManager;
113
114 private DataRecorder mRecorder;
115
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700116 private String mIface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700117
118 private static final int NOTIFICATION_WARNING = 2;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700119
120 private Notification mThrottlingNotification;
121 private boolean mWarningNotificationSent = false;
122
Robert Greenwaltfee46832010-05-06 12:25:13 -0700123 private InterfaceObserver mInterfaceObserver;
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700124 private SettingsObserver mSettingsObserver;
125
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700126 private AtomicInteger mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700127 private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
128 private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
129
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700130 private static final String PROPERTIES_FILE = "/etc/gps.conf";
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700131
132 private Intent mPollStickyBroadcast;
133
134 private TrustedTime mTime;
135
136 private static INetworkManagementService getNetworkManagementService() {
137 final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
138 return INetworkManagementService.Stub.asInterface(b);
139 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700140
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700141 public ThrottleService(Context context) {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700142 // TODO: move to using cached NtpTrustedTime
143 this(context, getNetworkManagementService(), new NtpTrustedTime(),
144 context.getResources().getString(R.string.config_datause_iface));
145 }
146
147 public ThrottleService(Context context, INetworkManagementService nmService, TrustedTime time,
148 String iface) {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700149 if (VDBG) Slog.v(TAG, "Starting ThrottleService");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700150 mContext = context;
151
Robert Greenwalt24488bd2010-05-10 16:56:43 -0700152 mPolicyThreshold = new AtomicLong();
153 mPolicyThrottleValue = new AtomicInteger();
154 mThrottleIndex = new AtomicInteger();
155
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700156 mIface = iface;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700157 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
158 Intent pollIntent = new Intent(ACTION_POLL, null);
159 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
160 Intent resetIntent = new Intent(ACTION_RESET, null);
161 mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
162
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700163 mNMService = nmService;
164 mTime = time;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700165
166 mNotificationManager = (NotificationManager)mContext.getSystemService(
167 Context.NOTIFICATION_SERVICE);
168 }
169
Robert Greenwaltfee46832010-05-06 12:25:13 -0700170 private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
171 private int mMsg;
172 private Handler mHandler;
173 private String mIface;
174
175 InterfaceObserver(Handler handler, int msg, String iface) {
176 super();
177 mHandler = handler;
178 mMsg = msg;
179 mIface = iface;
180 }
181
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700182 public void interfaceStatusChanged(String iface, boolean link) {
Robert Greenwaltfee46832010-05-06 12:25:13 -0700183 if (link) {
184 if (TextUtils.equals(iface, mIface)) {
185 mHandler.obtainMessage(mMsg).sendToTarget();
186 }
187 }
188 }
189
190 public void interfaceAdded(String iface) {
191 // TODO - an interface added in the UP state should also trigger a StatusChanged
192 // notification..
193 if (TextUtils.equals(iface, mIface)) {
194 mHandler.obtainMessage(mMsg).sendToTarget();
195 }
196 }
197
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700198 public void interfaceLinkStateChanged(String iface, boolean linkState) {}
199
Robert Greenwaltfee46832010-05-06 12:25:13 -0700200 public void interfaceRemoved(String iface) {}
201 }
202
203
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700204 private static class SettingsObserver extends ContentObserver {
205 private int mMsg;
206 private Handler mHandler;
207 SettingsObserver(Handler handler, int msg) {
208 super(handler);
209 mHandler = handler;
210 mMsg = msg;
211 }
212
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700213 void register(Context context) {
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700214 ContentResolver resolver = context.getContentResolver();
215 resolver.registerContentObserver(Settings.Secure.getUriFor(
216 Settings.Secure.THROTTLE_POLLING_SEC), false, this);
217 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700218 Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700219 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700220 Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700221 resolver.registerContentObserver(Settings.Secure.getUriFor(
222 Settings.Secure.THROTTLE_RESET_DAY), false, this);
223 resolver.registerContentObserver(Settings.Secure.getUriFor(
224 Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
225 resolver.registerContentObserver(Settings.Secure.getUriFor(
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700226 Settings.Secure.THROTTLE_HELP_URI), false, this);
Robert Greenwaltd1055a22010-05-25 15:54:52 -0700227 resolver.registerContentObserver(Settings.Secure.getUriFor(
228 Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC), false, this);
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700229 }
230
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700231 void unregister(Context context) {
232 final ContentResolver resolver = context.getContentResolver();
233 resolver.unregisterContentObserver(this);
234 }
235
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700236 @Override
237 public void onChange(boolean selfChange) {
238 mHandler.obtainMessage(mMsg).sendToTarget();
239 }
240 }
241
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700242 private void enforceAccessPermission() {
243 mContext.enforceCallingOrSelfPermission(
244 android.Manifest.permission.ACCESS_NETWORK_STATE,
245 "ThrottleService");
246 }
247
Robert Greenwalt05d06732010-04-19 11:10:38 -0700248 private long ntpToWallTime(long ntpTime) {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700249 // get time quickly without worrying about trusted state
250 long bestNow = mTime.hasCache() ? mTime.currentTimeMillis()
251 : System.currentTimeMillis();
Robert Greenwalt05d06732010-04-19 11:10:38 -0700252 long localNow = System.currentTimeMillis();
253 return localNow + (ntpTime - bestNow);
254 }
255
Irfan Sheriffcf282362010-04-16 16:53:20 -0700256 // TODO - fetch for the iface
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700257 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt05d06732010-04-19 11:10:38 -0700258
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700259 public long getResetTime(String iface) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700260 enforceAccessPermission();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700261 long resetTime = 0;
Irfan Sheriffcf282362010-04-16 16:53:20 -0700262 if (mRecorder != null) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700263 resetTime = mRecorder.getPeriodEnd();
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700264 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700265 resetTime = ntpToWallTime(resetTime);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700266 return resetTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700267 }
Irfan Sheriffcf282362010-04-16 16:53:20 -0700268
269 // TODO - fetch for the iface
Robert Greenwalt05d06732010-04-19 11:10:38 -0700270 // return time in the local, system wall time, correcting for the use of ntp
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700271 public long getPeriodStartTime(String iface) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700272 long startTime = 0;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700273 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700274 if (mRecorder != null) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700275 startTime = mRecorder.getPeriodStart();
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700276 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700277 startTime = ntpToWallTime(startTime);
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700278 return startTime;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700279 }
280 //TODO - a better name? getCliffByteCountThreshold?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700281 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700282 public long getCliffThreshold(String iface, int cliff) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700283 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700284 if (cliff == 1) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700285 return mPolicyThreshold.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700286 }
287 return 0;
288 }
289 // TODO - a better name? getThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700290 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700291 public int getCliffLevel(String iface, int cliff) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700292 enforceAccessPermission();
Irfan Sheriffcf282362010-04-16 16:53:20 -0700293 if (cliff == 1) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700294 return mPolicyThrottleValue.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700295 }
296 return 0;
297 }
298
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700299 public String getHelpUri() {
300 enforceAccessPermission();
301 return Settings.Secure.getString(mContext.getContentResolver(),
302 Settings.Secure.THROTTLE_HELP_URI);
303 }
304
Irfan Sheriffcf282362010-04-16 16:53:20 -0700305 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700306 public long getByteCount(String iface, int dir, int period, int ago) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700307 enforceAccessPermission();
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700308 if ((period == ThrottleManager.PERIOD_CYCLE) && (mRecorder != null)) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700309 if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
310 if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
311 }
312 return 0;
313 }
314
315 // TODO - a better name - getCurrentThrottleRate?
Irfan Sheriffcf282362010-04-16 16:53:20 -0700316 // TODO - fetch for the iface
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700317 public int getThrottle(String iface) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700318 enforceAccessPermission();
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700319 if (mThrottleIndex.get() == 1) {
320 return mPolicyThrottleValue.get();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700321 }
322 return 0;
323 }
324
325 void systemReady() {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700326 if (VDBG) Slog.v(TAG, "systemReady");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700327 mContext.registerReceiver(
328 new BroadcastReceiver() {
329 @Override
330 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700331 dispatchPoll();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700332 }
333 }, new IntentFilter(ACTION_POLL));
334
335 mContext.registerReceiver(
336 new BroadcastReceiver() {
337 @Override
338 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700339 dispatchReset();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700340 }
341 }, new IntentFilter(ACTION_RESET));
342
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700343 FileInputStream stream = null;
344 try {
345 Properties properties = new Properties();
346 File file = new File(PROPERTIES_FILE);
347 stream = new FileInputStream(file);
348 properties.load(stream);
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700349 final String ntpServer = properties.getProperty("NTP_SERVER", null);
350 if (mTime instanceof NtpTrustedTime) {
351 ((NtpTrustedTime) mTime).setNtpServer(ntpServer, MAX_NTP_FETCH_WAIT);
352 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700353 } catch (IOException e) {
354 Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
355 } finally {
356 if (stream != null) {
357 try {
358 stream.close();
359 } catch (Exception e) {}
360 }
361 }
Robert Greenwaltc76c15e2010-06-16 14:42:16 -0700362
363 // use a new thread as we don't want to stall the system for file writes
364 mThread = new HandlerThread(TAG);
365 mThread.start();
366 mHandler = new MyHandler(mThread.getLooper());
367 mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
368
369 mInterfaceObserver = new InterfaceObserver(mHandler, EVENT_IFACE_UP, mIface);
370 try {
371 mNMService.registerObserver(mInterfaceObserver);
372 } catch (RemoteException e) {
373 Slog.e(TAG, "Could not register InterfaceObserver " + e);
374 }
375
376 mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700377 mSettingsObserver.register(mContext);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700378 }
379
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700380 void shutdown() {
381 // TODO: eventually connect with ShutdownThread to persist stats during
382 // graceful shutdown.
383
384 if (mThread != null) {
385 mThread.quit();
386 }
387
388 if (mSettingsObserver != null) {
389 mSettingsObserver.unregister(mContext);
390 }
391
392 if (mPollStickyBroadcast != null) {
393 mContext.removeStickyBroadcast(mPollStickyBroadcast);
394 }
395 }
396
397 void dispatchPoll() {
398 mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
399 }
400
401 void dispatchReset() {
402 mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
403 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700404
405 private static final int EVENT_REBOOT_RECOVERY = 0;
406 private static final int EVENT_POLICY_CHANGED = 1;
407 private static final int EVENT_POLL_ALARM = 2;
408 private static final int EVENT_RESET_ALARM = 3;
Robert Greenwaltfee46832010-05-06 12:25:13 -0700409 private static final int EVENT_IFACE_UP = 4;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700410 private class MyHandler extends Handler {
411 public MyHandler(Looper l) {
412 super(l);
413 }
414
415 @Override
416 public void handleMessage(Message msg) {
417 switch (msg.what) {
418 case EVENT_REBOOT_RECOVERY:
419 onRebootRecovery();
420 break;
421 case EVENT_POLICY_CHANGED:
422 onPolicyChanged();
423 break;
424 case EVENT_POLL_ALARM:
425 onPollAlarm();
426 break;
427 case EVENT_RESET_ALARM:
428 onResetAlarm();
Robert Greenwaltfee46832010-05-06 12:25:13 -0700429 break;
430 case EVENT_IFACE_UP:
431 onIfaceUp();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700432 }
433 }
434
435 private void onRebootRecovery() {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700436 if (VDBG) Slog.v(TAG, "onRebootRecovery");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700437 // check for sim change TODO
438 // reregister for notification of policy change
439
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700440 mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700441
442 mRecorder = new DataRecorder(mContext, ThrottleService.this);
443
444 // get policy
445 mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
Robert Greenwaltfb9896b2010-04-22 15:39:38 -0700446
447 // if we poll now we won't have network connectivity or even imsi access
448 // queue up a poll to happen in a little while - after ntp and imsi are avail
449 // TODO - make this callback based (ie, listen for notificaitons)
450 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_POLL_ALARM),
451 INITIAL_POLL_DELAY_SEC * 1000);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700452 }
453
454 // check for new policy info (threshold limit/value/etc)
455 private void onPolicyChanged() {
456 boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
457
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700458 int pollingPeriod = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700459 R.integer.config_datause_polling_period_sec);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700460 mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
461 Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
462
463 // TODO - remove testing stuff?
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700464 long defaultThreshold = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700465 R.integer.config_datause_threshold_bytes);
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700466 int defaultValue = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700467 R.integer.config_datause_throttle_kbitsps);
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700468 long threshold = Settings.Secure.getLong(mContext.getContentResolver(),
469 Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
470 int value = Settings.Secure.getInt(mContext.getContentResolver(),
471 Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
472
473 mPolicyThreshold.set(threshold);
474 mPolicyThrottleValue.set(value);
475 if (testing) {
476 mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
477 mPolicyThreshold.set(TESTING_THRESHOLD);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700478 }
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700479
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700480 mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
481 Settings.Secure.THROTTLE_RESET_DAY, -1);
482 if (mPolicyResetDay == -1 ||
483 ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
484 Random g = new Random();
485 mPolicyResetDay = 1 + g.nextInt(28); // 1-28
486 Settings.Secure.putInt(mContext.getContentResolver(),
487 Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
488 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700489 if (mIface == null) {
490 mPolicyThreshold.set(0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700491 }
492
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700493 int defaultNotificationType = mContext.getResources().getInteger(
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700494 R.integer.config_datause_notification_type);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700495 mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700496 Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700497
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700498 final int maxNtpCacheAgeSec = Settings.Secure.getInt(mContext.getContentResolver(),
499 Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC,
500 (int) (MAX_NTP_CACHE_AGE / 1000));
501 mMaxNtpCacheAge = maxNtpCacheAgeSec * 1000;
Robert Greenwaltd1055a22010-05-25 15:54:52 -0700502
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700503 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700504 Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" +
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700505 mPolicyPollPeriodSec + ", threshold=" + mPolicyThreshold.get() +
506 ", value=" + mPolicyThrottleValue.get() + ", resetDay=" + mPolicyResetDay +
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700507 ", noteType=" + mPolicyNotificationsAllowedMask + ", mMaxNtpCacheAge=" +
508 mMaxNtpCacheAge);
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700509 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700510
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700511 // force updates
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700512 mThrottleIndex.set(THROTTLE_INDEX_UNINITIALIZED);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700513
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700514 onResetAlarm();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700515
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700516 onPollAlarm();
517
Robert Greenwalt81aa0971d2010-04-09 09:36:09 -0700518 Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
519 mContext.sendBroadcast(broadcast);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700520 }
521
522 private void onPollAlarm() {
523 long now = SystemClock.elapsedRealtime();
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700524 long next = now + mPolicyPollPeriodSec * 1000;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700525
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700526 // when trusted cache outdated, try refreshing
527 if (mTime.getCacheAge() > mMaxNtpCacheAge) {
528 if (mTime.forceRefresh()) {
529 if (VDBG) Slog.d(TAG, "updated trusted time, reseting alarm");
530 dispatchReset();
531 }
532 }
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700533
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700534 long incRead = 0;
535 long incWrite = 0;
536 try {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700537 final NetworkStats stats = mNMService.getNetworkStatsSummary();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700538 final int index = stats.findIndex(
539 mIface, NetworkStats.UID_ALL, NetworkStats.TAG_NONE);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700540
541 if (index != -1) {
542 incRead = stats.rx[index] - mLastRead;
543 incWrite = stats.tx[index] - mLastWrite;
544 } else {
545 // missing iface, assume stats are 0
546 Slog.w(TAG, "unable to find stats for iface " + mIface);
547 }
548
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700549 // handle iface resets - on some device the 3g iface comes and goes and gets
550 // totals reset to 0. Deal with it
551 if ((incRead < 0) || (incWrite < 0)) {
552 incRead += mLastRead;
553 incWrite += mLastWrite;
554 mLastRead = 0;
555 mLastWrite = 0;
556 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700557 } catch (RemoteException e) {
558 Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
559 }
Robert Greenwalt5f996892010-04-08 16:19:24 -0700560 // don't count this data if we're roaming.
561 boolean roaming = "true".equals(
562 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
563 if (!roaming) {
564 mRecorder.addData(incRead, incWrite);
565 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700566
567 long periodRx = mRecorder.getPeriodRx(0);
568 long periodTx = mRecorder.getPeriodTx(0);
569 long total = periodRx + periodTx;
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700570 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700571 Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
Robert Greenwalt5f996892010-04-08 16:19:24 -0700572 ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700573 }
574 mLastRead += incRead;
575 mLastWrite += incWrite;
576
577 checkThrottleAndPostNotification(total);
578
579 Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
580 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
581 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
Robert Greenwalt05d06732010-04-19 11:10:38 -0700582 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
583 broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700584 mContext.sendStickyBroadcast(broadcast);
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700585 mPollStickyBroadcast = broadcast;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700586
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700587 mAlarmManager.cancel(mPendingPollIntent);
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700588 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700589 }
590
Robert Greenwaltfee46832010-05-06 12:25:13 -0700591 private void onIfaceUp() {
592 // if we were throttled before, be sure and set it again - the iface went down
593 // (and may have disappeared all together) and these settings were lost
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700594 if (mThrottleIndex.get() == 1) {
Robert Greenwaltfee46832010-05-06 12:25:13 -0700595 try {
596 mNMService.setInterfaceThrottle(mIface, -1, -1);
597 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700598 mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
Robert Greenwaltfee46832010-05-06 12:25:13 -0700599 } catch (Exception e) {
600 Slog.e(TAG, "error setting Throttle: " + e);
601 }
602 }
603 }
604
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700605 private void checkThrottleAndPostNotification(long currentTotal) {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700606 // is throttling enabled?
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700607 long threshold = mPolicyThreshold.get();
608 if (threshold == 0) {
Robert Greenwaltcce83372010-04-23 17:35:29 -0700609 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700610 return;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700611 }
612
613 // have we spoken with an ntp server yet?
614 // this is controversial, but we'd rather err towards not throttling
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700615 if (!mTime.hasCache()) {
616 Slog.w(TAG, "missing trusted time, skipping throttle check");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700617 return;
618 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700619
620 // check if we need to throttle
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700621 if (currentTotal > threshold) {
622 if (mThrottleIndex.get() != 1) {
623 mThrottleIndex.set(1);
624 if (DBG) Slog.d(TAG, "Threshold " + threshold + " exceeded!");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700625 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700626 mNMService.setInterfaceThrottle(mIface,
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700627 mPolicyThrottleValue.get(), mPolicyThrottleValue.get());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700628 } catch (Exception e) {
629 Slog.e(TAG, "error setting Throttle: " + e);
630 }
631
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700632 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700633
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700634 postNotification(R.string.throttled_notification_title,
635 R.string.throttled_notification_message,
636 R.drawable.stat_sys_throttled,
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700637 Notification.FLAG_ONGOING_EVENT);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700638
639 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700640 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL,
641 mPolicyThrottleValue.get());
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700642 mContext.sendStickyBroadcast(broadcast);
643
644 } // else already up!
645 } else {
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700646 clearThrottleAndNotification();
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700647 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
648 // check if we should warn about throttle
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700649 // pretend we only have 1/2 the time remaining that we actually do
650 // if our burn rate in the period so far would have us exceed the limit
651 // in that 1/2 window, warn the user.
652 // this gets more generous in the early to middle period and converges back
653 // to the limit as we move toward the period end.
654
655 // adding another factor - it must be greater than the total cap/4
656 // else we may get false alarms very early in the period.. in the first
657 // tenth of a percent of the period if we used more than a tenth of a percent
658 // of the cap we'd get a warning and that's not desired.
659 long start = mRecorder.getPeriodStart();
660 long end = mRecorder.getPeriodEnd();
661 long periodLength = end - start;
662 long now = System.currentTimeMillis();
663 long timeUsed = now - start;
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700664 long warningThreshold = 2*threshold*timeUsed/(timeUsed+periodLength);
665 if ((currentTotal > warningThreshold) && (currentTotal > threshold/4)) {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700666 if (mWarningNotificationSent == false) {
667 mWarningNotificationSent = true;
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700668 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
669 postNotification(R.string.throttle_warning_notification_title,
670 R.string.throttle_warning_notification_message,
671 R.drawable.stat_sys_throttled,
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700672 0);
673 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700674 } else {
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700675 if (mWarningNotificationSent == true) {
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700676 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
Robert Greenwalte2c0ce02010-04-09 12:31:46 -0700677 mWarningNotificationSent =false;
678 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700679 }
680 }
681 }
682 }
683
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700684 private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700685 Intent intent = new Intent();
686 // TODO - fix up intent
Robert Greenwalt2a7b7302010-04-12 14:56:31 -0700687 intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700688 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
689
690 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
691
692 Resources r = Resources.getSystem();
693 CharSequence title = r.getText(titleInt);
694 CharSequence message = r.getText(messageInt);
695 if (mThrottlingNotification == null) {
696 mThrottlingNotification = new Notification();
697 mThrottlingNotification.when = 0;
698 // TODO - fixup icon
699 mThrottlingNotification.icon = icon;
700 mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700701 }
Robert Greenwaltc87dc6d2010-04-08 16:00:26 -0700702 mThrottlingNotification.flags = flags;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700703 mThrottlingNotification.tickerText = title;
704 mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
705
706 mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
707 }
708
709
Robert Greenwalt39e163f2010-05-07 16:52:17 -0700710 private void clearThrottleAndNotification() {
711 if (mThrottleIndex.get() != THROTTLE_INDEX_UNTHROTTLED) {
712 mThrottleIndex.set(THROTTLE_INDEX_UNTHROTTLED);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700713 try {
Robert Greenwaltd3bb93f2010-04-12 19:20:55 -0700714 mNMService.setInterfaceThrottle(mIface, -1, -1);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700715 } catch (Exception e) {
716 Slog.e(TAG, "error clearing Throttle: " + e);
717 }
718 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
719 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
720 mContext.sendStickyBroadcast(broadcast);
Robert Greenwalt5bf16d62010-04-23 13:15:44 -0700721 mNotificationManager.cancel(R.drawable.stat_sys_throttled);
722 mWarningNotificationSent = false;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700723 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700724 }
725
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700726 private Calendar calculatePeriodEnd(long now) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700727 Calendar end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700728 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700729 int day = end.get(Calendar.DAY_OF_MONTH);
730 end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
731 end.set(Calendar.HOUR_OF_DAY, 0);
732 end.set(Calendar.MINUTE, 0);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -0700733 end.set(Calendar.SECOND, 0);
734 end.set(Calendar.MILLISECOND, 0);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700735 if (day >= mPolicyResetDay) {
736 int month = end.get(Calendar.MONTH);
737 if (month == Calendar.DECEMBER) {
738 end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
739 month = Calendar.JANUARY - 1;
740 }
741 end.set(Calendar.MONTH, month + 1);
742 }
743
744 // TODO - remove!
745 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
746 end = GregorianCalendar.getInstance();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700747 end.setTimeInMillis(now);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700748 end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
749 }
750 return end;
751 }
752 private Calendar calculatePeriodStart(Calendar end) {
753 Calendar start = (Calendar)end.clone();
754 int month = end.get(Calendar.MONTH);
755 if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
756 month = Calendar.DECEMBER + 1;
757 start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
758 }
759 start.set(Calendar.MONTH, month - 1);
760
761 // TODO - remove!!
762 if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
763 start = (Calendar)end.clone();
764 start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
765 }
766 return start;
767 }
768
769 private void onResetAlarm() {
Robert Greenwalt687f2a02010-06-08 10:10:54 -0700770 if (VDBG || (mPolicyThreshold.get() != 0)) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700771 Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
772 " bytes read and " + mRecorder.getPeriodTx(0) + " written");
773 }
774
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700775 // when trusted cache outdated, try refreshing
776 if (mTime.getCacheAge() > mMaxNtpCacheAge) {
777 mTime.forceRefresh();
778 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700779
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700780 // as long as we have a trusted time cache, we always reset alarms,
781 // even if the refresh above failed.
782 if (mTime.hasCache()) {
783 final long now = mTime.currentTimeMillis();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700784 Calendar end = calculatePeriodEnd(now);
785 Calendar start = calculatePeriodStart(end);
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700786
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700787 if (mRecorder.setNextPeriod(start, end)) {
Robert Greenwalt05d06732010-04-19 11:10:38 -0700788 onPollAlarm();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700789 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700790
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700791 mAlarmManager.cancel(mPendingResetIntent);
792 long offset = end.getTimeInMillis() - now;
793 // use Elapsed realtime so clock changes don't fool us.
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700794 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME,
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700795 SystemClock.elapsedRealtime() + offset,
796 mPendingResetIntent);
797 } else {
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700798 if (VDBG) Slog.d(TAG, "no trusted time, not resetting period");
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700799 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700800 }
801 }
802
803 // records bytecount data for a given time and accumulates it into larger time windows
804 // for logging and other purposes
805 //
806 // since time can be changed (user or network action) we will have to track the time of the
807 // last recording and deal with it.
808 private static class DataRecorder {
809 long[] mPeriodRxData;
810 long[] mPeriodTxData;
811 int mCurrentPeriod;
812 int mPeriodCount;
813
814 Calendar mPeriodStart;
815 Calendar mPeriodEnd;
816
817 ThrottleService mParent;
818 Context mContext;
Robert Greenwalte6e98822010-04-15 08:27:14 -0700819 String mImsi = null;
820
821 TelephonyManager mTelephonyManager;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700822
823 DataRecorder(Context context, ThrottleService parent) {
824 mContext = context;
825 mParent = parent;
826
Robert Greenwalte6e98822010-04-15 08:27:14 -0700827 mTelephonyManager = (TelephonyManager)mContext.getSystemService(
828 Context.TELEPHONY_SERVICE);
829
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700830 synchronized (mParent) {
831 mPeriodCount = 6;
832 mPeriodRxData = new long[mPeriodCount];
833 mPeriodTxData = new long[mPeriodCount];
834
835 mPeriodStart = Calendar.getInstance();
836 mPeriodEnd = Calendar.getInstance();
837
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700838 retrieve();
839 }
840 }
841
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700842 boolean setNextPeriod(Calendar start, Calendar end) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700843 // TODO - how would we deal with a dual-IMSI device?
844 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700845 boolean startNewPeriod = true;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700846
Robert Greenwalt27fba672010-04-26 12:29:14 -0700847 if (start.equals(mPeriodStart) && end.equals(mPeriodEnd)) {
848 // same endpoints - keep collecting
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700849 if (VDBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700850 Slog.d(TAG, "same period (" + start.getTimeInMillis() + "," +
851 end.getTimeInMillis() +") - ammending data");
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700852 }
Robert Greenwalt27fba672010-04-26 12:29:14 -0700853 startNewPeriod = false;
854 } else {
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700855 if (VDBG) {
Robert Greenwalt27fba672010-04-26 12:29:14 -0700856 if(start.equals(mPeriodEnd) || start.after(mPeriodEnd)) {
857 Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
858 end.getTimeInMillis() + ") - old end was " +
859 mPeriodEnd.getTimeInMillis() + ", following");
860 } else {
861 Slog.d(TAG, "new period (" + start.getTimeInMillis() + "," +
862 end.getTimeInMillis() + ") replacing old (" +
863 mPeriodStart.getTimeInMillis() + "," +
864 mPeriodEnd.getTimeInMillis() + ")");
865 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700866 }
867 synchronized (mParent) {
868 ++mCurrentPeriod;
869 if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
870 mPeriodRxData[mCurrentPeriod] = 0;
871 mPeriodTxData[mCurrentPeriod] = 0;
872 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700873 }
874 setPeriodStart(start);
875 setPeriodEnd(end);
876 record();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700877 return startNewPeriod;
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700878 }
879
880 public long getPeriodEnd() {
881 synchronized (mParent) {
882 return mPeriodEnd.getTimeInMillis();
883 }
884 }
885
886 private void setPeriodEnd(Calendar end) {
887 synchronized (mParent) {
888 mPeriodEnd = end;
889 }
890 }
891
892 public long getPeriodStart() {
893 synchronized (mParent) {
894 return mPeriodStart.getTimeInMillis();
895 }
896 }
897
898 private void setPeriodStart(Calendar start) {
899 synchronized (mParent) {
900 mPeriodStart = start;
901 }
902 }
903
904 public int getPeriodCount() {
905 synchronized (mParent) {
906 return mPeriodCount;
907 }
908 }
909
910 private void zeroData(int field) {
911 synchronized (mParent) {
912 for(int period = 0; period<mPeriodCount; period++) {
913 mPeriodRxData[period] = 0;
914 mPeriodTxData[period] = 0;
915 }
916 mCurrentPeriod = 0;
917 }
918
919 }
920
921 // if time moves backward accumulate all read/write that's lost into the now
922 // otherwise time moved forward.
923 void addData(long bytesRead, long bytesWritten) {
Robert Greenwalte6e98822010-04-15 08:27:14 -0700924 checkForSubscriberId();
Robert Greenwalt7171ea82010-04-14 22:37:12 -0700925
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700926 synchronized (mParent) {
927 mPeriodRxData[mCurrentPeriod] += bytesRead;
928 mPeriodTxData[mCurrentPeriod] += bytesWritten;
929 }
930 record();
931 }
932
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700933 private File getDataFile() {
934 File dataDir = Environment.getDataDirectory();
935 File throttleDir = new File(dataDir, "system/throttle");
936 throttleDir.mkdirs();
Robert Greenwalte6e98822010-04-15 08:27:14 -0700937 String mImsi = mTelephonyManager.getSubscriberId();
938 File dataFile;
939 if (mImsi == null) {
940 dataFile = useMRUFile(throttleDir);
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700941 if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700942 } else {
943 String imsiHash = Integer.toString(mImsi.hashCode());
944 dataFile = new File(throttleDir, imsiHash);
945 }
946 // touch the file so it's not LRU
947 dataFile.setLastModified(System.currentTimeMillis());
948 checkAndDeleteLRUDataFile(throttleDir);
Robert Greenwaltb8912f52010-04-09 17:27:26 -0700949 return dataFile;
950 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -0700951
Robert Greenwalte6e98822010-04-15 08:27:14 -0700952 // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
953 private void checkForSubscriberId() {
954 if (mImsi != null) return;
955
956 mImsi = mTelephonyManager.getSubscriberId();
957 if (mImsi == null) return;
958
Robert Greenwalt5a671d02010-06-07 16:43:16 -0700959 if (VDBG) Slog.d(TAG, "finally have imsi - retreiving data");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700960 retrieve();
961 }
962
963 private final static int MAX_SIMS_SUPPORTED = 3;
964
965 private void checkAndDeleteLRUDataFile(File dir) {
966 File[] files = dir.listFiles();
967
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700968 if (files == null || files.length <= MAX_SIMS_SUPPORTED) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700969 if (DBG) Slog.d(TAG, "Too many data files");
Robert Greenwalte6e98822010-04-15 08:27:14 -0700970 do {
971 File oldest = null;
972 for (File f : files) {
973 if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
974 oldest = f;
975 }
976 }
977 if (oldest == null) return;
Robert Greenwaltbf7de392010-04-21 17:09:38 -0700978 if (DBG) Slog.d(TAG, " deleting " + oldest);
Robert Greenwalte6e98822010-04-15 08:27:14 -0700979 oldest.delete();
980 files = dir.listFiles();
981 } while (files.length > MAX_SIMS_SUPPORTED);
982 }
983
984 private File useMRUFile(File dir) {
985 File newest = null;
986 File[] files = dir.listFiles();
987
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700988 if (files != null) {
989 for (File f : files) {
990 if ((newest == null) || (newest.lastModified() < f.lastModified())) {
991 newest = f;
992 }
Robert Greenwalte6e98822010-04-15 08:27:14 -0700993 }
994 }
995 if (newest == null) {
996 newest = new File(dir, "temp");
997 }
998 return newest;
999 }
1000
1001
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001002 private static final int DATA_FILE_VERSION = 1;
1003
1004 private void record() {
1005 // 1 int version
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001006 // 1 int mPeriodCount
1007 // 13*6 long[PERIOD_COUNT] mPeriodRxData
1008 // 13*6 long[PERIOD_COUNT] mPeriodTxData
1009 // 1 int mCurrentPeriod
1010 // 13 long periodStartMS
1011 // 13 long periodEndMS
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001012 // 200 chars max
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001013 StringBuilder builder = new StringBuilder();
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001014 builder.append(DATA_FILE_VERSION);
1015 builder.append(":");
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001016 builder.append(mPeriodCount);
1017 builder.append(":");
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001018 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001019 builder.append(mPeriodRxData[i]);
1020 builder.append(":");
1021 }
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001022 for(int i = 0; i < mPeriodCount; i++) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001023 builder.append(mPeriodTxData[i]);
1024 builder.append(":");
1025 }
1026 builder.append(mCurrentPeriod);
1027 builder.append(":");
1028 builder.append(mPeriodStart.getTimeInMillis());
1029 builder.append(":");
1030 builder.append(mPeriodEnd.getTimeInMillis());
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001031
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001032 BufferedWriter out = null;
1033 try {
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001034 out = new BufferedWriter(new FileWriter(getDataFile()), 256);
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001035 out.write(builder.toString());
1036 } catch (IOException e) {
1037 Slog.e(TAG, "Error writing data file");
1038 return;
1039 } finally {
1040 if (out != null) {
1041 try {
1042 out.close();
1043 } catch (Exception e) {}
1044 }
1045 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001046 }
1047
1048 private void retrieve() {
Robert Greenwalt05d06732010-04-19 11:10:38 -07001049 // clean out any old data first. If we fail to read we don't want old stuff
1050 zeroData(0);
1051
Robert Greenwaltb8912f52010-04-09 17:27:26 -07001052 File f = getDataFile();
1053 byte[] buffer;
1054 FileInputStream s = null;
1055 try {
1056 buffer = new byte[(int)f.length()];
1057 s = new FileInputStream(f);
1058 s.read(buffer);
1059 } catch (IOException e) {
1060 Slog.e(TAG, "Error reading data file");
1061 return;
1062 } finally {
1063 if (s != null) {
1064 try {
1065 s.close();
1066 } catch (Exception e) {}
1067 }
1068 }
1069 String data = new String(buffer);
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001070 if (data == null || data.length() == 0) {
1071 if (DBG) Slog.d(TAG, "data file empty");
1072 return;
1073 }
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001074 String[] parsed = data.split(":");
1075 int parsedUsed = 0;
1076 if (parsed.length < 6) {
1077 Slog.e(TAG, "reading data file with insufficient length - ignoring");
1078 return;
1079 }
1080
Robert Greenwalt9e3983f2010-05-11 07:06:13 -07001081 int periodCount;
1082 long[] periodRxData;
1083 long[] periodTxData;
1084 int currentPeriod;
1085 Calendar periodStart;
1086 Calendar periodEnd;
1087 try {
1088 if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
1089 Slog.e(TAG, "reading data file with bad version - ignoring");
1090 return;
1091 }
1092
1093 periodCount = Integer.parseInt(parsed[parsedUsed++]);
1094 if (parsed.length != 5 + (2 * periodCount)) {
1095 Slog.e(TAG, "reading data file with bad length (" + parsed.length +
1096 " != " + (5 + (2 * periodCount)) + ") - ignoring");
1097 return;
1098 }
1099 periodRxData = new long[periodCount];
1100 for (int i = 0; i < periodCount; i++) {
1101 periodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
1102 }
1103 periodTxData = new long[periodCount];
1104 for (int i = 0; i < periodCount; i++) {
1105 periodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
1106 }
1107
1108 currentPeriod = Integer.parseInt(parsed[parsedUsed++]);
1109
1110 periodStart = new GregorianCalendar();
1111 periodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1112 periodEnd = new GregorianCalendar();
1113 periodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
1114 } catch (Exception e) {
1115 Slog.e(TAG, "Error parsing data file - ignoring");
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001116 return;
1117 }
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001118 synchronized (mParent) {
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001119 mPeriodCount = periodCount;
1120 mPeriodRxData = periodRxData;
1121 mPeriodTxData = periodTxData;
Robert Greenwalt9e3983f2010-05-11 07:06:13 -07001122 mCurrentPeriod = currentPeriod;
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001123 mPeriodStart = periodStart;
1124 mPeriodEnd = periodEnd;
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001125 }
1126 }
1127
1128 long getPeriodRx(int which) {
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001129 synchronized (mParent) {
1130 if (which > mPeriodCount) return 0;
1131 which = mCurrentPeriod - which;
1132 if (which < 0) which += mPeriodCount;
1133 return mPeriodRxData[which];
1134 }
1135 }
1136 long getPeriodTx(int which) {
1137 synchronized (mParent) {
1138 if (which > mPeriodCount) return 0;
1139 which = mCurrentPeriod - which;
1140 if (which < 0) which += mPeriodCount;
1141 return mPeriodTxData[which];
1142 }
1143 }
1144 }
1145
1146 @Override
1147 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1148 if (mContext.checkCallingOrSelfPermission(
1149 android.Manifest.permission.DUMP)
1150 != PackageManager.PERMISSION_GRANTED) {
1151 pw.println("Permission Denial: can't dump ThrottleService " +
1152 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1153 Binder.getCallingUid());
1154 return;
1155 }
1156 pw.println();
1157
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001158 pw.println("The threshold is " + mPolicyThreshold.get() +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001159 ", after which you experince throttling to " +
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001160 mPolicyThrottleValue.get() + "kbps");
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001161 pw.println("Current period is " +
1162 (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
Robert Greenwalt7171ea82010-04-14 22:37:12 -07001163 "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001164 " seconds.");
1165 pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
Robert Greenwalt39e163f2010-05-07 16:52:17 -07001166 pw.println("Current Throttle Index is " + mThrottleIndex.get());
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -07001167 pw.println("mMaxNtpCacheAge=" + mMaxNtpCacheAge);
Robert Greenwalt8c7e6092010-04-14 17:31:20 -07001168
Robert Greenwalt9e696c22010-04-01 14:45:18 -07001169 for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
1170 pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
1171 mRecorder.getPeriodTx(i));
1172 }
1173 }
1174}