Merge "Check for NLS bind permission when rebinding services" into udc-dev am: be2c9642f4
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/26485132
Change-Id: Ia6e81d41c75be3dd677b6ebae8ea61d5a71d7aac
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 12fc263..98b288c 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -939,6 +939,23 @@
return false;
}
+ protected boolean isPackageOrComponentAllowedWithPermission(ComponentName component,
+ int userId) {
+ if (!(isPackageOrComponentAllowed(component.flattenToString(), userId)
+ || isPackageOrComponentAllowed(component.getPackageName(), userId))) {
+ return false;
+ }
+ return componentHasBindPermission(component, userId);
+ }
+
+ private boolean componentHasBindPermission(ComponentName component, int userId) {
+ ServiceInfo info = getServiceInfo(component, userId);
+ if (info == null) {
+ return false;
+ }
+ return mConfig.bindPermission.equals(info.permission);
+ }
+
boolean isPackageOrComponentUserSet(String pkgOrComponent, int userId) {
synchronized (mApproved) {
ArraySet<String> services = mUserSetServices.get(userId);
@@ -1000,6 +1017,7 @@
for (int uid : uidList) {
if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
anyServicesInvolved = true;
+ trimApprovedListsForInvalidServices(pkgName, UserHandle.getUserId(uid));
}
}
}
@@ -1132,8 +1150,7 @@
synchronized (mMutex) {
if (enabled) {
- if (isPackageOrComponentAllowed(component.flattenToString(), userId)
- || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
+ if (isPackageOrComponentAllowedWithPermission(component, userId)) {
registerServiceLocked(component, userId);
} else {
Slog.d(TAG, component + " no longer has permission to be bound");
@@ -1252,6 +1269,33 @@
return removed;
}
+ private void trimApprovedListsForInvalidServices(String packageName, int userId) {
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+ if (approvedByType == null) {
+ return;
+ }
+ for (int i = 0; i < approvedByType.size(); i++) {
+ final ArraySet<String> approved = approvedByType.valueAt(i);
+ for (int j = approved.size() - 1; j >= 0; j--) {
+ final String approvedPackageOrComponent = approved.valueAt(j);
+ if (TextUtils.equals(getPackageName(approvedPackageOrComponent), packageName)) {
+ final ComponentName component = ComponentName.unflattenFromString(
+ approvedPackageOrComponent);
+ if (component != null && !componentHasBindPermission(component, userId)) {
+ approved.removeAt(j);
+ if (DEBUG) {
+ Slog.v(TAG, "Removing " + approvedPackageOrComponent
+ + " from approved list; no bind permission found "
+ + mConfig.bindPermission);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
protected String getPackageName(String packageOrComponent) {
final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
if (component != null) {
@@ -1488,8 +1532,7 @@
void reregisterService(final ComponentName cn, final int userId) {
// If rebinding a package that died, ensure it still has permission
// after the rebind delay
- if (isPackageOrComponentAllowed(cn.getPackageName(), userId)
- || isPackageOrComponentAllowed(cn.flattenToString(), userId)) {
+ if (isPackageOrComponentAllowedWithPermission(cn, userId)) {
registerService(cn, userId);
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 541739d..4ef3a6e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -36,6 +36,7 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -883,6 +884,7 @@
return true;
});
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a", 0, true);
service.reregisterService(cn, 0);
@@ -913,6 +915,7 @@
return true;
});
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a", 0, false);
service.reregisterService(cn, 0);
@@ -943,6 +946,7 @@
return true;
});
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a/a", 0, true);
service.reregisterService(cn, 0);
@@ -973,6 +977,7 @@
return true;
});
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a/a", 0, false);
service.reregisterService(cn, 0);
@@ -1130,6 +1135,58 @@
}
@Test
+ public void testUpgradeAppNoPermissionNoRebind() throws Exception {
+ Context context = spy(getContext());
+ doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any());
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles,
+ mIpm,
+ APPROVAL_BY_COMPONENT);
+
+ List<String> packages = new ArrayList<>();
+ packages.add("package");
+ addExpectedServices(service, packages, 0);
+
+ final ComponentName unapprovedComponent = ComponentName.unflattenFromString("package/C1");
+ final ComponentName approvedComponent = ComponentName.unflattenFromString("package/C2");
+
+ // Both components are approved initially
+ mExpectedPrimaryComponentNames.clear();
+ mExpectedPrimaryPackages.clear();
+ mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
+ mExpectedSecondaryComponentNames.clear();
+ mExpectedSecondaryPackages.clear();
+
+ loadXml(service);
+
+ //Component package/C1 loses bind permission
+ when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer(
+ (Answer<ServiceInfo>) invocation -> {
+ ComponentName invocationCn = invocation.getArgument(0);
+ if (invocationCn != null) {
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = invocationCn.getPackageName();
+ serviceInfo.name = invocationCn.getClassName();
+ if (invocationCn.equals(unapprovedComponent)) {
+ serviceInfo.permission = "none";
+ } else {
+ serviceInfo.permission = service.getConfig().bindPermission;
+ }
+ serviceInfo.metaData = null;
+ return serviceInfo;
+ }
+ return null;
+ }
+ );
+
+ // Trigger package update
+ service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});
+
+ assertFalse(service.isComponentEnabledForCurrentProfiles(unapprovedComponent));
+ assertTrue(service.isComponentEnabledForCurrentProfiles(approvedComponent));
+ }
+
+ @Test
public void testSetPackageOrComponentEnabled() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,