Merge "Remove data from DiscreteRegistry for uninstalled packages." into sc-dev
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index 232005b..f2e422d 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -44,6 +44,7 @@
import android.os.Process;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
+import android.util.AtomicFile;
import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -83,7 +84,7 @@
*/
final class DiscreteRegistry {
- static final String TIMELINE_FILE_SUFFIX = "tl";
+ static final String DISCRETE_HISTORY_FILE_SUFFIX = "tl";
private static final String TAG = DiscreteRegistry.class.getSimpleName();
private static final String PROPERTY_DISCRETE_HISTORY_CUTOFF = "discrete_history_cutoff_millis";
@@ -194,17 +195,6 @@
}
}
- private void createDiscreteAccessDir() {
- if (!mDiscreteAccessDir.exists()) {
- if (!mDiscreteAccessDir.mkdirs()) {
- Slog.e(TAG, "Failed to create DiscreteRegistry directory");
- }
- FileUtils.setPermissions(mDiscreteAccessDir.getPath(),
- FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
- }
- }
-
- /* can be called only after HistoricalRegistry.isPersistenceInitialized() check */
void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag,
@AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime,
long accessDuration) {
@@ -220,80 +210,34 @@
void writeAndClearAccessHistory() {
synchronized (mOnDiskLock) {
if (mDiscreteAccessDir == null) {
- Slog.e(TAG, "State not saved - persistence not initialized.");
+ Slog.d(TAG, "State not saved - persistence not initialized.");
return;
}
- final File[] files = mDiscreteAccessDir.listFiles();
- if (files != null && files.length > 0) {
- for (File f : files) {
- final String fileName = f.getName();
- if (!fileName.endsWith(TIMELINE_FILE_SUFFIX)) {
- continue;
- }
- try {
- long timestamp = Long.valueOf(fileName.substring(0,
- fileName.length() - TIMELINE_FILE_SUFFIX.length()));
- if (Instant.now().minus(sDiscreteHistoryCutoff,
- ChronoUnit.MILLIS).toEpochMilli() > timestamp) {
- f.delete();
- Slog.e(TAG, "Deleting file " + fileName);
-
- }
- } catch (Throwable t) {
- Slog.e(TAG, "Error while cleaning timeline files: " + t.getMessage() + " "
- + t.getStackTrace());
- }
- }
- }
DiscreteOps discreteOps;
synchronized (mInMemoryLock) {
discreteOps = mDiscreteOps;
mDiscreteOps = new DiscreteOps();
mCachedOps = null;
}
- if (discreteOps.isEmpty()) {
- return;
- }
- long currentTimeStamp = Instant.now().toEpochMilli();
- try {
- final File file = new File(mDiscreteAccessDir,
- currentTimeStamp + TIMELINE_FILE_SUFFIX);
- discreteOps.writeToFile(file);
- } catch (Throwable t) {
- Slog.e(TAG,
- "Error writing timeline state: " + t.getMessage() + " "
- + Arrays.toString(t.getStackTrace()));
+ deleteOldDiscreteHistoryFilesLocked();
+ if (!discreteOps.isEmpty()) {
+ persistDiscreteOpsLocked(discreteOps);
}
}
}
- void getHistoricalDiscreteOps(AppOpsManager.HistoricalOps result, long beginTimeMillis,
- long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
+ void addFilteredDiscreteOpsToHistoricalOps(AppOpsManager.HistoricalOps result,
+ long beginTimeMillis, long endTimeMillis,
+ @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
@Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
- DiscreteOps discreteOps = getAndCacheDiscreteOps();
+ DiscreteOps discreteOps = getAllDiscreteOps();
discreteOps.filter(beginTimeMillis, endTimeMillis, filter, uidFilter, packageNameFilter,
opNamesFilter, attributionTagFilter, flagsFilter);
discreteOps.applyToHistoricalOps(result);
return;
}
- private DiscreteOps getAndCacheDiscreteOps() {
- DiscreteOps discreteOps = new DiscreteOps();
-
- synchronized (mOnDiskLock) {
- synchronized (mInMemoryLock) {
- discreteOps.merge(mDiscreteOps);
- }
- if (mCachedOps == null) {
- mCachedOps = new DiscreteOps();
- readDiscreteOpsFromDisk(mCachedOps);
- }
- discreteOps.merge(mCachedOps);
- }
- return discreteOps;
- }
-
private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) {
synchronized (mOnDiskLock) {
long beginTimeMillis = Instant.now().minus(sDiscreteHistoryCutoff,
@@ -303,11 +247,11 @@
if (files != null && files.length > 0) {
for (File f : files) {
final String fileName = f.getName();
- if (!fileName.endsWith(TIMELINE_FILE_SUFFIX)) {
+ if (!fileName.endsWith(DISCRETE_HISTORY_FILE_SUFFIX)) {
continue;
}
long timestamp = Long.valueOf(fileName.substring(0,
- fileName.length() - TIMELINE_FILE_SUFFIX.length()));
+ fileName.length() - DISCRETE_HISTORY_FILE_SUFFIX.length()));
if (timestamp < beginTimeMillis) {
continue;
}
@@ -322,8 +266,19 @@
synchronized (mInMemoryLock) {
mDiscreteOps = new DiscreteOps();
}
- FileUtils.deleteContentsAndDir(mDiscreteAccessDir);
- createDiscreteAccessDir();
+ clearOnDiskHistoryLocked();
+ }
+ }
+
+ void clearHistory(int uid, String packageName) {
+ synchronized (mOnDiskLock) {
+ DiscreteOps discreteOps;
+ synchronized (mInMemoryLock) {
+ discreteOps = getAllDiscreteOps();
+ clearHistory();
+ }
+ discreteOps.clearHistory(uid, packageName);
+ persistDiscreteOpsLocked(discreteOps);
}
}
@@ -332,7 +287,7 @@
@AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp,
@NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix,
int nDiscreteOps) {
- DiscreteOps discreteOps = getAndCacheDiscreteOps();
+ DiscreteOps discreteOps = getAllDiscreteOps();
String[] opNamesFilter = dumpOp == OP_NONE ? null
: new String[]{AppOpsManager.opToPublicName(dumpOp)};
discreteOps.filter(0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter,
@@ -340,17 +295,26 @@
discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps);
}
- public static boolean isDiscreteOp(int op, int uid, @AppOpsManager.OpFlags int flags) {
- if (!ArrayUtils.contains(sDiscreteOps, op)) {
- return false;
+ private void clearOnDiskHistoryLocked() {
+ mCachedOps = null;
+ FileUtils.deleteContentsAndDir(mDiscreteAccessDir);
+ createDiscreteAccessDir();
+ }
+
+ private DiscreteOps getAllDiscreteOps() {
+ DiscreteOps discreteOps = new DiscreteOps();
+
+ synchronized (mOnDiskLock) {
+ synchronized (mInMemoryLock) {
+ discreteOps.merge(mDiscreteOps);
+ }
+ if (mCachedOps == null) {
+ mCachedOps = new DiscreteOps();
+ readDiscreteOpsFromDisk(mCachedOps);
+ }
+ discreteOps.merge(mCachedOps);
+ return discreteOps;
}
- if (uid < Process.FIRST_APPLICATION_UID) {
- return false;
- }
- if ((flags & (sDiscreteFlags)) == 0) {
- return false;
- }
- return true;
}
private final class DiscreteOps {
@@ -399,6 +363,15 @@
}
}
+ private void clearHistory(int uid, String packageName) {
+ if (mUids.containsKey(uid)) {
+ mUids.get(uid).clearPackage(packageName);
+ if (mUids.get(uid).isEmpty()) {
+ mUids.remove(uid);
+ }
+ }
+ }
+
private void applyToHistoricalOps(AppOpsManager.HistoricalOps result) {
int nUids = mUids.size();
for (int i = 0; i < nUids; i++) {
@@ -406,8 +379,7 @@
}
}
- private void writeToFile(File f) throws Exception {
- FileOutputStream stream = new FileOutputStream(f);
+ private void writeToStream(FileOutputStream stream) throws Exception {
TypedXmlSerializer out = Xml.resolveSerializer(stream);
out.startDocument(null, true);
@@ -423,7 +395,6 @@
}
out.endTag(null, TAG_HISTORY);
out.endDocument();
- stream.close();
}
private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf,
@@ -475,6 +446,60 @@
}
}
+ private void createDiscreteAccessDir() {
+ if (!mDiscreteAccessDir.exists()) {
+ if (!mDiscreteAccessDir.mkdirs()) {
+ Slog.e(TAG, "Failed to create DiscreteRegistry directory");
+ }
+ FileUtils.setPermissions(mDiscreteAccessDir.getPath(),
+ FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
+ }
+ }
+
+ private void persistDiscreteOpsLocked(DiscreteOps discreteOps) {
+ long currentTimeStamp = Instant.now().toEpochMilli();
+ final AtomicFile file = new AtomicFile(new File(mDiscreteAccessDir,
+ currentTimeStamp + DISCRETE_HISTORY_FILE_SUFFIX));
+ FileOutputStream stream = null;
+ try {
+ stream = file.startWrite();
+ discreteOps.writeToStream(stream);
+ file.finishWrite(stream);
+ } catch (Throwable t) {
+ Slog.e(TAG,
+ "Error writing timeline state: " + t.getMessage() + " "
+ + Arrays.toString(t.getStackTrace()));
+ if (stream != null) {
+ file.failWrite(stream);
+ }
+ }
+ }
+
+ private void deleteOldDiscreteHistoryFilesLocked() {
+ final File[] files = mDiscreteAccessDir.listFiles();
+ if (files != null && files.length > 0) {
+ for (File f : files) {
+ final String fileName = f.getName();
+ if (!fileName.endsWith(DISCRETE_HISTORY_FILE_SUFFIX)) {
+ continue;
+ }
+ try {
+ long timestamp = Long.valueOf(fileName.substring(0,
+ fileName.length() - DISCRETE_HISTORY_FILE_SUFFIX.length()));
+ if (Instant.now().minus(sDiscreteHistoryCutoff,
+ ChronoUnit.MILLIS).toEpochMilli() > timestamp) {
+ f.delete();
+ Slog.e(TAG, "Deleting file " + fileName);
+
+ }
+ } catch (Throwable t) {
+ Slog.e(TAG, "Error while cleaning timeline files: " + t.getMessage() + " "
+ + t.getStackTrace());
+ }
+ }
+ }
+ }
+
private void createDiscreteAccessDirLocked() {
if (!mDiscreteAccessDir.exists()) {
if (!mDiscreteAccessDir.mkdirs()) {
@@ -524,6 +549,10 @@
}
}
+ private void clearPackage(String packageName) {
+ mPackages.remove(packageName);
+ }
+
void addDiscreteAccess(int op, @NonNull String packageName, @Nullable String attributionTag,
@AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
long accessTime, long accessDuration) {
@@ -934,5 +963,25 @@
}
return result;
}
+
+ private static boolean isDiscreteOp(int op, int uid, @AppOpsManager.OpFlags int flags) {
+ if (!ArrayUtils.contains(sDiscreteOps, op)) {
+ return false;
+ }
+ if (!isDiscreteUid(uid)) {
+ return false;
+ }
+ if ((flags & (sDiscreteFlags)) == 0) {
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean isDiscreteUid(int uid) {
+ if (uid < Process.FIRST_APPLICATION_UID) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 9ff5492..fcf82fa 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -394,8 +394,8 @@
}
if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
- mDiscreteRegistry.getHistoricalDiscreteOps(result, beginTimeMillis, endTimeMillis,
- filter, uid, packageName, opNames, attributionTag,
+ mDiscreteRegistry.addFilteredDiscreteOpsToHistoricalOps(result, beginTimeMillis,
+ endTimeMillis, filter, uid, packageName, opNames, attributionTag,
flags);
}
@@ -428,8 +428,8 @@
inMemoryAdjEndTimeMillis);
if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
- mDiscreteRegistry.getHistoricalDiscreteOps(result, beginTimeMillis, endTimeMillis,
- filter, uid, packageName, opNames, attributionTag, flags);
+ mDiscreteRegistry.addFilteredDiscreteOpsToHistoricalOps(result, beginTimeMillis,
+ endTimeMillis, filter, uid, packageName, opNames, attributionTag, flags);
}
if ((historyFlags & HISTORY_FLAG_AGGREGATE) != 0) {
@@ -645,6 +645,7 @@
mPersistence.clearHistoryDLocked(uid, packageName);
}
}
+ mDiscreteRegistry.clearHistory(uid, packageName);
}
void writeAndClearDiscreteHistory() {