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

Commit 41d377f4 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Use the right token to clear service info caches in the different instances." into main

parents 92cb2b79 b2fe2bc1
Loading
Loading
Loading
Loading
+37 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.content.pm;

import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -558,7 +559,8 @@ public abstract class RegisteredServicesCache<V> {
        if (Flags.optimizeParsingInRegisteredServicesCache()) {
            synchronized (mUserIdToServiceInfoCaches) {
                if (mUserIdToServiceInfoCaches.numElementsForKey(userId) > 0) {
                    final Integer token = Integer.valueOf(userId);
                    final ServiceInfoCachesToken<V> token = new ServiceInfoCachesToken<V>(
                            this /* RegisteredServicesCache<V> */, userId);
                    mBackgroundHandler.removeCallbacksAndEqualMessages(token);
                    mBackgroundHandler.postDelayed(
                            new ClearServiceInfoCachesTimeoutRunnable(userId), token,
@@ -962,4 +964,38 @@ public abstract class RegisteredServicesCache<V> {
            }
        }
    }

    /**
     * Use the token to make sure the service info caches to be cleared in the different instances.
     * @param <V> The type of the value.
     *
     * @hide
     */
    public static final class ServiceInfoCachesToken<V> {
        public final RegisteredServicesCache<V> mRegisteredServicesCache;
        public final int mUserId;

        public ServiceInfoCachesToken(RegisteredServicesCache<V> registeredServicesCache,
                int userId) {
            this.mRegisteredServicesCache = registeredServicesCache;
            this.mUserId = userId;
        }

        @Override
        public boolean equals(@Nullable Object o) {
            if (o instanceof ServiceInfoCachesToken) {
                final ServiceInfoCachesToken<V> other = (ServiceInfoCachesToken<V>) o;
                return mRegisteredServicesCache == other.mRegisteredServicesCache
                        && mUserId == other.mUserId;
            }
            return false;
        }

        @Override
        public int hashCode() {
            int result = mRegisteredServicesCache != null ? mRegisteredServicesCache.hashCode() : 0;
            result = 31 * result + mUserId;
            return result;
        }
    }
}
+88 −2
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;

import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -344,9 +345,13 @@ public class RegisteredServicesCacheUnitTest {
        // of U1 user.
        doAnswer(invocation -> {
            Message message = invocation.getArgument(0);
            if (!message.obj.equals(Integer.valueOf(U0))) {
            if (message.obj instanceof RegisteredServicesCache.ServiceInfoCachesToken) {
                final RegisteredServicesCache.ServiceInfoCachesToken token =
                        (RegisteredServicesCache.ServiceInfoCachesToken) message.obj;
                if (token.mUserId == U1) {
                    message.getCallback().run();
                }
            }
            return true;
        }).when(mMockBackgroundHandler).sendMessageAtTime(any(Message.class), anyLong());

@@ -369,6 +374,87 @@ public class RegisteredServicesCacheUnitTest {
        verify(testServicesCache, times(1)).parseServiceInfo(eq(mResolveInfo2), eq(2000L));
    }

    @Test
    public void testClearServiceInfoCachesForTwoDifferentInstancesAfterTimeout() throws Exception {
        PackageInfo packageInfo1 = createPackageInfo(1000L /* lastUpdateTime */);
        when(mMockPackageManager.getPackageInfoAsUser(eq(mResolveInfo1.serviceInfo.packageName),
                anyInt(), eq(U0))).thenReturn(packageInfo1);

        TestRegisteredServicesCache testServicesCache1 = spy(
                new TestRegisteredServicesCache(mMockInjector, null /* serializerAndParser */));
        final RegisteredServicesCache.ServiceInfo<TestServiceType> serviceInfo1 = newServiceInfo(
                mTestServiceType1, UID1, mResolveInfo1.serviceInfo.getComponentName(),
                1000L /* lastUpdateTime */);
        testServicesCache1.addServiceForQuerying(U0, mResolveInfo1, serviceInfo1);

        TestRegisteredServicesCache testServicesCache2 = spy(
                new TestRegisteredServicesCache(mMockInjector, null /* serializerAndParser */));
        testServicesCache2.addServiceForQuerying(U0, mResolveInfo1, serviceInfo1);

        final ArrayList<RegisteredServicesCache<TestServiceType>> registeredServicesCacheArrayList =
                new ArrayList<>();

        doAnswer(invocation -> {
            Message message = invocation.getArgument(0);
            if (message.obj instanceof RegisteredServicesCache.ServiceInfoCachesToken) {
                final RegisteredServicesCache.ServiceInfoCachesToken token =
                        (RegisteredServicesCache.ServiceInfoCachesToken) message.obj;
                Log.d(TAG, "RegisteredServicesCache token: " + token.mRegisteredServicesCache);
                registeredServicesCacheArrayList.add(token.mRegisteredServicesCache);
            }
            return true;
        }).when(mMockBackgroundHandler).sendMessageAtTime(any(Message.class), anyLong());

        testServicesCache1.getAllServices(U0);
        verify(mMockBackgroundHandler, times(1)).sendMessageAtTime(any(Message.class), anyLong());

        testServicesCache2.getAllServices(U0);
        verify(mMockBackgroundHandler, times(2)).sendMessageAtTime(any(Message.class), anyLong());

        assertThat(registeredServicesCacheArrayList.size()).isEqualTo(2);
        assertThat(registeredServicesCacheArrayList.get(0)).isNotEqualTo(
                registeredServicesCacheArrayList.get(1));
    }

    @Test
    public void testClearServiceInfoCachesForTwoSameInstancesAfterTimeout() throws Exception {
        PackageInfo packageInfo1 = createPackageInfo(1000L /* lastUpdateTime */);
        when(mMockPackageManager.getPackageInfoAsUser(eq(mResolveInfo1.serviceInfo.packageName),
                anyInt(), eq(U0))).thenReturn(packageInfo1);

        TestRegisteredServicesCache testServicesCache1 = spy(
                new TestRegisteredServicesCache(mMockInjector, null /* serializerAndParser */));
        final RegisteredServicesCache.ServiceInfo<TestServiceType> serviceInfo1 = newServiceInfo(
                mTestServiceType1, UID1, mResolveInfo1.serviceInfo.getComponentName(),
                1000L /* lastUpdateTime */);
        testServicesCache1.addServiceForQuerying(U0, mResolveInfo1, serviceInfo1);

        final ArrayList<RegisteredServicesCache<TestServiceType>> registeredServicesCacheArrayList =
                new ArrayList<>();

        doAnswer(invocation -> {
            Message message = invocation.getArgument(0);
            if (message.obj instanceof RegisteredServicesCache.ServiceInfoCachesToken) {
                final RegisteredServicesCache.ServiceInfoCachesToken token =
                        (RegisteredServicesCache.ServiceInfoCachesToken) message.obj;
                Log.d(TAG, "RegisteredServicesCache token: " + token.mRegisteredServicesCache);
                registeredServicesCacheArrayList.add(token.mRegisteredServicesCache);
            }
            return true;
        }).when(mMockBackgroundHandler).sendMessageAtTime(any(Message.class), anyLong());

        testServicesCache1.getAllServices(U0);
        verify(mMockBackgroundHandler, times(1)).sendMessageAtTime(any(Message.class), anyLong());

        testServicesCache1.invalidateCache(U0);
        testServicesCache1.getAllServices(U0);
        verify(mMockBackgroundHandler, times(2)).sendMessageAtTime(any(Message.class), anyLong());

        assertThat(registeredServicesCacheArrayList.size()).isEqualTo(2);
        assertThat(registeredServicesCacheArrayList.get(0)).isEqualTo(
                registeredServicesCacheArrayList.get(1));
    }

    private static RegisteredServicesCache.ServiceInfo<TestServiceType> newServiceInfo(
            TestServiceType type, int uid, ComponentName componentName, long lastUpdateTime) {
        final ComponentInfo info = new ComponentInfo();