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