1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.pm; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.testng.Assert.assertThrows; 22 23 import android.content.pm.UserProperties; 24 import android.os.Parcel; 25 import android.platform.test.annotations.Presubmit; 26 import android.util.Xml; 27 28 import androidx.test.filters.MediumTest; 29 import androidx.test.runner.AndroidJUnit4; 30 31 import com.android.modules.utils.TypedXmlPullParser; 32 import com.android.modules.utils.TypedXmlSerializer; 33 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 37 import java.io.ByteArrayInputStream; 38 import java.io.ByteArrayOutputStream; 39 import java.nio.charset.StandardCharsets; 40 import java.util.function.Supplier; 41 42 /** 43 * Tests for UserManager's {@link UserProperties}. 44 * 45 * Additional test coverage (that actually exercises the functionality) can be found in 46 * {@link UserManagerTest} and 47 * {@link UserManagerServiceUserTypeTest} (for {@link UserProperties#updateFromXml}). 48 * 49 * <p>Run with: atest UserManagerServiceUserPropertiesTest 50 */ 51 @Presubmit 52 @RunWith(AndroidJUnit4.class) 53 @MediumTest 54 public class UserManagerServiceUserPropertiesTest { 55 56 /** Test that UserProperties can properly read the xml information that it writes. */ 57 @Test testWriteReadXml()58 public void testWriteReadXml() throws Exception { 59 final UserProperties defaultProps = new UserProperties.Builder() 60 .setShowInLauncher(21) 61 .setStartWithParent(false) 62 .setShowInSettings(45) 63 .setInheritDevicePolicy(67) 64 .setUseParentsContacts(false) 65 .setCrossProfileIntentFilterAccessControl(10) 66 .setCrossProfileIntentResolutionStrategy(0) 67 .setMediaSharedWithParent(false) 68 .setCredentialShareableWithParent(true) 69 .setDeleteAppWithParent(false) 70 .build(); 71 final UserProperties actualProps = new UserProperties(defaultProps); 72 actualProps.setShowInLauncher(14); 73 actualProps.setShowInSettings(32); 74 actualProps.setInheritDevicePolicy(51); 75 actualProps.setUseParentsContacts(true); 76 actualProps.setCrossProfileIntentFilterAccessControl(20); 77 actualProps.setCrossProfileIntentResolutionStrategy(1); 78 actualProps.setMediaSharedWithParent(true); 79 actualProps.setCredentialShareableWithParent(false); 80 actualProps.setDeleteAppWithParent(true); 81 82 // Write the properties to xml. 83 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 84 final TypedXmlSerializer out = Xml.newFastSerializer(); 85 out.setOutput(baos, StandardCharsets.UTF_8.name()); 86 out.startDocument(null, true); 87 out.startTag(null, "testTag"); 88 actualProps.writeToXml(out); 89 out.endTag(null, "testTag"); 90 out.endDocument(); 91 92 // Now read those properties from xml. 93 final ByteArrayInputStream input = new ByteArrayInputStream(baos.toByteArray()); 94 final TypedXmlPullParser parser = Xml.newFastPullParser(); 95 parser.setInput(input, StandardCharsets.UTF_8.name()); 96 parser.nextTag(); 97 final UserProperties readProps = new UserProperties(parser, defaultProps); 98 99 assertUserPropertiesEquals(actualProps, readProps); 100 } 101 102 /** Tests parcelling an object in which all properties are present. */ 103 @Test testParcelUnparcel()104 public void testParcelUnparcel() throws Exception { 105 final UserProperties originalProps = new UserProperties.Builder() 106 .setShowInLauncher(2145) 107 .build(); 108 final UserProperties readProps = parcelThenUnparcel(originalProps); 109 assertUserPropertiesEquals(originalProps, readProps); 110 } 111 112 /** Tests copying a UserProperties object varying permissions. */ 113 @Test testCopyLacksPermissions()114 public void testCopyLacksPermissions() throws Exception { 115 final UserProperties defaultProps = new UserProperties.Builder() 116 .setShowInLauncher(2145) 117 .setStartWithParent(true) 118 .setShowInSettings(3452) 119 .setInheritDevicePolicy(1732) 120 .setMediaSharedWithParent(true) 121 .setDeleteAppWithParent(true) 122 .build(); 123 final UserProperties orig = new UserProperties(defaultProps); 124 orig.setShowInLauncher(2841); 125 orig.setStartWithParent(false); 126 orig.setShowInSettings(1437); 127 orig.setInheritDevicePolicy(9456); 128 orig.setDeleteAppWithParent(false); 129 130 // Test every permission level. (Currently, it's linear so it's easy.) 131 for (int permLevel = 0; permLevel < 4; permLevel++) { 132 final boolean exposeAll = permLevel >= 3; 133 final boolean hasManage = permLevel >= 2; 134 final boolean hasQuery = permLevel >= 1; 135 136 // Make a possibly-not-full-permission (i.e. partial) copy and check that it is correct. 137 final UserProperties copy = new UserProperties(orig, exposeAll, hasManage, hasQuery); 138 verifyTestCopyLacksPermissions(orig, copy, exposeAll, hasManage, hasQuery); 139 if (permLevel < 1) { 140 // PropertiesPresent should definitely be different since not all items were copied. 141 assertThat(orig.getPropertiesPresent()).isNotEqualTo(copy.getPropertiesPresent()); 142 } 143 144 // Now, just like in the SystemServer, parcel/unparcel the copy and make sure that the 145 // unparcelled version behaves just like the partial copy did. 146 final UserProperties readProps = parcelThenUnparcel(copy); 147 verifyTestCopyLacksPermissions(orig, readProps, exposeAll, hasManage, hasQuery); 148 } 149 } 150 151 /** 152 * Verifies that the copy of orig has the expected properties 153 * for the test {@link #testCopyLacksPermissions}. 154 */ verifyTestCopyLacksPermissions( UserProperties orig, UserProperties copy, boolean exposeAll, boolean hasManagePermission, boolean hasQueryPermission)155 private void verifyTestCopyLacksPermissions( 156 UserProperties orig, 157 UserProperties copy, 158 boolean exposeAll, 159 boolean hasManagePermission, 160 boolean hasQueryPermission) { 161 162 // Items requiring exposeAll. 163 assertEqualGetterOrThrows(orig::getStartWithParent, copy::getStartWithParent, exposeAll); 164 assertEqualGetterOrThrows(orig::getInheritDevicePolicy, 165 copy::getInheritDevicePolicy, exposeAll); 166 assertEqualGetterOrThrows(orig::getCrossProfileIntentFilterAccessControl, 167 copy::getCrossProfileIntentFilterAccessControl, exposeAll); 168 assertEqualGetterOrThrows(orig::getCrossProfileIntentResolutionStrategy, 169 copy::getCrossProfileIntentResolutionStrategy, exposeAll); 170 assertEqualGetterOrThrows(orig::getDeleteAppWithParent, 171 copy::getDeleteAppWithParent, exposeAll); 172 173 // Items requiring hasManagePermission - put them here using hasManagePermission. 174 assertEqualGetterOrThrows(orig::getShowInSettings, copy::getShowInSettings, 175 hasManagePermission); 176 assertEqualGetterOrThrows(orig::getUseParentsContacts, 177 copy::getUseParentsContacts, hasManagePermission); 178 179 // Items requiring hasQueryPermission - put them here using hasQueryPermission. 180 181 // Items with no permission requirements. 182 assertEqualGetterOrThrows(orig::getShowInLauncher, copy::getShowInLauncher, true); 183 assertEqualGetterOrThrows(orig::isMediaSharedWithParent, 184 copy::isMediaSharedWithParent, true); 185 assertEqualGetterOrThrows(orig::isCredentialShareableWithParent, 186 copy::isCredentialShareableWithParent, true); 187 } 188 189 /** 190 * If hasPerm, then asserts that value of actualGetter equals value of expectedGetter. 191 * If !hasPerm, then asserts that actualGetter throws a SecurityException. 192 */ 193 @SuppressWarnings("ReturnValueIgnored") assertEqualGetterOrThrows( Supplier expectedGetter, Supplier actualGetter, boolean hasPerm)194 private void assertEqualGetterOrThrows( 195 Supplier expectedGetter, 196 Supplier actualGetter, 197 boolean hasPerm) { 198 if (hasPerm) { 199 assertThat(expectedGetter.get()).isEqualTo(actualGetter.get()); 200 } else { 201 assertThrows(SecurityException.class, actualGetter::get); 202 } 203 } 204 parcelThenUnparcel(UserProperties originalProps)205 private UserProperties parcelThenUnparcel(UserProperties originalProps) { 206 final Parcel out = Parcel.obtain(); 207 originalProps.writeToParcel(out, 0); 208 final byte[] data = out.marshall(); 209 out.recycle(); 210 211 final Parcel in = Parcel.obtain(); 212 in.unmarshall(data, 0, data.length); 213 in.setDataPosition(0); 214 final UserProperties readProps = UserProperties.CREATOR.createFromParcel(in); 215 in.recycle(); 216 217 return readProps; 218 } 219 220 /** Checks that two UserProperties get the same values. */ assertUserPropertiesEquals(UserProperties expected, UserProperties actual)221 private void assertUserPropertiesEquals(UserProperties expected, UserProperties actual) { 222 assertThat(expected.getPropertiesPresent()).isEqualTo(actual.getPropertiesPresent()); 223 assertThat(expected.getShowInLauncher()).isEqualTo(actual.getShowInLauncher()); 224 assertThat(expected.getStartWithParent()).isEqualTo(actual.getStartWithParent()); 225 assertThat(expected.getShowInSettings()).isEqualTo(actual.getShowInSettings()); 226 assertThat(expected.getInheritDevicePolicy()).isEqualTo(actual.getInheritDevicePolicy()); 227 assertThat(expected.getUseParentsContacts()).isEqualTo(actual.getUseParentsContacts()); 228 assertThat(expected.getCrossProfileIntentFilterAccessControl()) 229 .isEqualTo(actual.getCrossProfileIntentFilterAccessControl()); 230 assertThat(expected.getCrossProfileIntentResolutionStrategy()) 231 .isEqualTo(actual.getCrossProfileIntentResolutionStrategy()); 232 assertThat(expected.isMediaSharedWithParent()) 233 .isEqualTo(actual.isMediaSharedWithParent()); 234 assertThat(expected.isCredentialShareableWithParent()) 235 .isEqualTo(actual.isCredentialShareableWithParent()); 236 assertThat(expected.getDeleteAppWithParent()).isEqualTo(actual.getDeleteAppWithParent()); 237 } 238 } 239