From 3836d735cab4b58e207fcdd95e85d27f414f7cd5 Mon Sep 17 00:00:00 2001 From: Stanislav Zholnin Date: Wed, 17 Mar 2021 08:24:10 +0000 Subject: [PATCH] Remove data from DiscreteRegistry for uninstalled packages. Refactoring and bug fixes. Bug: 176965672 Test: in development Change-Id: I6d3956df87e7a924cedb545d6f9eae3cfb41062b --- .../server/appop/DiscreteRegistry.java | 217 +++++++++++------- .../server/appop/HistoricalRegistry.java | 9 +- 2 files changed, 138 insertions(+), 88 deletions(-) diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java index 232005b7559b0..f2e422d3ee7cb 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.FileUtils; 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 @@ import java.util.List; */ 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 @@ final class DiscreteRegistry { } } - 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 @@ final class DiscreteRegistry { 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 @@ final class DiscreteRegistry { 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 @@ final class DiscreteRegistry { 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 @@ final class DiscreteRegistry { @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 @@ final class DiscreteRegistry { 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 @@ final class DiscreteRegistry { } } + 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 @@ final class DiscreteRegistry { } } - 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 @@ final class DiscreteRegistry { } out.endTag(null, TAG_HISTORY); out.endDocument(); - stream.close(); } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @@ -475,6 +446,60 @@ final class DiscreteRegistry { } } + 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 @@ final class DiscreteRegistry { } } + 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 @@ final class DiscreteRegistry { } 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 9ff54926df3a7..fcf82faca850e 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 @@ final class HistoricalRegistry { } 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 @@ final class HistoricalRegistry { 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 @@ final class HistoricalRegistry { mPersistence.clearHistoryDLocked(uid, packageName); } } + mDiscreteRegistry.clearHistory(uid, packageName); } void writeAndClearDiscreteHistory() {