Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80f4322b authored by Lee Shombert's avatar Lee Shombert
Browse files

Clean up PropertyInvalidatedCache for SystemApi

Bug: 152453213
Tag: #refactor

This commit prepares PropertyInvalidatedCache to function as a system
api.  The changes may be summarized as follows:

 1. Visibility changes - some formerly protected or public methods are
    now private.

 2. Use of ParcelFileDescriptor instead of FileDescriptor.

 3. Null-ness annotations have been added to public methods.

 4. An onTrimMemory() method has been created that hides some class
    internals from ActivityThread.

An existing test (os/PropertyInvalidatedCacheTest) has been deleted.
Its contents have been merged into app/PropertyInvalidatedCacheTests.
The deleted test may never have been used.

Test: atest PropertyInvalidatedCacheTests

Change-Id: I619e715c3deca016b21c69bf34a8e61771957e68
parent f2af4d99
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -1646,7 +1646,7 @@ public final class ActivityThread extends ClientTransactionHandler

        @Override
        public void dumpCacheInfo(ParcelFileDescriptor pfd, String[] args) {
            PropertyInvalidatedCache.dumpCacheInfo(pfd.getFileDescriptor(), args);
            PropertyInvalidatedCache.dumpCacheInfo(pfd, args);
            IoUtils.closeQuietly(pfd);
        }

@@ -6378,9 +6378,7 @@ public final class ActivityThread extends ClientTransactionHandler
        if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);

        if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
            for (PropertyInvalidatedCache pic : PropertyInvalidatedCache.getActiveCaches()) {
                pic.clear();
            }
            PropertyInvalidatedCache.onTrimMemory();
        }

        final ArrayList<ComponentCallbacks2> callbacks =
+73 −35
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
@@ -29,7 +30,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastPrintWriter;

import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
@@ -355,11 +355,12 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
    private final int mMaxEntries;

    /**
     * Make a new property invalidated cache.
     * Make a new property invalidated cache.  This constructor names the cache after the
     * property name.  New clients should prefer the constructor that takes an explicit
     * cache name.
     *
     * @param maxEntries Maximum number of entries to cache; LRU discard
     * @param propertyName Name of the system property holding the cache invalidation nonce
     * Defaults the cache name to the property name.
     * @param propertyName Name of the system property holding the cache invalidation nonce.
     */
    public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
        this(maxEntries, propertyName, propertyName);
@@ -418,7 +419,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
     * Enable or disable testing.  The testing property map is cleared every time this
     * method is called.
     */
    @VisibleForTesting
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public static void setTestMode(boolean mode) {
        sTesting = mode;
        synchronized (sTestingPropertyMap) {
@@ -430,8 +431,8 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
     * Enable testing the specific cache key.  Only keys in the map are subject to testing.
     * There is no method to stop testing a property name.  Just disable the test mode.
     */
    @VisibleForTesting
    public static void testPropertyName(String name) {
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public static void testPropertyName(@NonNull String name) {
        synchronized (sTestingPropertyMap) {
            sTestingPropertyMap.put(name, (long) NONCE_UNSET);
        }
@@ -505,21 +506,23 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
     * block. If this function returns null, the result of the cache query is null. There is no
     * "negative cache" in the query: we don't cache null results at all.
     */
    public abstract Result recompute(Query query);
    public abstract @NonNull Result recompute(@NonNull Query query);

    /**
     * Return true if the query should bypass the cache.  The default behavior is to
     * always use the cache but the method can be overridden for a specific class.
     */
    public boolean bypass(Query query) {
    public boolean bypass(@NonNull Query query) {
        return false;
    }

    /**
     * Determines if a pair of responses are considered equal. Used to determine whether
     * a cache is inadvertently returning stale results when VERIFY is set to true.
     * Determines if a pair of responses are considered equal. Used to determine whether a
     * cache is inadvertently returning stale results when VERIFY is set to true.  Some
     * existing clients override this method, but it is now deprecated in favor of a valid
     * equals() method on the Result class.
     */
    protected boolean resultEquals(Result cachedResult, Result fetchedResult) {
    public boolean resultEquals(Result cachedResult, Result fetchedResult) {
        // If a service crashes and returns a null result, the cached value remains valid.
        if (fetchedResult != null) {
            return Objects.equals(cachedResult, fetchedResult);
@@ -544,8 +547,11 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
    }

    /**
     * Disable the use of this cache in this process.
     * Disable the use of this cache in this process.  This method is using during
     * testing.  To disable a cache in normal code, use disableLocal().
     * @hide
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public final void disableInstance() {
        synchronized (mLock) {
            mDisabled = true;
@@ -558,7 +564,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
     * using the key will be disabled now, and all future cache instances that use the key will be
     * disabled in their constructor.
     */
    public static final void disableLocal(@NonNull String name) {
    private static final void disableLocal(@NonNull String name) {
        synchronized (sCorkLock) {
            sDisabledKeys.add(name);
            for (PropertyInvalidatedCache cache : sCaches.keySet()) {
@@ -569,8 +575,22 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
        }
    }

    /**
     * Stop disabling local caches with a particular name.  Any caches that are currently
     * disabled remain disabled (the "disabled" setting is sticky).  However, new caches
     * with this name will not be disabled.  It is not an error if the cache name is not
     * found in the list of disabled caches.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public final void clearDisableLocal() {
        synchronized (sCorkLock) {
            sDisabledKeys.remove(mCacheName);
        }
    }

    /**
     * Disable this cache in the current process, and all other caches that use the same
     * name.  This does not affect caches that have a different name but use the same
     * property.
     */
    public final void disableLocal() {
@@ -580,6 +600,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
    /**
     * Return whether the cache is disabled in this process.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public final boolean isDisabledLocal() {
        return mDisabled || !sEnabled;
    }
@@ -587,7 +608,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
    /**
     * Get a value from the cache or recompute it.
     */
    public Result query(Query query) {
    public @NonNull Result query(@NonNull Query query) {
        // Let access to mDisabled race: it's atomic anyway.
        long currentNonce = (!isDisabledLocal()) ? getCurrentNonce() : NONCE_DISABLED;
        if (bypass(query)) {
@@ -704,6 +725,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
     * the cache objects to invalidate all of the cache objects becomes confusing and you should
     * just use the static version of this function.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public final void disableSystemWide() {
        disableSystemWide(mPropertyName);
    }
@@ -714,7 +736,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
     *
     * @param name Name of the cache-key property to invalidate
     */
    public static void disableSystemWide(@NonNull String name) {
    private static void disableSystemWide(@NonNull String name) {
        if (!sEnabled) {
            return;
        }
@@ -784,8 +806,8 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
                    "invalidating cache [%s]: [%s] -> [%s]",
                    name, nonce, Long.toString(newValue)));
        }
        // TODO(dancol): add an atomic compare and exchange property set operation to avoid a
        // small race with concurrent disable here.
        // There is a small race with concurrent disables here.  A compare-and-exchange
        // property operation would be required to eliminate the race condition.
        setNonce(name, newValue);
        long invalidateCount = sInvalidates.getOrDefault(name, (long) 0);
        sInvalidates.put(name, ++invalidateCount);
@@ -990,6 +1012,10 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
        }
    }

    /**
     * Return the result generated by a given query to the cache, performing debugging checks when
     * enabled.
     */
    private Result maybeCheckConsistency(Query query, Result proposedResult) {
        if (VERIFY) {
            Result resultToCompare = recompute(query);
@@ -1007,24 +1033,27 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
    }

    /**
     * Return the name of the cache, to be used in debug messages.  The
     * method is public so clients can use it.
     * Return the name of the cache, to be used in debug messages.
     */
    public String cacheName() {
    private final @NonNull String cacheName() {
        return mCacheName;
    }

    /**
     * Return the query as a string, to be used in debug messages.  The
     * method is public so clients can use it in external debug messages.
     * Return the query as a string, to be used in debug messages.  New clients should not
     * override this, but should instead add the necessary toString() method to the Query
     * class.
     */
    public String queryToString(Query query) {
    protected @NonNull String queryToString(@NonNull Query 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.
     * Disable all caches in the local process.  This is primarily useful for testing when
     * the test needs to bypass the cache or when the test is for a server, and the test
     * process does not have privileges to write SystemProperties. Once disabled it is not
     * possible to re-enable caching in the current process.  If a client wants to
     * temporarily disable caching, use the corking mechanism.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public static void disableForTestMode() {
@@ -1044,7 +1073,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
    /**
     * Returns a list of caches alive at the current time.
     */
    public static ArrayList<PropertyInvalidatedCache> getActiveCaches() {
    private static @NonNull ArrayList<PropertyInvalidatedCache> getActiveCaches() {
        synchronized (sCorkLock) {
            return new ArrayList<PropertyInvalidatedCache>(sCaches.keySet());
        }
@@ -1053,7 +1082,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
    /**
     * Returns a list of the active corks in a process.
     */
    public static ArrayList<Map.Entry<String, Integer>> getActiveCorks() {
    private static @NonNull ArrayList<Map.Entry<String, Integer>> getActiveCorks() {
        synchronized (sCorkLock) {
            return new ArrayList<Map.Entry<String, Integer>>(sCorks.entrySet());
        }
@@ -1104,14 +1133,14 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
    }

    /**
     * Dumps contents of every cache in the process to the provided FileDescriptor.
     * Dumps the contents of every cache in the process to the provided ParcelFileDescriptor.
     */
    public static void dumpCacheInfo(FileDescriptor fd, String[] args) {
    public static void dumpCacheInfo(@NonNull ParcelFileDescriptor pfd, @NonNull String[] args) {
        ArrayList<PropertyInvalidatedCache> activeCaches;
        ArrayList<Map.Entry<String, Integer>> activeCorks;

        try  (
            FileOutputStream fout = new FileOutputStream(fd);
            FileOutputStream fout = new FileOutputStream(pfd.getFileDescriptor());
            PrintWriter pw = new FastPrintWriter(fout);
        ) {
            if (!sEnabled) {
@@ -1142,4 +1171,13 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
            Log.e(TAG, "Failed to dump PropertyInvalidatedCache instances");
        }
    }

    /**
     * Trim memory by clearing all the caches.
     */
    public static void onTrimMemory() {
        for (PropertyInvalidatedCache pic : getActiveCaches()) {
            pic.clear();
        }
    }
}
+165 −2
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package android.app;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;

import androidx.test.filters.SmallTest;

@@ -25,7 +27,9 @@ import org.junit.Test;

/**
 * Test for verifying the behavior of {@link PropertyInvalidatedCache}.  This test does
 * not use any actual binder calls - it is entirely self-contained.
 * not use any actual binder calls - it is entirely self-contained.  This test also relies
 * on the test mode of {@link PropertyInvalidatedCache} because Android SELinux rules do
 * not grant test processes the permission to set system properties.
 * <p>
 * Build/Install/Run:
 *  atest FrameworksCoreTests:PropertyInvalidatedCacheTests
@@ -33,6 +37,8 @@ import org.junit.Test;
@SmallTest
public class PropertyInvalidatedCacheTests {

    // This property is never set.  The test process does not have permission to set any
    // properties.
    static final String CACHE_PROPERTY = "cache_key.cache_test_a";

    // This class is a proxy for binder calls.  It contains a counter that increments
@@ -58,7 +64,8 @@ public class PropertyInvalidatedCacheTests {
        }
    }

    // Clear the test mode after every test, in case this process is used for other tests.
    // Clear the test mode after every test, in case this process is used for other
    // tests. This also resets the test property map.
    @After
    public void tearDown() throws Exception {
        PropertyInvalidatedCache.setTestMode(false);
@@ -176,5 +183,161 @@ public class PropertyInvalidatedCacheTests {
                    }
                };
        assertEquals(true, cache1.getDisabledState());

        // Remove the record of caches being locally disabled.  This is a clean-up step.
        cache1.clearDisableLocal();
        assertEquals(true, cache1.getDisabledState());
        assertEquals(true, cache2.getDisabledState());
        assertEquals(false, cache3.getDisabledState());

        // Create a new cache1.  Verify that the new instance is not disabled.
        cache1 = new PropertyInvalidatedCache<>(4, CACHE_PROPERTY) {
                    @Override
                    public Boolean recompute(Integer x) {
                        return tester.query(x);
                    }
                };
        assertEquals(false, cache1.getDisabledState());
    }

    private static final String UNSET_KEY = "Aiw7woh6ie4toh7W";

    private static class TestCache extends PropertyInvalidatedCache<Integer, String> {
        TestCache() {
            this(CACHE_PROPERTY);
        }

        TestCache(String key) {
            super(4, key);
            setTestMode(true);
            testPropertyName(key);
        }

        @Override
        public String recompute(Integer qv) {
            mRecomputeCount += 1;
            return "foo" + qv.toString();
        }

        int getRecomputeCount() {
            return mRecomputeCount;
        }

        private int mRecomputeCount = 0;
    }

    @Test
    public void testCacheRecompute() {
        TestCache cache = new TestCache();
        cache.invalidateCache();
        assertEquals(cache.isDisabledLocal(), false);
        assertEquals("foo5", cache.query(5));
        assertEquals(1, cache.getRecomputeCount());
        assertEquals("foo5", cache.query(5));
        assertEquals(1, cache.getRecomputeCount());
        assertEquals("foo6", cache.query(6));
        assertEquals(2, cache.getRecomputeCount());
        cache.invalidateCache();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(3, cache.getRecomputeCount());
    }

    @Test
    public void testCacheInitialState() {
        TestCache cache = new TestCache();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(2, cache.getRecomputeCount());
        cache.invalidateCache();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(3, cache.getRecomputeCount());
    }

    @Test
    public void testCachePropertyUnset() {
        TestCache cache = new TestCache(UNSET_KEY);
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(2, cache.getRecomputeCount());
    }

    @Test
    public void testCacheDisableState() {
        TestCache cache = new TestCache();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(2, cache.getRecomputeCount());
        cache.invalidateCache();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(3, cache.getRecomputeCount());
        cache.disableSystemWide();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(5, cache.getRecomputeCount());
        cache.invalidateCache();  // Should not reenable
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(7, cache.getRecomputeCount());
    }

    @Test
    public void testRefreshSameObject() {
        int[] refreshCount = new int[1];
        TestCache cache = new TestCache() {
            @Override
            public String refresh(String oldResult, Integer query) {
                refreshCount[0] += 1;
                return oldResult;
            }
        };
        cache.invalidateCache();
        String result1 = cache.query(5);
        assertEquals("foo5", result1);
        String result2 = cache.query(5);
        assertSame(result1, result2);
        assertEquals(1, cache.getRecomputeCount());
        assertEquals(1, refreshCount[0]);
        assertEquals("foo5", cache.query(5));
        assertEquals(2, refreshCount[0]);
    }

    @Test
    public void testRefreshInvalidateRace() {
        int[] refreshCount = new int[1];
        TestCache cache = new TestCache() {
            @Override
            public String refresh(String oldResult, Integer query) {
                refreshCount[0] += 1;
                invalidateCache();
                return new String(oldResult);
            }
        };
        cache.invalidateCache();
        String result1 = cache.query(5);
        assertEquals("foo5", result1);
        String result2 = cache.query(5);
        assertEquals(result1, result2);
        assertNotSame(result1, result2);
        assertEquals(2, cache.getRecomputeCount());
    }

    @Test
    public void testLocalProcessDisable() {
        TestCache cache = new TestCache();
        assertEquals(cache.isDisabledLocal(), false);
        cache.invalidateCache();
        assertEquals("foo5", cache.query(5));
        assertEquals(1, cache.getRecomputeCount());
        assertEquals("foo5", cache.query(5));
        assertEquals(1, cache.getRecomputeCount());
        assertEquals(cache.isDisabledLocal(), false);
        cache.disableLocal();
        assertEquals(cache.isDisabledLocal(), true);
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(3, cache.getRecomputeCount());
    }
}
+0 −168
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

import android.app.PropertyInvalidatedCache;
import android.test.suitebuilder.annotation.SmallTest;

import junit.framework.TestCase;

public class PropertyInvalidatedCacheTest extends TestCase {
    private static final String KEY = "sys.testkey";
    private static final String UNSET_KEY = "Aiw7woh6ie4toh7W";

    private static class TestCache extends PropertyInvalidatedCache<Integer, String> {
        TestCache() {
            this(KEY);
        }

        TestCache(String key) {
            super(4, key);
        }

        @Override
        public String recompute(Integer qv) {
            mRecomputeCount += 1;
            return "foo" + qv.toString();
        }

        int getRecomputeCount() {
            return mRecomputeCount;
        }

        private int mRecomputeCount = 0;
    }

    @Override
    protected void setUp() {
        SystemProperties.set(KEY, "");
    }

    @SmallTest
    public void testCacheRecompute() throws Exception {
        TestCache cache = new TestCache();
        cache.invalidateCache();
        assertEquals("foo5", cache.query(5));
        assertEquals(1, cache.getRecomputeCount());
        assertEquals("foo5", cache.query(5));
        assertEquals(1, cache.getRecomputeCount());
        assertEquals("foo6", cache.query(6));
        assertEquals(2, cache.getRecomputeCount());
        cache.invalidateCache();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(3, cache.getRecomputeCount());
    }

    @SmallTest
    public void testCacheInitialState() throws Exception {
        TestCache cache = new TestCache();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(2, cache.getRecomputeCount());
        cache.invalidateCache();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(3, cache.getRecomputeCount());
    }

    @SmallTest
    public void testCachePropertyUnset() throws Exception {
        TestCache cache = new TestCache(UNSET_KEY);
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(2, cache.getRecomputeCount());
    }

    @SmallTest
    public void testCacheDisableState() throws Exception {
        TestCache cache = new TestCache();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(2, cache.getRecomputeCount());
        cache.invalidateCache();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(3, cache.getRecomputeCount());
        cache.disableSystemWide();
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(5, cache.getRecomputeCount());
        cache.invalidateCache();  // Should not reenable
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(7, cache.getRecomputeCount());
    }

    @SmallTest
    public void testRefreshSameObject() throws Exception {
        int[] refreshCount = new int[1];
        TestCache cache = new TestCache() {
            @Override
            protected String refresh(String oldResult, Integer query) {
                refreshCount[0] += 1;
                return oldResult;
            }
        };
        cache.invalidateCache();
        String result1 = cache.query(5);
        assertEquals("foo5", result1);
        String result2 = cache.query(5);
        assertSame(result1, result2);
        assertEquals(1, cache.getRecomputeCount());
        assertEquals(1, refreshCount[0]);
        assertEquals("foo5", cache.query(5));
        assertEquals(2, refreshCount[0]);
    }

    @SmallTest
    public void testRefreshInvalidateRace() throws Exception {
        int[] refreshCount = new int[1];
        TestCache cache = new TestCache() {
            @Override
            protected String refresh(String oldResult, Integer query) {
                refreshCount[0] += 1;
                invalidateCache();
                return new String(oldResult);
            }
        };
        cache.invalidateCache();
        String result1 = cache.query(5);
        assertEquals("foo5", result1);
        String result2 = cache.query(5);
        assertEquals(result1, result2);
        assertNotSame(result1, result2);
        assertEquals(2, cache.getRecomputeCount());
    }

    @SmallTest
    public void testLocalProcessDisable() throws Exception {
        TestCache cache = new TestCache();
        cache.invalidateCache();
        assertEquals("foo5", cache.query(5));
        assertEquals(1, cache.getRecomputeCount());
        assertEquals("foo5", cache.query(5));
        assertEquals(1, cache.getRecomputeCount());
        assertEquals(cache.isDisabledLocal(), false);
        cache.disableLocal();
        assertEquals(cache.isDisabledLocal(), true);
        assertEquals("foo5", cache.query(5));
        assertEquals("foo5", cache.query(5));
        assertEquals(3, cache.getRecomputeCount());
    }

}
+0 −4
Original line number Diff line number Diff line
@@ -10359,10 +10359,6 @@ public class ActivityManagerService extends IActivityManager.Stub
            if (thread != null) {
                pw.println("\n\n** Cache info for pid " + pid + " [" + r.processName + "] **");
                pw.flush();
                if (pid == MY_PID) {
                    PropertyInvalidatedCache.dumpCacheInfo(fd, args);
                    continue;
                }
                try {
                    TransferPipe tp = new TransferPipe();
                    try {