[AppsFilter] read-only interface for snapshots

Provides a read-only interface that is used by computer and snapshots.
It fixes the data conflicts when AppsFilter is changed while a snapshot is
taken. This requires a watchable class for SparseSetArray.

Test: atest AppsFilterTest
Test: atest com.android.server.utils.WatcherTest
Test: m RUN_ERROR_PRONE=true framework services.core |& grep AppsFilter
BUG: 218411030
Change-Id: Ib9d13537b6cec911b2a189aea828e9baec650585
This commit is contained in:
Songchun Fan
2022-03-22 22:29:25 +00:00
parent 95387ac862
commit 8cb3e6aac9
13 changed files with 1072 additions and 563 deletions

View File

@@ -21,9 +21,26 @@ package android.util;
* @hide
*/
public class SparseSetArray<T> {
private final SparseArray<ArraySet<T>> mData = new SparseArray<>();
private final SparseArray<ArraySet<T>> mData;
public SparseSetArray() {
mData = new SparseArray<>();
}
/**
* Copy constructor
*/
public SparseSetArray(SparseSetArray<T> src) {
final int arraySize = src.size();
mData = new SparseArray<>(arraySize);
for (int i = 0; i < arraySize; i++) {
final int key = src.keyAt(i);
final ArraySet<T> set = src.get(key);
final int setSize = set.size();
for (int j = 0; j < setSize; j++) {
add(key, set.valueAt(j));
}
}
}
/**

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2022 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 com.android.server.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Process;
import android.util.ArrayMap;
import android.util.SparseArray;
import com.android.internal.util.function.QuadFunction;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import java.io.PrintWriter;
/**
* Read-only interface used by computer and snapshots to query the visibility of packages
*/
public interface AppsFilterSnapshot {
/**
* Fetches all app Ids that a given setting is currently visible to, per provided user. This
* only includes UIDs >= {@link Process#FIRST_APPLICATION_UID} as all other UIDs can already see
* all applications.
*
* If the setting is visible to all UIDs, null is returned. If an app is not visible to any
* applications, the int array will be empty.
*
* @param users the set of users that should be evaluated for this calculation
* @param existingSettings the set of all package settings that currently exist on device
* @return a SparseArray mapping userIds to a sorted int array of appIds that may view the
* provided setting or null if the app is visible to all and no allow list should be
* applied.
*/
SparseArray<int[]> getVisibilityAllowList(PackageStateInternal setting, int[] users,
ArrayMap<String, ? extends PackageStateInternal> existingSettings);
/**
* Returns true if the calling package should not be able to see the target package, false if no
* filtering should be done.
*
* @param callingUid the uid of the caller attempting to access a package
* @param callingSetting the setting attempting to access a package or null if it could not be
* found
* @param targetPkgSetting the package being accessed
* @param userId the user in which this access is being attempted
*/
boolean shouldFilterApplication(int callingUid, @Nullable Object callingSetting,
PackageStateInternal targetPkgSetting, int userId);
/**
* Returns whether the querying package is allowed to see the target package.
*
* @param querying the querying package
* @param potentialTarget the package name of the target package
*/
boolean canQueryPackage(@NonNull AndroidPackage querying, String potentialTarget);
/**
* Dump the packages that are queryable by the querying package.
*
* @param pw the output print writer
* @param filteringAppId the querying package's app ID
* @param dumpState the state of the dumping
* @param users the users for which the packages are installed
* @param getPackagesForUid the function that produces the package names for given uids
*/
void dumpQueries(PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState,
int[] users,
QuadFunction<Integer, Integer, Integer, Boolean, String[]> getPackagesForUid);
}

View File

@@ -348,7 +348,7 @@ public class ComputerEngine implements Computer {
private final ResolveInfo mInstantAppInstallerInfo;
private final InstantAppRegistry mInstantAppRegistry;
private final ApplicationInfo mLocalAndroidApplication;
private final AppsFilter mAppsFilter;
private final AppsFilterSnapshot mAppsFilter;
private final WatchedArrayMap<String, Integer> mFrozenPackages;
// Immutable service attribute

View File

@@ -724,7 +724,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
@Watched
final AppsFilter mAppsFilter;
final AppsFilterImpl mAppsFilter;
final PackageParser2.Callback mPackageParserCallback;
@@ -981,7 +981,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
public final InstantAppRegistry instantAppRegistry;
public final ApplicationInfo androidApplication;
public final String appPredictionServicePackage;
public final AppsFilter appsFilter;
public final AppsFilterSnapshot appsFilter;
public final ComponentResolverApi componentResolver;
public final PackageManagerService service;
public final WatchedArrayMap<String, Integer> frozenPackages;
@@ -1433,7 +1433,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
domainVerificationService, lock),
(i, pm) -> AppsFilter.create(i, i.getLocalService(PackageManagerInternal.class)),
(i, pm) -> AppsFilterImpl.create(i,
i.getLocalService(PackageManagerInternal.class)),
(i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
(i, pm) -> SystemConfig.getInstance(),
(i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),

View File

@@ -99,7 +99,7 @@ public class PackageManagerServiceInjector {
private final Singleton<UserManagerService>
mUserManagerProducer;
private final Singleton<Settings> mSettingsProducer;
private final Singleton<AppsFilter> mAppsFilterProducer;
private final Singleton<AppsFilterImpl> mAppsFilterProducer;
private final Singleton<PlatformCompat>
mPlatformCompatProducer;
private final Singleton<SystemConfig> mSystemConfigProducer;
@@ -148,7 +148,7 @@ public class PackageManagerServiceInjector {
Producer<PermissionManagerServiceInternal> permissionManagerServiceProducer,
Producer<UserManagerService> userManagerProducer,
Producer<Settings> settingsProducer,
Producer<AppsFilter> appsFilterProducer,
Producer<AppsFilterImpl> appsFilterProducer,
Producer<PlatformCompat> platformCompatProducer,
Producer<SystemConfig> systemConfigProducer,
Producer<PackageDexOptimizer> packageDexOptimizerProducer,
@@ -282,7 +282,7 @@ public class PackageManagerServiceInjector {
return mSettingsProducer.get(this, mPackageManager);
}
public AppsFilter getAppsFilter() {
public AppsFilterImpl getAppsFilter() {
return mAppsFilterProducer.get(this, mPackageManager);
}

View File

@@ -272,6 +272,13 @@ public class WatchedArrayList<E> extends WatchableImpl
return mStorage.contains(o);
}
/**
* Return true if all the objects in the given collection are in this array list.
*/
public boolean containsAll(Collection<?> c) {
return mStorage.containsAll(c);
}
/**
* Ensure capacity.
*/

View File

@@ -18,6 +18,7 @@ package com.android.server.utils;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
@@ -168,12 +169,19 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
* A copy constructor that can be used for snapshotting.
*/
private WatchedSparseBooleanMatrix(WatchedSparseBooleanMatrix r) {
mOrder = r.mOrder;
mSize = r.mSize;
mKeys = r.mKeys.clone();
mMap = r.mMap.clone();
mInUse = r.mInUse.clone();
mValues = r.mValues.clone();
copyFrom(r);
}
/**
* Copy from src to this.
*/
public void copyFrom(@NonNull WatchedSparseBooleanMatrix src) {
mOrder = src.mOrder;
mSize = src.mSize;
mKeys = src.mKeys.clone();
mMap = src.mMap.clone();
mInUse = src.mInUse.clone();
mValues = src.mValues.clone();
}
/**

View File

@@ -0,0 +1,177 @@
/*
* Copyright (C) 2022 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 com.android.server.utils;
import android.annotation.NonNull;
import android.util.ArraySet;
import android.util.SparseSetArray;
/**
* A watched variant of SparseSetArray. Changes to the array are notified to
* registered {@link Watcher}s.
* @param <T> The element type, stored in the SparseSetArray.
*/
public class WatchedSparseSetArray<T> extends WatchableImpl implements Snappable {
// The storage
private final SparseSetArray mStorage;
// A private convenience function
private void onChanged() {
dispatchChange(this);
}
public WatchedSparseSetArray() {
mStorage = new SparseSetArray();
}
/**
* Creates a new WatchedSparseSetArray from an existing WatchedSparseSetArray and copy its data
*/
public WatchedSparseSetArray(@NonNull WatchedSparseSetArray<T> watchedSparseSetArray) {
mStorage = new SparseSetArray(watchedSparseSetArray.untrackedStorage());
}
/**
* Return the underlying storage. This breaks the wrapper but is necessary when
* passing the array to distant methods.
*/
public SparseSetArray<T> untrackedStorage() {
return mStorage;
}
/**
* Add a value for key n.
* @return FALSE when the value already existed for the given key, TRUE otherwise.
*/
public boolean add(int n, T value) {
final boolean res = mStorage.add(n, value);
onChanged();
return res;
}
/**
* Removes all mappings from this SparseSetArray.
*/
public void clear() {
mStorage.clear();
onChanged();
}
/**
* @return whether the value exists for the key n.
*/
public boolean contains(int n, T value) {
return mStorage.contains(n, value);
}
/**
* @return the set of items of key n
*/
public ArraySet<T> get(int n) {
return mStorage.get(n);
}
/**
* Remove a value for key n.
* @return TRUE when the value existed for the given key and removed, FALSE otherwise.
*/
public boolean remove(int n, T value) {
if (mStorage.remove(n, value)) {
onChanged();
return true;
}
return false;
}
/**
* Remove all values for key n.
*/
public void remove(int n) {
mStorage.remove(n);
onChanged();
}
/**
* Return the size of the SparseSetArray.
*/
public int size() {
return mStorage.size();
}
/**
* Return the key stored at the given index.
*/
public int keyAt(int index) {
return mStorage.keyAt(index);
}
/**
* Return the size of the array at the given index.
*/
public int sizeAt(int index) {
return mStorage.sizeAt(index);
}
/**
* Return the value in the SetArray at the given key index and value index.
*/
public T valueAt(int intIndex, int valueIndex) {
return (T) mStorage.valueAt(intIndex, valueIndex);
}
@NonNull
@Override
public Object snapshot() {
WatchedSparseSetArray l = new WatchedSparseSetArray(this);
l.seal();
return l;
}
/**
* Make <this> a snapshot of the argument. Note that <this> is immutable when the
* method returns. <this> must be empty when the function is called.
* @param r The source array, which is copied into <this>
*/
public void snapshot(@NonNull WatchedSparseSetArray<T> r) {
snapshot(this, r);
}
/**
* Make the destination a copy of the source. If the element is a subclass of Snapper then the
* copy contains snapshots of the elements. Otherwise the copy contains references to the
* elements. The destination must be initially empty. Upon return, the destination is
* immutable.
* @param dst The destination array. It must be empty.
* @param src The source array. It is not modified.
*/
public static void snapshot(@NonNull WatchedSparseSetArray dst,
@NonNull WatchedSparseSetArray src) {
if (dst.size() != 0) {
throw new IllegalArgumentException("snapshot destination is not empty");
}
final int arraySize = src.size();
for (int i = 0; i < arraySize; i++) {
final ArraySet set = src.get(i);
final int setSize = set.size();
for (int j = 0; j < setSize; j++) {
dst.add(src.keyAt(i), set.valueAt(j));
}
}
dst.seal();
}
}

View File

@@ -34,7 +34,6 @@ import com.android.server.pm.test.override.PackageManagerComponentLabelIconOverr
import com.android.server.testutils.TestHandler
import com.android.server.testutils.mock
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.spy
import com.android.server.testutils.whenever
import com.android.server.wm.ActivityTaskManagerInternal
import com.google.common.truth.Truth.assertThat
@@ -46,13 +45,9 @@ import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.intThat
import org.mockito.Mockito.never
import org.mockito.Mockito.same
import org.mockito.Mockito.verify
import org.testng.Assert.assertThrows
import java.io.File
import java.util.UUID
@@ -365,7 +360,7 @@ class PackageManagerComponentLabelIconOverrideTest {
val mockActivityTaskManager: ActivityTaskManagerInternal = mockThrowOnUnmocked {
whenever(this.isCallerRecents(anyInt())) { false }
}
val mockAppsFilter: AppsFilter = mockThrowOnUnmocked {
val mockAppsFilter: AppsFilterImpl = mockThrowOnUnmocked {
whenever(this.shouldFilterApplication(anyInt(), any<PackageSetting>(),
any<PackageSetting>(), anyInt())) { false }
whenever(this.snapshot()) { this@mockThrowOnUnmocked }

View File

@@ -194,7 +194,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
val packageParser: PackageParser2 = mock()
val keySetManagerService: KeySetManagerService = mock()
val packageAbiHelper: PackageAbiHelper = mock()
val appsFilter: AppsFilter = mock {
val appsFilter: AppsFilterImpl = mock {
whenever(snapshot()) { this@mock }
}
val dexManager: DexManager = mock()

View File

@@ -77,7 +77,7 @@ import java.util.concurrent.Executor;
@Presubmit
@RunWith(JUnit4.class)
public class AppsFilterTest {
public class AppsFilterImplTest {
private static final int DUMMY_CALLING_APPID = 10345;
private static final int DUMMY_TARGET_APPID = 10556;
@@ -98,9 +98,9 @@ public class AppsFilterTest {
}
@Mock
AppsFilter.FeatureConfig mFeatureConfigMock;
AppsFilterImpl.FeatureConfig mFeatureConfigMock;
@Mock
AppsFilter.StateProvider mStateProvider;
AppsFilterImpl.StateProvider mStateProvider;
@Mock
Executor mMockExecutor;
@Mock
@@ -204,11 +204,11 @@ public class AppsFilterTest {
MockitoAnnotations.initMocks(this);
doAnswer(invocation -> {
((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
((AppsFilterImpl.StateProvider.CurrentStateCallback) invocation.getArgument(0))
.currentState(mExisting, USER_INFO_LIST);
return new Object();
}).when(mStateProvider)
.runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
.runWithState(any(AppsFilterImpl.StateProvider.CurrentStateCallback.class));
doAnswer(invocation -> {
((Runnable) invocation.getArgument(0)).run();
@@ -218,14 +218,14 @@ public class AppsFilterTest {
when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true);
when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))).thenAnswer(
(Answer<Boolean>) invocation ->
((AndroidPackage)invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion()
((AndroidPackage) invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion()
>= Build.VERSION_CODES.R);
}
@Test
public void testSystemReadyPropogates() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -236,8 +236,8 @@ public class AppsFilterTest {
@Test
public void testQueriesAction_FilterMatches() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -259,8 +259,8 @@ public class AppsFilterTest {
}
@Test
public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -308,8 +308,8 @@ public class AppsFilterTest {
@Test
public void testQueriesProvider_FilterMatches() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -333,8 +333,8 @@ public class AppsFilterTest {
@Test
public void testOnUserUpdated_FilterMatches() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
@@ -356,11 +356,11 @@ public class AppsFilterTest {
// adds new user
doAnswer(invocation -> {
((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
((AppsFilterImpl.StateProvider.CurrentStateCallback) invocation.getArgument(0))
.currentState(mExisting, USER_INFO_LIST_WITH_ADDED);
return new Object();
}).when(mStateProvider)
.runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
.runWithState(any(AppsFilterImpl.StateProvider.CurrentStateCallback.class));
appsFilter.onUserCreated(ADDED_USER);
for (int subjectUserId : USER_ARRAY_WITH_ADDED) {
@@ -373,11 +373,11 @@ public class AppsFilterTest {
// delete user
doAnswer(invocation -> {
((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
((AppsFilterImpl.StateProvider.CurrentStateCallback) invocation.getArgument(0))
.currentState(mExisting, USER_INFO_LIST);
return new Object();
}).when(mStateProvider)
.runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
.runWithState(any(AppsFilterImpl.StateProvider.CurrentStateCallback.class));
appsFilter.onUserDeleted(ADDED_USER);
for (int subjectUserId : USER_ARRAY) {
@@ -391,8 +391,8 @@ public class AppsFilterTest {
@Test
public void testQueriesDifferentProvider_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -416,8 +416,8 @@ public class AppsFilterTest {
@Test
public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -435,8 +435,8 @@ public class AppsFilterTest {
@Test
public void testQueriesAction_NoMatchingAction_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -452,8 +452,8 @@ public class AppsFilterTest {
@Test
public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -473,8 +473,8 @@ public class AppsFilterTest {
@Test
public void testNoQueries_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -490,7 +490,7 @@ public class AppsFilterTest {
@Test
public void testNoUsesLibrary_Filters() throws Exception {
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
mMockExecutor, mMockPmInternal);
@@ -516,7 +516,7 @@ public class AppsFilterTest {
@Test
public void testUsesLibrary_DoesntFilter() throws Exception {
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
mMockExecutor, mMockPmInternal);
@@ -543,7 +543,7 @@ public class AppsFilterTest {
@Test
public void testUsesOptionalLibrary_DoesntFilter() throws Exception {
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
mMockExecutor, mMockPmInternal);
@@ -570,7 +570,7 @@ public class AppsFilterTest {
@Test
public void testUsesLibrary_ShareUid_DoesntFilter() throws Exception {
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
mMockExecutor, mMockPmInternal);
@@ -602,8 +602,8 @@ public class AppsFilterTest {
@Test
public void testForceQueryable_SystemDoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -621,8 +621,8 @@ public class AppsFilterTest {
@Test
public void testForceQueryable_NonSystemFilters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -638,9 +638,10 @@ public class AppsFilterTest {
@Test
public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
false, null, mMockExecutor, mMockPmInternal);
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
new String[]{"com.some.package"}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -657,8 +658,8 @@ public class AppsFilterTest {
@Test
public void testSystemSignedTarget_DoesntFilter() throws CertificateException {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
appsFilter.onSystemReady();
@@ -686,9 +687,10 @@ public class AppsFilterTest {
@Test
public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
false, null, mMockExecutor, mMockPmInternal);
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
new String[]{"com.some.package"}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -704,8 +706,8 @@ public class AppsFilterTest {
@Test
public void testSystemQueryable_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{},
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{},
true /* system force queryable */, null, mMockExecutor,
mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
@@ -723,8 +725,8 @@ public class AppsFilterTest {
@Test
public void testQueriesPackage_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -742,8 +744,8 @@ public class AppsFilterTest {
public void testNoQueries_FeatureOff_DoesntFilter() throws Exception {
when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
.thenReturn(false);
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -759,8 +761,8 @@ public class AppsFilterTest {
@Test
public void testSystemUid_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -775,8 +777,8 @@ public class AppsFilterTest {
@Test
public void testSystemUidSecondaryUser_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -792,8 +794,8 @@ public class AppsFilterTest {
@Test
public void testNonSystemUid_NoCallingSetting_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -807,8 +809,8 @@ public class AppsFilterTest {
@Test
public void testNoTargetPackage_filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -838,7 +840,7 @@ public class AppsFilterTest {
.setOverlayTargetOverlayableName("overlayableName");
ParsingPackage actor = pkg("com.some.package.actor");
final AppsFilter appsFilter = new AppsFilter(
final AppsFilterImpl appsFilter = new AppsFilterImpl(
mStateProvider,
mFeatureConfigMock,
new String[]{},
@@ -933,7 +935,7 @@ public class AppsFilterTest {
when(mMockPmInternal.getSharedUserPackages(any(Integer.class))).thenReturn(
actorSharedSettingPackages
);
final AppsFilter appsFilter = new AppsFilter(
final AppsFilterImpl appsFilter = new AppsFilterImpl(
mStateProvider,
mFeatureConfigMock,
new String[]{},
@@ -985,8 +987,8 @@ public class AppsFilterTest {
@Test
public void testInitiatingApp_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -1003,8 +1005,8 @@ public class AppsFilterTest {
@Test
public void testUninstalledInitiatingApp_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -1021,8 +1023,8 @@ public class AppsFilterTest {
@Test
public void testOriginatingApp_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -1046,8 +1048,8 @@ public class AppsFilterTest {
@Test
public void testInstallingApp_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -1071,8 +1073,8 @@ public class AppsFilterTest {
@Test
public void testInstrumentation_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -1100,8 +1102,8 @@ public class AppsFilterTest {
@Test
public void testWhoCanSee() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -1173,8 +1175,8 @@ public class AppsFilterTest {
@Test
public void testOnChangeReport() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
@@ -1246,8 +1248,8 @@ public class AppsFilterTest {
@Test
public void testOnChangeReportedFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -1270,6 +1272,53 @@ public class AppsFilterTest {
watcher.verifyNoChangeReported("shouldFilterApplication");
}
@Test
public void testAppsFilterRead() throws Exception {
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
DUMMY_TARGET_APPID);
PackageSetting instrumentation = simulateAddPackage(appsFilter,
pkgWithInstrumentation("com.some.other.package", "com.some.package"),
DUMMY_CALLING_APPID);
final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1;
final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2;
PackageSetting queriesProvider = simulateAddPackage(appsFilter,
pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"),
queriesProviderAppId);
appsFilter.grantImplicitAccess(
hasProviderAppId, queriesProviderAppId, false /* retainOnUpdate */);
AppsFilterSnapshot snapshot = appsFilter.snapshot();
assertFalse(
snapshot.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
SYSTEM_USER));
assertFalse(
snapshot.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation,
SYSTEM_USER));
SparseArray<int[]> queriesProviderFilter =
snapshot.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)), contains(queriesProviderAppId));
assertTrue(snapshot.canQueryPackage(instrumentation.getPkg(),
target.getPackageName()));
// New changes don't affect the snapshot
appsFilter.removePackage(target, false);
assertTrue(
appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
SYSTEM_USER));
assertFalse(
snapshot.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
SYSTEM_USER));
}
private List<Integer> toList(int[] array) {
ArrayList<Integer> ret = new ArrayList<>(array.length);
for (int i = 0; i < array.length; i++) {
@@ -1282,7 +1331,7 @@ public class AppsFilterTest {
PackageSettingBuilder withBuilder(PackageSettingBuilder builder);
}
private void simulateAddBasicAndroid(AppsFilter appsFilter) throws Exception {
private void simulateAddBasicAndroid(AppsFilterImpl appsFilter) throws Exception {
final Signature frameworkSignature = Mockito.mock(Signature.class);
final SigningDetails frameworkSigningDetails =
new SigningDetails(new Signature[]{frameworkSignature}, 1);
@@ -1291,17 +1340,17 @@ public class AppsFilterTest {
b -> b.setSigningDetails(frameworkSigningDetails));
}
private PackageSetting simulateAddPackage(AppsFilter filter,
private PackageSetting simulateAddPackage(AppsFilterImpl filter,
ParsingPackage newPkgBuilder, int appId) {
return simulateAddPackage(filter, newPkgBuilder, appId, null /*settingBuilder*/);
}
private PackageSetting simulateAddPackage(AppsFilter filter,
private PackageSetting simulateAddPackage(AppsFilterImpl filter,
ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) {
return simulateAddPackage(filter, newPkgBuilder, appId, action, null /*sharedUserSetting*/);
}
private PackageSetting simulateAddPackage(AppsFilter filter,
private PackageSetting simulateAddPackage(AppsFilterImpl filter,
ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action,
@Nullable SharedUserSetting sharedUserSetting) {
final PackageSetting setting =
@@ -1324,7 +1373,7 @@ public class AppsFilterTest {
return setting;
}
private void simulateAddPackage(PackageSetting setting, AppsFilter filter,
private void simulateAddPackage(PackageSetting setting, AppsFilterImpl filter,
@Nullable SharedUserSetting sharedUserSetting) {
mExisting.put(setting.getPackageName(), setting);
if (sharedUserSetting != null) {

View File

@@ -17,6 +17,7 @@
package com.android.server.utils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -860,6 +861,54 @@ public class WatcherTest {
}
}
@Test
public void testWatchedSparseSetArray() {
final String name = "WatchedSparseSetArray";
WatchableTester tester;
// Test WatchedSparseSetArray
WatchedSparseSetArray array = new WatchedSparseSetArray();
tester = new WatchableTester(array, name);
tester.verify(0, "Initial array - no registration");
array.add(INDEX_A, 1);
tester.verify(0, "Updates with no registration");
tester.register();
tester.verify(0, "Updates with no registration");
array.add(INDEX_B, 2);
tester.verify(1, "Updates with registration");
array.add(INDEX_B, 4);
array.add(INDEX_C, 5);
tester.verify(3, "Updates with registration");
// Special methods
assertTrue(array.remove(INDEX_C, 5));
tester.verify(4, "Removed 5 from key 3");
array.remove(INDEX_B);
tester.verify(5, "Removed everything for key 2");
// Snapshot
{
WatchedSparseSetArray arraySnap = (WatchedSparseSetArray) array.snapshot();
tester.verify(5, "Generate snapshot");
// Verify that the snapshot is a proper copy of the source.
assertEquals("WatchedSparseSetArray snap same size",
array.size(), arraySnap.size());
for (int i = 0; i < array.size(); i++) {
ArraySet set = array.get(array.keyAt(i));
ArraySet setSnap = arraySnap.get(arraySnap.keyAt(i));
assertNotNull(set);
assertTrue(set.equals(setSnap));
}
array.add(INDEX_D, 9);
tester.verify(6, "Tick after snapshot");
// Verify that the array is sealed
verifySealed(name, ()->arraySnap.add(INDEX_D, 10));
assertTrue(!array.isSealed());
assertTrue(arraySnap.isSealed());
}
array.clear();
tester.verify(7, "Cleared all entries");
}
private static class IndexGenerator {
private final int mSeed;
private final Random mRandom;
@@ -1084,6 +1133,18 @@ public class WatcherTest {
assertEquals(a.equals(s), true);
a.put(rowIndex, colIndex, !a.get(rowIndex, colIndex));
assertEquals(a.equals(s), false);
// Verify copy-in/out
{
final String msg = name + " copy";
WatchedSparseBooleanMatrix copy = new WatchedSparseBooleanMatrix();
copy.copyFrom(matrix);
final int end = copy.size();
assertTrue(msg + " size mismatch " + end + " " + matrix.size(), end == matrix.size());
for (int i = 0; i < end; i++) {
assertEquals(copy.keyAt(i), keys[i]);
}
}
}
@Test