• 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 
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