Merge "Usage Stats: don't block writing stats to disk." into gingerbread
This commit is contained in:
committed by
Android (Google) Code Review
commit
866362fcb4
@ -44,6 +44,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
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
|
* This service collects the statistics associated with usage
|
||||||
@ -88,11 +91,13 @@ public final class UsageStatsService extends IUsageStats.Stub {
|
|||||||
private boolean mIsResumed;
|
private boolean mIsResumed;
|
||||||
private File mFile;
|
private File mFile;
|
||||||
private String mFileLeaf;
|
private String mFileLeaf;
|
||||||
//private File mBackupFile;
|
|
||||||
private long mLastWriteElapsedTime;
|
|
||||||
private File mDir;
|
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 {
|
static class TimeStats {
|
||||||
int count;
|
int count;
|
||||||
@ -241,31 +246,33 @@ public final class UsageStatsService extends IUsageStats.Stub {
|
|||||||
mFileLeaf = getCurrentDateStr(FILE_PREFIX);
|
mFileLeaf = getCurrentDateStr(FILE_PREFIX);
|
||||||
mFile = new File(mDir, mFileLeaf);
|
mFile = new File(mDir, mFileLeaf);
|
||||||
readStatsFromFile();
|
readStatsFromFile();
|
||||||
mLastWriteElapsedTime = SystemClock.elapsedRealtime();
|
mLastWriteElapsedTime.set(SystemClock.elapsedRealtime());
|
||||||
// mCal was set by getCurrentDateStr(), want to use that same time.
|
// 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.
|
* Utility method to convert date into string.
|
||||||
*/
|
*/
|
||||||
private String getCurrentDateStr(String prefix) {
|
private String getCurrentDateStr(String prefix) {
|
||||||
mCal.setTimeInMillis(System.currentTimeMillis());
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
if (prefix != null) {
|
synchronized (mCal) {
|
||||||
sb.append(prefix);
|
mCal.setTimeInMillis(System.currentTimeMillis());
|
||||||
|
if (prefix != null) {
|
||||||
|
sb.append(prefix);
|
||||||
|
}
|
||||||
|
sb.append(mCal.get(Calendar.YEAR));
|
||||||
|
int mm = mCal.get(Calendar.MONTH) - Calendar.JANUARY +1;
|
||||||
|
if (mm < 10) {
|
||||||
|
sb.append("0");
|
||||||
|
}
|
||||||
|
sb.append(mm);
|
||||||
|
int dd = mCal.get(Calendar.DAY_OF_MONTH);
|
||||||
|
if (dd < 10) {
|
||||||
|
sb.append("0");
|
||||||
|
}
|
||||||
|
sb.append(dd);
|
||||||
}
|
}
|
||||||
sb.append(mCal.get(Calendar.YEAR));
|
|
||||||
int mm = mCal.get(Calendar.MONTH) - Calendar.JANUARY +1;
|
|
||||||
if (mm < 10) {
|
|
||||||
sb.append("0");
|
|
||||||
}
|
|
||||||
sb.append(mm);
|
|
||||||
int dd = mCal.get(Calendar.DAY_OF_MONTH);
|
|
||||||
if (dd < 10) {
|
|
||||||
sb.append("0");
|
|
||||||
}
|
|
||||||
sb.append(dd);
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,23 +367,56 @@ public final class UsageStatsService extends IUsageStats.Stub {
|
|||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
mCal.setTimeInMillis(System.currentTimeMillis());
|
||||||
final int curDay = mCal.get(Calendar.DAY_OF_YEAR);
|
curDay = mCal.get(Calendar.DAY_OF_YEAR);
|
||||||
// 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...
|
final boolean dayChanged = curDay != mLastWriteDay.get();
|
||||||
// we can probably live with this.
|
|
||||||
final boolean dayChanged = curDay != mLastWriteDay;
|
// Determine if the day changed... note that this will be wrong
|
||||||
long currElapsedTime = SystemClock.elapsedRealtime();
|
// if the year has changed but we are in the same day of year...
|
||||||
if (!force) {
|
// we can probably live with this.
|
||||||
if (((currElapsedTime-mLastWriteElapsedTime) < FILE_WRITE_INTERVAL) &&
|
final long currElapsedTime = SystemClock.elapsedRealtime();
|
||||||
(!dayChanged)) {
|
|
||||||
// wait till the next update
|
// Fast common path, without taking the often-contentious
|
||||||
return;
|
// mFileLock.
|
||||||
}
|
if (!force) {
|
||||||
|
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
|
// Get the most recent file
|
||||||
mFileLeaf = getCurrentDateStr(FILE_PREFIX);
|
mFileLeaf = getCurrentDateStr(FILE_PREFIX);
|
||||||
// Copy current file to back up
|
// Copy current file to back up
|
||||||
@ -395,10 +435,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Write mStats to file
|
// Write mStats to file
|
||||||
writeStatsFLOCK();
|
writeStatsFLOCK(mFile);
|
||||||
mLastWriteElapsedTime = currElapsedTime;
|
mLastWriteElapsedTime.set(currElapsedTime);
|
||||||
if (dayChanged) {
|
if (dayChanged) {
|
||||||
mLastWriteDay = curDay;
|
mLastWriteDay.set(curDay);
|
||||||
// clear stats
|
// clear stats
|
||||||
synchronized (mStats) {
|
synchronized (mStats) {
|
||||||
mStats.clear();
|
mStats.clear();
|
||||||
@ -418,10 +458,11 @@ public final class UsageStatsService extends IUsageStats.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Slog.d(TAG, "Dumped usage stats.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeStatsFLOCK() throws IOException {
|
private void writeStatsFLOCK(File file) throws IOException {
|
||||||
FileOutputStream stream = new FileOutputStream(mFile);
|
FileOutputStream stream = new FileOutputStream(file);
|
||||||
try {
|
try {
|
||||||
Parcel out = Parcel.obtain();
|
Parcel out = Parcel.obtain();
|
||||||
writeStatsToParcelFLOCK(out);
|
writeStatsToParcelFLOCK(out);
|
||||||
|
Reference in New Issue
Block a user