137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe/* 237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * Copyright (C) 2016 The Android Open Source Project 337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * 437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * Licensed under the Apache License, Version 2.0 (the "License"); 537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * you may not use this file except in compliance with the License. 637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * You may obtain a copy of the License at 737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * 837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * http://www.apache.org/licenses/LICENSE-2.0 937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * 1037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * Unless required by applicable law or agreed to in writing, software 1137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * distributed under the License is distributed on an "AS IS" BASIS, 1237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * See the License for the specific language governing permissions and 1437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * limitations under the License. 1537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe */ 1637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 1737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampepackage com.android.server.pm; 1837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 1937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampeimport android.os.Environment; 2037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampeimport android.os.SystemClock; 2137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampeimport android.util.AtomicFile; 2237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 2337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampeimport java.io.File; 2437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampeimport java.util.concurrent.atomic.AtomicBoolean; 2537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampeimport java.util.concurrent.atomic.AtomicLong; 2637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 2737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe/** 2837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * A simple base class for statistics that need to be saved/restored from a dedicated file. This 2937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * class provides a base implementation that: 3037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * <ul> 3137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * <li>Provide an AtomicFile to the actual read/write code 3237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * <li>A background-thread write and a synchronous write 3337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * <li>Write-limiting for the background-thread (by default writes are at least 30 minutes apart) 3437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * <li>Can lock on the provided data object before writing 3537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * </ul> 3637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * For completion, a subclass needs to implement actual {@link #writeInternal(Object) writing} and 3737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe * {@link #readInternal(Object) reading}. 3837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe */ 3937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampepublic abstract class AbstractStatsBase<T> { 4037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 4137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe private static final int WRITE_INTERVAL_MS = 4237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe (PackageManagerService.DEBUG_DEXOPT) ? 0 : 30*60*1000; 4337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe private final Object mFileLock = new Object(); 4437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe private final AtomicLong mLastTimeWritten = new AtomicLong(0); 4537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false); 4637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe private final String mFileName; 4737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe private final String mBackgroundThreadName; 4837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe private final boolean mLock; 4937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 5037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe protected AbstractStatsBase(String fileName, String threadName, boolean lock) { 5137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe mFileName = fileName; 5237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe mBackgroundThreadName = threadName; 5337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe mLock = lock; 5437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 5537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 5637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe protected AtomicFile getFile() { 5737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe File dataDir = Environment.getDataDirectory(); 5837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe File systemDir = new File(dataDir, "system"); 5937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe File fname = new File(systemDir, mFileName); 6037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe return new AtomicFile(fname); 6137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 6237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 630318162abcbd07a0472989df43e00e353fac731bCalin Juravle protected void writeNow(final T data) { 6437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe writeImpl(data); 6537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe mLastTimeWritten.set(SystemClock.elapsedRealtime()); 6637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 6737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 680318162abcbd07a0472989df43e00e353fac731bCalin Juravle protected boolean maybeWriteAsync(final T data) { 6937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe if (SystemClock.elapsedRealtime() - mLastTimeWritten.get() < WRITE_INTERVAL_MS 7037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe && !PackageManagerService.DEBUG_DEXOPT) { 7137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe return false; 7237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 7337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 7437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe if (mBackgroundWriteRunning.compareAndSet(false, true)) { 7537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe new Thread(mBackgroundThreadName) { 7637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe @Override 7737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe public void run() { 7837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe try { 7937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe writeImpl(data); 8037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe mLastTimeWritten.set(SystemClock.elapsedRealtime()); 8137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } finally { 8237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe mBackgroundWriteRunning.set(false); 8337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 8437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 8537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe }.start(); 8637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe return true; 8737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 8837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 8937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe return false; 9037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 9137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 9237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe private void writeImpl(T data) { 9337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe if (mLock) { 9437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe synchronized (data) { 9537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe synchronized (mFileLock) { 9637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe writeInternal(data); 9737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 9837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 9937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } else { 10037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe synchronized (mFileLock) { 10137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe writeInternal(data); 10237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 10337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 10437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 10537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 10637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe protected abstract void writeInternal(T data); 10737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 1080318162abcbd07a0472989df43e00e353fac731bCalin Juravle protected void read(T data) { 10937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe if (mLock) { 11037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe synchronized (data) { 11137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe synchronized (mFileLock) { 11237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe readInternal(data); 11337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 11437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 11537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } else { 11637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe synchronized (mFileLock) { 11737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe readInternal(data); 11837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 11937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 12037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe // We use the current time as last-written. read() is called on system server startup 12137e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe // (current situation), and we want to postpone I/O at boot. 12237e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe mLastTimeWritten.set(SystemClock.elapsedRealtime()); 12337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe } 12437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe 12537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe protected abstract void readInternal(T data); 12637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe} 127