[DO NOT MERGE] Handle config override via settings correctly

am: dc0f443cb6

Change-Id: Ifd39caee9a0dcea1314a3559a69d29ae08f1ce03
This commit is contained in:
Svet Ganov
2019-06-06 11:39:22 -07:00
committed by android-build-merger
3 changed files with 159 additions and 48 deletions

View File

@@ -201,7 +201,7 @@ public class AppOpsService extends IAppOpsService.Stub {
@VisibleForTesting @VisibleForTesting
final SparseArray<UidState> mUidStates = new SparseArray<>(); final SparseArray<UidState> mUidStates = new SparseArray<>();
private final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this); final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
long mLastRealtime; long mLastRealtime;

View File

@@ -108,6 +108,12 @@ import java.util.concurrent.TimeUnit;
* must be called with the mInMemoryLock, xxxDMLocked suffix means the method * must be called with the mInMemoryLock, xxxDMLocked suffix means the method
* must be called with the mOnDiskLock and mInMemoryLock locks acquired in that * must be called with the mOnDiskLock and mInMemoryLock locks acquired in that
* exact order. * exact order.
* <p>
* INITIALIZATION: We can initialize persistence only after the system is ready
* as we need to check the optional configuration override from the settings
* database which is not initialized at the time the app ops service is created.
* This means that all entry points that touch persistence should be short
* circuited via isPersistenceInitialized() check.
*/ */
// TODO (bug:122218838): Make sure we handle start of epoch time // TODO (bug:122218838): Make sure we handle start of epoch time
// TODO (bug:122218838): Validate changed time is handled correctly // TODO (bug:122218838): Validate changed time is handled correctly
@@ -177,14 +183,33 @@ final class HistoricalRegistry {
// Object managing persistence (read/write) // Object managing persistence (read/write)
@GuardedBy("mOnDiskLock") @GuardedBy("mOnDiskLock")
private Persistence mPersistence = new Persistence(mBaseSnapshotInterval, private Persistence mPersistence;
mIntervalCompressionMultiplier);
HistoricalRegistry(@NonNull Object lock) { HistoricalRegistry(@NonNull Object lock) {
mInMemoryLock = lock; mInMemoryLock = lock;
if (mMode != AppOpsManager.HISTORICAL_MODE_DISABLED) { }
synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) { void systemReady(@NonNull ContentResolver resolver) {
final Uri uri = Settings.Global.getUriFor(Settings.Global.APPOP_HISTORY_PARAMETERS);
resolver.registerContentObserver(uri, false, new ContentObserver(
FgThread.getHandler()) {
@Override
public void onChange(boolean selfChange) {
updateParametersFromSetting(resolver);
}
});
updateParametersFromSetting(resolver);
synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) {
if (mMode != AppOpsManager.HISTORICAL_MODE_DISABLED) {
// Can be uninitialized if there is no config in the settings table.
if (!isPersistenceInitializedMLocked()) {
mPersistence = new Persistence(mBaseSnapshotInterval,
mIntervalCompressionMultiplier);
}
// When starting always adjust history to now. // When starting always adjust history to now.
final long lastPersistTimeMills = final long lastPersistTimeMills =
mPersistence.getLastPersistTimeMillisDLocked(); mPersistence.getLastPersistTimeMillisDLocked();
@@ -197,16 +222,8 @@ final class HistoricalRegistry {
} }
} }
void systemReady(@NonNull ContentResolver resolver) { private boolean isPersistenceInitializedMLocked() {
updateParametersFromSetting(resolver); return mPersistence != null;
final Uri uri = Settings.Global.getUriFor(Settings.Global.APPOP_HISTORY_PARAMETERS);
resolver.registerContentObserver(uri, false, new ContentObserver(
FgThread.getHandler()) {
@Override
public void onChange(boolean selfChange) {
updateParametersFromSetting(resolver);
}
});
} }
private void updateParametersFromSetting(@NonNull ContentResolver resolver) { private void updateParametersFromSetting(@NonNull ContentResolver resolver) {
@@ -274,6 +291,11 @@ final class HistoricalRegistry {
makeRelativeToEpochStart(currentOps, nowMillis); makeRelativeToEpochStart(currentOps, nowMillis);
currentOps.accept(visitor); currentOps.accept(visitor);
if(isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
return;
}
final List<HistoricalOps> ops = mPersistence.readHistoryDLocked(); final List<HistoricalOps> ops = mPersistence.readHistoryDLocked();
if (ops != null) { if (ops != null) {
// TODO (bug:122218838): Make sure this is properly dumped // TODO (bug:122218838): Make sure this is properly dumped
@@ -302,12 +324,21 @@ final class HistoricalRegistry {
void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName, void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
@Nullable String[] opNames, long beginTimeMillis, long endTimeMillis, @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
@OpFlags int flags, @NonNull RemoteCallback callback) { @OpFlags int flags, @NonNull RemoteCallback callback) {
final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis); synchronized (mOnDiskLock) {
mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames, synchronized (mInMemoryLock) {
beginTimeMillis, endTimeMillis, flags); if (!isPersistenceInitializedMLocked()) {
final Bundle payload = new Bundle(); Slog.e(LOG_TAG, "Interaction before persistence initialized");
payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result); callback.sendResult(new Bundle());
callback.sendResult(payload); return;
}
final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
beginTimeMillis, endTimeMillis, flags);
final Bundle payload = new Bundle();
payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
callback.sendResult(payload);
}
}
} }
void getHistoricalOps(int uid, @NonNull String packageName, void getHistoricalOps(int uid, @NonNull String packageName,
@@ -331,6 +362,12 @@ final class HistoricalRegistry {
boolean collectOpsFromDisk; boolean collectOpsFromDisk;
synchronized (mInMemoryLock) { synchronized (mInMemoryLock) {
if (!isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
callback.sendResult(new Bundle());
return;
}
currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis); currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis() if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
|| inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) { || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
@@ -374,6 +411,10 @@ final class HistoricalRegistry {
@UidState int uidState, @OpFlags int flags) { @UidState int uidState, @OpFlags int flags) {
synchronized (mInMemoryLock) { synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) { if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
return;
}
getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis()) getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
.increaseAccessCount(op, uid, packageName, uidState, flags, 1); .increaseAccessCount(op, uid, packageName, uidState, flags, 1);
} }
@@ -384,6 +425,10 @@ final class HistoricalRegistry {
@UidState int uidState, @OpFlags int flags) { @UidState int uidState, @OpFlags int flags) {
synchronized (mInMemoryLock) { synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) { if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
return;
}
getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis()) getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
.increaseRejectCount(op, uid, packageName, uidState, flags, 1); .increaseRejectCount(op, uid, packageName, uidState, flags, 1);
} }
@@ -394,6 +439,10 @@ final class HistoricalRegistry {
@UidState int uidState, @OpFlags int flags, long increment) { @UidState int uidState, @OpFlags int flags, long increment) {
synchronized (mInMemoryLock) { synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) { if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
return;
}
getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis()) getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
.increaseAccessDuration(op, uid, packageName, uidState, flags, increment); .increaseAccessDuration(op, uid, packageName, uidState, flags, increment);
} }
@@ -404,6 +453,8 @@ final class HistoricalRegistry {
long baseSnapshotInterval, long intervalCompressionMultiplier) { long baseSnapshotInterval, long intervalCompressionMultiplier) {
synchronized (mOnDiskLock) { synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) { synchronized (mInMemoryLock) {
// NOTE: We allow this call if persistence is not initialized as
// it is a part of the persistence initialization process.
boolean resampleHistory = false; boolean resampleHistory = false;
Slog.i(LOG_TAG, "New history parameters: mode:" Slog.i(LOG_TAG, "New history parameters: mode:"
+ AppOpsManager.historicalModeToString(mMode) + " baseSnapshotInterval:" + AppOpsManager.historicalModeToString(mMode) + " baseSnapshotInterval:"
@@ -412,7 +463,7 @@ final class HistoricalRegistry {
if (mMode != mode) { if (mMode != mode) {
mMode = mode; mMode = mode;
if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) { if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) {
clearHistoryOnDiskLocked(); clearHistoryOnDiskDLocked();
} }
} }
if (mBaseSnapshotInterval != baseSnapshotInterval) { if (mBaseSnapshotInterval != baseSnapshotInterval) {
@@ -433,6 +484,10 @@ final class HistoricalRegistry {
void offsetHistory(long offsetMillis) { void offsetHistory(long offsetMillis) {
synchronized (mOnDiskLock) { synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) { synchronized (mInMemoryLock) {
if (!isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
return;
}
final List<HistoricalOps> history = mPersistence.readHistoryDLocked(); final List<HistoricalOps> history = mPersistence.readHistoryDLocked();
clearHistory(); clearHistory();
if (history != null) { if (history != null) {
@@ -453,6 +508,10 @@ final class HistoricalRegistry {
void addHistoricalOps(HistoricalOps ops) { void addHistoricalOps(HistoricalOps ops) {
final List<HistoricalOps> pendingWrites; final List<HistoricalOps> pendingWrites;
synchronized (mInMemoryLock) { synchronized (mInMemoryLock) {
if (!isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
return;
}
// The history files start from mBaseSnapshotInterval - take this into account. // The history files start from mBaseSnapshotInterval - take this into account.
ops.offsetBeginAndEndTime(mBaseSnapshotInterval); ops.offsetBeginAndEndTime(mBaseSnapshotInterval);
mPendingWrites.offerFirst(ops); mPendingWrites.offerFirst(ops);
@@ -468,6 +527,10 @@ final class HistoricalRegistry {
} }
void resetHistoryParameters() { void resetHistoryParameters() {
if (!isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
return;
}
setHistoryParameters(DEFAULT_MODE, DEFAULT_SNAPSHOT_INTERVAL_MILLIS, setHistoryParameters(DEFAULT_MODE, DEFAULT_SNAPSHOT_INTERVAL_MILLIS,
DEFAULT_COMPRESSION_STEP); DEFAULT_COMPRESSION_STEP);
} }
@@ -475,6 +538,10 @@ final class HistoricalRegistry {
void clearHistory(int uid, String packageName) { void clearHistory(int uid, String packageName) {
synchronized (mOnDiskLock) { synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) { synchronized (mInMemoryLock) {
if (!isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
return;
}
if (mMode != AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) { if (mMode != AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
return; return;
} }
@@ -493,18 +560,24 @@ final class HistoricalRegistry {
void clearHistory() { void clearHistory() {
synchronized (mOnDiskLock) { synchronized (mOnDiskLock) {
clearHistoryOnDiskLocked(); synchronized (mInMemoryLock) {
if (!isPersistenceInitializedMLocked()) {
Slog.e(LOG_TAG, "Interaction before persistence initialized");
return;
}
clearHistoryOnDiskDLocked();
}
} }
} }
private void clearHistoryOnDiskLocked() { private void clearHistoryOnDiskDLocked() {
BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY); BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);
synchronized (mInMemoryLock) { synchronized (mInMemoryLock) {
mCurrentHistoricalOps = null; mCurrentHistoricalOps = null;
mNextPersistDueTimeMillis = System.currentTimeMillis(); mNextPersistDueTimeMillis = System.currentTimeMillis();
mPendingWrites.clear(); mPendingWrites.clear();
} }
mPersistence.clearHistoryDLocked(); Persistence.clearHistoryDLocked();
} }
private @NonNull HistoricalOps getUpdatedPendingHistoricalOpsMLocked(long now) { private @NonNull HistoricalOps getUpdatedPendingHistoricalOpsMLocked(long now) {
@@ -639,7 +712,7 @@ final class HistoricalRegistry {
mIntervalCompressionMultiplier = intervalCompressionMultiplier; mIntervalCompressionMultiplier = intervalCompressionMultiplier;
} }
private final AtomicDirectory mHistoricalAppOpsDir = new AtomicDirectory( private static final AtomicDirectory sHistoricalAppOpsDir = new AtomicDirectory(
new File(new File(Environment.getDataSystemDirectory(), "appops"), "history")); new File(new File(Environment.getDataSystemDirectory(), "appops"), "history"));
private File generateFile(@NonNull File baseDir, int depth) { private File generateFile(@NonNull File baseDir, int depth) {
@@ -663,8 +736,8 @@ final class HistoricalRegistry {
persistHistoricalOpsDLocked(historicalOps); persistHistoricalOpsDLocked(historicalOps);
} }
void clearHistoryDLocked() { static void clearHistoryDLocked() {
mHistoricalAppOpsDir.delete(); sHistoricalAppOpsDir.delete();
} }
void persistHistoricalOpsDLocked(@NonNull List<HistoricalOps> ops) { void persistHistoricalOpsDLocked(@NonNull List<HistoricalOps> ops) {
@@ -673,8 +746,8 @@ final class HistoricalRegistry {
enforceOpsWellFormed(ops); enforceOpsWellFormed(ops);
} }
try { try {
final File newBaseDir = mHistoricalAppOpsDir.startWrite(); final File newBaseDir = sHistoricalAppOpsDir.startWrite();
final File oldBaseDir = mHistoricalAppOpsDir.getBackupDirectory(); final File oldBaseDir = sHistoricalAppOpsDir.getBackupDirectory();
final HistoricalFilesInvariant filesInvariant; final HistoricalFilesInvariant filesInvariant;
if (DEBUG) { if (DEBUG) {
filesInvariant = new HistoricalFilesInvariant(); filesInvariant = new HistoricalFilesInvariant();
@@ -686,10 +759,10 @@ final class HistoricalRegistry {
if (DEBUG) { if (DEBUG) {
filesInvariant.stopTracking(newBaseDir); filesInvariant.stopTracking(newBaseDir);
} }
mHistoricalAppOpsDir.finishWrite(); sHistoricalAppOpsDir.finishWrite();
} catch (Throwable t) { } catch (Throwable t) {
wtf("Failed to write historical app ops, restoring backup", t, null); wtf("Failed to write historical app ops, restoring backup", t, null);
mHistoricalAppOpsDir.failWrite(); sHistoricalAppOpsDir.failWrite();
} }
} }
@@ -715,22 +788,36 @@ final class HistoricalRegistry {
long getLastPersistTimeMillisDLocked() { long getLastPersistTimeMillisDLocked() {
File baseDir = null; File baseDir = null;
try { try {
baseDir = mHistoricalAppOpsDir.startRead(); baseDir = sHistoricalAppOpsDir.startRead();
final File[] files = baseDir.listFiles(); final File[] files = baseDir.listFiles();
if (files != null && files.length > 0) { if (files != null && files.length > 0) {
final Set<File> historyFiles = new ArraySet<>(); File shortestFile = null;
Collections.addAll(historyFiles, files); for (File candidate : files) {
for (int i = 0;; i++) { final String candidateName = candidate.getName();
final File file = generateFile(baseDir, i); if (!candidateName.endsWith(HISTORY_FILE_SUFFIX)) {
if (historyFiles.contains(file)) { continue;
return file.lastModified(); }
if (shortestFile == null) {
shortestFile = candidate;
} else if (candidateName.length() < shortestFile.getName().length()) {
shortestFile = candidate;
} }
} }
if (shortestFile == null) {
return 0;
}
final String shortestNameNoExtension = shortestFile.getName()
.replace(HISTORY_FILE_SUFFIX, "");
try {
return Long.parseLong(shortestNameNoExtension);
} catch (NumberFormatException e) {
return 0;
}
} }
mHistoricalAppOpsDir.finishRead(); sHistoricalAppOpsDir.finishRead();
} catch (Throwable e) { } catch (Throwable e) {
wtf("Error reading historical app ops. Deleting history.", e, baseDir); wtf("Error reading historical app ops. Deleting history.", e, baseDir);
mHistoricalAppOpsDir.delete(); sHistoricalAppOpsDir.delete();
} }
return 0; return 0;
} }
@@ -755,7 +842,7 @@ final class HistoricalRegistry {
long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags) { long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags) {
File baseDir = null; File baseDir = null;
try { try {
baseDir = mHistoricalAppOpsDir.startRead(); baseDir = sHistoricalAppOpsDir.startRead();
final HistoricalFilesInvariant filesInvariant; final HistoricalFilesInvariant filesInvariant;
if (DEBUG) { if (DEBUG) {
filesInvariant = new HistoricalFilesInvariant(); filesInvariant = new HistoricalFilesInvariant();
@@ -770,11 +857,11 @@ final class HistoricalRegistry {
if (DEBUG) { if (DEBUG) {
filesInvariant.stopTracking(baseDir); filesInvariant.stopTracking(baseDir);
} }
mHistoricalAppOpsDir.finishRead(); sHistoricalAppOpsDir.finishRead();
return ops; return ops;
} catch (Throwable t) { } catch (Throwable t) {
wtf("Error reading historical app ops. Deleting history.", t, baseDir); wtf("Error reading historical app ops. Deleting history.", t, baseDir);
mHistoricalAppOpsDir.delete(); sHistoricalAppOpsDir.delete();
} }
return null; return null;
} }
@@ -1241,7 +1328,7 @@ final class HistoricalRegistry {
private void writeHistoricalOpsDLocked(@Nullable List<HistoricalOps> allOps, private void writeHistoricalOpsDLocked(@Nullable List<HistoricalOps> allOps,
long intervalOverflowMillis, @NonNull File file) throws IOException { long intervalOverflowMillis, @NonNull File file) throws IOException {
final FileOutputStream output = mHistoricalAppOpsDir.openWrite(file); final FileOutputStream output = sHistoricalAppOpsDir.openWrite(file);
try { try {
final XmlSerializer serializer = Xml.newSerializer(); final XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(output, StandardCharsets.UTF_8.name()); serializer.setOutput(output, StandardCharsets.UTF_8.name());
@@ -1263,9 +1350,9 @@ final class HistoricalRegistry {
} }
serializer.endTag(null, TAG_HISTORY); serializer.endTag(null, TAG_HISTORY);
serializer.endDocument(); serializer.endDocument();
mHistoricalAppOpsDir.closeWrite(output); sHistoricalAppOpsDir.closeWrite(output);
} catch (IOException e) { } catch (IOException e) {
mHistoricalAppOpsDir.failWrite(output); sHistoricalAppOpsDir.failWrite(output);
throw e; throw e;
} }
} }

View File

@@ -37,12 +37,15 @@ import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Process; import android.os.Process;
import android.os.RemoteCallback; import android.os.RemoteCallback;
import android.provider.Settings;
import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -68,11 +71,14 @@ public class AppOpsServiceTest {
private File mAppOpsFile; private File mAppOpsFile;
private Context mContext; private Context mContext;
private Handler mHandler; private Handler mHandler;
private AppOpsManager mAppOpsManager;
private AppOpsService mAppOpsService; private AppOpsService mAppOpsService;
private String mMyPackageName; private String mMyPackageName;
private int mMyUid; private int mMyUid;
private long mTestStartMillis; private long mTestStartMillis;
private static String sDefaultAppopHistoryParameters;
@Before @Before
public void setUp() { public void setUp() {
mContext = InstrumentationRegistry.getTargetContext(); mContext = InstrumentationRegistry.getTargetContext();
@@ -88,11 +94,29 @@ public class AppOpsServiceTest {
mMyPackageName = mContext.getOpPackageName(); mMyPackageName = mContext.getOpPackageName();
mMyUid = Process.myUid(); mMyUid = Process.myUid();
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
mAppOpsService.mHistoricalRegistry.systemReady(mContext.getContentResolver());
mAppOpsService.mContext = mContext; mAppOpsService.mContext = mContext;
mTestStartMillis = System.currentTimeMillis(); mTestStartMillis = System.currentTimeMillis();
} }
@BeforeClass
public static void configureDesiredAppopHistoryParameters() {
final Context context = InstrumentationRegistry.getTargetContext();
sDefaultAppopHistoryParameters = Settings.Global.getString(context.getContentResolver(),
Settings.Global.APPOP_HISTORY_PARAMETERS);
Settings.Global.putString(InstrumentationRegistry.getTargetContext().getContentResolver(),
Settings.Global.APPOP_HISTORY_PARAMETERS, null);
}
@AfterClass
public static void restoreDefaultAppopHistoryParameters() {
Settings.Global.putString(InstrumentationRegistry.getTargetContext().getContentResolver(),
Settings.Global.APPOP_HISTORY_PARAMETERS,
sDefaultAppopHistoryParameters);
}
@Test @Test
public void testGetOpsForPackage_noOpsLogged() { public void testGetOpsForPackage_noOpsLogged() {
assertThat(getLoggedOps()).isNull(); assertThat(getLoggedOps()).isNull();