• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.NonNull;
20 import android.annotation.Nullable;
21 import android.content.pm.ApplicationInfo;
22 import android.content.pm.PackageManager;
23 import android.content.pm.UserInfo;
24 import android.service.pm.PackageProto;
25 import android.util.ArrayMap;
26 import android.util.ArraySet;
27 import android.util.proto.ProtoOutputStream;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.server.pm.parsing.pkg.AndroidPackage;
31 import com.android.server.pm.permission.LegacyPermissionDataProvider;
32 import com.android.server.pm.permission.LegacyPermissionState;
33 import com.android.server.pm.pkg.PackageStateUnserialized;
34 import com.android.server.utils.SnapshotCache;
35 
36 import java.io.File;
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.UUID;
44 
45 /**
46  * Settings data for a particular package we know about.
47  */
48 public class PackageSetting extends PackageSettingBase {
49 
50     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
51     public int appId;
52 
53     /**
54      * This can be null whenever a physical APK on device is missing. This can be the result of
55      * removing an external storage device where the APK resides.
56      *
57      * This will result in the system reading the {@link PackageSetting} from disk, but without
58      * being able to parse the base APK's AndroidManifest.xml to read all of its metadata. The data
59      * that is written and read in {@link Settings} includes a minimal set of metadata needed to
60      * perform other checks in the system.
61      *
62      * This is important in order to enforce uniqueness within the system, as the package, even if
63      * on a removed storage device, is still considered installed. Another package of the same
64      * application ID or declaring the same permissions or similar cannot be installed.
65      *
66      * Re-attaching the storage device to make the APK available should allow the user to use the
67      * app once the device reboots or otherwise re-scans it.
68      *
69      * It is expected that all code that uses a {@link PackageSetting} understands this inner field
70      * may be null. Note that this relationship only works one way. It should not be possible to
71      * have an entry inside {@link PackageManagerService#mPackages} without a corresponding
72      * {@link PackageSetting} inside {@link Settings#mPackages}.
73      *
74      * @deprecated Use {@link #getPkg()}. The setter is favored to avoid unintended mutation.
75      */
76     @Nullable
77     @Deprecated
78     public AndroidPackage pkg;
79 
80     /**
81      * WARNING. The object reference is important. We perform integer equality and NOT
82      * object equality to check whether shared user settings are the same.
83      */
84     SharedUserSetting sharedUser;
85 
86     /**
87      * Temporary holding space for the shared user ID. While parsing package settings, the
88      * shared users tag may come after the packages. In this case, we must delay linking the
89      * shared user setting with the package setting. The shared user ID lets us link the
90      * two objects.
91      */
92     private int sharedUserId;
93 
94     /**
95      *  Maps mime group name to the set of Mime types in a group. Mime groups declared
96      *  by app are populated with empty sets at construction.
97      *  Mime groups can not be created/removed at runtime, thus keys in this map should not change
98      */
99     @Nullable
100     Map<String, ArraySet<String>> mimeGroups;
101 
102     @NonNull
103     private PackageStateUnserialized pkgState = new PackageStateUnserialized();
104 
105     @NonNull
106     private UUID mDomainSetId;
107 
108     /**
109      * Snapshot support.
110      */
111     private final SnapshotCache<PackageSetting> mSnapshot;
112 
makeCache()113     private SnapshotCache<PackageSetting> makeCache() {
114         return new SnapshotCache<PackageSetting>(this, this) {
115             @Override
116             public PackageSetting createSnapshot() {
117                 return new PackageSetting(mSource, true);
118             }};
119     }
120 
121     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
122     public PackageSetting(String name, String realName, @NonNull File codePath,
123             String legacyNativeLibraryPathString, String primaryCpuAbiString,
124             String secondaryCpuAbiString, String cpuAbiOverrideString,
125             long pVersionCode, int pkgFlags, int privateFlags,
126             int sharedUserId, String[] usesStaticLibraries,
127             long[] usesStaticLibrariesVersions, Map<String, ArraySet<String>> mimeGroups,
128             @NonNull UUID domainSetId) {
129         super(name, realName, codePath, legacyNativeLibraryPathString,
130                 primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
131                 pVersionCode, pkgFlags, privateFlags,
132                 usesStaticLibraries, usesStaticLibrariesVersions);
133         this.sharedUserId = sharedUserId;
134         mDomainSetId = domainSetId;
135         copyMimeGroups(mimeGroups);
136         mSnapshot = makeCache();
137     }
138 
139     /**
140      * New instance of PackageSetting replicating the original settings.
141      * Note that it keeps the same PackageParser.Package instance.
142      */
143     PackageSetting(PackageSetting orig) {
144         super(orig, orig.realName);
145         doCopy(orig);
146         mSnapshot = makeCache();
147     }
148 
149     /**
150      * New instance of PackageSetting replicating the original settings, but, allows specifying
151      * a real package name.
152      * Note that it keeps the same PackageParser.Package instance.
153      */
154     PackageSetting(PackageSetting orig, String realPkgName) {
155         super(orig, realPkgName);
156         doCopy(orig);
157         mSnapshot = makeCache();
158     }
159 
160     /**
161      * Create a snapshot.  The copy constructor is already in use and cannot be modified
162      * for this purpose.
163      */
164     PackageSetting(PackageSetting orig, boolean snapshot) {
165         super(orig, snapshot);
166         // The existing doCopy() method cannot be used in here because sharedUser must be
167         // a snapshot, and not a reference.  Also, the pkgState must be copied.  However,
168         // this code should otherwise be kept in sync with doCopy().
169         appId = orig.appId;
170         pkg = orig.pkg;
171         sharedUser = orig.sharedUser == null ? null : orig.sharedUser.snapshot();
172         sharedUserId = orig.sharedUserId;
173         copyMimeGroups(orig.mimeGroups);
174         pkgState = orig.pkgState;
175         mDomainSetId = orig.getDomainSetId();
176         mSnapshot = new SnapshotCache.Sealed();
177     }
178 
179     /**
180      * Return the package snapshot.
181      */
182     public PackageSetting snapshot() {
183         return mSnapshot.snapshot();
184     }
185 
186     /** @see #pkg **/
187     @Nullable
188     public AndroidPackage getPkg() {
189         return pkg;
190     }
191 
192     public int getSharedUserId() {
193         if (sharedUser != null) {
194             return sharedUser.userId;
195         }
196         return sharedUserId;
197     }
198 
199     public SharedUserSetting getSharedUser() {
200         return sharedUser;
201     }
202 
203     @Override
204     public String toString() {
205         return "PackageSetting{"
206             + Integer.toHexString(System.identityHashCode(this))
207             + " " + name + "/" + appId + "}";
208     }
209 
210     public void copyFrom(PackageSetting orig) {
211         super.copyFrom(orig);
212         doCopy(orig);
213     }
214 
215     private void doCopy(PackageSetting orig) {
216         appId = orig.appId;
217         pkg = orig.pkg;
218         sharedUser = orig.sharedUser;
219         sharedUserId = orig.sharedUserId;
220         copyMimeGroups(orig.mimeGroups);
221         mDomainSetId = orig.getDomainSetId();
222     }
223 
224     private void copyMimeGroups(@Nullable Map<String, ArraySet<String>> newMimeGroups) {
225         if (newMimeGroups == null) {
226             mimeGroups = null;
227             return;
228         }
229 
230         mimeGroups = new ArrayMap<>(newMimeGroups.size());
231         for (String mimeGroup : newMimeGroups.keySet()) {
232             ArraySet<String> mimeTypes = newMimeGroups.get(mimeGroup);
233 
234             if (mimeTypes != null) {
235                 mimeGroups.put(mimeGroup, new ArraySet<>(mimeTypes));
236             } else {
237                 mimeGroups.put(mimeGroup, new ArraySet<>());
238             }
239         }
240     }
241 
242     /**
243      * Updates declared MIME groups, removing no longer declared groups
244      * and keeping previous state of MIME groups
245      */
246     void updateMimeGroups(@Nullable Set<String> newMimeGroupNames) {
247         if (newMimeGroupNames == null) {
248             mimeGroups = null;
249             return;
250         }
251 
252         if (mimeGroups == null) {
253             // set mimeGroups to empty map to avoid repeated null-checks in the next loop
254             mimeGroups = Collections.emptyMap();
255         }
256 
257         ArrayMap<String, ArraySet<String>> updatedMimeGroups =
258                 new ArrayMap<>(newMimeGroupNames.size());
259 
260         for (String mimeGroup : newMimeGroupNames) {
261             if (mimeGroups.containsKey(mimeGroup)) {
262                 updatedMimeGroups.put(mimeGroup, mimeGroups.get(mimeGroup));
263             } else {
264                 updatedMimeGroups.put(mimeGroup, new ArraySet<>());
265             }
266         }
267         mimeGroups = updatedMimeGroups;
268     }
269 
270     @Deprecated
271     @Override
272     public LegacyPermissionState getLegacyPermissionState() {
273         return (sharedUser != null)
274                 ? sharedUser.getLegacyPermissionState()
275                 : super.getLegacyPermissionState();
276     }
277 
278     public int getAppId() {
279         return appId;
280     }
281 
282     public void setInstallPermissionsFixed(boolean fixed) {
283         installPermissionsFixed = fixed;
284     }
285 
286     public boolean areInstallPermissionsFixed() {
287         return installPermissionsFixed;
288     }
289 
290     public boolean isPrivileged() {
291         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
292     }
293 
294     public boolean isOem() {
295         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
296     }
297 
298     public boolean isVendor() {
299         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
300     }
301 
302     public boolean isProduct() {
303         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
304     }
305 
306     public boolean isSystemExt() {
307         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
308     }
309 
310     public boolean isOdm() {
311         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
312     }
313 
314     public boolean isSystem() {
315         return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
316     }
317 
318     @Override
319     public boolean isSharedUser() {
320         return sharedUser != null;
321     }
322 
323     public boolean isMatch(int flags) {
324         if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
325             return isSystem();
326         }
327         return true;
328     }
329 
330     public boolean setMimeGroup(String mimeGroup, List<String> mimeTypes) {
331         ArraySet<String> oldMimeTypes = getMimeGroupInternal(mimeGroup);
332         if (oldMimeTypes == null) {
333             throw new IllegalArgumentException("Unknown MIME group " + mimeGroup
334                     + " for package " + name);
335         }
336 
337         ArraySet<String> newMimeTypes = new ArraySet<>(mimeTypes);
338         boolean hasChanges = !newMimeTypes.equals(oldMimeTypes);
339         mimeGroups.put(mimeGroup, newMimeTypes);
340         return hasChanges;
341     }
342 
343     public List<String> getMimeGroup(String mimeGroup) {
344         ArraySet<String> mimeTypes = getMimeGroupInternal(mimeGroup);
345         if (mimeTypes == null) {
346             throw new IllegalArgumentException("Unknown MIME group " + mimeGroup
347                     + " for package " + name);
348         }
349         return new ArrayList<>(mimeTypes);
350     }
351 
352     private ArraySet<String> getMimeGroupInternal(String mimeGroup) {
353         return mimeGroups != null ? mimeGroups.get(mimeGroup) : null;
354     }
355 
356     public void dumpDebug(ProtoOutputStream proto, long fieldId, List<UserInfo> users,
357             LegacyPermissionDataProvider dataProvider) {
358         final long packageToken = proto.start(fieldId);
359         proto.write(PackageProto.NAME, (realName != null ? realName : name));
360         proto.write(PackageProto.UID, appId);
361         proto.write(PackageProto.VERSION_CODE, versionCode);
362         proto.write(PackageProto.INSTALL_TIME_MS, firstInstallTime);
363         proto.write(PackageProto.UPDATE_TIME_MS, lastUpdateTime);
364         proto.write(PackageProto.INSTALLER_NAME, installSource.installerPackageName);
365 
366         if (pkg != null) {
367             proto.write(PackageProto.VERSION_STRING, pkg.getVersionName());
368 
369             long splitToken = proto.start(PackageProto.SPLITS);
370             proto.write(PackageProto.SplitProto.NAME, "base");
371             proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.getBaseRevisionCode());
372             proto.end(splitToken);
373 
374             if (pkg.getSplitNames() != null) {
375                 for (int i = 0; i < pkg.getSplitNames().length; i++) {
376                     splitToken = proto.start(PackageProto.SPLITS);
377                     proto.write(PackageProto.SplitProto.NAME, pkg.getSplitNames()[i]);
378                     proto.write(PackageProto.SplitProto.REVISION_CODE,
379                             pkg.getSplitRevisionCodes()[i]);
380                     proto.end(splitToken);
381                 }
382             }
383 
384             long sourceToken = proto.start(PackageProto.INSTALL_SOURCE);
385             proto.write(PackageProto.InstallSourceProto.INITIATING_PACKAGE_NAME,
386                     installSource.initiatingPackageName);
387             proto.write(PackageProto.InstallSourceProto.ORIGINATING_PACKAGE_NAME,
388                     installSource.originatingPackageName);
389             proto.end(sourceToken);
390         }
391         proto.write(PackageProto.StatesProto.IS_LOADING, isPackageLoading());
392         writeUsersInfoToProto(proto, PackageProto.USERS);
393         writePackageUserPermissionsProto(proto, PackageProto.USER_PERMISSIONS, users, dataProvider);
394         proto.end(packageToken);
395     }
396 
397     /**
398      * TODO (b/170263003) refactor to dump to permissiongr proto
399      * Dumps the permissions that are granted to users for this package.
400      */
401     void writePackageUserPermissionsProto(ProtoOutputStream proto, long fieldId,
402             List<UserInfo> users, LegacyPermissionDataProvider dataProvider) {
403         Collection<LegacyPermissionState.PermissionState> runtimePermissionStates;
404         for (UserInfo user : users) {
405             final long permissionsToken = proto.start(PackageProto.USER_PERMISSIONS);
406             proto.write(PackageProto.UserPermissionsProto.ID, user.id);
407 
408             runtimePermissionStates = dataProvider.getLegacyPermissionState(appId)
409                     .getPermissionStates(user.id);
410             for (LegacyPermissionState.PermissionState permission : runtimePermissionStates) {
411                 if (permission.isGranted()) {
412                     proto.write(PackageProto.UserPermissionsProto.GRANTED_PERMISSIONS,
413                             permission.getName());
414                 }
415             }
416             proto.end(permissionsToken);
417         }
418     }
419 
420     /** Updates all fields in the current setting from another. */
421     public void updateFrom(PackageSetting other) {
422         super.updateFrom(other);
423         appId = other.appId;
424         pkg = other.pkg;
425         sharedUserId = other.sharedUserId;
426         sharedUser = other.sharedUser;
427         mDomainSetId = other.mDomainSetId;
428 
429         Set<String> mimeGroupNames = other.mimeGroups != null ? other.mimeGroups.keySet() : null;
430         updateMimeGroups(mimeGroupNames);
431 
432         getPkgState().updateFrom(other.getPkgState());
433     }
434 
435     @NonNull
436     public PackageStateUnserialized getPkgState() {
437         return pkgState;
438     }
439 
440     @NonNull
441     public UUID getDomainSetId() {
442         return mDomainSetId;
443     }
444 
445     public PackageSetting setDomainSetId(@NonNull UUID domainSetId) {
446         mDomainSetId = domainSetId;
447         return this;
448     }
449 }
450