From 12eec8896f1fe3b8529c48376a4ff450f5f0c292 Mon Sep 17 00:00:00 2001 From: Sarup Dalwani Date: Wed, 9 Nov 2022 08:48:09 +0000 Subject: [PATCH] Update mechanism for CrossProfileIntentFilters on OTA Mechanism would be triggered on OTA, identified in PackageManager. The update task is triggered in different thread. Update task clears all the CrossProfileIntentFitlers between user and parent, then it applies the new default filters. Onlt the users who have user property updateCrossProfileIntentFiltersOnOTA set would be eligible for the update. Bug: 258376391 Test: Manually tested the flow Change-Id: I0223466c07006daa195a318e105e7aca338aa3c8 --- .../android/content/pm/UserProperties.java | 61 ++++++++++- .../pm/CrossProfileIntentFilterHelper.java | 100 ++++++++++++++++++ .../server/pm/PackageManagerService.java | 36 +++---- .../pm/PackageManagerServiceInjector.java | 14 ++- .../android/server/pm/UserTypeFactory.java | 3 +- .../src/com/android/server/pm/MockSystem.kt | 3 + 6 files changed, 195 insertions(+), 22 deletions(-) create mode 100644 services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java index fd35378efba26..fb61b3769e98f 100644 --- a/core/java/android/content/pm/UserProperties.java +++ b/core/java/android/content/pm/UserProperties.java @@ -46,6 +46,8 @@ public final class UserProperties implements Parcelable { private static final String ATTR_SHOW_IN_SETTINGS = "showInSettings"; private static final String ATTR_INHERIT_DEVICE_POLICY = "inheritDevicePolicy"; private static final String ATTR_USE_PARENTS_CONTACTS = "useParentsContacts"; + private static final String ATTR_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA = + "updateCrossProfileIntentFiltersOnOTA"; /** Index values of each property (to indicate whether they are present in this object). */ @IntDef(prefix = "INDEX_", value = { @@ -54,6 +56,7 @@ public final class UserProperties implements Parcelable { INDEX_SHOW_IN_SETTINGS, INDEX_INHERIT_DEVICE_POLICY, INDEX_USE_PARENTS_CONTACTS, + INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA }) @Retention(RetentionPolicy.SOURCE) private @interface PropertyIndex { @@ -63,6 +66,7 @@ public final class UserProperties implements Parcelable { private static final int INDEX_SHOW_IN_SETTINGS = 2; private static final int INDEX_INHERIT_DEVICE_POLICY = 3; private static final int INDEX_USE_PARENTS_CONTACTS = 4; + private static final int INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA = 5; /** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */ private long mPropertiesPresent = 0; @@ -199,6 +203,7 @@ public final class UserProperties implements Parcelable { // Add items that require exposeAllFields to be true (strictest permission level). setStartWithParent(orig.getStartWithParent()); setInheritDevicePolicy(orig.getInheritDevicePolicy()); + setUpdateCrossProfileIntentFiltersOnOTA(orig.getUpdateCrossProfileIntentFiltersOnOTA()); } if (hasManagePermission) { // Add items that require MANAGE_USERS or stronger. @@ -354,6 +359,34 @@ public final class UserProperties implements Parcelable { */ private boolean mUseParentsContacts; + /** + * Returns true if user needs to update default + * {@link com.android.server.pm.CrossProfileIntentFilter} with its parents during an OTA update + * @hide + */ + public boolean getUpdateCrossProfileIntentFiltersOnOTA() { + if (isPresent(INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA)) { + return mUpdateCrossProfileIntentFiltersOnOTA; + } + if (mDefaultProperties != null) { + return mDefaultProperties.mUpdateCrossProfileIntentFiltersOnOTA; + } + throw new SecurityException("You don't have permission to query " + + "updateCrossProfileIntentFiltersOnOTA"); + } + + /** @hide */ + public void setUpdateCrossProfileIntentFiltersOnOTA(boolean val) { + this.mUpdateCrossProfileIntentFiltersOnOTA = val; + setPresent(INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA); + } + + /* + Indicate if {@link com.android.server.pm.CrossProfileIntentFilter}s need to be updated during + OTA update between user-parent + */ + private boolean mUpdateCrossProfileIntentFiltersOnOTA; + @Override public String toString() { // Please print in increasing order of PropertyIndex. @@ -364,6 +397,8 @@ public final class UserProperties implements Parcelable { + ", mShowInSettings=" + getShowInSettings() + ", mInheritDevicePolicy=" + getInheritDevicePolicy() + ", mUseParentsContacts=" + getUseParentsContacts() + + ", mUpdateCrossProfileIntentFiltersOnOTA=" + + getUpdateCrossProfileIntentFiltersOnOTA() + "}"; } @@ -380,6 +415,8 @@ public final class UserProperties implements Parcelable { pw.println(prefix + " mShowInSettings=" + getShowInSettings()); pw.println(prefix + " mInheritDevicePolicy=" + getInheritDevicePolicy()); pw.println(prefix + " mUseParentsContacts=" + getUseParentsContacts()); + pw.println(prefix + " mUpdateCrossProfileIntentFiltersOnOTA=" + + getUpdateCrossProfileIntentFiltersOnOTA()); } /** @@ -428,6 +465,9 @@ public final class UserProperties implements Parcelable { case ATTR_USE_PARENTS_CONTACTS: setUseParentsContacts(parser.getAttributeBoolean(i)); break; + case ATTR_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA: + setUpdateCrossProfileIntentFiltersOnOTA(parser.getAttributeBoolean(i)); + break; default: Slog.w(LOG_TAG, "Skipping unknown property " + attributeName); } @@ -462,6 +502,11 @@ public final class UserProperties implements Parcelable { serializer.attributeBoolean(null, ATTR_USE_PARENTS_CONTACTS, mUseParentsContacts); } + if (isPresent(INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA)) { + serializer.attributeBoolean(null, + ATTR_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA, + mUpdateCrossProfileIntentFiltersOnOTA); + } } // For use only with an object that has already had any permission-lacking fields stripped out. @@ -473,6 +518,7 @@ public final class UserProperties implements Parcelable { dest.writeInt(mShowInSettings); dest.writeInt(mInheritDevicePolicy); dest.writeBoolean(mUseParentsContacts); + dest.writeBoolean(mUpdateCrossProfileIntentFiltersOnOTA); } /** @@ -488,6 +534,7 @@ public final class UserProperties implements Parcelable { mShowInSettings = source.readInt(); mInheritDevicePolicy = source.readInt(); mUseParentsContacts = source.readBoolean(); + mUpdateCrossProfileIntentFiltersOnOTA = source.readBoolean(); } @Override @@ -517,6 +564,7 @@ public final class UserProperties implements Parcelable { private @ShowInSettings int mShowInSettings = SHOW_IN_SETTINGS_WITH_PARENT; private @InheritDevicePolicy int mInheritDevicePolicy = INHERIT_DEVICE_POLICY_NO; private boolean mUseParentsContacts = false; + private boolean mUpdateCrossProfileIntentFiltersOnOTA = false; public Builder setShowInLauncher(@ShowInLauncher int showInLauncher) { mShowInLauncher = showInLauncher; @@ -546,6 +594,13 @@ public final class UserProperties implements Parcelable { return this; } + /** Sets the value for {@link #mUpdateCrossProfileIntentFiltersOnOTA} */ + public Builder setUpdateCrossProfileIntentFiltersOnOTA(boolean + updateCrossProfileIntentFiltersOnOTA) { + mUpdateCrossProfileIntentFiltersOnOTA = updateCrossProfileIntentFiltersOnOTA; + return this; + } + /** Builds a UserProperties object with *all* values populated. */ public UserProperties build() { return new UserProperties( @@ -553,7 +608,8 @@ public final class UserProperties implements Parcelable { mStartWithParent, mShowInSettings, mInheritDevicePolicy, - mUseParentsContacts); + mUseParentsContacts, + mUpdateCrossProfileIntentFiltersOnOTA); } } // end Builder @@ -563,7 +619,7 @@ public final class UserProperties implements Parcelable { boolean startWithParent, @ShowInSettings int showInSettings, @InheritDevicePolicy int inheritDevicePolicy, - boolean useParentsContacts) { + boolean useParentsContacts, boolean updateCrossProfileIntentFiltersOnOTA) { mDefaultProperties = null; setShowInLauncher(showInLauncher); @@ -571,5 +627,6 @@ public final class UserProperties implements Parcelable { setShowInSettings(showInSettings); setInheritDevicePolicy(inheritDevicePolicy); setUseParentsContacts(useParentsContacts); + setUpdateCrossProfileIntentFiltersOnOTA(updateCrossProfileIntentFiltersOnOTA); } } diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java b/services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java new file mode 100644 index 0000000000000..e682586314ac4 --- /dev/null +++ b/services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java @@ -0,0 +1,100 @@ +/* + * 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.content.Context; +import android.content.pm.UserInfo; +import android.content.pm.UserProperties; +import android.util.ArraySet; + +/** + * Helper class to manage {@link com.android.server.pm.CrossProfileIntentFilter}s. + */ +public class CrossProfileIntentFilterHelper { + private Context mContext; + private UserManagerInternal mUserManagerInternal; + private Settings mSettings; + private UserManagerService mUserManagerService; + private PackageManagerTracedLock mLock; + + public CrossProfileIntentFilterHelper(Settings settings, UserManagerService userManagerService, + PackageManagerTracedLock lock, UserManagerInternal userManagerInternal, + Context context) { + mSettings = settings; + mUserManagerService = userManagerService; + mLock = lock; + mContext = context; + mUserManagerInternal = userManagerInternal; + } + + /** + * For users that have + * {@link android.content.pm.UserProperties#getUpdateCrossProfileIntentFiltersOnOTA} set, this + * task will update default {@link com.android.server.pm.CrossProfileIntentFilter} between that + * user and its parent. This will only update CrossProfileIntentFilters set by system package. + * The new default are configured in {@link UserTypeDetails}. + */ + public void updateDefaultCrossProfileIntentFilter() { + for (UserInfo userInfo : mUserManagerInternal.getUsers(false)) { + + UserProperties currentUserProperties = mUserManagerInternal + .getUserProperties(userInfo.id); + + if (currentUserProperties.getUpdateCrossProfileIntentFiltersOnOTA()) { + int parentUserId = mUserManagerInternal.getProfileParentId(userInfo.id); + if (parentUserId != userInfo.id) { + clearCrossProfileIntentFilters(userInfo.id, + mContext.getOpPackageName(), parentUserId); + clearCrossProfileIntentFilters(parentUserId, + mContext.getOpPackageName(), userInfo.id); + + mUserManagerInternal.setDefaultCrossProfileIntentFilters(parentUserId, + userInfo.id); + } + } + } + } + + /** + * Clear {@link CrossProfileIntentFilter}s configured on source user by ownerPackage + * targeting the targetUserId. If targetUserId is null then it will clear + * {@link CrossProfileIntentFilter} for any target user. + * @param sourceUserId source user for whom CrossProfileIntentFilter would be configured + * @param ownerPackage package who would have configured CrossProfileIntentFilter + * @param targetUserId user id for which CrossProfileIntentFilter will be removed. + * This can be null in which case it will clear for any target user. + */ + public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage, + Integer targetUserId) { + synchronized (mLock) { + CrossProfileIntentResolver resolver = mSettings + .editCrossProfileIntentResolverLPw(sourceUserId); + ArraySet set = + new ArraySet<>(resolver.filterSet()); + for (CrossProfileIntentFilter filter : set) { + //Only remove if calling user is allowed based on access control of + // {@link CrossProfileIntentFilter} + if (filter.getOwnerPackage().equals(ownerPackage) + && (targetUserId == null || filter.mTargetUserId == targetUserId) + && mUserManagerService.isCrossProfileIntentFilterAccessible(sourceUserId, + filter.mTargetUserId, /* addCrossProfileIntentFilter */ false)) { + resolver.removeFilter(filter); + } + } + } + } +} diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 91f7011c90c71..e6e2f79884936 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1537,7 +1537,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService (i, pm) -> new BackgroundDexOptService(i.getContext(), i.getDexManager(), pm), (i, pm) -> IBackupManager.Stub.asInterface(ServiceManager.getService( Context.BACKUP_SERVICE)), - (i, pm) -> new SharedLibrariesImpl(pm, i)); + (i, pm) -> new SharedLibrariesImpl(pm, i), + (i, pm) -> new CrossProfileIntentFilterHelper(i.getSettings(), + i.getUserManagerService(), i.getLock(), i.getUserManagerInternal(), + context)); if (Build.VERSION.SDK_INT <= 0) { Slog.w(TAG, "**** ro.build.version.sdk not set!"); @@ -2029,13 +2032,21 @@ public class PackageManagerService implements PackageSender, TestUtilityService final WatchedArrayMap packageSettings = mSettings.getPackagesLocked(); - // Save the names of pre-existing packages prior to scanning, so we can determine - // which system packages are completely new due to an upgrade. if (isDeviceUpgrading()) { + // Save the names of pre-existing packages prior to scanning, so we can determine + // which system packages are completely new due to an upgrade. mExistingPackages = new ArraySet<>(packageSettings.size()); for (PackageSetting ps : packageSettings.values()) { mExistingPackages.add(ps.getPackageName()); } + + // Triggering {@link com.android.server.pm.crossprofile. + // CrossProfileIntentFilterHelper.updateDefaultCrossProfileIntentFilter} to update + // {@link CrossProfileIntentFilter}s between eligible users and their parent + t.traceBegin("cross profile intent filter update"); + mInjector.getCrossProfileIntentFilterHelper() + .updateDefaultCrossProfileIntentFilter(); + t.traceEnd(); } mCacheDir = PackageManagerServiceUtils.preparePackageParserCache( @@ -3448,6 +3459,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService scheduleWritePackageRestrictions(sourceUserId); } + // Enforcing that callingUid is owning pkg on userId private void enforceOwnerRights(@NonNull Computer snapshot, String pkg, int callingUid) { // The system owns everything. @@ -4638,21 +4650,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService enforceOwnerRights(snapshot, ownerPackage, callingUid); PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(), UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId); - synchronized (mLock) { - CrossProfileIntentResolver resolver = - mSettings.editCrossProfileIntentResolverLPw(sourceUserId); - ArraySet set = - new ArraySet<>(resolver.filterSet()); - for (CrossProfileIntentFilter filter : set) { - //Only remove if calling user is allowed based on access control of - // {@link CrossProfileIntentFilter} - if (filter.getOwnerPackage().equals(ownerPackage) - && mUserManager.isCrossProfileIntentFilterAccessible(sourceUserId, - filter.mTargetUserId, /* addCrossProfileIntentFilter */ false)) { - resolver.removeFilter(filter); - } - } - } + PackageManagerService.this.mInjector.getCrossProfileIntentFilterHelper() + .clearCrossProfileIntentFilters(sourceUserId, ownerPackage, + null); scheduleWritePackageRestrictions(sourceUserId); } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java index 396994b045144..76e6e45fc8739 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java @@ -139,6 +139,7 @@ public class PackageManagerServiceInjector { private final Singleton mBackgroundDexOptService; private final Singleton mIBackupManager; private final Singleton mSharedLibrariesProducer; + private final Singleton mCrossProfileIntentFilterHelperProducer; PackageManagerServiceInjector(Context context, PackageManagerTracedLock lock, Installer installer, Object installLock, PackageAbiHelper abiHelper, @@ -176,7 +177,8 @@ public class PackageManagerServiceInjector { ServiceProducer getSystemServiceProducer, Producer backgroundDexOptService, Producer iBackupManager, - Producer sharedLibrariesProducer) { + Producer sharedLibrariesProducer, + Producer crossProfileIntentFilterHelperProducer) { mContext = context; mLock = lock; mInstaller = installer; @@ -228,6 +230,8 @@ public class PackageManagerServiceInjector { mBackgroundDexOptService = new Singleton<>(backgroundDexOptService); mIBackupManager = new Singleton<>(iBackupManager); mSharedLibrariesProducer = new Singleton<>(sharedLibrariesProducer); + mCrossProfileIntentFilterHelperProducer = new Singleton<>( + crossProfileIntentFilterHelperProducer); } /** @@ -262,6 +266,14 @@ public class PackageManagerServiceInjector { return mLock; } + /** + * {@link CrossProfileIntentFilterHelper} which manages {@link CrossProfileIntentFilter} + * @return CrossProfileIntentFilterHelper + */ + public CrossProfileIntentFilterHelper getCrossProfileIntentFilterHelper() { + return mCrossProfileIntentFilterHelperProducer.get(this, mPackageManager); + } + public Installer getInstaller() { return mInstaller; } diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java index 8fb5773706c56..2bb72b8cae42d 100644 --- a/services/core/java/com/android/server/pm/UserTypeFactory.java +++ b/services/core/java/com/android/server/pm/UserTypeFactory.java @@ -132,7 +132,8 @@ public final class UserTypeFactory { .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT) .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_WITH_PARENT) .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT) - .setUseParentsContacts(true)); + .setUseParentsContacts(true) + .setUpdateCrossProfileIntentFiltersOnOTA(true)); } /** diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt index 27d0662d118ed..4f562710c789b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt @@ -193,6 +193,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { val incrementalManager: IncrementalManager = mock() val platformCompat: PlatformCompat = mock() val settings: Settings = mock() + val crossProfileIntentFilterHelper: CrossProfileIntentFilterHelper = mock() val resources: Resources = mock() val systemConfig: SystemConfig = mock() val apexManager: ApexManager = mock() @@ -279,6 +280,8 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { whenever(mocks.injector.incrementalManager).thenReturn(mocks.incrementalManager) whenever(mocks.injector.compatibility).thenReturn(mocks.platformCompat) whenever(mocks.injector.settings).thenReturn(mocks.settings) + whenever(mocks.injector.crossProfileIntentFilterHelper) + .thenReturn(mocks.crossProfileIntentFilterHelper) whenever(mocks.injector.dexManager).thenReturn(mocks.dexManager) whenever(mocks.injector.systemConfig).thenReturn(mocks.systemConfig) whenever(mocks.injector.apexManager).thenReturn(mocks.apexManager)