diff options
| -rw-r--r-- | services/java/com/android/server/am/UsageStatsService.java | 121 |
1 files changed, 81 insertions, 40 deletions
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java index 1b9e1c77fa87..3f15d0a5bffd 100644 --- a/services/java/com/android/server/am/UsageStatsService.java +++ b/services/java/com/android/server/am/UsageStatsService.java @@ -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,31 +246,33 @@ 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(); - 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"); + synchronized (mCal) { + 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(dd); return sb.toString(); } @@ -360,23 +367,56 @@ public final class UsageStatsService extends IUsageStats.Stub { 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()); - final int 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... - // we can probably live with this. - final boolean dayChanged = curDay != mLastWriteDay; - long currElapsedTime = SystemClock.elapsedRealtime(); - if (!force) { - if (((currElapsedTime-mLastWriteElapsedTime) < FILE_WRITE_INTERVAL) && - (!dayChanged)) { - // wait till the next update - return; - } + 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 long currElapsedTime = SystemClock.elapsedRealtime(); + + // Fast common path, without taking the often-contentious + // 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 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); |