Merge "Usage Stats: don't block writing stats to disk." into gingerbread

This commit is contained in:
Brad Fitzpatrick
2010-08-03 16:57:47 -07:00
committed by Android (Google) Code Review

View File

@ -44,6 +44,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* This service collects the statistics associated with usage
@ -88,11 +91,13 @@ public final class UsageStatsService extends IUsageStats.Stub {
private boolean mIsResumed;
private File mFile;
private String mFileLeaf;
//private File mBackupFile;
private long mLastWriteElapsedTime;
private File mDir;
private Calendar mCal;
private int mLastWriteDay;
private Calendar mCal; // guarded by itself
private final AtomicInteger mLastWriteDay = new AtomicInteger(-1);
private final AtomicLong mLastWriteElapsedTime = new AtomicLong(0);
private final AtomicBoolean mUnforcedDiskWriteRunning = new AtomicBoolean(false);
static class TimeStats {
int count;
@ -241,17 +246,18 @@ public final class UsageStatsService extends IUsageStats.Stub {
mFileLeaf = getCurrentDateStr(FILE_PREFIX);
mFile = new File(mDir, mFileLeaf);
readStatsFromFile();
mLastWriteElapsedTime = SystemClock.elapsedRealtime();
mLastWriteElapsedTime.set(SystemClock.elapsedRealtime());
// mCal was set by getCurrentDateStr(), want to use that same time.
mLastWriteDay = mCal.get(Calendar.DAY_OF_YEAR);
mLastWriteDay.set(mCal.get(Calendar.DAY_OF_YEAR));
}
/*
* Utility method to convert date into string.
*/
private String getCurrentDateStr(String prefix) {
mCal.setTimeInMillis(System.currentTimeMillis());
StringBuilder sb = new StringBuilder();
synchronized (mCal) {
mCal.setTimeInMillis(System.currentTimeMillis());
if (prefix != null) {
sb.append(prefix);
}
@ -266,6 +272,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
sb.append("0");
}
sb.append(dd);
}
return sb.toString();
}
@ -361,22 +368,55 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
private void writeStatsToFile(boolean force) {
synchronized (mFileLock) {
/**
* Conditionally start up a disk write if it's been awhile, or the
* day has rolled over.
*
* This is called indirectly from user-facing actions (when
* 'force' is false) so it tries to be quick, without writing to
* disk directly or acquiring heavy locks.
*
* @params force do an unconditional, synchronous stats flush
* to disk on the current thread.
*/
private void writeStatsToFile(final boolean force) {
int curDay;
synchronized (mCal) {
mCal.setTimeInMillis(System.currentTimeMillis());
final int curDay = mCal.get(Calendar.DAY_OF_YEAR);
curDay = mCal.get(Calendar.DAY_OF_YEAR);
}
final boolean dayChanged = curDay != mLastWriteDay.get();
// Determine if the day changed... note that this will be wrong
// if the year has changed but we are in the same day of year...
// we can probably live with this.
final boolean dayChanged = curDay != mLastWriteDay;
long currElapsedTime = SystemClock.elapsedRealtime();
final long currElapsedTime = SystemClock.elapsedRealtime();
// Fast common path, without taking the often-contentious
// mFileLock.
if (!force) {
if (((currElapsedTime-mLastWriteElapsedTime) < FILE_WRITE_INTERVAL) &&
(!dayChanged)) {
if (!dayChanged &&
(currElapsedTime - mLastWriteElapsedTime.get()) < FILE_WRITE_INTERVAL) {
// wait till the next update
return;
}
if (mUnforcedDiskWriteRunning.compareAndSet(false, true)) {
new Thread("UsageStatsService_DiskWriter") {
public void run() {
try {
Slog.d(TAG, "Disk writer thread starting.");
writeStatsToFile(true);
} finally {
mUnforcedDiskWriteRunning.set(false);
Slog.d(TAG, "Disk writer thread ending.");
}
}
}.start();
}
return;
}
synchronized (mFileLock) {
// Get the most recent file
mFileLeaf = getCurrentDateStr(FILE_PREFIX);
// Copy current file to back up
@ -395,10 +435,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
try {
// Write mStats to file
writeStatsFLOCK();
mLastWriteElapsedTime = currElapsedTime;
writeStatsFLOCK(mFile);
mLastWriteElapsedTime.set(currElapsedTime);
if (dayChanged) {
mLastWriteDay = curDay;
mLastWriteDay.set(curDay);
// clear stats
synchronized (mStats) {
mStats.clear();
@ -418,10 +458,11 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
}
Slog.d(TAG, "Dumped usage stats.");
}
private void writeStatsFLOCK() throws IOException {
FileOutputStream stream = new FileOutputStream(mFile);
private void writeStatsFLOCK(File file) throws IOException {
FileOutputStream stream = new FileOutputStream(file);
try {
Parcel out = Parcel.obtain();
writeStatsToParcelFLOCK(out);