Optimize slice permission checks a bit

Don't constantly get the current assistant/home, only get them when
we expect we may be out of date.

Test: uiservicestests
Change-Id: I60226f57b3788dac63609f7cc9a5a4b72cfce7a6
Fixes: 72749787
This commit is contained in:
Jason Monk
2018-05-21 13:36:21 -04:00
parent 167b451daa
commit e009a8ed6e
2 changed files with 132 additions and 7 deletions

View File

@@ -55,6 +55,7 @@ import android.os.ShellCallback;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml.Encoding;
import com.android.internal.annotations.GuardedBy;
@@ -77,6 +78,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
public class SliceManagerService extends ISliceManager.Stub {
@@ -90,6 +92,10 @@ public class SliceManagerService extends ISliceManager.Stub {
@GuardedBy("mLock")
private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
@GuardedBy("mLock")
private final SparseArray<PackageMatchingCache> mAssistantLookup = new SparseArray<>();
@GuardedBy("mLock")
private final SparseArray<PackageMatchingCache> mHomeLookup = new SparseArray<>();
private final Handler mHandler;
private final SlicePermissionManager mPermissions;
@@ -453,17 +459,37 @@ public class SliceManagerService extends ISliceManager.Stub {
}
private boolean isAssistant(String pkg, int userId) {
final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
if (cn == null) {
return false;
}
return cn.getPackageName().equals(pkg);
return getAssistantMatcher(userId).matches(pkg);
}
private boolean isDefaultHomeApp(String pkg, int userId) {
String defaultHome = getDefaultHome(userId);
return getHomeMatcher(userId).matches(pkg);
}
return pkg != null && Objects.equals(pkg, defaultHome);
private PackageMatchingCache getAssistantMatcher(int userId) {
PackageMatchingCache matcher = mAssistantLookup.get(userId);
if (matcher == null) {
matcher = new PackageMatchingCache(() -> getAssistant(userId));
mAssistantLookup.put(userId, matcher);
}
return matcher;
}
private PackageMatchingCache getHomeMatcher(int userId) {
PackageMatchingCache matcher = mHomeLookup.get(userId);
if (matcher == null) {
matcher = new PackageMatchingCache(() -> getDefaultHome(userId));
mHomeLookup.put(userId, matcher);
}
return matcher;
}
private String getAssistant(int userId) {
final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
if (cn == null) {
return null;
}
return cn.getPackageName();
}
// Based on getDefaultHome in ShortcutService.
@@ -559,6 +585,30 @@ public class SliceManagerService extends ISliceManager.Stub {
return mPermissions.getAllPackagesGranted(pkg);
}
/**
* Holder that caches a package that has access to a slice.
*/
static class PackageMatchingCache {
private final Supplier<String> mPkgSource;
private String mCurrentPkg;
public PackageMatchingCache(Supplier<String> pkgSource) {
mPkgSource = pkgSource;
}
public boolean matches(String pkgCandidate) {
if (pkgCandidate == null) return false;
if (Objects.equals(pkgCandidate, mCurrentPkg)) {
return true;
}
// Failed on cached value, try updating.
mCurrentPkg = mPkgSource.get();
return Objects.equals(pkgCandidate, mCurrentPkg);
}
}
public static class Lifecycle extends SystemService {
private SliceManagerService mService;

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2018 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.slice;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import com.android.server.UiServiceTestCase;
import com.android.server.slice.SliceManagerService.PackageMatchingCache;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.function.Supplier;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class PackageMatchingCacheTest extends UiServiceTestCase {
private final Supplier<String> supplier = mock(Supplier.class);
private final PackageMatchingCache cache = new PackageMatchingCache(supplier);
@Test
public void testNulls() {
// Doesn't get for a null input
cache.matches(null);
verify(supplier, never()).get();
// Gets once valid input in sent.
cache.matches("");
verify(supplier).get();
}
@Test
public void testCaching() {
when(supplier.get()).thenReturn("ret.pkg");
assertTrue(cache.matches("ret.pkg"));
assertTrue(cache.matches("ret.pkg"));
assertTrue(cache.matches("ret.pkg"));
verify(supplier, times(1)).get();
}
@Test
public void testGetOnFailure() {
when(supplier.get()).thenReturn("ret.pkg");
assertTrue(cache.matches("ret.pkg"));
when(supplier.get()).thenReturn("other.pkg");
assertTrue(cache.matches("other.pkg"));
verify(supplier, times(2)).get();
}
}