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