blob: 0053f588621a90a8afd79383912e3d9a64587bb3 [file] [log] [blame]
Andreas Gampe37e5fdc2016-07-12 22:42:41 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.pm;
18
19import android.os.Environment;
20import android.os.SystemClock;
21import android.util.AtomicFile;
22
23import java.io.File;
24import java.util.concurrent.atomic.AtomicBoolean;
25import java.util.concurrent.atomic.AtomicLong;
26
27/**
28 * A simple base class for statistics that need to be saved/restored from a dedicated file. This
29 * class provides a base implementation that:
30 * <ul>
31 * <li>Provide an AtomicFile to the actual read/write code
32 * <li>A background-thread write and a synchronous write
33 * <li>Write-limiting for the background-thread (by default writes are at least 30 minutes apart)
34 * <li>Can lock on the provided data object before writing
35 * </ul>
36 * For completion, a subclass needs to implement actual {@link #writeInternal(Object) writing} and
37 * {@link #readInternal(Object) reading}.
38 */
39public abstract class AbstractStatsBase<T> {
40
41 private static final int WRITE_INTERVAL_MS =
42 (PackageManagerService.DEBUG_DEXOPT) ? 0 : 30*60*1000;
43 private final Object mFileLock = new Object();
44 private final AtomicLong mLastTimeWritten = new AtomicLong(0);
45 private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
46 private final String mFileName;
47 private final String mBackgroundThreadName;
48 private final boolean mLock;
49
50 protected AbstractStatsBase(String fileName, String threadName, boolean lock) {
51 mFileName = fileName;
52 mBackgroundThreadName = threadName;
53 mLock = lock;
54 }
55
56 protected AtomicFile getFile() {
57 File dataDir = Environment.getDataDirectory();
58 File systemDir = new File(dataDir, "system");
59 File fname = new File(systemDir, mFileName);
60 return new AtomicFile(fname);
61 }
62
Calin Juravle03181622016-12-01 17:53:07 +000063 protected void writeNow(final T data) {
Andreas Gampe37e5fdc2016-07-12 22:42:41 -070064 writeImpl(data);
65 mLastTimeWritten.set(SystemClock.elapsedRealtime());
66 }
67
Calin Juravle03181622016-12-01 17:53:07 +000068 protected boolean maybeWriteAsync(final T data) {
Andreas Gampe37e5fdc2016-07-12 22:42:41 -070069 if (SystemClock.elapsedRealtime() - mLastTimeWritten.get() < WRITE_INTERVAL_MS
70 && !PackageManagerService.DEBUG_DEXOPT) {
71 return false;
72 }
73
74 if (mBackgroundWriteRunning.compareAndSet(false, true)) {
75 new Thread(mBackgroundThreadName) {
76 @Override
77 public void run() {
78 try {
79 writeImpl(data);
80 mLastTimeWritten.set(SystemClock.elapsedRealtime());
81 } finally {
82 mBackgroundWriteRunning.set(false);
83 }
84 }
85 }.start();
86 return true;
87 }
88
89 return false;
90 }
91
92 private void writeImpl(T data) {
93 if (mLock) {
94 synchronized (data) {
95 synchronized (mFileLock) {
96 writeInternal(data);
97 }
98 }
99 } else {
100 synchronized (mFileLock) {
101 writeInternal(data);
102 }
103 }
104 }
105
106 protected abstract void writeInternal(T data);
107
Calin Juravle03181622016-12-01 17:53:07 +0000108 protected void read(T data) {
Andreas Gampe37e5fdc2016-07-12 22:42:41 -0700109 if (mLock) {
110 synchronized (data) {
111 synchronized (mFileLock) {
112 readInternal(data);
113 }
114 }
115 } else {
116 synchronized (mFileLock) {
117 readInternal(data);
118 }
119 }
120 // We use the current time as last-written. read() is called on system server startup
121 // (current situation), and we want to postpone I/O at boot.
122 mLastTimeWritten.set(SystemClock.elapsedRealtime());
123 }
124
125 protected abstract void readInternal(T data);
126}