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