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