summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Winson <chiuwinson@google.com> 2019-05-07 16:29:59 -0700
committer Winson Chiu <chiuwinson@google.com> 2019-05-10 19:24:02 +0000
commit4e3b435c0ee794790131f24dc8cd76cd9102510c (patch)
tree6ec2371bb75a8f5053d372bf494bc47e8a6b301c
parent8197beee185717aa29d96448cd1f29f4dc76e3b6 (diff)
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
-rw-r--r--core/java/android/app/AppOpsManager.java15
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java2
-rw-r--r--services/core/java/com/android/server/appop/HistoricalRegistry.java35
-rw-r--r--services/tests/servicestests/AndroidManifest.xml1
-rw-r--r--services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java46
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> 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 @@
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
+ <uses-permission android:name="android.permission.MANAGE_APPOPS"/>
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
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 c42a71858f26..d90117905de6 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.assertThat;
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 @@ public class AppOpsServiceTest {
}
@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);