am c2093636: am 7171ea81: Make ThrottleService more tamper resistant.

Merge commit 'c2093636db6141426ca7fe88f07b30a284e36759' into kraken

* commit 'c2093636db6141426ca7fe88f07b30a284e36759':
  Make ThrottleService more tamper resistant.
This commit is contained in:
Robert Greenwalt
2010-04-18 12:35:10 -07:00
committed by Android Git Automerger

View File

@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
import android.content.res.Resources; import android.content.res.Resources;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.net.IThrottleManager; import android.net.IThrottleManager;
import android.net.SntpClient;
import android.net.ThrottleManager; import android.net.ThrottleManager;
import android.os.Binder; import android.os.Binder;
import android.os.Environment; import android.os.Environment;
@@ -47,6 +48,7 @@ import android.provider.Settings;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.util.Slog; import android.util.Slog;
import com.android.internal.R;
import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.TelephonyProperties;
import java.io.BufferedWriter; import java.io.BufferedWriter;
@@ -58,6 +60,7 @@ import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.Calendar; import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Properties;
import java.util.Random; import java.util.Random;
// TODO - add comments - reference the ThrottleManager for public API // TODO - add comments - reference the ThrottleManager for public API
@@ -73,7 +76,7 @@ public class ThrottleService extends IThrottleManager.Stub {
private Context mContext; private Context mContext;
private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1; private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
private static final int TESTING_RESET_PERIOD_SEC = 60 * 3; private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
private static final long TESTING_THRESHOLD = 1 * 1024 * 1024; private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
private static final int PERIOD_COUNT = 6; private static final int PERIOD_COUNT = 6;
@@ -114,10 +117,16 @@ public class ThrottleService extends IThrottleManager.Stub {
private static final int THROTTLE_INDEX_UNINITIALIZED = -1; private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
private static final int THROTTLE_INDEX_UNTHROTTLED = 0; private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
private static final String PROPERTIES_FILE = "/etc/gps.conf";
private String mNtpServer;
private boolean mNtpActive;
public ThrottleService(Context context) { public ThrottleService(Context context) {
if (DBG) Slog.d(TAG, "Starting ThrottleService"); if (DBG) Slog.d(TAG, "Starting ThrottleService");
mContext = context; mContext = context;
mNtpActive = false;
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
Intent pollIntent = new Intent(ACTION_POLL, null); Intent pollIntent = new Intent(ACTION_POLL, null);
mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0); mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
@@ -169,21 +178,33 @@ public class ThrottleService extends IThrottleManager.Stub {
} }
// TODO - fetch for the iface // TODO - fetch for the iface
// return time in the local, system wall time, correcting for the use of ntp
public synchronized long getResetTime(String iface) { public synchronized long getResetTime(String iface) {
enforceAccessPermission(); enforceAccessPermission();
long resetTime = 0;
if (mRecorder != null) { if (mRecorder != null) {
mRecorder.getPeriodEnd(); long bestEnd = mRecorder.getPeriodEnd();
long bestNow = getBestTime();
long localNow = System.currentTimeMillis();
resetTime = localNow + (bestEnd - bestNow);
} }
return 0; return resetTime;
} }
// TODO - fetch for the iface // TODO - fetch for the iface
// return time in the loca, system wall tiem, correcting for the use of ntp
public synchronized long getPeriodStartTime(String iface) { public synchronized long getPeriodStartTime(String iface) {
enforceAccessPermission(); enforceAccessPermission();
long startTime = 0;
if (mRecorder != null) { if (mRecorder != null) {
mRecorder.getPeriodStart(); long bestStart = mRecorder.getPeriodStart();
long bestNow = getBestTime();
long localNow = System.currentTimeMillis();
startTime = localNow + (bestStart - bestNow);
} }
return 0; return startTime;
} }
//TODO - a better name? getCliffByteCountThreshold? //TODO - a better name? getCliffByteCountThreshold?
// TODO - fetch for the iface // TODO - fetch for the iface
@@ -257,6 +278,23 @@ public class ThrottleService extends IThrottleManager.Stub {
mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED); mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
mSettingsObserver.observe(mContext); mSettingsObserver.observe(mContext);
FileInputStream stream = null;
try {
Properties properties = new Properties();
File file = new File(PROPERTIES_FILE);
stream = new FileInputStream(file);
properties.load(stream);
mNtpServer = properties.getProperty("NTP_SERVER", null);
} catch (IOException e) {
Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
} finally {
if (stream != null) {
try {
stream.close();
} catch (Exception e) {}
}
}
} }
@@ -297,13 +335,6 @@ public class ThrottleService extends IThrottleManager.Stub {
// get policy // get policy
mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget(); mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
// evaluate current conditions
mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
}
private void onSimChange() {
// TODO
} }
// check for new policy info (threshold limit/value/etc) // check for new policy info (threshold limit/value/etc)
@@ -311,15 +342,15 @@ public class ThrottleService extends IThrottleManager.Stub {
boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true"); boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
int pollingPeriod = mContext.getResources().getInteger( int pollingPeriod = mContext.getResources().getInteger(
com.android.internal.R.integer.config_datause_polling_period_sec); R.integer.config_datause_polling_period_sec);
mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(), mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod); Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
// TODO - remove testing stuff? // TODO - remove testing stuff?
long defaultThreshold = mContext.getResources().getInteger( long defaultThreshold = mContext.getResources().getInteger(
com.android.internal.R.integer.config_datause_threshold_bytes); R.integer.config_datause_threshold_bytes);
int defaultValue = mContext.getResources().getInteger( int defaultValue = mContext.getResources().getInteger(
com.android.internal.R.integer.config_datause_throttle_kbitsps); R.integer.config_datause_throttle_kbitsps);
synchronized (ThrottleService.this) { synchronized (ThrottleService.this) {
mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(), mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(),
Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold); Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
@@ -340,8 +371,7 @@ public class ThrottleService extends IThrottleManager.Stub {
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay); Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
} }
mIface = mContext.getResources().getString( mIface = mContext.getResources().getString(R.string.config_datause_iface);
com.android.internal.R.string.config_datause_iface);
synchronized (ThrottleService.this) { synchronized (ThrottleService.this) {
if (mIface == null) { if (mIface == null) {
mPolicyThreshold = 0; mPolicyThreshold = 0;
@@ -349,7 +379,7 @@ public class ThrottleService extends IThrottleManager.Stub {
} }
int defaultNotificationType = mContext.getResources().getInteger( int defaultNotificationType = mContext.getResources().getInteger(
com.android.internal.R.integer.config_datause_notification_type); R.integer.config_datause_notification_type);
mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(), mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType); Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
@@ -369,6 +399,9 @@ public class ThrottleService extends IThrottleManager.Stub {
private void onPollAlarm() { private void onPollAlarm() {
long now = SystemClock.elapsedRealtime(); long now = SystemClock.elapsedRealtime();
long next = now + mPolicyPollPeriodSec*1000; long next = now + mPolicyPollPeriodSec*1000;
checkForAuthoritativeTime();
long incRead = 0; long incRead = 0;
long incWrite = 0; long incWrite = 0;
try { try {
@@ -407,8 +440,8 @@ public class ThrottleService extends IThrottleManager.Stub {
Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION); Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx); broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx); broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, mRecorder.getPeriodStart()); broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, ThrottleService.this.getPeriodStartTime(mIface));
broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, mRecorder.getPeriodEnd()); broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, ThrottleService.this.getResetTime(mIface));
mContext.sendStickyBroadcast(broadcast); mContext.sendStickyBroadcast(broadcast);
mAlarmManager.cancel(mPendingPollIntent); mAlarmManager.cancel(mPendingPollIntent);
@@ -417,8 +450,15 @@ public class ThrottleService extends IThrottleManager.Stub {
private void checkThrottleAndPostNotification(long currentTotal) { private void checkThrottleAndPostNotification(long currentTotal) {
// is throttling enabled? // is throttling enabled?
if (mPolicyThreshold == 0) if (mPolicyThreshold == 0) {
return; return;
}
// have we spoken with an ntp server yet?
// this is controversial, but we'd rather err towards not throttling
if ((mNtpServer != null) && !mNtpActive) {
return;
}
// check if we need to throttle // check if we need to throttle
if (currentTotal > mPolicyThreshold) { if (currentTotal > mPolicyThreshold) {
@@ -434,12 +474,11 @@ public class ThrottleService extends IThrottleManager.Stub {
Slog.e(TAG, "error setting Throttle: " + e); Slog.e(TAG, "error setting Throttle: " + e);
} }
mNotificationManager.cancel(com.android.internal.R.drawable. mNotificationManager.cancel(R.drawable.stat_sys_throttled);
stat_sys_throttled);
postNotification(com.android.internal.R.string.throttled_notification_title, postNotification(R.string.throttled_notification_title,
com.android.internal.R.string.throttled_notification_message, R.string.throttled_notification_message,
com.android.internal.R.drawable.stat_sys_throttled, R.drawable.stat_sys_throttled,
Notification.FLAG_ONGOING_EVENT); Notification.FLAG_ONGOING_EVENT);
Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION); Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
@@ -469,19 +508,15 @@ public class ThrottleService extends IThrottleManager.Stub {
if ((currentTotal > warningThreshold) && (currentTotal > mPolicyThreshold/4)) { if ((currentTotal > warningThreshold) && (currentTotal > mPolicyThreshold/4)) {
if (mWarningNotificationSent == false) { if (mWarningNotificationSent == false) {
mWarningNotificationSent = true; mWarningNotificationSent = true;
mNotificationManager.cancel(com.android.internal.R.drawable. mNotificationManager.cancel(R.drawable.stat_sys_throttled);
stat_sys_throttled); postNotification(R.string.throttle_warning_notification_title,
postNotification(com.android.internal.R.string. R.string.throttle_warning_notification_message,
throttle_warning_notification_title, R.drawable.stat_sys_throttled,
com.android.internal.R.string.
throttle_warning_notification_message,
com.android.internal.R.drawable.stat_sys_throttled,
0); 0);
} }
} else { } else {
if (mWarningNotificationSent == true) { if (mWarningNotificationSent == true) {
mNotificationManager.cancel(com.android.internal.R.drawable. mNotificationManager.cancel(R.drawable.stat_sys_throttled);
stat_sys_throttled);
mWarningNotificationSent =false; mWarningNotificationSent =false;
} }
} }
@@ -529,12 +564,13 @@ public class ThrottleService extends IThrottleManager.Stub {
broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1); broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
mContext.sendStickyBroadcast(broadcast); mContext.sendStickyBroadcast(broadcast);
} }
mNotificationManager.cancel(com.android.internal.R.drawable.stat_sys_throttled); mNotificationManager.cancel(R.drawable.stat_sys_throttled);
mWarningNotificationSent = false; mWarningNotificationSent = false;
} }
private Calendar calculatePeriodEnd() { private Calendar calculatePeriodEnd(long now) {
Calendar end = GregorianCalendar.getInstance(); Calendar end = GregorianCalendar.getInstance();
end.setTimeInMillis(now);
int day = end.get(Calendar.DAY_OF_MONTH); int day = end.get(Calendar.DAY_OF_MONTH);
end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay); end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
end.set(Calendar.HOUR_OF_DAY, 0); end.set(Calendar.HOUR_OF_DAY, 0);
@@ -553,6 +589,7 @@ public class ThrottleService extends IThrottleManager.Stub {
// TODO - remove! // TODO - remove!
if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) { if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
end = GregorianCalendar.getInstance(); end = GregorianCalendar.getInstance();
end.setTimeInMillis(now);
end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC); end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
} }
return end; return end;
@@ -580,19 +617,59 @@ public class ThrottleService extends IThrottleManager.Stub {
" bytes read and " + mRecorder.getPeriodTx(0) + " written"); " bytes read and " + mRecorder.getPeriodTx(0) + " written");
} }
Calendar end = calculatePeriodEnd(); long now = getBestTime();
Calendar start = calculatePeriodStart(end);
clearThrottleAndNotification(); if (mNtpActive || (mNtpServer == null)) {
Calendar end = calculatePeriodEnd(now);
Calendar start = calculatePeriodStart(end);
mRecorder.setNextPeriod(start,end); if (mRecorder.setNextPeriod(start, end)) {
clearThrottleAndNotification();
}
mAlarmManager.cancel(mPendingResetIntent); mAlarmManager.cancel(mPendingResetIntent);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, end.getTimeInMillis(), long offset = end.getTimeInMillis() - now;
mPendingResetIntent); // use Elapsed realtime so clock changes don't fool us.
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + offset,
mPendingResetIntent);
} else {
if (DBG) Slog.d(TAG, "no authoritative time - not resetting period");
}
} }
} }
private void checkForAuthoritativeTime() {
if (mNtpActive || (mNtpServer == null)) return;
SntpClient client = new SntpClient();
if (client.requestTime(mNtpServer, 10000)) {
mNtpActive = true;
if (DBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
}
}
private long getBestTime() {
SntpClient client = new SntpClient();
long time;
if ((mNtpServer != null) && client.requestTime(mNtpServer, 10000)) {
time = client.getNtpTime() ;
if (!mNtpActive) {
mNtpActive = true;
if (DBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
}
if (DBG) Slog.d(TAG, "using Authoritative time: " + time);
} else {
time = System.currentTimeMillis();
if (DBG) Slog.d(TAG, "using User time: " + time);
mNtpActive = false;
}
return time;
}
// records bytecount data for a given time and accumulates it into larger time windows // records bytecount data for a given time and accumulates it into larger time windows
// for logging and other purposes // for logging and other purposes
// //
@@ -633,16 +710,16 @@ public class ThrottleService extends IThrottleManager.Stub {
} }
} }
void setNextPeriod(Calendar start, Calendar end) { boolean setNextPeriod(Calendar start, Calendar end) {
// TODO - how would we deal with a dual-IMSI device? // TODO - how would we deal with a dual-IMSI device?
checkForSubscriberId(); checkForSubscriberId();
boolean startNewPeriod = true;
if (DBG) { if (DBG) {
Slog.d(TAG, "setting next period to " + start.getTimeInMillis() + Slog.d(TAG, "setting next period to " + start.getTimeInMillis() +
" --until-- " + end.getTimeInMillis()); " --until-- " + end.getTimeInMillis());
} }
// if we roll back in time to a previous period, toss out the current data // if we rolled back in time, toss out
// if we roll forward to the next period, advance to the next // if we rolled foward, advance to the next
if (end.before(mPeriodStart)) { if (end.before(mPeriodStart)) {
if (DBG) { if (DBG) {
Slog.d(TAG, " old start was " + mPeriodStart.getTimeInMillis() + ", wiping"); Slog.d(TAG, " old start was " + mPeriodStart.getTimeInMillis() + ", wiping");
@@ -662,11 +739,13 @@ public class ThrottleService extends IThrottleManager.Stub {
mPeriodTxData[mCurrentPeriod] = 0; mPeriodTxData[mCurrentPeriod] = 0;
} }
} else { } else {
startNewPeriod = false;
if (DBG) Slog.d(TAG, " we fit - ammending to last period"); if (DBG) Slog.d(TAG, " we fit - ammending to last period");
} }
setPeriodStart(start); setPeriodStart(start);
setPeriodEnd(end); setPeriodEnd(end);
record(); record();
return startNewPeriod;
} }
public long getPeriodEnd() { public long getPeriodEnd() {
@@ -714,6 +793,7 @@ public class ThrottleService extends IThrottleManager.Stub {
// otherwise time moved forward. // otherwise time moved forward.
void addData(long bytesRead, long bytesWritten) { void addData(long bytesRead, long bytesWritten) {
checkForSubscriberId(); checkForSubscriberId();
synchronized (mParent) { synchronized (mParent) {
mPeriodRxData[mCurrentPeriod] += bytesRead; mPeriodRxData[mCurrentPeriod] += bytesRead;
mPeriodTxData[mCurrentPeriod] += bytesWritten; mPeriodTxData[mCurrentPeriod] += bytesWritten;
@@ -817,11 +897,10 @@ public class ThrottleService extends IThrottleManager.Stub {
builder.append(mPeriodStart.getTimeInMillis()); builder.append(mPeriodStart.getTimeInMillis());
builder.append(":"); builder.append(":");
builder.append(mPeriodEnd.getTimeInMillis()); builder.append(mPeriodEnd.getTimeInMillis());
builder.append(":");
BufferedWriter out = null; BufferedWriter out = null;
try { try {
out = new BufferedWriter(new FileWriter(getDataFile()),256); out = new BufferedWriter(new FileWriter(getDataFile()), 256);
out.write(builder.toString()); out.write(builder.toString());
} catch (IOException e) { } catch (IOException e) {
Slog.e(TAG, "Error writing data file"); Slog.e(TAG, "Error writing data file");
@@ -854,7 +933,10 @@ public class ThrottleService extends IThrottleManager.Stub {
} }
} }
String data = new String(buffer); String data = new String(buffer);
if (data == null || data.length() == 0) return; if (data == null || data.length() == 0) {
if (DBG) Slog.d(TAG, "data file empty");
return;
}
synchronized (mParent) { synchronized (mParent) {
String[] parsed = data.split(":"); String[] parsed = data.split(":");
int parsedUsed = 0; int parsedUsed = 0;
@@ -869,7 +951,10 @@ public class ThrottleService extends IThrottleManager.Stub {
} }
mPeriodCount = Integer.parseInt(parsed[parsedUsed++]); mPeriodCount = Integer.parseInt(parsed[parsedUsed++]);
if (parsed.length != 4 + (2 * mPeriodCount)) return; if (parsed.length != 5 + (2 * mPeriodCount)) {
Slog.e(TAG, "reading data file with bad length ("+parsed.length+" != "+(4 + (2*mPeriodCount))+") - ignoring");
return;
}
mPeriodRxData = new long[mPeriodCount]; mPeriodRxData = new long[mPeriodCount];
for(int i = 0; i < mPeriodCount; i++) { for(int i = 0; i < mPeriodCount; i++) {
@@ -922,7 +1007,7 @@ public class ThrottleService extends IThrottleManager.Stub {
mPolicyThrottleValue + "kbps"); mPolicyThrottleValue + "kbps");
pw.println("Current period is " + pw.println("Current period is " +
(mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " + (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
"and ends in " + (mRecorder.getPeriodEnd() - System.currentTimeMillis()) / 1000 + "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
" seconds."); " seconds.");
pw.println("Polling every " + mPolicyPollPeriodSec + " seconds"); pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
pw.println("Current Throttle Index is " + mThrottleIndex); pw.println("Current Throttle Index is " + mThrottleIndex);