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)