1 /* 2 * Copyright (C) 2017 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 android.content.pm.cts; 18 19 import static android.content.pm.PackageInfo.INSTALL_LOCATION_AUTO; 20 import static android.content.pm.PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; 21 import static android.content.pm.PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL; 22 import static android.content.pm.PackageInfo.INSTALL_LOCATION_UNSPECIFIED; 23 import static android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL; 24 import static android.content.pm.PackageInstaller.SessionParams.MODE_INHERIT_EXISTING; 25 import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE; 26 import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP; 27 import static android.content.pm.PackageManager.INSTALL_REASON_POLICY; 28 import static android.content.pm.PackageManager.INSTALL_REASON_UNKNOWN; 29 import static android.content.pm.PackageManager.INSTALL_REASON_USER; 30 import static android.content.pm.PackageManager.INSTALL_SCENARIO_BULK; 31 import static android.content.pm.PackageManager.INSTALL_SCENARIO_BULK_SECONDARY; 32 import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT; 33 import static android.content.pm.PackageManager.INSTALL_SCENARIO_FAST; 34 35 import static com.google.common.truth.Truth.assertThat; 36 37 import static org.junit.Assert.fail; 38 39 import android.content.pm.Flags; 40 import android.content.pm.PackageInstaller; 41 import android.content.pm.PackageInstaller.SessionInfo; 42 import android.content.pm.PackageInstaller.SessionParams; 43 import android.content.pm.cts.util.AbandonAllPackageSessionsRule; 44 import android.graphics.Bitmap; 45 import android.net.Uri; 46 import android.platform.test.annotations.AppModeFull; 47 import android.util.Log; 48 49 import androidx.test.InstrumentationRegistry; 50 51 import org.junit.After; 52 import org.junit.Before; 53 import org.junit.Rule; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 import org.junit.runners.Parameterized; 57 58 import java.util.ArrayList; 59 import java.util.Collection; 60 import java.util.List; 61 import java.util.function.Consumer; 62 63 @RunWith(Parameterized.class) 64 @AppModeFull // TODO(Instant) Figure out which APIs should work. 65 public class InstallSessionParamsUnitTest { 66 private static final String LOG_TAG = InstallSessionParamsUnitTest.class.getSimpleName(); 67 private static Optional UNSET = new Optional(false, null); 68 69 @Rule 70 public AbandonAllPackageSessionsRule mAbandonSessionsRule = new AbandonAllPackageSessionsRule(); 71 72 @Parameterized.Parameter(0) 73 public Optional<Integer> mode; 74 @Parameterized.Parameter(1) 75 public Optional<Integer> installLocation; 76 @Parameterized.Parameter(2) 77 public Optional<Integer> size; 78 @Parameterized.Parameter(3) 79 public Optional<String> appPackageName; 80 @Parameterized.Parameter(4) 81 public Optional<Bitmap> appIcon; 82 @Parameterized.Parameter(5) 83 public Optional<String> appLabel; 84 @Parameterized.Parameter(6) 85 public Optional<Uri> originatingUri; 86 @Parameterized.Parameter(7) 87 public Optional<Integer> originatingUid; 88 @Parameterized.Parameter(8) 89 public Optional<Uri> referredUri; 90 @Parameterized.Parameter(9) 91 public Optional<Integer> installReason; 92 @Parameterized.Parameter(10) 93 public Optional<Integer> installScenario; 94 @Parameterized.Parameter(11) 95 public Optional<Integer> packageSource; 96 @Parameterized.Parameter(12) 97 public Optional<Boolean> enableAutoDependencyInstall; 98 @Parameterized.Parameter(13) 99 public boolean expectFailure; 100 101 private PackageInstaller mInstaller = InstrumentationRegistry.getInstrumentation() 102 .getTargetContext() 103 .getPackageManager() 104 .getPackageInstaller(); 105 106 /** 107 * Generate test-parameters where all params are the same, but one param cycles through all 108 * values. 109 */ getSingleParameterChangingTests( Object[][][] allParameterValues, int changingParameterIndex, Object[] changingParameterValues, boolean expectFailure)110 private static ArrayList<Object[]> getSingleParameterChangingTests( 111 Object[][][] allParameterValues, int changingParameterIndex, 112 Object[] changingParameterValues, boolean expectFailure) { 113 ArrayList<Object[]> params = new ArrayList<>(); 114 115 for (Object changingParameterValue : changingParameterValues) { 116 ArrayList<Object> singleTestParams = new ArrayList<>(); 117 118 // parameterIndex is the index of the parameter (0 = mode, ...) 119 for (int parameterIndex = 0; parameterIndex < allParameterValues.length; 120 parameterIndex++) { 121 Object[][] parameterValues = allParameterValues[parameterIndex]; 122 123 if (parameterIndex == changingParameterIndex) { 124 if (changingParameterValue == UNSET) { 125 // No need to wrap UNSET again 126 singleTestParams.add(UNSET); 127 } else { 128 singleTestParams.add(Optional.of(changingParameterValue)); 129 } 130 } else { 131 singleTestParams.add(Optional.of(parameterValues[0][0])); 132 } 133 } 134 singleTestParams.add(expectFailure); 135 params.add(singleTestParams.toArray()); 136 } 137 138 return params; 139 } 140 141 /** 142 * Generate test-parameters for all tests. 143 */ 144 @Parameterized.Parameters getParameters()145 public static Collection<Object[]> getParameters() { 146 // {{{valid parameters}, {invalid parameters}}} 147 Object[][][] allParameterValues = { 148 /*mode*/ 149 {{MODE_FULL_INSTALL, MODE_INHERIT_EXISTING}, {0xfff}}, 150 /*installLocation*/ 151 {{INSTALL_LOCATION_UNSPECIFIED, INSTALL_LOCATION_AUTO, 152 INSTALL_LOCATION_INTERNAL_ONLY, INSTALL_LOCATION_PREFER_EXTERNAL, 153 /* parame is not verified */ 0xfff}, {}}, 154 /*size*/ 155 {{1, 8092, Integer.MAX_VALUE, /* param is not verified */ -1, 0}, {}}, 156 /*appPackageName*/ 157 {{"a.package.name", null, /* param is not verified */ "android"}, {}}, 158 /*appIcon*/ 159 {{null, Bitmap.createBitmap(42, 42, Bitmap.Config.ARGB_8888)}, {}}, 160 /*appLabel*/ 161 {{"A label", null}, {}}, 162 /*originatingUri*/ 163 {{Uri.parse("android.com"), null}, {}}, 164 /*originatingUid*/ 165 {{-1, 0, 1}, {}}, 166 /*referredUri*/ 167 {{Uri.parse("android.com"), null}, {}}, 168 /*installReason*/ 169 {{INSTALL_REASON_UNKNOWN, INSTALL_REASON_POLICY, INSTALL_REASON_DEVICE_RESTORE, 170 INSTALL_REASON_DEVICE_SETUP, INSTALL_REASON_USER, 171 /* parame is not verified */ 0xfff}, {}}, 172 /*installScenario*/ 173 {{INSTALL_SCENARIO_DEFAULT, INSTALL_SCENARIO_FAST, INSTALL_SCENARIO_BULK, 174 INSTALL_SCENARIO_BULK_SECONDARY}, {}}, 175 /*packageSource*/ 176 {{PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, 177 PackageInstaller.PACKAGE_SOURCE_OTHER, 178 PackageInstaller.PACKAGE_SOURCE_STORE, 179 PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE, 180 PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE}, {}}, 181 /*enableAutoDependencyInstall*/ 182 {{true, false}, {}} 183 }; 184 185 ArrayList<Object[]> allTestParams = new ArrayList<>(); 186 187 // changingParameterIndex is the index the parameter that changes (0 = mode ...) 188 for (int changingParameterIndex = 0; changingParameterIndex < allParameterValues.length; 189 changingParameterIndex++) { 190 // Allowed values 191 allTestParams.addAll(getSingleParameterChangingTests(allParameterValues, 192 changingParameterIndex, allParameterValues[changingParameterIndex][0], false)); 193 194 // Value unset (mode param cannot be unset) 195 if (changingParameterIndex != 0) { 196 Object[] unset = {UNSET}; 197 allTestParams.addAll(getSingleParameterChangingTests(allParameterValues, 198 changingParameterIndex, unset, false)); 199 } 200 201 // Illegal values 202 allTestParams.addAll(getSingleParameterChangingTests(allParameterValues, 203 changingParameterIndex, allParameterValues[changingParameterIndex][1], true)); 204 } 205 206 return allTestParams; 207 } 208 209 /** 210 * Get the sessionInfo if this package owns the session. 211 * 212 * @param sessionId The id of the session 213 * 214 * @return The {@link PackageInstaller.SessionInfo} object, or {@code null} if session is not 215 * owned by the this package. 216 */ getSessionInfo(int sessionId)217 private SessionInfo getSessionInfo(int sessionId) { 218 List<SessionInfo> mySessionInfos = mInstaller.getMySessions(); 219 220 for (SessionInfo sessionInfo : mySessionInfos) { 221 if (sessionInfo.getSessionId() == sessionId) { 222 return sessionInfo; 223 } 224 } 225 226 return null; 227 } 228 229 @Before onBefore()230 public void onBefore() throws Exception { 231 PackageManagerShellCommandInstallTest.setSystemProperty( 232 "debug.pm.install_skip_size_check_for_maxint", "1"); 233 } 234 235 @After onAfter()236 public void onAfter() throws Exception { 237 // Set the test override to invalid. 238 PackageManagerShellCommandInstallTest.setSystemProperty( 239 "debug.pm.install_skip_size_check_for_maxint", "invalid"); 240 } 241 242 @Test checkSessionParams()243 public void checkSessionParams() throws Exception { 244 Log.i(LOG_TAG, "mode=" + mode + " installLocation=" + installLocation + " size=" + size 245 + " appPackageName=" + appPackageName + " appIcon=" + appIcon + " appLabel=" 246 + appLabel + " originatingUri=" + originatingUri + " originatingUid=" 247 + originatingUid + " referredUri=" + referredUri + " installReason=" + installReason 248 + " installScenario=" + installScenario + " expectFailure=" + expectFailure); 249 250 SessionParams params = new SessionParams(mode.get()); 251 installLocation.ifPresent(params::setInstallLocation); 252 size.ifPresent(params::setSize); 253 appPackageName.ifPresent(params::setAppPackageName); 254 appIcon.ifPresent(params::setAppIcon); 255 appLabel.ifPresent(params::setAppLabel); 256 originatingUri.ifPresent(params::setOriginatingUri); 257 originatingUid.ifPresent(params::setOriginatingUid); 258 referredUri.ifPresent(params::setReferrerUri); 259 installReason.ifPresent(params::setInstallReason); 260 installScenario.ifPresent(params::setInstallScenario); 261 packageSource.ifPresent(params::setPackageSource); 262 if (Flags.sdkDependencyInstaller()) { 263 // Verify that auto install of dependencies is enabled by default. 264 assertThat(params.isAutoInstallDependenciesEnabled).isTrue(); 265 enableAutoDependencyInstall.ifPresent(params::setAutoInstallDependenciesEnabled); 266 } 267 268 int sessionId; 269 try { 270 sessionId = mInstaller.createSession(params); 271 272 if (expectFailure) { 273 fail("Creating session did not fail"); 274 } 275 } catch (Exception e) { 276 if (expectFailure) { 277 return; 278 } 279 280 throw e; 281 } 282 283 SessionInfo info = getSessionInfo(sessionId); 284 285 assertThat(info.getMode()).isEqualTo(mode.get()); 286 packageSource.ifPresent(i -> assertThat(info.getPackageSource()).isEqualTo(i)); 287 installLocation.ifPresent(i -> assertThat(info.getInstallLocation()).isEqualTo(i)); 288 size.ifPresent(i -> assertThat(info.getSize()).isEqualTo(i)); 289 appPackageName.ifPresent(s -> assertThat(info.getAppPackageName()).isEqualTo(s)); 290 291 if (appIcon.isPresent()) { 292 if (appIcon.get() == null) { 293 assertThat(info.getAppIcon()).isNull(); 294 } else { 295 assertThat(appIcon.get().sameAs(info.getAppIcon())).isTrue(); 296 } 297 } 298 299 appLabel.ifPresent(s -> assertThat(info.getAppLabel()).isEqualTo(s)); 300 originatingUri.ifPresent(uri -> assertThat(info.getOriginatingUri()).isEqualTo(uri)); 301 originatingUid.ifPresent(i -> assertThat(info.getOriginatingUid()).isEqualTo(i)); 302 referredUri.ifPresent(uri -> assertThat(info.getReferrerUri()).isEqualTo(uri)); 303 installReason.ifPresent(i -> assertThat(info.getInstallReason()).isEqualTo(i)); 304 if (Flags.sdkDependencyInstaller()) { 305 enableAutoDependencyInstall.ifPresent( 306 i -> assertThat(info.isAutoInstallDependenciesEnabled()).isEqualTo(i)); 307 } 308 } 309 310 /** Similar to java.util.Optional but distinguishing between null and unset */ 311 private static class Optional<T> { 312 private final boolean mIsSet; 313 private final T mValue; 314 Optional(boolean isSet, T value)315 Optional(boolean isSet, T value) { 316 mIsSet = isSet; 317 mValue = value; 318 } 319 of(T value)320 static <T> Optional of(T value) { 321 return new Optional(true, value); 322 } 323 get()324 T get() { 325 if (!mIsSet) { 326 throw new IllegalStateException(this + " is not set"); 327 } 328 return mValue; 329 } 330 toString()331 public String toString() { 332 if (!mIsSet) { 333 return "unset"; 334 } else if (mValue == null) { 335 return "null"; 336 } else { 337 return mValue.toString(); 338 } 339 } 340 isPresent()341 boolean isPresent() { 342 return mIsSet; 343 } 344 ifPresent(Consumer<T> consumer)345 void ifPresent(Consumer<T> consumer) { 346 if (mIsSet) { 347 consumer.accept(mValue); 348 } 349 } 350 } 351 } 352