Merge "Add new UserProperty deleteAppWithParent."
This commit is contained in:
@@ -2399,6 +2399,14 @@ public abstract class PackageManager {
|
||||
*/
|
||||
public static final int DELETE_FAILED_APP_PINNED = -7;
|
||||
|
||||
/**
|
||||
* Deletion failed return code: this is passed to the
|
||||
* {@link IPackageDeleteObserver} if the system failed to delete the package
|
||||
* for any child profile with {@link UserProperties#getDeleteAppWithParent()} as true.
|
||||
* @hide
|
||||
*/
|
||||
public static final int DELETE_FAILED_FOR_CHILD_PROFILE = -8;
|
||||
|
||||
/**
|
||||
* Return code that is passed to the {@link IPackageMoveObserver} when the
|
||||
* package has been successfully moved by the system.
|
||||
|
||||
@@ -61,6 +61,7 @@ public final class UserProperties implements Parcelable {
|
||||
"mediaSharedWithParent";
|
||||
private static final String ATTR_CREDENTIAL_SHAREABLE_WITH_PARENT =
|
||||
"credentialShareableWithParent";
|
||||
private static final String ATTR_DELETE_APP_WITH_PARENT = "deleteAppWithParent";
|
||||
|
||||
/** Index values of each property (to indicate whether they are present in this object). */
|
||||
@IntDef(prefix = "INDEX_", value = {
|
||||
@@ -73,7 +74,8 @@ public final class UserProperties implements Parcelable {
|
||||
INDEX_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL,
|
||||
INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY,
|
||||
INDEX_MEDIA_SHARED_WITH_PARENT,
|
||||
INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT
|
||||
INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT,
|
||||
INDEX_DELETE_APP_WITH_PARENT,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
private @interface PropertyIndex {
|
||||
@@ -88,6 +90,7 @@ public final class UserProperties implements Parcelable {
|
||||
private static final int INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY = 7;
|
||||
private static final int INDEX_MEDIA_SHARED_WITH_PARENT = 8;
|
||||
private static final int INDEX_CREDENTIAL_SHAREABLE_WITH_PARENT = 9;
|
||||
private static final int INDEX_DELETE_APP_WITH_PARENT = 10;
|
||||
/** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
|
||||
private long mPropertiesPresent = 0;
|
||||
|
||||
@@ -312,6 +315,7 @@ public final class UserProperties implements Parcelable {
|
||||
setCrossProfileIntentFilterAccessControl(
|
||||
orig.getCrossProfileIntentFilterAccessControl());
|
||||
setCrossProfileIntentResolutionStrategy(orig.getCrossProfileIntentResolutionStrategy());
|
||||
setDeleteAppWithParent(orig.getDeleteAppWithParent());
|
||||
}
|
||||
if (hasManagePermission) {
|
||||
// Add items that require MANAGE_USERS or stronger.
|
||||
@@ -417,6 +421,24 @@ public final class UserProperties implements Parcelable {
|
||||
}
|
||||
private boolean mStartWithParent;
|
||||
|
||||
/**
|
||||
* Returns whether an app in the profile should be deleted when the same package in
|
||||
* the parent user is being deleted.
|
||||
* This only applies for users that have parents (i.e. for profiles).
|
||||
* @hide
|
||||
*/
|
||||
public boolean getDeleteAppWithParent() {
|
||||
if (isPresent(INDEX_DELETE_APP_WITH_PARENT)) return mDeleteAppWithParent;
|
||||
if (mDefaultProperties != null) return mDefaultProperties.mDeleteAppWithParent;
|
||||
throw new SecurityException("You don't have permission to query deleteAppWithParent");
|
||||
}
|
||||
/** @hide */
|
||||
public void setDeleteAppWithParent(boolean val) {
|
||||
this.mDeleteAppWithParent = val;
|
||||
setPresent(INDEX_DELETE_APP_WITH_PARENT);
|
||||
}
|
||||
private boolean mDeleteAppWithParent;
|
||||
|
||||
/**
|
||||
* Return whether, and how, select user restrictions or device policies should be inherited
|
||||
* from other user.
|
||||
@@ -609,6 +631,7 @@ public final class UserProperties implements Parcelable {
|
||||
+ getCrossProfileIntentResolutionStrategy()
|
||||
+ ", mMediaSharedWithParent=" + isMediaSharedWithParent()
|
||||
+ ", mCredentialShareableWithParent=" + isCredentialShareableWithParent()
|
||||
+ ", mDeleteAppWithParent=" + getDeleteAppWithParent()
|
||||
+ "}";
|
||||
}
|
||||
|
||||
@@ -634,6 +657,7 @@ public final class UserProperties implements Parcelable {
|
||||
pw.println(prefix + " mMediaSharedWithParent=" + isMediaSharedWithParent());
|
||||
pw.println(prefix + " mCredentialShareableWithParent="
|
||||
+ isCredentialShareableWithParent());
|
||||
pw.println(prefix + " mDeleteAppWithParent=" + getDeleteAppWithParent());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -697,6 +721,9 @@ public final class UserProperties implements Parcelable {
|
||||
case ATTR_CREDENTIAL_SHAREABLE_WITH_PARENT:
|
||||
setCredentialShareableWithParent(parser.getAttributeBoolean(i));
|
||||
break;
|
||||
case ATTR_DELETE_APP_WITH_PARENT:
|
||||
setDeleteAppWithParent(parser.getAttributeBoolean(i));
|
||||
break;
|
||||
default:
|
||||
Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
|
||||
}
|
||||
@@ -752,6 +779,10 @@ public final class UserProperties implements Parcelable {
|
||||
serializer.attributeBoolean(null, ATTR_CREDENTIAL_SHAREABLE_WITH_PARENT,
|
||||
mCredentialShareableWithParent);
|
||||
}
|
||||
if (isPresent(INDEX_DELETE_APP_WITH_PARENT)) {
|
||||
serializer.attributeBoolean(null, ATTR_DELETE_APP_WITH_PARENT,
|
||||
mDeleteAppWithParent);
|
||||
}
|
||||
}
|
||||
|
||||
// For use only with an object that has already had any permission-lacking fields stripped out.
|
||||
@@ -768,6 +799,7 @@ public final class UserProperties implements Parcelable {
|
||||
dest.writeInt(mCrossProfileIntentResolutionStrategy);
|
||||
dest.writeBoolean(mMediaSharedWithParent);
|
||||
dest.writeBoolean(mCredentialShareableWithParent);
|
||||
dest.writeBoolean(mDeleteAppWithParent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -788,6 +820,7 @@ public final class UserProperties implements Parcelable {
|
||||
mCrossProfileIntentResolutionStrategy = source.readInt();
|
||||
mMediaSharedWithParent = source.readBoolean();
|
||||
mCredentialShareableWithParent = source.readBoolean();
|
||||
mDeleteAppWithParent = source.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -825,6 +858,7 @@ public final class UserProperties implements Parcelable {
|
||||
CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT;
|
||||
private boolean mMediaSharedWithParent = false;
|
||||
private boolean mCredentialShareableWithParent = false;
|
||||
private boolean mDeleteAppWithParent = false;
|
||||
|
||||
public Builder setShowInLauncher(@ShowInLauncher int showInLauncher) {
|
||||
mShowInLauncher = showInLauncher;
|
||||
@@ -886,6 +920,12 @@ public final class UserProperties implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the value for {@link #mDeleteAppWithParent}*/
|
||||
public Builder setDeleteAppWithParent(boolean deleteAppWithParent) {
|
||||
mDeleteAppWithParent = deleteAppWithParent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds a UserProperties object with *all* values populated. */
|
||||
public UserProperties build() {
|
||||
return new UserProperties(
|
||||
@@ -898,7 +938,8 @@ public final class UserProperties implements Parcelable {
|
||||
mCrossProfileIntentFilterAccessControl,
|
||||
mCrossProfileIntentResolutionStrategy,
|
||||
mMediaSharedWithParent,
|
||||
mCredentialShareableWithParent);
|
||||
mCredentialShareableWithParent,
|
||||
mDeleteAppWithParent);
|
||||
}
|
||||
} // end Builder
|
||||
|
||||
@@ -912,8 +953,8 @@ public final class UserProperties implements Parcelable {
|
||||
@CrossProfileIntentFilterAccessControlLevel int crossProfileIntentFilterAccessControl,
|
||||
@CrossProfileIntentResolutionStrategy int crossProfileIntentResolutionStrategy,
|
||||
boolean mediaSharedWithParent,
|
||||
boolean credentialShareableWithParent) {
|
||||
|
||||
boolean credentialShareableWithParent,
|
||||
boolean deleteAppWithParent) {
|
||||
mDefaultProperties = null;
|
||||
setShowInLauncher(showInLauncher);
|
||||
setStartWithParent(startWithParent);
|
||||
@@ -925,5 +966,6 @@ public final class UserProperties implements Parcelable {
|
||||
setCrossProfileIntentResolutionStrategy(crossProfileIntentResolutionStrategy);
|
||||
setMediaSharedWithParent(mediaSharedWithParent);
|
||||
setCredentialShareableWithParent(credentialShareableWithParent);
|
||||
setDeleteAppWithParent(deleteAppWithParent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.SharedLibraryInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.pm.UserProperties;
|
||||
import android.content.pm.VersionedPackage;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
@@ -776,19 +777,23 @@ final class DeletePackageHelper {
|
||||
userId, deleteFlags, false /*removedBySystem*/);
|
||||
|
||||
// Get a list of child user profiles and delete if package is
|
||||
// present in clone profile.
|
||||
// present in that profile.
|
||||
int[] childUserIds = mUserManagerInternal.getProfileIds(userId, true);
|
||||
int returnCodeOfChild;
|
||||
for (int childId : childUserIds) {
|
||||
if (childId != userId) {
|
||||
UserInfo userInfo = mUserManagerInternal.getUserInfo(childId);
|
||||
if (userInfo != null && userInfo.isCloneProfile()) {
|
||||
returnCode = deletePackageX(internalPackageName, versionCode,
|
||||
childId, deleteFlags, false /*removedBySystem*/);
|
||||
break;
|
||||
if (childId == userId) continue;
|
||||
UserProperties userProperties = mUserManagerInternal
|
||||
.getUserProperties(childId);
|
||||
if (userProperties != null && userProperties.getDeleteAppWithParent()) {
|
||||
returnCodeOfChild = deletePackageX(internalPackageName, versionCode,
|
||||
childId, deleteFlags, false /*removedBySystem*/);
|
||||
if (returnCodeOfChild != PackageManager.DELETE_SUCCEEDED) {
|
||||
Slog.w(TAG, "Package delete failed for user " + childId
|
||||
+ ", returnCode " + returnCodeOfChild);
|
||||
returnCode = PackageManager.DELETE_FAILED_FOR_CHILD_PROFILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
int[] blockUninstallUserIds = getBlockUninstallForUsers(innerSnapshot,
|
||||
internalPackageName, users);
|
||||
|
||||
@@ -136,7 +136,7 @@ public final class UserTypeFactory {
|
||||
.CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING)
|
||||
.setMediaSharedWithParent(true)
|
||||
.setCredentialShareableWithParent(true)
|
||||
);
|
||||
.setDeleteAppWithParent(true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
crossProfileIntentResolutionStrategy='0'
|
||||
mediaSharedWithParent='true'
|
||||
credentialShareableWithParent='false'
|
||||
showInSettings='23'
|
||||
inheritDevicePolicy='450'
|
||||
deleteAppWithParent='false'
|
||||
/>
|
||||
</profile-type>
|
||||
<profile-type name='custom.test.1' max-allowed-per-parent='14' />
|
||||
|
||||
@@ -66,6 +66,7 @@ public class UserManagerServiceUserPropertiesTest {
|
||||
.setCrossProfileIntentResolutionStrategy(0)
|
||||
.setMediaSharedWithParent(false)
|
||||
.setCredentialShareableWithParent(true)
|
||||
.setDeleteAppWithParent(false)
|
||||
.build();
|
||||
final UserProperties actualProps = new UserProperties(defaultProps);
|
||||
actualProps.setShowInLauncher(14);
|
||||
@@ -76,6 +77,7 @@ public class UserManagerServiceUserPropertiesTest {
|
||||
actualProps.setCrossProfileIntentResolutionStrategy(1);
|
||||
actualProps.setMediaSharedWithParent(true);
|
||||
actualProps.setCredentialShareableWithParent(false);
|
||||
actualProps.setDeleteAppWithParent(true);
|
||||
|
||||
// Write the properties to xml.
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
@@ -116,12 +118,14 @@ public class UserManagerServiceUserPropertiesTest {
|
||||
.setShowInSettings(3452)
|
||||
.setInheritDevicePolicy(1732)
|
||||
.setMediaSharedWithParent(true)
|
||||
.setDeleteAppWithParent(true)
|
||||
.build();
|
||||
final UserProperties orig = new UserProperties(defaultProps);
|
||||
orig.setShowInLauncher(2841);
|
||||
orig.setStartWithParent(false);
|
||||
orig.setShowInSettings(1437);
|
||||
orig.setInheritDevicePolicy(9456);
|
||||
orig.setDeleteAppWithParent(false);
|
||||
|
||||
// Test every permission level. (Currently, it's linear so it's easy.)
|
||||
for (int permLevel = 0; permLevel < 4; permLevel++) {
|
||||
@@ -163,6 +167,8 @@ public class UserManagerServiceUserPropertiesTest {
|
||||
copy::getCrossProfileIntentFilterAccessControl, exposeAll);
|
||||
assertEqualGetterOrThrows(orig::getCrossProfileIntentResolutionStrategy,
|
||||
copy::getCrossProfileIntentResolutionStrategy, exposeAll);
|
||||
assertEqualGetterOrThrows(orig::getDeleteAppWithParent,
|
||||
copy::getDeleteAppWithParent, exposeAll);
|
||||
|
||||
// Items requiring hasManagePermission - put them here using hasManagePermission.
|
||||
assertEqualGetterOrThrows(orig::getShowInSettings, copy::getShowInSettings,
|
||||
@@ -227,5 +233,6 @@ public class UserManagerServiceUserPropertiesTest {
|
||||
.isEqualTo(actual.isMediaSharedWithParent());
|
||||
assertThat(expected.isCredentialShareableWithParent())
|
||||
.isEqualTo(actual.isCredentialShareableWithParent());
|
||||
assertThat(expected.getDeleteAppWithParent()).isEqualTo(actual.getDeleteAppWithParent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,11 @@ public class UserManagerServiceUserTypeTest {
|
||||
.setCrossProfileIntentFilterAccessControl(10)
|
||||
.setCrossProfileIntentResolutionStrategy(1)
|
||||
.setMediaSharedWithParent(true)
|
||||
.setCredentialShareableWithParent(false);
|
||||
.setCredentialShareableWithParent(false)
|
||||
.setShowInSettings(900)
|
||||
.setInheritDevicePolicy(340)
|
||||
.setDeleteAppWithParent(true);
|
||||
|
||||
final UserTypeDetails type = new UserTypeDetails.Builder()
|
||||
.setName("a.name")
|
||||
.setEnabled(1)
|
||||
@@ -152,6 +156,10 @@ public class UserManagerServiceUserTypeTest {
|
||||
.getCrossProfileIntentResolutionStrategy());
|
||||
assertTrue(type.getDefaultUserPropertiesReference().isMediaSharedWithParent());
|
||||
assertFalse(type.getDefaultUserPropertiesReference().isCredentialShareableWithParent());
|
||||
assertEquals(900, type.getDefaultUserPropertiesReference().getShowInSettings());
|
||||
assertEquals(340, type.getDefaultUserPropertiesReference()
|
||||
.getInheritDevicePolicy());
|
||||
assertTrue(type.getDefaultUserPropertiesReference().getDeleteAppWithParent());
|
||||
|
||||
assertEquals(23, type.getBadgeLabel(0));
|
||||
assertEquals(24, type.getBadgeLabel(1));
|
||||
@@ -287,7 +295,11 @@ public class UserManagerServiceUserTypeTest {
|
||||
.setCrossProfileIntentFilterAccessControl(10)
|
||||
.setCrossProfileIntentResolutionStrategy(1)
|
||||
.setMediaSharedWithParent(false)
|
||||
.setCredentialShareableWithParent(true);
|
||||
.setCredentialShareableWithParent(true)
|
||||
.setShowInSettings(20)
|
||||
.setInheritDevicePolicy(21)
|
||||
.setDeleteAppWithParent(true);
|
||||
|
||||
final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
|
||||
builders.put(userTypeAosp1, new UserTypeDetails.Builder()
|
||||
.setName(userTypeAosp1)
|
||||
@@ -323,6 +335,10 @@ public class UserManagerServiceUserTypeTest {
|
||||
assertFalse(aospType.getDefaultUserPropertiesReference().isMediaSharedWithParent());
|
||||
assertTrue(aospType.getDefaultUserPropertiesReference()
|
||||
.isCredentialShareableWithParent());
|
||||
assertEquals(20, aospType.getDefaultUserPropertiesReference().getShowInSettings());
|
||||
assertEquals(21, aospType.getDefaultUserPropertiesReference()
|
||||
.getInheritDevicePolicy());
|
||||
assertTrue(aospType.getDefaultUserPropertiesReference().getDeleteAppWithParent());
|
||||
|
||||
// userTypeAosp2 should be modified.
|
||||
aospType = builders.get(userTypeAosp2).createUserTypeDetails();
|
||||
@@ -362,6 +378,11 @@ public class UserManagerServiceUserTypeTest {
|
||||
assertTrue(aospType.getDefaultUserPropertiesReference().isMediaSharedWithParent());
|
||||
assertFalse(aospType.getDefaultUserPropertiesReference()
|
||||
.isCredentialShareableWithParent());
|
||||
assertEquals(23, aospType.getDefaultUserPropertiesReference().getShowInSettings());
|
||||
assertEquals(450, aospType.getDefaultUserPropertiesReference()
|
||||
.getInheritDevicePolicy());
|
||||
assertFalse(aospType.getDefaultUserPropertiesReference()
|
||||
.getDeleteAppWithParent());
|
||||
|
||||
// userTypeOem1 should be created.
|
||||
UserTypeDetails.Builder customType = builders.get(userTypeOem1);
|
||||
|
||||
@@ -192,6 +192,7 @@ public final class UserManagerTest {
|
||||
.isEqualTo(cloneUserProperties.isMediaSharedWithParent());
|
||||
assertThat(typeProps.isCredentialShareableWithParent())
|
||||
.isEqualTo(cloneUserProperties.isCredentialShareableWithParent());
|
||||
assertThrows(SecurityException.class, cloneUserProperties::getDeleteAppWithParent);
|
||||
|
||||
// Verify clone user parent
|
||||
assertThat(mUserManager.getProfileParent(mainUserId)).isNull();
|
||||
@@ -844,8 +845,10 @@ public final class UserManagerTest {
|
||||
assertThrows(SecurityException.class, userProps::getInheritDevicePolicy);
|
||||
assertThat(userProps.isMediaSharedWithParent()).isFalse();
|
||||
assertThat(userProps.isCredentialShareableWithParent()).isTrue();
|
||||
assertThrows(SecurityException.class, userProps::getDeleteAppWithParent);
|
||||
}
|
||||
|
||||
|
||||
// Make sure only max managed profiles can be created
|
||||
@MediumTest
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user