| /* |
| * 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 static com.google.common.truth.Truth.assertThat; |
| |
| import static org.testng.Assert.assertThrows; |
| |
| import android.content.pm.UserProperties; |
| import android.os.Parcel; |
| import android.platform.test.annotations.Presubmit; |
| import android.util.Xml; |
| |
| import androidx.test.filters.MediumTest; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import com.android.modules.utils.TypedXmlPullParser; |
| import com.android.modules.utils.TypedXmlSerializer; |
| |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.nio.charset.StandardCharsets; |
| import java.util.function.Supplier; |
| |
| /** |
| * Tests for UserManager's {@link UserProperties}. |
| * |
| * Additional test coverage (that actually exercises the functionality) can be found in |
| * {@link UserManagerTest} and |
| * {@link UserManagerServiceUserTypeTest} (for {@link UserProperties#updateFromXml}). |
| * |
| * <p>Run with: atest UserManagerServiceUserPropertiesTest |
| */ |
| @Presubmit |
| @RunWith(AndroidJUnit4.class) |
| @MediumTest |
| public class UserManagerServiceUserPropertiesTest { |
| |
| /** Test that UserProperties can properly read the xml information that it writes. */ |
| @Test |
| public void testWriteReadXml() throws Exception { |
| final UserProperties defaultProps = new UserProperties.Builder() |
| .setShowInLauncher(21) |
| .setStartWithParent(false) |
| .build(); |
| final UserProperties actualProps = new UserProperties(defaultProps); |
| actualProps.setShowInLauncher(14); |
| |
| // Write the properties to xml. |
| final ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| final TypedXmlSerializer out = Xml.newFastSerializer(); |
| out.setOutput(baos, StandardCharsets.UTF_8.name()); |
| out.startDocument(null, true); |
| out.startTag(null, "testTag"); |
| actualProps.writeToXml(out); |
| out.endTag(null, "testTag"); |
| out.endDocument(); |
| |
| // Now read those properties from xml. |
| final ByteArrayInputStream input = new ByteArrayInputStream(baos.toByteArray()); |
| final TypedXmlPullParser parser = Xml.newFastPullParser(); |
| parser.setInput(input, StandardCharsets.UTF_8.name()); |
| parser.nextTag(); |
| final UserProperties readProps = new UserProperties(parser, defaultProps); |
| |
| assertUserPropertiesEquals(actualProps, readProps); |
| } |
| |
| /** Tests parcelling an object in which all properties are present. */ |
| @Test |
| public void testParcelUnparcel() throws Exception { |
| final UserProperties originalProps = new UserProperties.Builder() |
| .setShowInLauncher(2145) |
| .build(); |
| final UserProperties readProps = parcelThenUnparcel(originalProps); |
| assertUserPropertiesEquals(originalProps, readProps); |
| } |
| |
| /** Tests copying a UserProperties object varying permissions. */ |
| @Test |
| public void testCopyLacksPermissions() throws Exception { |
| final UserProperties defaultProps = new UserProperties.Builder() |
| .setShowInLauncher(2145) |
| .setStartWithParent(true) |
| .build(); |
| final UserProperties orig = new UserProperties(defaultProps); |
| orig.setShowInLauncher(2841); |
| orig.setStartWithParent(false); |
| |
| // Test every permission level. (Currently, it's linear so it's easy.) |
| for (int permLevel = 0; permLevel < 4; permLevel++) { |
| final boolean exposeAll = permLevel >= 3; |
| final boolean hasManage = permLevel >= 2; |
| final boolean hasQuery = permLevel >= 1; |
| |
| // Make a possibly-not-full-permission (i.e. partial) copy and check that it is correct. |
| final UserProperties copy = new UserProperties(orig, exposeAll, hasManage, hasQuery); |
| verifyTestCopyLacksPermissions(orig, copy, exposeAll, hasManage, hasQuery); |
| if (permLevel < 1) { |
| // PropertiesPresent should definitely be different since not all items were copied. |
| assertThat(orig.getPropertiesPresent()).isNotEqualTo(copy.getPropertiesPresent()); |
| } |
| |
| // Now, just like in the SystemServer, parcel/unparcel the copy and make sure that the |
| // unparcelled version behaves just like the partial copy did. |
| final UserProperties readProps = parcelThenUnparcel(copy); |
| verifyTestCopyLacksPermissions(orig, readProps, exposeAll, hasManage, hasQuery); |
| } |
| } |
| |
| /** |
| * Verifies that the copy of orig has the expected properties |
| * for the test {@link #testCopyLacksPermissions}. |
| */ |
| private void verifyTestCopyLacksPermissions( |
| UserProperties orig, |
| UserProperties copy, |
| boolean exposeAll, |
| boolean hasManagePermission, |
| boolean hasQueryPermission) { |
| |
| // Items requiring exposeAll. |
| assertEqualGetterOrThrows(orig::getStartWithParent, copy::getStartWithParent, exposeAll); |
| |
| // Items requiring hasManagePermission - put them here using hasManagePermission. |
| // Items requiring hasQueryPermission - put them here using hasQueryPermission. |
| |
| // Items with no permission requirements. |
| assertEqualGetterOrThrows(orig::getShowInLauncher, copy::getShowInLauncher, true); |
| } |
| |
| /** |
| * If hasPerm, then asserts that value of actualGetter equals value of expectedGetter. |
| * If !hasPerm, then asserts that actualGetter throws a SecurityException. |
| */ |
| @SuppressWarnings("ReturnValueIgnored") |
| private void assertEqualGetterOrThrows( |
| Supplier expectedGetter, |
| Supplier actualGetter, |
| boolean hasPerm) { |
| if (hasPerm) { |
| assertThat(expectedGetter.get()).isEqualTo(actualGetter.get()); |
| } else { |
| assertThrows(SecurityException.class, actualGetter::get); |
| } |
| } |
| |
| private UserProperties parcelThenUnparcel(UserProperties originalProps) { |
| final Parcel out = Parcel.obtain(); |
| originalProps.writeToParcel(out, 0); |
| final byte[] data = out.marshall(); |
| out.recycle(); |
| |
| final Parcel in = Parcel.obtain(); |
| in.unmarshall(data, 0, data.length); |
| in.setDataPosition(0); |
| final UserProperties readProps = UserProperties.CREATOR.createFromParcel(in); |
| in.recycle(); |
| |
| return readProps; |
| } |
| |
| /** Checks that two UserProperties get the same values. */ |
| private void assertUserPropertiesEquals(UserProperties expected, UserProperties actual) { |
| assertThat(expected.getPropertiesPresent()).isEqualTo(actual.getPropertiesPresent()); |
| assertThat(expected.getShowInLauncher()).isEqualTo(actual.getShowInLauncher()); |
| assertThat(expected.getStartWithParent()).isEqualTo(actual.getStartWithParent()); |
| } |
| } |