Merge "Disable binder caches in unit tests" into rvc-dev am: 9bca3a380d

Change-Id: I5c3f77f70b12ccf00909bca4f44249357c69f062
This commit is contained in:
Lee Shombert
2020-04-19 19:26:27 +00:00
committed by Automerger Merge Worker
3 changed files with 45 additions and 3 deletions

View File

@@ -25,6 +25,7 @@ import android.os.SystemProperties;
import android.util.Log; import android.util.Log;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -159,6 +160,13 @@ import java.util.concurrent.atomic.AtomicLong;
* this local case, there's no IPC, so use of the cache is (depending on exact * this local case, there's no IPC, so use of the cache is (depending on exact
* circumstance) unnecessary. * circumstance) unnecessary.
* *
* For security, there is a whitelist of processes that are allowed to invalidate a cache.
* The whitelist includes normal runtime processes but does not include test processes.
* Test processes must call {@code PropertyInvalidatedCache.disableForTestMode()} to disable
* all cache activity in that process.
*
* Caching can be disabled completely by initializing {@code sEnabled} to false and rebuilding.
*
* @param <Query> The class used to index cache entries: must be hashable and comparable * @param <Query> The class used to index cache entries: must be hashable and comparable
* @param <Result> The class holding cache entries; use a boxed primitive if possible * @param <Result> The class holding cache entries; use a boxed primitive if possible
* *
@@ -170,9 +178,14 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
private static final String TAG = "PropertyInvalidatedCache"; private static final String TAG = "PropertyInvalidatedCache";
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
private static final boolean ENABLE = true;
private static final boolean VERIFY = false; private static final boolean VERIFY = false;
/**
* If sEnabled is false then all cache operations are stubbed out. Set
* it to false inside test processes.
*/
private static boolean sEnabled = true;
private static final Object sCorkLock = new Object(); private static final Object sCorkLock = new Object();
/** /**
@@ -300,7 +313,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
* Return whether the cache is disabled in this process. * Return whether the cache is disabled in this process.
*/ */
public final boolean isDisabledLocal() { public final boolean isDisabledLocal() {
return mDisabled; return mDisabled || !sEnabled;
} }
/** /**
@@ -308,7 +321,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
*/ */
public Result query(Query query) { public Result query(Query query) {
// Let access to mDisabled race: it's atomic anyway. // Let access to mDisabled race: it's atomic anyway.
long currentNonce = (ENABLE && !mDisabled) ? getCurrentNonce() : NONCE_DISABLED; long currentNonce = (!isDisabledLocal()) ? getCurrentNonce() : NONCE_DISABLED;
for (;;) { for (;;) {
if (currentNonce == NONCE_DISABLED || currentNonce == NONCE_UNSET) { if (currentNonce == NONCE_DISABLED || currentNonce == NONCE_UNSET) {
if (DEBUG) { if (DEBUG) {
@@ -419,6 +432,9 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
* @param name Name of the cache-key property to invalidate * @param name Name of the cache-key property to invalidate
*/ */
public static void disableSystemWide(@NonNull String name) { public static void disableSystemWide(@NonNull String name) {
if (!sEnabled) {
return;
}
SystemProperties.set(name, Long.toString(NONCE_DISABLED)); SystemProperties.set(name, Long.toString(NONCE_DISABLED));
} }
@@ -437,6 +453,14 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
* @param name Name of the cache-key property to invalidate * @param name Name of the cache-key property to invalidate
*/ */
public static void invalidateCache(@NonNull String name) { public static void invalidateCache(@NonNull String name) {
if (!sEnabled) {
if (DEBUG) {
Log.w(TAG, String.format(
"cache invalidate %s suppressed", name));
}
return;
}
// Take the cork lock so invalidateCache() racing against corkInvalidations() doesn't // Take the cork lock so invalidateCache() racing against corkInvalidations() doesn't
// clobber a cork-written NONCE_UNSET with a cache key we compute before the cork. // clobber a cork-written NONCE_UNSET with a cache key we compute before the cork.
// The property service is single-threaded anyway, so we don't lose any concurrency by // The property service is single-threaded anyway, so we don't lose any concurrency by
@@ -676,4 +700,14 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
public String queryToString(Query query) { public String queryToString(Query query) {
return Objects.toString(query); return Objects.toString(query);
} }
/**
* Disable all caches in the local process. Once disabled it is not
* possible to re-enable caching in the current process.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public static void disableForTestMode() {
Log.d(TAG, "disabling all caches in the process");
sEnabled = false;
}
} }

View File

@@ -26,6 +26,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.PropertyInvalidatedCache;
import android.content.Context; import android.content.Context;
import android.hardware.display.BrightnessConfiguration; import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.Curve; import android.hardware.display.Curve;
@@ -120,6 +121,9 @@ public class DisplayManagerServiceTest {
LocalServices.addService(LightsManager.class, mMockLightsManager); LocalServices.addService(LightsManager.class, mMockLightsManager);
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
// Disable binder caches in this process.
PropertyInvalidatedCache.disableForTestMode();
} }
@Test @Test

View File

@@ -35,6 +35,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import android.app.PropertyInvalidatedCache;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@@ -98,6 +99,9 @@ public class UserSystemPackageInstallerTest {
if (Looper.myLooper() == null) { if (Looper.myLooper() == null) {
Looper.prepare(); Looper.prepare();
} }
// Disable binder caches in this process.
PropertyInvalidatedCache.disableForTestMode();
LocalServices.removeServiceForTest(UserManagerInternal.class); LocalServices.removeServiceForTest(UserManagerInternal.class);
UserManagerService ums = new UserManagerService(InstrumentationRegistry.getContext()); UserManagerService ums = new UserManagerService(InstrumentationRegistry.getContext());