PackageManagerSettingsTests.java revision b6f06813b1eccbd96a6a71de599a36a3a3e08955
1135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent/* 2135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * Copyright (C) 2012 The Android Open Source Project 3135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * 4135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * Licensed under the Apache License, Version 2.0 (the "License"); 5135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * you may not use this file except in compliance with the License. 6135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * You may obtain a copy of the License at 7135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * 8135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * http://www.apache.org/licenses/LICENSE-2.0 9135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * 10135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * Unless required by applicable law or agreed to in writing, software 11135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * distributed under the License is distributed on an "AS IS" BASIS, 12135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * See the License for the specific language governing permissions and 14135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent * limitations under the License. 15135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent */ 16135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 17135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentpackage com.android.server.pm; 18135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 19135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; 20135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 21135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; 22135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 23135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 24135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.hamcrest.CoreMatchers.is; 25135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.hamcrest.CoreMatchers.not; 26135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.hamcrest.CoreMatchers.notNullValue; 27135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.hamcrest.CoreMatchers.nullValue; 28135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.junit.Assert.assertEquals; 29135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.junit.Assert.assertNotSame; 30135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.junit.Assert.assertNull; 31135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.junit.Assert.assertSame; 32135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.junit.Assert.assertThat; 33135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.junit.Assert.assertTrue; 34135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport static org.junit.Assert.fail; 35135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 36135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.annotation.NonNull; 37135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.content.pm.ApplicationInfo; 38135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.content.pm.PackageParser; 39135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.content.pm.PackageUserState; 40135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.content.pm.UserInfo; 41135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.os.UserHandle; 423856b090cd04ba5dd4a59a12430ed724d5995909Steve Blockimport android.os.UserManagerInternal; 43135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.security.keystore.ArrayUtils; 44135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.support.test.InstrumentationRegistry; 45135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.support.test.runner.AndroidJUnit4; 46135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.test.suitebuilder.annotation.SmallTest; 47135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.util.ArrayMap; 48135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.util.ArraySet; 49135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.util.Log; 50135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport android.util.LongSparseArray; 51135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 52135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport com.android.internal.os.AtomicFile; 53135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport com.android.server.LocalServices; 54135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 55135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport org.junit.Before; 56135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport org.junit.Test; 57135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport org.junit.runner.RunWith; 58135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 593856b090cd04ba5dd4a59a12430ed724d5995909Steve Blockimport java.io.File; 60135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport java.io.FileOutputStream; 61135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport java.io.IOException; 62135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport java.security.PublicKey; 63135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport java.util.ArrayList; 64135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport java.util.Arrays; 65135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentimport java.util.List; 66135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 67135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent@RunWith(AndroidJUnit4.class) 68135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent@SmallTest 693856b090cd04ba5dd4a59a12430ed724d5995909Steve Blockpublic class PackageManagerSettingsTests { 70135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final String PACKAGE_NAME_2 = "com.google.app2"; 71135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final String PACKAGE_NAME_3 = "com.android.app3"; 72135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final String PACKAGE_NAME_1 = "com.google.app1"; 73135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent public static final String TAG = "PackageManagerSettingsTests"; 74135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent protected final String PREFIX = "android.content.pm"; 75135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 76135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent /** make sure our initialized KeySetManagerService metadata matches packages.xml */ 77135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent @Test 783856b090cd04ba5dd4a59a12430ed724d5995909Steve Block public void testReadKeySetSettings() 79135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent throws ReflectiveOperationException, IllegalAccessException { 80135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent /* write out files and read */ 81135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent writeOldFiles(); 82135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent Settings settings = 83135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object()); 84135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(settings.readLPw(createFakeUsers()), is(true)); 853856b090cd04ba5dd4a59a12430ed724d5995909Steve Block verifyKeySetMetaData(settings); 86135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent } 87135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 88135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent /** read in data, write it out, and read it back in. Verify same. */ 89135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent @Test 90135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent public void testWriteKeySetSettings() 91135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent throws ReflectiveOperationException, IllegalAccessException { 92135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent // write out files and read 93135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent writeOldFiles(); 94135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent Settings settings = 95135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object()); 96135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(settings.readLPw(createFakeUsers()), is(true)); 97135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 98135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent // write out, read back in and verify the same 99135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent settings.writeLPr(); 100135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(settings.readLPw(createFakeUsers()), is(true)); 101135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent verifyKeySetMetaData(settings); 102135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent } 103135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 104135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent @Test 105135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent public void testSettingsReadOld() { 1063856b090cd04ba5dd4a59a12430ed724d5995909Steve Block // Write the package files and make sure they're parsed properly the first time 107135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent writeOldFiles(); 108135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent Settings settings = 109135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object()); 110135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(settings.readLPw(createFakeUsers()), is(true)); 111135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue())); 112135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(settings.getPackageLPr(PACKAGE_NAME_1), is(notNullValue())); 113135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 114135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_1); 115135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DEFAULT)); 116135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(ps.getNotLaunched(0), is(true)); 117135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 118135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ps = settings.getPackageLPr(PACKAGE_NAME_2); 1193856b090cd04ba5dd4a59a12430ed724d5995909Steve Block assertThat(ps.getStopped(0), is(false)); 120135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED_USER)); 121135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT)); 122135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent } 123135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 124135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent @Test 125135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent public void testNewPackageRestrictionsFile() throws ReflectiveOperationException { 126135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent // Write the package files and make sure they're parsed properly the first time 127135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent writeOldFiles(); 128135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent Settings settings = 129135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object()); 130135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(settings.readLPw(createFakeUsers()), is(true)); 131135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent settings.writeLPr(); 132135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 1333856b090cd04ba5dd4a59a12430ed724d5995909Steve Block // Create Settings again to make it read from the new files 134135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent settings = new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object()); 135135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(settings.readLPw(createFakeUsers()), is(true)); 136135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 137135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2); 138135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED_USER)); 139135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT)); 140135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent } 141135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 142135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent @Test 143135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent public void testEnableDisable() { 144135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent // Write the package files and make sure they're parsed properly the first time 145135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent writeOldFiles(); 146135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent Settings settings = 147135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object()); 148135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(settings.readLPw(createFakeUsers()), is(true)); 149135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 150135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent // Enable/Disable a package 151135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_1); 152135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null); 153135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1, null); 154135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED)); 155135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_ENABLED)); 156135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 157135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent // Enable/Disable a component 158135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ArraySet<String> components = new ArraySet<String>(); 159135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent String component1 = PACKAGE_NAME_1 + "/.Component1"; 160135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent components.add(component1); 161135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ps.setDisabledComponents(components, 0); 162135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ArraySet<String> componentsDisabled = ps.getDisabledComponents(0); 163135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(componentsDisabled.size(), is(1)); 164135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(componentsDisabled.toArray()[0], is(component1)); 165135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent boolean hasEnabled = 166135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ps.getEnabledComponents(0) != null && ps.getEnabledComponents(1).size() > 0; 167135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(hasEnabled, is(false)); 168135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 169135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent // User 1 should not have any disabled components 170135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent boolean hasDisabled = 171135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ps.getDisabledComponents(1) != null && ps.getDisabledComponents(1).size() > 0; 172135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(hasDisabled, is(false)); 173135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ps.setEnabledComponents(components, 1); 174135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(ps.getEnabledComponents(1).size(), is(1)); 175135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent hasEnabled = ps.getEnabledComponents(0) != null && ps.getEnabledComponents(0).size() > 0; 176135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(hasEnabled, is(false)); 177135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent } 178135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 179135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final String PACKAGE_NAME = "com.android.bar"; 180135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final String REAL_PACKAGE_NAME = "com.android.foo"; 181135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final String PARENT_PACKAGE_NAME = "com.android.bar.parent"; 182135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final String CHILD_PACKAGE_NAME_01 = "com.android.bar.child01"; 183135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final String CHILD_PACKAGE_NAME_02 = "com.android.bar.child02"; 184135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final String CHILD_PACKAGE_NAME_03 = "com.android.bar.child03"; 185135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final File INITIAL_CODE_PATH = 186135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent new File(InstrumentationRegistry.getContext().getFilesDir(), "com.android.bar-1"); 187135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final File UPDATED_CODE_PATH = 188135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent new File(InstrumentationRegistry.getContext().getFilesDir(), "com.android.bar-2"); 189135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final int INITIAL_VERSION_CODE = 10023; 190135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent private static final int UPDATED_VERSION_CODE = 10025; 191135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 192135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent @Test 193135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent public void testPackageStateCopy01() { 194135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final List<String> childPackageNames = new ArrayList<>(); 195135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent childPackageNames.add(CHILD_PACKAGE_NAME_01); 196135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent childPackageNames.add(CHILD_PACKAGE_NAME_02); 197135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent childPackageNames.add(CHILD_PACKAGE_NAME_03); 198135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final PackageSetting origPkgSetting01 = new PackageSetting( 199135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent PACKAGE_NAME, 200135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent REAL_PACKAGE_NAME, 201135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent INITIAL_CODE_PATH /*codePath*/, 202135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent INITIAL_CODE_PATH /*resourcePath*/, 203135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*legacyNativeLibraryPathString*/, 2043856b090cd04ba5dd4a59a12430ed724d5995909Steve Block "x86_64" /*primaryCpuAbiString*/, 205135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent "x86" /*secondaryCpuAbiString*/, 206135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*cpuAbiOverrideString*/, 207135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent INITIAL_VERSION_CODE, 208135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE, 209135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN, 210135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent PARENT_PACKAGE_NAME, 211135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent childPackageNames, 212135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 0, 213135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*usesStaticLibraries*/, 214135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*usesStaticLibrariesVersions*/); 215135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final PackageSetting testPkgSetting01 = new PackageSetting(origPkgSetting01); 216135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent verifySettingCopy(origPkgSetting01, testPkgSetting01); 2173856b090cd04ba5dd4a59a12430ed724d5995909Steve Block } 218135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 219135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent @Test 220135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent public void testPackageStateCopy02() { 221135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final List<String> childPackageNames = new ArrayList<>(); 222135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent childPackageNames.add(CHILD_PACKAGE_NAME_01); 223135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent childPackageNames.add(CHILD_PACKAGE_NAME_02); 224135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent childPackageNames.add(CHILD_PACKAGE_NAME_03); 225135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final PackageSetting origPkgSetting01 = new PackageSetting( 226135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent PACKAGE_NAME /*pkgName*/, 227135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent REAL_PACKAGE_NAME /*realPkgName*/, 2283856b090cd04ba5dd4a59a12430ed724d5995909Steve Block INITIAL_CODE_PATH /*codePath*/, 229135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent INITIAL_CODE_PATH /*resourcePath*/, 230135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*legacyNativeLibraryPathString*/, 231135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent "x86_64" /*primaryCpuAbiString*/, 232135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent "x86" /*secondaryCpuAbiString*/, 233135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*cpuAbiOverrideString*/, 234135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent INITIAL_VERSION_CODE, 235135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE, 236135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN, 2373856b090cd04ba5dd4a59a12430ed724d5995909Steve Block PARENT_PACKAGE_NAME, 238135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent childPackageNames, 239135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 0, 240135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*usesStaticLibraries*/, 241135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*usesStaticLibrariesVersions*/); 242135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final PackageSetting testPkgSetting01 = new PackageSetting( 243135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent PACKAGE_NAME /*pkgName*/, 244135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent REAL_PACKAGE_NAME /*realPkgName*/, 245135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent UPDATED_CODE_PATH /*codePath*/, 2463856b090cd04ba5dd4a59a12430ed724d5995909Steve Block UPDATED_CODE_PATH /*resourcePath*/, 247135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*legacyNativeLibraryPathString*/, 248135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*primaryCpuAbiString*/, 249135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*secondaryCpuAbiString*/, 250135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*cpuAbiOverrideString*/, 251135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent UPDATED_VERSION_CODE, 252135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 0 /*pkgFlags*/, 253135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 0 /*pkgPrivateFlags*/, 254135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*parentPkgName*/, 255135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*childPkgNames*/, 256135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 0, 257135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*usesStaticLibraries*/, 258135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*usesStaticLibrariesVersions*/); 259135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent testPkgSetting01.copyFrom(origPkgSetting01); 260135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent verifySettingCopy(origPkgSetting01, testPkgSetting01); 261135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent } 262135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 263135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent /** Update package */ 264135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent @Test 265135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent public void testUpdatePackageSetting01() throws PackageManagerException { 266135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final PackageSetting testPkgSetting01 = 267135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/); 268135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent testPkgSetting01.setInstalled(false /*installed*/, 0 /*userId*/); 269135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(testPkgSetting01.pkgFlags, is(0)); 270135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(testPkgSetting01.pkgPrivateFlags, is(0)); 271135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final PackageSetting oldPkgSetting01 = new PackageSetting(testPkgSetting01); 272135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent Settings.updatePackageSetting( 273135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent testPkgSetting01, 274135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*disabledPkg*/, 275135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*sharedUser*/, 276135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent UPDATED_CODE_PATH /*codePath*/, 277135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*legacyNativeLibraryPath*/, 278135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent "arm64-v8a" /*primaryCpuAbi*/, 279135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent "armeabi" /*secondaryCpuAbi*/, 280135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 0 /*pkgFlags*/, 281135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 0 /*pkgPrivateFlags*/, 282135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*childPkgNames*/, 283135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent UserManagerService.getInstance(), 284135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*usesStaticLibraries*/, 285135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*usesStaticLibrariesVersions*/); 286135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a")); 287135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi")); 288135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(testPkgSetting01.origPackage, is(nullValue())); 289135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(testPkgSetting01.pkgFlags, is(0)); 290135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(testPkgSetting01.pkgPrivateFlags, is(0)); 291135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final PackageUserState userState = testPkgSetting01.readUserState(0); 292135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final PackageUserState oldUserState = oldPkgSetting01.readUserState(0); 293135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent verifyUserState(userState, oldUserState, false /*userStateChanged*/, false /*notLaunched*/, 294135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent false /*stopped*/, false /*installed*/); 295135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent } 296135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent 297135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent /** Update package; package now on /system, install for user '0' */ 298135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent @Test 299135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent public void testUpdatePackageSetting02() throws PackageManagerException { 300135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final PackageSetting testPkgSetting01 = 301135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/); 302135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent testPkgSetting01.setInstalled(false /*installed*/, 0 /*userId*/); 303135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(testPkgSetting01.pkgFlags, is(0)); 304135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent assertThat(testPkgSetting01.pkgPrivateFlags, is(0)); 305135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent final PackageSetting oldPkgSetting01 = new PackageSetting(testPkgSetting01); 306135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent Settings.updatePackageSetting( 307135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent testPkgSetting01, 308135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*disabledPkg*/, 309135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*sharedUser*/, 310135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent UPDATED_CODE_PATH /*codePath*/, 311135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent null /*legacyNativeLibraryPath*/, 312135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent "arm64-v8a" /*primaryCpuAbi*/, 313135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent "armeabi" /*secondaryCpuAbi*/, 314135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/, 315135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/, 316 null /*childPkgNames*/, 317 UserManagerService.getInstance(), 318 null /*usesStaticLibraries*/, 319 null /*usesStaticLibrariesVersions*/); 320 assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a")); 321 assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi")); 322 assertThat(testPkgSetting01.origPackage, is(nullValue())); 323 assertThat(testPkgSetting01.pkgFlags, is(ApplicationInfo.FLAG_SYSTEM)); 324 assertThat(testPkgSetting01.pkgPrivateFlags, is(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)); 325 final PackageUserState userState = testPkgSetting01.readUserState(0); 326 final PackageUserState oldUserState = oldPkgSetting01.readUserState(0); 327 // WARNING: When creating a shallow copy of the PackageSetting we do NOT create 328 // new contained objects. For example, this means that changes to the user state 329 // in testPkgSetting01 will also change the user state in its copy. 330 verifyUserState(userState, oldUserState, false /*userStateChanged*/, false /*notLaunched*/, 331 false /*stopped*/, true /*installed*/); 332 } 333 334 /** Update package; changing shared user throws exception */ 335 @Test 336 public void testUpdatePackageSetting03() { 337 final Settings testSettings01 = new Settings(new Object() /*lock*/); 338 final SharedUserSetting testUserSetting01 = createSharedUserSetting( 339 testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/); 340 final PackageSetting testPkgSetting01 = 341 createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/); 342 try { 343 Settings.updatePackageSetting( 344 testPkgSetting01, 345 null /*disabledPkg*/, 346 testUserSetting01 /*sharedUser*/, 347 UPDATED_CODE_PATH /*codePath*/, 348 null /*legacyNativeLibraryPath*/, 349 "arm64-v8a" /*primaryCpuAbi*/, 350 "armeabi" /*secondaryCpuAbi*/, 351 0 /*pkgFlags*/, 352 0 /*pkgPrivateFlags*/, 353 null /*childPkgNames*/, 354 UserManagerService.getInstance(), 355 null /*usesStaticLibraries*/, 356 null /*usesStaticLibrariesVersions*/); 357 fail("Expected a PackageManagerException"); 358 } catch (PackageManagerException expected) { 359 } 360 } 361 362 /** Create a new PackageSetting based on an original package setting */ 363 @Test 364 public void testCreateNewSetting01() { 365 final PackageSetting originalPkgSetting01 = 366 createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/); 367 final PackageSignatures originalSignatures = originalPkgSetting01.signatures; 368 final PackageSetting testPkgSetting01 = Settings.createNewSetting( 369 REAL_PACKAGE_NAME, 370 originalPkgSetting01 /*originalPkg*/, 371 null /*disabledPkg*/, 372 null /*realPkgName*/, 373 null /*sharedUser*/, 374 UPDATED_CODE_PATH /*codePath*/, 375 UPDATED_CODE_PATH /*resourcePath*/, 376 null /*legacyNativeLibraryPath*/, 377 "arm64-v8a" /*primaryCpuAbi*/, 378 "armeabi" /*secondaryCpuAbi*/, 379 UPDATED_VERSION_CODE /*versionCode*/, 380 ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/, 381 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/, 382 null /*installUser*/, 383 false /*allowInstall*/, 384 false /*instantApp*/, 385 null /*parentPkgName*/, 386 null /*childPkgNames*/, 387 UserManagerService.getInstance(), 388 null /*usesStaticLibraries*/, 389 null /*usesStaticLibrariesVersions*/); 390 assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH)); 391 assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); 392 assertThat(testPkgSetting01.pkgFlags, is(ApplicationInfo.FLAG_SYSTEM)); 393 assertThat(testPkgSetting01.pkgPrivateFlags, is(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)); 394 assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a")); 395 assertThat(testPkgSetting01.resourcePath, is(UPDATED_CODE_PATH)); 396 assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi")); 397 assertSame(testPkgSetting01.origPackage, originalPkgSetting01); 398 // signatures object must be different 399 assertNotSame(testPkgSetting01.signatures, originalSignatures); 400 assertThat(testPkgSetting01.versionCode, is(UPDATED_VERSION_CODE)); 401 final PackageUserState userState = testPkgSetting01.readUserState(0); 402 verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/, 403 false /*notLaunched*/, false /*stopped*/, true /*installed*/); 404 } 405 406 /** Create a new non-system PackageSetting */ 407 @Test 408 public void testCreateNewSetting02() { 409 final PackageSetting testPkgSetting01 = Settings.createNewSetting( 410 PACKAGE_NAME, 411 null /*originalPkg*/, 412 null /*disabledPkg*/, 413 null /*realPkgName*/, 414 null /*sharedUser*/, 415 INITIAL_CODE_PATH /*codePath*/, 416 INITIAL_CODE_PATH /*resourcePath*/, 417 null /*legacyNativeLibraryPath*/, 418 "x86_64" /*primaryCpuAbiString*/, 419 "x86" /*secondaryCpuAbiString*/, 420 INITIAL_VERSION_CODE /*versionCode*/, 421 0 /*pkgFlags*/, 422 0 /*pkgPrivateFlags*/, 423 UserHandle.SYSTEM /*installUser*/, 424 true /*allowInstall*/, 425 false /*instantApp*/, 426 null /*parentPkgName*/, 427 null /*childPkgNames*/, 428 UserManagerService.getInstance(), 429 null /*usesStaticLibraries*/, 430 null /*usesStaticLibrariesVersions*/); 431 assertThat(testPkgSetting01.appId, is(0)); 432 assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH)); 433 assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); 434 assertThat(testPkgSetting01.origPackage, is(nullValue())); 435 assertThat(testPkgSetting01.pkgFlags, is(0)); 436 assertThat(testPkgSetting01.pkgPrivateFlags, is(0)); 437 assertThat(testPkgSetting01.primaryCpuAbiString, is("x86_64")); 438 assertThat(testPkgSetting01.resourcePath, is(INITIAL_CODE_PATH)); 439 assertThat(testPkgSetting01.secondaryCpuAbiString, is("x86")); 440 assertThat(testPkgSetting01.versionCode, is(INITIAL_VERSION_CODE)); 441 // by default, the package is considered stopped 442 final PackageUserState userState = testPkgSetting01.readUserState(0); 443 verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/, 444 true /*notLaunched*/, true /*stopped*/, true /*installed*/); 445 } 446 447 /** Create PackageSetting for a shared user */ 448 @Test 449 public void testCreateNewSetting03() { 450 final Settings testSettings01 = new Settings(new Object() /*lock*/); 451 final SharedUserSetting testUserSetting01 = createSharedUserSetting( 452 testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/); 453 final PackageSetting testPkgSetting01 = Settings.createNewSetting( 454 PACKAGE_NAME, 455 null /*originalPkg*/, 456 null /*disabledPkg*/, 457 null /*realPkgName*/, 458 testUserSetting01 /*sharedUser*/, 459 INITIAL_CODE_PATH /*codePath*/, 460 INITIAL_CODE_PATH /*resourcePath*/, 461 null /*legacyNativeLibraryPath*/, 462 "x86_64" /*primaryCpuAbiString*/, 463 "x86" /*secondaryCpuAbiString*/, 464 INITIAL_VERSION_CODE /*versionCode*/, 465 0 /*pkgFlags*/, 466 0 /*pkgPrivateFlags*/, 467 null /*installUser*/, 468 false /*allowInstall*/, 469 false /*instantApp*/, 470 null /*parentPkgName*/, 471 null /*childPkgNames*/, 472 UserManagerService.getInstance(), 473 null /*usesStaticLibraries*/, 474 null /*usesStaticLibrariesVersions*/); 475 assertThat(testPkgSetting01.appId, is(10064)); 476 assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH)); 477 assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); 478 assertThat(testPkgSetting01.origPackage, is(nullValue())); 479 assertThat(testPkgSetting01.pkgFlags, is(0)); 480 assertThat(testPkgSetting01.pkgPrivateFlags, is(0)); 481 assertThat(testPkgSetting01.primaryCpuAbiString, is("x86_64")); 482 assertThat(testPkgSetting01.resourcePath, is(INITIAL_CODE_PATH)); 483 assertThat(testPkgSetting01.secondaryCpuAbiString, is("x86")); 484 assertThat(testPkgSetting01.versionCode, is(INITIAL_VERSION_CODE)); 485 final PackageUserState userState = testPkgSetting01.readUserState(0); 486 verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/, 487 false /*notLaunched*/, false /*stopped*/, true /*installed*/); 488 } 489 490 /** Create a new PackageSetting based on a disabled package setting */ 491 @Test 492 public void testCreateNewSetting04() { 493 final PackageSetting disabledPkgSetting01 = 494 createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/); 495 disabledPkgSetting01.appId = 10064; 496 final PackageSignatures disabledSignatures = disabledPkgSetting01.signatures; 497 final PackageSetting testPkgSetting01 = Settings.createNewSetting( 498 PACKAGE_NAME, 499 null /*originalPkg*/, 500 disabledPkgSetting01 /*disabledPkg*/, 501 null /*realPkgName*/, 502 null /*sharedUser*/, 503 UPDATED_CODE_PATH /*codePath*/, 504 UPDATED_CODE_PATH /*resourcePath*/, 505 null /*legacyNativeLibraryPath*/, 506 "arm64-v8a" /*primaryCpuAbi*/, 507 "armeabi" /*secondaryCpuAbi*/, 508 UPDATED_VERSION_CODE /*versionCode*/, 509 0 /*pkgFlags*/, 510 0 /*pkgPrivateFlags*/, 511 null /*installUser*/, 512 false /*allowInstall*/, 513 false /*instantApp*/, 514 null /*parentPkgName*/, 515 null /*childPkgNames*/, 516 UserManagerService.getInstance(), 517 null /*usesStaticLibraries*/, 518 null /*usesStaticLibrariesVersions*/); 519 assertThat(testPkgSetting01.appId, is(10064)); 520 assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH)); 521 assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); 522 assertThat(testPkgSetting01.origPackage, is(nullValue())); 523 assertThat(testPkgSetting01.pkgFlags, is(0)); 524 assertThat(testPkgSetting01.pkgPrivateFlags, is(0)); 525 assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a")); 526 assertThat(testPkgSetting01.resourcePath, is(UPDATED_CODE_PATH)); 527 assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi")); 528 assertNotSame(testPkgSetting01.signatures, disabledSignatures); 529 assertThat(testPkgSetting01.versionCode, is(UPDATED_VERSION_CODE)); 530 final PackageUserState userState = testPkgSetting01.readUserState(0); 531 verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/, 532 false /*notLaunched*/, false /*stopped*/, true /*installed*/); 533 } 534 535 @Test 536 public void testInsertPackageSetting() { 537 final PackageSetting ps = createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/); 538 final PackageParser.Package pkg = new PackageParser.Package(PACKAGE_NAME); 539 pkg.applicationInfo.setCodePath(ps.codePathString); 540 pkg.applicationInfo.setResourcePath(ps.resourcePathString); 541 final Settings settings = 542 new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object()); 543 pkg.usesStaticLibraries = new ArrayList<>( 544 Arrays.asList("foo.bar1", "foo.bar2", "foo.bar3")); 545 pkg.usesStaticLibrariesVersions = new int[] {2, 4, 6}; 546 settings.insertPackageSettingLPw(ps, pkg); 547 assertEquals(pkg, ps.pkg); 548 assertArrayEquals(pkg.usesStaticLibraries.toArray(new String[0]), ps.usesStaticLibraries); 549 assertArrayEquals(pkg.usesStaticLibrariesVersions, ps.usesStaticLibrariesVersions); 550 551 pkg.usesStaticLibraries = null; 552 pkg.usesStaticLibrariesVersions = null; 553 settings.insertPackageSettingLPw(ps, pkg); 554 assertEquals(pkg, ps.pkg); 555 assertNull("Actual: " + Arrays.toString(ps.usesStaticLibraries), ps.usesStaticLibraries); 556 assertNull("Actual: " + Arrays.toString(ps.usesStaticLibrariesVersions), 557 ps.usesStaticLibrariesVersions); 558 } 559 560 private <T> void assertArrayEquals(T[] a, T[] b) { 561 assertTrue("Expected: " + Arrays.toString(a) + ", actual: " + Arrays.toString(b), 562 Arrays.equals(a, b)); 563 } 564 565 private void assertArrayEquals(int[] a, int[] b) { 566 assertTrue("Expected: " + Arrays.toString(a) + ", actual: " + Arrays.toString(b), 567 Arrays.equals(a, b)); 568 } 569 570 private void verifyUserState(PackageUserState userState, PackageUserState oldUserState, 571 boolean userStateChanged) { 572 verifyUserState(userState, oldUserState, userStateChanged, false /*notLaunched*/, 573 false /*stopped*/, true /*installed*/); 574 } 575 576 private void verifyUserState(PackageUserState userState, PackageUserState oldUserState, 577 boolean userStateChanged, boolean notLaunched, boolean stopped, boolean installed) { 578 assertThat(userState.enabled, is(0)); 579 assertThat(userState.hidden, is(false)); 580 assertThat(userState.installed, is(installed)); 581 assertThat(userState.notLaunched, is(notLaunched)); 582 assertThat(userState.stopped, is(stopped)); 583 assertThat(userState.suspended, is(false)); 584 if (oldUserState != null) { 585 assertThat(userState.equals(oldUserState), is(not(userStateChanged))); 586 } 587 } 588 589 private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) { 590 assertThat(origPkgSetting, is(not(testPkgSetting))); 591 assertThat(origPkgSetting.appId, is(testPkgSetting.appId)); 592 // different but equal objects 593 assertNotSame(origPkgSetting.childPackageNames, testPkgSetting.childPackageNames); 594 assertThat(origPkgSetting.childPackageNames, is(testPkgSetting.childPackageNames)); 595 assertSame(origPkgSetting.codePath, testPkgSetting.codePath); 596 assertThat(origPkgSetting.codePath, is(testPkgSetting.codePath)); 597 assertSame(origPkgSetting.codePathString, testPkgSetting.codePathString); 598 assertThat(origPkgSetting.codePathString, is(testPkgSetting.codePathString)); 599 assertSame(origPkgSetting.cpuAbiOverrideString, testPkgSetting.cpuAbiOverrideString); 600 assertThat(origPkgSetting.cpuAbiOverrideString, is(testPkgSetting.cpuAbiOverrideString)); 601 assertThat(origPkgSetting.firstInstallTime, is(testPkgSetting.firstInstallTime)); 602 assertSame(origPkgSetting.installerPackageName, testPkgSetting.installerPackageName); 603 assertThat(origPkgSetting.installerPackageName, is(testPkgSetting.installerPackageName)); 604 assertThat(origPkgSetting.installPermissionsFixed, 605 is(testPkgSetting.installPermissionsFixed)); 606 assertThat(origPkgSetting.installStatus, is(testPkgSetting.installStatus)); 607 assertThat(origPkgSetting.isOrphaned, is(testPkgSetting.isOrphaned)); 608 assertSame(origPkgSetting.keySetData, testPkgSetting.keySetData); 609 assertThat(origPkgSetting.keySetData, is(testPkgSetting.keySetData)); 610 assertThat(origPkgSetting.lastUpdateTime, is(testPkgSetting.lastUpdateTime)); 611 assertSame(origPkgSetting.legacyNativeLibraryPathString, 612 testPkgSetting.legacyNativeLibraryPathString); 613 assertThat(origPkgSetting.legacyNativeLibraryPathString, 614 is(testPkgSetting.legacyNativeLibraryPathString)); 615 assertNotSame(origPkgSetting.mPermissionsState, testPkgSetting.mPermissionsState); 616 assertThat(origPkgSetting.mPermissionsState, is(testPkgSetting.mPermissionsState)); 617 assertThat(origPkgSetting.name, is(testPkgSetting.name)); 618 // oldCodePaths is _not_ copied 619 // assertNotSame(origPkgSetting.oldCodePaths, testPkgSetting.oldCodePaths); 620 // assertThat(origPkgSetting.oldCodePaths, is(not(testPkgSetting.oldCodePaths))); 621 assertSame(origPkgSetting.origPackage, testPkgSetting.origPackage); 622 assertThat(origPkgSetting.origPackage, is(testPkgSetting.origPackage)); 623 assertSame(origPkgSetting.parentPackageName, testPkgSetting.parentPackageName); 624 assertThat(origPkgSetting.parentPackageName, is(testPkgSetting.parentPackageName)); 625 assertSame(origPkgSetting.pkg, testPkgSetting.pkg); 626 // No equals() method for this object 627 // assertThat(origPkgSetting.pkg, is(testPkgSetting.pkg)); 628 assertThat(origPkgSetting.pkgFlags, is(testPkgSetting.pkgFlags)); 629 assertThat(origPkgSetting.pkgPrivateFlags, is(testPkgSetting.pkgPrivateFlags)); 630 assertSame(origPkgSetting.primaryCpuAbiString, testPkgSetting.primaryCpuAbiString); 631 assertThat(origPkgSetting.primaryCpuAbiString, is(testPkgSetting.primaryCpuAbiString)); 632 assertThat(origPkgSetting.realName, is(testPkgSetting.realName)); 633 assertSame(origPkgSetting.resourcePath, testPkgSetting.resourcePath); 634 assertThat(origPkgSetting.resourcePath, is(testPkgSetting.resourcePath)); 635 assertSame(origPkgSetting.resourcePathString, testPkgSetting.resourcePathString); 636 assertThat(origPkgSetting.resourcePathString, is(testPkgSetting.resourcePathString)); 637 assertSame(origPkgSetting.secondaryCpuAbiString, testPkgSetting.secondaryCpuAbiString); 638 assertThat(origPkgSetting.secondaryCpuAbiString, is(testPkgSetting.secondaryCpuAbiString)); 639 assertSame(origPkgSetting.sharedUser, testPkgSetting.sharedUser); 640 assertThat(origPkgSetting.sharedUser, is(testPkgSetting.sharedUser)); 641 assertSame(origPkgSetting.signatures, testPkgSetting.signatures); 642 assertThat(origPkgSetting.signatures, is(testPkgSetting.signatures)); 643 assertThat(origPkgSetting.timeStamp, is(testPkgSetting.timeStamp)); 644 assertThat(origPkgSetting.uidError, is(testPkgSetting.uidError)); 645 assertNotSame(origPkgSetting.getUserState(), is(testPkgSetting.getUserState())); 646 // No equals() method for SparseArray object 647 // assertThat(origPkgSetting.getUserState(), is(testPkgSetting.getUserState())); 648 assertSame(origPkgSetting.verificationInfo, testPkgSetting.verificationInfo); 649 assertThat(origPkgSetting.verificationInfo, is(testPkgSetting.verificationInfo)); 650 assertThat(origPkgSetting.versionCode, is(testPkgSetting.versionCode)); 651 assertSame(origPkgSetting.volumeUuid, testPkgSetting.volumeUuid); 652 assertThat(origPkgSetting.volumeUuid, is(testPkgSetting.volumeUuid)); 653 } 654 655 private SharedUserSetting createSharedUserSetting(Settings settings, String userName, 656 int sharedUserId, int pkgFlags, int pkgPrivateFlags) { 657 return settings.addSharedUserLPw( 658 userName, 659 sharedUserId, 660 pkgFlags, 661 pkgPrivateFlags); 662 } 663 private PackageSetting createPackageSetting(int sharedUserId, int pkgFlags) { 664 return new PackageSetting( 665 PACKAGE_NAME, 666 REAL_PACKAGE_NAME, 667 INITIAL_CODE_PATH /*codePath*/, 668 INITIAL_CODE_PATH /*resourcePath*/, 669 null /*legacyNativeLibraryPathString*/, 670 "x86_64" /*primaryCpuAbiString*/, 671 "x86" /*secondaryCpuAbiString*/, 672 null /*cpuAbiOverrideString*/, 673 INITIAL_VERSION_CODE, 674 pkgFlags, 675 0 /*privateFlags*/, 676 null /*parentPackageName*/, 677 null /*childPackageNames*/, 678 sharedUserId, 679 null /*usesStaticLibraries*/, 680 null /*usesStaticLibrariesVersions*/); 681 } 682 683 private @NonNull List<UserInfo> createFakeUsers() { 684 ArrayList<UserInfo> users = new ArrayList<>(); 685 users.add(new UserInfo(UserHandle.USER_SYSTEM, "test user", UserInfo.FLAG_INITIALIZED)); 686 return users; 687 } 688 689 private void writeFile(File file, byte[] data) { 690 file.mkdirs(); 691 try { 692 AtomicFile aFile = new AtomicFile(file); 693 FileOutputStream fos = aFile.startWrite(); 694 fos.write(data); 695 aFile.finishWrite(fos); 696 } catch (IOException ioe) { 697 Log.e(TAG, "Cannot write file " + file.getPath()); 698 } 699 } 700 701 private void writePackagesXml() { 702 writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages.xml"), 703 ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" 704 + "<packages>" 705 + "<last-platform-version internal=\"15\" external=\"0\" fingerprint=\"foo\" />" 706 + "<permission-trees>" 707 + "<item name=\"com.google.android.permtree\" package=\"com.google.android.permpackage\" />" 708 + "</permission-trees>" 709 + "<permissions>" 710 + "<item name=\"android.permission.WRITE_CALL_LOG\" package=\"android\" protection=\"1\" />" 711 + "<item name=\"android.permission.ASEC_ACCESS\" package=\"android\" protection=\"2\" />" 712 + "<item name=\"android.permission.ACCESS_WIMAX_STATE\" package=\"android\" />" 713 + "<item name=\"android.permission.REBOOT\" package=\"android\" protection=\"18\" />" 714 + "</permissions>" 715 + "<package name=\"com.google.app1\" codePath=\"/system/app/app1.apk\" nativeLibraryPath=\"/data/data/com.google.app1/lib\" flags=\"1\" ft=\"1360e2caa70\" it=\"135f2f80d08\" ut=\"1360e2caa70\" version=\"1109\" sharedUserId=\"11000\">" 716 + "<sigs count=\"1\">" 717 + "<cert index=\"0\" key=\"" + KeySetStrings.ctsKeySetCertA + "\" />" 718 + "</sigs>" 719 + "<proper-signing-keyset identifier=\"1\" />" 720 + "</package>" 721 + "<package name=\"com.google.app2\" codePath=\"/system/app/app2.apk\" nativeLibraryPath=\"/data/data/com.google.app2/lib\" flags=\"1\" ft=\"1360e578718\" it=\"135f2f80d08\" ut=\"1360e578718\" version=\"15\" enabled=\"3\" userId=\"11001\">" 722 + "<sigs count=\"1\">" 723 + "<cert index=\"0\" />" 724 + "</sigs>" 725 + "<proper-signing-keyset identifier=\"1\" />" 726 + "<defined-keyset alias=\"AB\" identifier=\"4\" />" 727 + "</package>" 728 + "<package name=\"com.android.app3\" codePath=\"/system/app/app3.apk\" nativeLibraryPath=\"/data/data/com.android.app3/lib\" flags=\"1\" ft=\"1360e577b60\" it=\"135f2f80d08\" ut=\"1360e577b60\" version=\"15\" userId=\"11030\">" 729 + "<sigs count=\"1\">" 730 + "<cert index=\"1\" key=\"" + KeySetStrings.ctsKeySetCertB + "\" />" 731 + "</sigs>" 732 + "<proper-signing-keyset identifier=\"2\" />" 733 + "<upgrade-keyset identifier=\"3\" />" 734 + "<defined-keyset alias=\"C\" identifier=\"3\" />" 735 + "</package>" 736 + "<shared-user name=\"com.android.shared1\" userId=\"11000\">" 737 + "<sigs count=\"1\">" 738 + "<cert index=\"1\" />" 739 + "</sigs>" 740 + "<perms>" 741 + "<item name=\"android.permission.REBOOT\" />" 742 + "</perms>" 743 + "</shared-user>" 744 + "<keyset-settings version=\"1\">" 745 + "<keys>" 746 + "<public-key identifier=\"1\" value=\"" + KeySetStrings.ctsKeySetPublicKeyA + "\" />" 747 + "<public-key identifier=\"2\" value=\"" + KeySetStrings.ctsKeySetPublicKeyB + "\" />" 748 + "<public-key identifier=\"3\" value=\"" + KeySetStrings.ctsKeySetPublicKeyC + "\" />" 749 + "</keys>" 750 + "<keysets>" 751 + "<keyset identifier=\"1\">" 752 + "<key-id identifier=\"1\" />" 753 + "</keyset>" 754 + "<keyset identifier=\"2\">" 755 + "<key-id identifier=\"2\" />" 756 + "</keyset>" 757 + "<keyset identifier=\"3\">" 758 + "<key-id identifier=\"3\" />" 759 + "</keyset>" 760 + "<keyset identifier=\"4\">" 761 + "<key-id identifier=\"1\" />" 762 + "<key-id identifier=\"2\" />" 763 + "</keyset>" 764 + "</keysets>" 765 + "<lastIssuedKeyId value=\"3\" />" 766 + "<lastIssuedKeySetId value=\"4\" />" 767 + "</keyset-settings>" 768 + "</packages>").getBytes()); 769 } 770 771 private void writeStoppedPackagesXml() { 772 writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages-stopped.xml"), 773 ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" 774 + "<stopped-packages>" 775 + "<pkg name=\"com.google.app1\" nl=\"1\" />" 776 + "<pkg name=\"com.android.app3\" nl=\"1\" />" 777 + "</stopped-packages>") 778 .getBytes()); 779 } 780 781 private void writePackagesList() { 782 writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages.list"), 783 ( "com.google.app1 11000 0 /data/data/com.google.app1 seinfo1" 784 + "com.google.app2 11001 0 /data/data/com.google.app2 seinfo2" 785 + "com.android.app3 11030 0 /data/data/com.android.app3 seinfo3") 786 .getBytes()); 787 } 788 789 private void deleteSystemFolder() { 790 File systemFolder = new File(InstrumentationRegistry.getContext().getFilesDir(), "system"); 791 deleteFolder(systemFolder); 792 } 793 794 private static void deleteFolder(File folder) { 795 File[] files = folder.listFiles(); 796 if (files != null) { 797 for (File file : files) { 798 deleteFolder(file); 799 } 800 } 801 folder.delete(); 802 } 803 804 private void writeOldFiles() { 805 deleteSystemFolder(); 806 writePackagesXml(); 807 writeStoppedPackagesXml(); 808 writePackagesList(); 809 } 810 811 @Before 812 public void createUserManagerServiceRef() throws ReflectiveOperationException { 813 InstrumentationRegistry.getInstrumentation().runOnMainSync((Runnable) () -> { 814 try { 815 // unregister the user manager from the local service 816 LocalServices.removeServiceForTest(UserManagerInternal.class); 817 new UserManagerService(InstrumentationRegistry.getContext()); 818 } catch (Exception e) { 819 e.printStackTrace(); 820 fail("Could not create user manager service; " + e); 821 } 822 }); 823 } 824 825 private void verifyKeySetMetaData(Settings settings) 826 throws ReflectiveOperationException, IllegalAccessException { 827 ArrayMap<String, PackageSetting> packages = settings.mPackages; 828 KeySetManagerService ksms = settings.mKeySetManagerService; 829 830 /* verify keyset and public key ref counts */ 831 assertThat(KeySetUtils.getKeySetRefCount(ksms, 1), is(2)); 832 assertThat(KeySetUtils.getKeySetRefCount(ksms, 2), is(1)); 833 assertThat(KeySetUtils.getKeySetRefCount(ksms, 3), is(1)); 834 assertThat(KeySetUtils.getKeySetRefCount(ksms, 4), is(1)); 835 assertThat(KeySetUtils.getPubKeyRefCount(ksms, 1), is(2)); 836 assertThat(KeySetUtils.getPubKeyRefCount(ksms, 2), is(2)); 837 assertThat(KeySetUtils.getPubKeyRefCount(ksms, 3), is(1)); 838 839 /* verify public keys properly read */ 840 PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); 841 PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB); 842 PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC); 843 assertThat(KeySetUtils.getPubKey(ksms, 1), is(keyA)); 844 assertThat(KeySetUtils.getPubKey(ksms, 2), is(keyB)); 845 assertThat(KeySetUtils.getPubKey(ksms, 3), is(keyC)); 846 847 /* verify mapping is correct (ks -> pub keys) */ 848 LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(ksms); 849 ArraySet<Long> mapping = ksMapping.get(1); 850 assertThat(mapping.size(), is(1)); 851 assertThat(mapping.contains(new Long(1)), is(true)); 852 mapping = ksMapping.get(2); 853 assertThat(mapping.size(), is(1)); 854 assertThat(mapping.contains(new Long(2)), is(true)); 855 mapping = ksMapping.get(3); 856 assertThat(mapping.size(), is(1)); 857 assertThat(mapping.contains(new Long(3)), is(true)); 858 mapping = ksMapping.get(4); 859 assertThat(mapping.size(), is(2)); 860 assertThat(mapping.contains(new Long(1)), is(true)); 861 assertThat(mapping.contains(new Long(2)), is(true)); 862 863 /* verify lastIssuedIds are consistent */ 864 assertThat(KeySetUtils.getLastIssuedKeyId(ksms), is(3L)); 865 assertThat(KeySetUtils.getLastIssuedKeySetId(ksms), is(4L)); 866 867 /* verify packages have been given the appropriate information */ 868 PackageSetting ps = packages.get("com.google.app1"); 869 assertThat(ps.keySetData.getProperSigningKeySet(), is(1L)); 870 ps = packages.get("com.google.app2"); 871 assertThat(ps.keySetData.getProperSigningKeySet(), is(1L)); 872 assertThat(ps.keySetData.getAliases().get("AB"), is(4L)); 873 ps = packages.get("com.android.app3"); 874 assertThat(ps.keySetData.getProperSigningKeySet(), is(2L)); 875 assertThat(ps.keySetData.getAliases().get("C"), is(3L)); 876 assertThat(ps.keySetData.getUpgradeKeySets().length, is(1)); 877 assertThat(ps.keySetData.getUpgradeKeySets()[0], is(3L)); 878 } 879} 880