1 /* 2 * Copyright 2019 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 com.android.server.pm; 18 19 import android.annotation.Nullable; 20 21 import com.android.internal.util.Preconditions; 22 23 import java.util.Objects; 24 25 /** 26 * Immutable class holding information about where the request to install or update an app 27 * came from. 28 */ 29 final class InstallSource { 30 /** 31 * An instance of InstallSource representing an absence of knowledge of the source of 32 * a package. Used in preference to null. 33 */ 34 static final InstallSource EMPTY = new InstallSource(null, null, null, null, false, false, 35 null); 36 37 /** We also memoize this case because it is common - all un-updated system apps. */ 38 private static final InstallSource EMPTY_ORPHANED = new InstallSource( 39 null, null, null, null, true, false, null); 40 41 /** 42 * The package that requested the installation, if known. May not correspond to a currently 43 * installed package if {@link #isInitiatingPackageUninstalled} is true. 44 */ 45 @Nullable 46 final String initiatingPackageName; 47 48 /** 49 * The signing details of the initiating package, if known. Always null if 50 * {@link #initiatingPackageName} is null. 51 */ 52 @Nullable 53 final PackageSignatures initiatingPackageSignatures; 54 55 /** 56 * The package on behalf of which the initiating package requested the installation, if any. 57 * For example if a downloaded APK is installed via the Package Installer this could be the 58 * app that performed the download. This value is provided by the initiating package and not 59 * verified by the framework. 60 */ 61 @Nullable 62 final String originatingPackageName; 63 64 /** 65 * Package name of the app that installed this package (the installer of record). Note that 66 * this may be modified. 67 */ 68 @Nullable 69 final String installerPackageName; 70 71 72 /** 73 * {@link android.content.Context#getAttributionTag()} of installing context. 74 */ 75 @Nullable 76 final String installerAttributionTag; 77 78 /** Indicates if the package that was the installerPackageName has been uninstalled. */ 79 final boolean isOrphaned; 80 81 /** 82 * Indicates if the package in initiatingPackageName has been uninstalled. Always false if 83 * {@link #initiatingPackageName} is null. 84 */ 85 final boolean isInitiatingPackageUninstalled; 86 create(@ullable String initiatingPackageName, @Nullable String originatingPackageName, @Nullable String installerPackageName, @Nullable String installerAttributionTag)87 static InstallSource create(@Nullable String initiatingPackageName, 88 @Nullable String originatingPackageName, @Nullable String installerPackageName, 89 @Nullable String installerAttributionTag) { 90 return create(initiatingPackageName, originatingPackageName, installerPackageName, 91 installerAttributionTag, false, false); 92 } 93 create(@ullable String initiatingPackageName, @Nullable String originatingPackageName, @Nullable String installerPackageName, @Nullable String installerAttributionTag, boolean isOrphaned, boolean isInitiatingPackageUninstalled)94 static InstallSource create(@Nullable String initiatingPackageName, 95 @Nullable String originatingPackageName, @Nullable String installerPackageName, 96 @Nullable String installerAttributionTag, boolean isOrphaned, 97 boolean isInitiatingPackageUninstalled) { 98 return createInternal( 99 intern(initiatingPackageName), 100 intern(originatingPackageName), 101 intern(installerPackageName), 102 installerAttributionTag, 103 isOrphaned, isInitiatingPackageUninstalled, null); 104 } 105 createInternal(@ullable String initiatingPackageName, @Nullable String originatingPackageName, @Nullable String installerPackageName, @Nullable String installerAttributionTag, boolean isOrphaned, boolean isInitiatingPackageUninstalled, @Nullable PackageSignatures initiatingPackageSignatures)106 private static InstallSource createInternal(@Nullable String initiatingPackageName, 107 @Nullable String originatingPackageName, @Nullable String installerPackageName, 108 @Nullable String installerAttributionTag, boolean isOrphaned, 109 boolean isInitiatingPackageUninstalled, 110 @Nullable PackageSignatures initiatingPackageSignatures) { 111 if (initiatingPackageName == null && originatingPackageName == null 112 && installerPackageName == null && initiatingPackageSignatures == null 113 && !isInitiatingPackageUninstalled) { 114 return isOrphaned ? EMPTY_ORPHANED : EMPTY; 115 } 116 return new InstallSource(initiatingPackageName, originatingPackageName, 117 installerPackageName, installerAttributionTag, isOrphaned, 118 isInitiatingPackageUninstalled, initiatingPackageSignatures 119 ); 120 } 121 InstallSource(@ullable String initiatingPackageName, @Nullable String originatingPackageName, @Nullable String installerPackageName, @Nullable String installerAttributionTag, boolean isOrphaned, boolean isInitiatingPackageUninstalled, @Nullable PackageSignatures initiatingPackageSignatures)122 private InstallSource(@Nullable String initiatingPackageName, 123 @Nullable String originatingPackageName, @Nullable String installerPackageName, 124 @Nullable String installerAttributionTag, boolean isOrphaned, 125 boolean isInitiatingPackageUninstalled, 126 @Nullable PackageSignatures initiatingPackageSignatures) { 127 if (initiatingPackageName == null) { 128 Preconditions.checkArgument(initiatingPackageSignatures == null); 129 Preconditions.checkArgument(!isInitiatingPackageUninstalled); 130 } 131 this.initiatingPackageName = initiatingPackageName; 132 this.originatingPackageName = originatingPackageName; 133 this.installerPackageName = installerPackageName; 134 this.installerAttributionTag = installerAttributionTag; 135 this.isOrphaned = isOrphaned; 136 this.isInitiatingPackageUninstalled = isInitiatingPackageUninstalled; 137 this.initiatingPackageSignatures = initiatingPackageSignatures; 138 } 139 140 /** 141 * Return an InstallSource the same as this one except with the specified 142 * {@link #installerPackageName}. 143 */ setInstallerPackage(@ullable String installerPackageName)144 InstallSource setInstallerPackage(@Nullable String installerPackageName) { 145 if (Objects.equals(installerPackageName, this.installerPackageName)) { 146 return this; 147 } 148 return createInternal(initiatingPackageName, originatingPackageName, 149 intern(installerPackageName), installerAttributionTag, isOrphaned, 150 isInitiatingPackageUninstalled, initiatingPackageSignatures 151 ); 152 } 153 154 /** 155 * Return an InstallSource the same as this one except with the specified value for 156 * {@link #isOrphaned}. 157 */ setIsOrphaned(boolean isOrphaned)158 InstallSource setIsOrphaned(boolean isOrphaned) { 159 if (isOrphaned == this.isOrphaned) { 160 return this; 161 } 162 return createInternal(initiatingPackageName, originatingPackageName, installerPackageName, 163 installerAttributionTag, isOrphaned, isInitiatingPackageUninstalled, 164 initiatingPackageSignatures); 165 } 166 167 /** 168 * Return an InstallSource the same as this one except with the specified 169 * {@link #initiatingPackageSignatures}. 170 */ setInitiatingPackageSignatures(@ullable PackageSignatures signatures)171 InstallSource setInitiatingPackageSignatures(@Nullable PackageSignatures signatures) { 172 if (signatures == initiatingPackageSignatures) { 173 return this; 174 } 175 return createInternal(initiatingPackageName, originatingPackageName, installerPackageName, 176 installerAttributionTag, isOrphaned, isInitiatingPackageUninstalled, signatures); 177 } 178 179 /** 180 * Return an InstallSource the same as this one updated to reflect that the specified installer 181 * package name has been uninstalled. 182 */ removeInstallerPackage(@ullable String packageName)183 InstallSource removeInstallerPackage(@Nullable String packageName) { 184 if (packageName == null) { 185 return this; 186 } 187 188 boolean modified = false; 189 boolean isInitiatingPackageUninstalled = this.isInitiatingPackageUninstalled; 190 String originatingPackageName = this.originatingPackageName; 191 String installerPackageName = this.installerPackageName; 192 boolean isOrphaned = this.isOrphaned; 193 194 if (packageName.equals(this.initiatingPackageName)) { 195 if (!isInitiatingPackageUninstalled) { 196 // In this case we deliberately do not clear the package name (and signatures). 197 // We allow an app to retrieve details of its own install initiator even after 198 // it has been uninstalled. 199 isInitiatingPackageUninstalled = true; 200 modified = true; 201 } 202 } 203 if (packageName.equals(originatingPackageName)) { 204 originatingPackageName = null; 205 modified = true; 206 } 207 if (packageName.equals(installerPackageName)) { 208 installerPackageName = null; 209 isOrphaned = true; 210 modified = true; 211 } 212 213 if (!modified) { 214 return this; 215 } 216 217 return createInternal(initiatingPackageName, originatingPackageName, installerPackageName, 218 null, isOrphaned, isInitiatingPackageUninstalled, initiatingPackageSignatures); 219 } 220 221 @Nullable intern(@ullable String packageName)222 private static String intern(@Nullable String packageName) { 223 return packageName == null ? null : packageName.intern(); 224 } 225 } 226