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
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
index c42a718..d901179 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -29,25 +29,28 @@
import static com.google.common.truth.Truth.assertWithMessage;
import android.app.ActivityManager;
+import android.app.AppOpsManager;
import android.app.AppOpsManager.OpEntry;
import android.app.AppOpsManager.PackageOps;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
+import android.os.RemoteCallback;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.server.appop.AppOpsService;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Unit tests for AppOpsService. Covers functionality that is difficult to test using CTS tests
@@ -216,6 +219,45 @@
}
@Test
+ public void testPackageRemovedHistoricalOps() throws InterruptedException {
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+
+ AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000);
+ historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, mMyPackageName,
+ AppOpsManager.UID_STATE_PERSISTENT, 0, 1);
+
+ mAppOpsService.addHistoricalOps(historicalOps);
+
+ AtomicReference<AppOpsManager.HistoricalOps> resultOpsRef = new AtomicReference<>();
+ AtomicReference<CountDownLatch> 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);
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);