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