am 866362fc
: Merge "Usage Stats: don\'t block writing stats to disk." into gingerbread
Merge commit '866362fcb4db93584143c21934ea355cbf9e0757' into gingerbread-plus-aosp * commit '866362fcb4db93584143c21934ea355cbf9e0757': Usage Stats: don't block writing stats to disk.
This commit is contained in:
@ -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);
|
||||
|
Reference in New Issue
Block a user