From 4e3b435c0ee794790131f24dc8cd76cd9102510c Mon Sep 17 00:00:00 2001 From: Winson Date: Tue, 7 May 2019 16:29:59 -0700 Subject: DO NOT MERGE: Delete persisted historical app ops on package uninstall They're removed from the current state, but not the persisted state. This adds HistoricalRegistry#clearHistoryForPackage which reads the disk state, strips the corresponding UID/package, and re-writes to disk. Bug: 129796626 Test: manual test app with location access Test: atest AppOpsServiceTest#testPackageRemovedHistoricalOps Change-Id: I8daa2e3474b400a3789b2eaf178441c6d1578af1 --- core/java/android/app/AppOpsManager.java | 15 +++++++ .../com/android/server/appop/AppOpsService.java | 2 + .../android/server/appop/HistoricalRegistry.java | 35 ++++++++++++++++ services/tests/servicestests/AndroidManifest.xml | 1 + .../android/server/appop/AppOpsServiceTest.java | 46 +++++++++++++++++++++- 5 files changed, 97 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 713fd1cf6879..a29b8fe37448 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -3119,6 +3119,15 @@ public class AppOpsManager { return mHistoricalUidOps.get(uid); } + /** @hide */ + public void clearHistory(int uid, @NonNull String packageName) { + HistoricalUidOps historicalUidOps = getOrCreateHistoricalUidOps(uid); + historicalUidOps.clearHistory(packageName); + if (historicalUidOps.isEmpty()) { + mHistoricalUidOps.remove(uid); + } + } + @Override public int describeContents() { return 0; @@ -3396,6 +3405,12 @@ public class AppOpsManager { return mHistoricalPackageOps.get(packageName); } + private void clearHistory(@NonNull String packageName) { + if (mHistoricalPackageOps != null) { + mHistoricalPackageOps.remove(packageName); + } + } + @Override public int describeContents() { return 0; diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index d04aa8931dca..db7abf891d1e 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -905,6 +905,8 @@ public class AppOpsService extends IAppOpsService.Stub { } } } + + mHistoricalRegistry.clearHistory(uid, packageName); } } diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index d723c7b5826d..69a1c9f584cb 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -472,6 +472,25 @@ final class HistoricalRegistry { DEFAULT_COMPRESSION_STEP); } + void clearHistory(int uid, String packageName) { + synchronized (mOnDiskLock) { + synchronized (mInMemoryLock) { + if (mMode != AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) { + return; + } + + for (int index = 0; index < mPendingWrites.size(); index++) { + mPendingWrites.get(index).clearHistory(uid, packageName); + } + + getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis()) + .clearHistory(uid, packageName); + + mPersistence.clearHistoryDLocked(uid, packageName); + } + } + } + void clearHistory() { synchronized (mOnDiskLock) { clearHistoryOnDiskLocked(); @@ -628,6 +647,22 @@ final class HistoricalRegistry { return new File(baseDir, Long.toString(globalBeginMillis) + HISTORY_FILE_SUFFIX); } + void clearHistoryDLocked(int uid, String packageName) { + List historicalOps = readHistoryDLocked(); + + if (historicalOps == null) { + return; + } + + for (int index = 0; index < historicalOps.size(); index++) { + historicalOps.get(index).clearHistory(uid, packageName); + } + + clearHistoryDLocked(); + + persistHistoricalOpsDLocked(historicalOps); + } + void clearHistoryDLocked() { mHistoricalAppOpsDir.delete(); } diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 01f2f6b26415..25bd4ec489a9 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -69,6 +69,7 @@ + resultOpsRef = new AtomicReference<>(); + AtomicReference latchRef = new AtomicReference<>(new CountDownLatch(1)); + RemoteCallback callback = new RemoteCallback(result -> { + resultOpsRef.set(result.getParcelable(AppOpsManager.KEY_HISTORICAL_OPS)); + latchRef.get().countDown(); + }); + + // First, do a fetch to ensure it's written + mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0, + callback); + + latchRef.get().await(5, TimeUnit.SECONDS); + assertThat(latchRef.get().getCount()).isEqualTo(0); + assertThat(resultOpsRef.get().isEmpty()).isFalse(); + + // Then, check it's deleted on removal + mAppOpsService.packageRemoved(mMyUid, mMyPackageName); + + latchRef.set(new CountDownLatch(1)); + + mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0, + callback); + + latchRef.get().await(5, TimeUnit.SECONDS); + assertThat(latchRef.get().getCount()).isEqualTo(0); + assertThat(resultOpsRef.get().isEmpty()).isTrue(); + } + @Test public void testUidRemoved() { mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); -- cgit v1.2.3-59-g8ed1b