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