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.SigningDetails; 23 import android.service.pm.PackageServiceDumpProto; 24 import android.util.ArrayMap; 25 import android.util.ArraySet; 26 import android.util.proto.ProtoOutputStream; 27 28 import com.android.internal.pm.pkg.component.ComponentMutateUtils; 29 import com.android.internal.pm.pkg.component.ParsedProcess; 30 import com.android.internal.pm.pkg.component.ParsedProcessImpl; 31 import com.android.internal.util.ArrayUtils; 32 import com.android.server.pm.permission.LegacyPermissionState; 33 import com.android.server.pm.pkg.AndroidPackage; 34 import com.android.server.pm.pkg.PackageStateInternal; 35 import com.android.server.pm.pkg.SharedUserApi; 36 import com.android.server.utils.SnapshotCache; 37 import com.android.server.utils.Watchable; 38 import com.android.server.utils.WatchedArraySet; 39 import com.android.server.utils.Watcher; 40 41 import libcore.util.EmptyArray; 42 43 import java.util.ArrayList; 44 import java.util.Collections; 45 import java.util.List; 46 import java.util.Map; 47 48 /** 49 * Settings data for a particular shared user ID we know about. 50 */ 51 public final class SharedUserSetting extends SettingBase implements SharedUserApi { 52 final String name; 53 54 int mAppId; 55 56 /** @see SharedUserApi#getUidFlags() **/ 57 int uidFlags; 58 int uidPrivateFlags; 59 60 /** @see SharedUserApi#getSeInfoTargetSdkVersion() **/ 61 int seInfoTargetSdkVersion; 62 63 private final WatchedArraySet<PackageSetting> mPackages; 64 private final SnapshotCache<WatchedArraySet<PackageSetting>> mPackagesSnapshot; 65 66 // It is possible for a system app to leave shared user ID by an update. 67 // We need to keep track of the shadowed PackageSettings so that it is possible to uninstall 68 // the update and revert the system app back into the original shared user ID. 69 final WatchedArraySet<PackageSetting> mDisabledPackages; 70 private final SnapshotCache<WatchedArraySet<PackageSetting>> mDisabledPackagesSnapshot; 71 72 /** 73 * The observer that watches for changes from array members 74 */ 75 private final Watcher mObserver = new Watcher() { 76 @Override 77 public void onChange(@Nullable Watchable what) { 78 SharedUserSetting.this.onChanged(); 79 } 80 }; 81 82 final PackageSignatures signatures = new PackageSignatures(); 83 Boolean signaturesChanged; 84 85 final ArrayMap<String, ParsedProcess> processes; 86 87 /** 88 * Snapshot support. 89 */ 90 private final SnapshotCache<SharedUserSetting> mSnapshot; 91 makeCache()92 private SnapshotCache<SharedUserSetting> makeCache() { 93 return new SnapshotCache<SharedUserSetting>(this, this) { 94 @Override 95 public SharedUserSetting createSnapshot() { 96 return new SharedUserSetting(mSource); 97 }}; 98 } 99 100 SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) { 101 super(_pkgFlags, _pkgPrivateFlags); 102 uidFlags = _pkgFlags; 103 uidPrivateFlags = _pkgPrivateFlags; 104 name = _name; 105 seInfoTargetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; 106 mPackages = new WatchedArraySet<>(); 107 mPackagesSnapshot = new SnapshotCache.Auto<>(mPackages, mPackages, 108 "SharedUserSetting.packages"); 109 mDisabledPackages = new WatchedArraySet<>(); 110 mDisabledPackagesSnapshot = new SnapshotCache.Auto<>(mDisabledPackages, mDisabledPackages, 111 "SharedUserSetting.mDisabledPackages"); 112 processes = new ArrayMap<>(); 113 registerObservers(); 114 mSnapshot = makeCache(); 115 } 116 117 // The copy constructor is used to create a snapshot 118 private SharedUserSetting(SharedUserSetting orig) { 119 super(orig); 120 name = orig.name; 121 mAppId = orig.mAppId; 122 uidFlags = orig.uidFlags; 123 uidPrivateFlags = orig.uidPrivateFlags; 124 mPackages = orig.mPackagesSnapshot.snapshot(); 125 mPackagesSnapshot = new SnapshotCache.Sealed<>(); 126 mDisabledPackages = orig.mDisabledPackagesSnapshot.snapshot(); 127 mDisabledPackagesSnapshot = new SnapshotCache.Sealed<>(); 128 // A SigningDetails seems to consist solely of final attributes, so 129 // it is safe to copy the reference. 130 signatures.mSigningDetails = orig.signatures.mSigningDetails; 131 signaturesChanged = orig.signaturesChanged; 132 processes = new ArrayMap<>(orig.processes); 133 mSnapshot = new SnapshotCache.Sealed<>(); 134 } 135 136 private void registerObservers() { 137 mPackages.registerObserver(mObserver); 138 mDisabledPackages.registerObserver(mObserver); 139 } 140 141 /** 142 * Return a read-only snapshot of this object. 143 */ 144 public SharedUserSetting snapshot() { 145 return mSnapshot.snapshot(); 146 } 147 148 @Override 149 public String toString() { 150 return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " " 151 + name + "/" + mAppId + "}"; 152 } 153 154 public void dumpDebug(ProtoOutputStream proto, long fieldId) { 155 long token = proto.start(fieldId); 156 proto.write(PackageServiceDumpProto.SharedUserProto.UID, mAppId); 157 proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name); 158 proto.end(token); 159 } 160 161 void addProcesses(Map<String, ParsedProcess> newProcs) { 162 if (newProcs != null) { 163 for (String key : newProcs.keySet()) { 164 ParsedProcess newProc = newProcs.get(key); 165 ParsedProcess proc = processes.get(newProc.getName()); 166 if (proc == null) { 167 proc = new ParsedProcessImpl(newProc); 168 processes.put(newProc.getName(), proc); 169 } else { 170 ComponentMutateUtils.addStateFrom(proc, newProc); 171 } 172 } 173 onChanged(); 174 } 175 } 176 177 boolean removePackage(PackageSetting packageSetting) { 178 if (!mPackages.remove(packageSetting)) { 179 return false; 180 } 181 // recalculate the pkgFlags for this shared user if needed 182 if ((this.getFlags() & packageSetting.getFlags()) != 0) { 183 int aggregatedFlags = uidFlags; 184 for (int i = 0; i < mPackages.size(); i++) { 185 PackageSetting ps = mPackages.valueAt(i); 186 aggregatedFlags |= ps.getFlags(); 187 } 188 setFlags(aggregatedFlags); 189 } 190 if ((this.getPrivateFlags() & packageSetting.getPrivateFlags()) != 0) { 191 int aggregatedPrivateFlags = uidPrivateFlags; 192 for (int i = 0; i < mPackages.size(); i++) { 193 PackageSetting ps = mPackages.valueAt(i); 194 aggregatedPrivateFlags |= ps.getPrivateFlags(); 195 } 196 setPrivateFlags(aggregatedPrivateFlags); 197 } 198 // recalculate processes. 199 updateProcesses(); 200 onChanged(); 201 return true; 202 } 203 204 void addPackage(PackageSetting packageSetting) { 205 // If this is the first package added to this shared user, temporarily (until next boot) use 206 // its targetSdkVersion when assigning seInfo for the shared user. 207 if ((mPackages.size() == 0) && (packageSetting.getPkg() != null)) { 208 seInfoTargetSdkVersion = packageSetting.getPkg().getTargetSdkVersion(); 209 } 210 if (mPackages.add(packageSetting)) { 211 setFlags(this.getFlags() | packageSetting.getFlags()); 212 setPrivateFlags(this.getPrivateFlags() | packageSetting.getPrivateFlags()); 213 onChanged(); 214 } 215 if (packageSetting.getPkg() != null) { 216 addProcesses(packageSetting.getPkg().getProcesses()); 217 } 218 } 219 220 @NonNull 221 @Override 222 public List<AndroidPackage> getPackages() { 223 if (mPackages == null || mPackages.size() == 0) { 224 return Collections.emptyList(); 225 } 226 final ArrayList<AndroidPackage> pkgList = new ArrayList<>(mPackages.size()); 227 for (int i = 0; i < mPackages.size(); i++) { 228 PackageSetting ps = mPackages.valueAt(i); 229 if ((ps == null) || (ps.getPkg() == null)) { 230 continue; 231 } 232 pkgList.add(ps.getPkg()); 233 } 234 return pkgList; 235 } 236 237 @Override 238 public boolean isPrivileged() { 239 return (this.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; 240 } 241 242 /** 243 * A shared user is considered "single user" if there is exactly one single package 244 * currently using it. In the case when that package is also a system app, the APK on 245 * the system partition has to also leave shared UID. 246 */ 247 public boolean isSingleUser() { 248 if (mPackages.size() != 1) { 249 return false; 250 } 251 if (mDisabledPackages.size() > 1) { 252 return false; 253 } 254 if (mDisabledPackages.size() == 1) { 255 final AndroidPackage pkg = mDisabledPackages.valueAt(0).getPkg(); 256 return pkg != null && pkg.isLeavingSharedUser(); 257 } 258 return true; 259 } 260 261 /** 262 * Determine the targetSdkVersion for a sharedUser and update pkg.applicationInfo.seInfo 263 * to ensure that all apps within the sharedUser share an SELinux domain. Use the lowest 264 * targetSdkVersion of all apps within the shared user, which corresponds to the least 265 * restrictive selinux domain. 266 */ 267 public void fixSeInfoLocked() { 268 if (mPackages == null || mPackages.size() == 0) { 269 return; 270 } 271 for (int i = 0; i < mPackages.size(); i++) { 272 PackageSetting ps = mPackages.valueAt(i); 273 if ((ps == null) || (ps.getPkg() == null)) { 274 continue; 275 } 276 if (ps.getPkg().getTargetSdkVersion() < seInfoTargetSdkVersion) { 277 seInfoTargetSdkVersion = ps.getPkg().getTargetSdkVersion(); 278 onChanged(); 279 } 280 } 281 282 for (int i = 0; i < mPackages.size(); i++) { 283 PackageSetting ps = mPackages.valueAt(i); 284 if ((ps == null) || (ps.getPkg() == null)) { 285 continue; 286 } 287 final boolean isPrivileged = isPrivileged() | ps.isPrivileged(); 288 ps.getPkgState().setOverrideSeInfo(SELinuxMMAC.getSeInfo(ps, ps.getPkg(), isPrivileged, 289 seInfoTargetSdkVersion)); 290 onChanged(); 291 } 292 } 293 294 /** 295 * Update tracked data about processes based on all known packages in the shared user ID. 296 */ 297 public void updateProcesses() { 298 processes.clear(); 299 for (int i = mPackages.size() - 1; i >= 0; i--) { 300 final AndroidPackage pkg = mPackages.valueAt(i).getPkg(); 301 if (pkg != null) { 302 addProcesses(pkg.getProcesses()); 303 } 304 } 305 } 306 307 /** Returns userIds which doesn't have any packages with this sharedUserId */ 308 public int[] getNotInstalledUserIds() { 309 int[] excludedUserIds = null; 310 for (int i = 0; i < mPackages.size(); i++) { 311 PackageSetting ps = mPackages.valueAt(i); 312 final int[] userIds = ps.getNotInstalledUserIds(); 313 if (excludedUserIds == null) { 314 excludedUserIds = userIds; 315 } else { 316 for (int userId : excludedUserIds) { 317 if (!ArrayUtils.contains(userIds, userId)) { 318 excludedUserIds = ArrayUtils.removeInt(excludedUserIds, userId); 319 } 320 } 321 } 322 } 323 return excludedUserIds == null ? EmptyArray.INT : excludedUserIds; 324 } 325 326 /** Updates all fields in this shared user setting from another. */ 327 public SharedUserSetting updateFrom(SharedUserSetting sharedUser) { 328 super.copySettingBase(sharedUser); 329 this.mAppId = sharedUser.mAppId; 330 this.uidFlags = sharedUser.uidFlags; 331 this.uidPrivateFlags = sharedUser.uidPrivateFlags; 332 this.seInfoTargetSdkVersion = sharedUser.seInfoTargetSdkVersion; 333 this.mPackages.clear(); 334 this.mPackages.addAll(sharedUser.mPackages); 335 this.signaturesChanged = sharedUser.signaturesChanged; 336 if (sharedUser.processes != null) { 337 final int numProcs = sharedUser.processes.size(); 338 this.processes.clear(); 339 this.processes.ensureCapacity(numProcs); 340 for (int i = 0; i < numProcs; i++) { 341 ParsedProcess proc = new ParsedProcessImpl(sharedUser.processes.valueAt(i)); 342 this.processes.put(proc.getName(), proc); 343 } 344 } else { 345 this.processes.clear(); 346 } 347 onChanged(); 348 return this; 349 } 350 351 @NonNull 352 @Override 353 public String getName() { 354 return name; 355 } 356 357 @Override 358 public int getAppId() { 359 return mAppId; 360 } 361 362 @Override 363 public int getUidFlags() { 364 return uidFlags; 365 } 366 367 @Override 368 public int getPrivateUidFlags() { 369 return uidPrivateFlags; 370 } 371 372 @Override 373 public int getSeInfoTargetSdkVersion() { 374 return seInfoTargetSdkVersion; 375 } 376 377 public WatchedArraySet<PackageSetting> getPackageSettings() { 378 return mPackages; 379 } 380 381 public WatchedArraySet<PackageSetting> getDisabledPackageSettings() { 382 return mDisabledPackages; 383 } 384 385 @NonNull 386 @Override 387 public ArraySet<? extends PackageStateInternal> getPackageStates() { 388 return mPackages.untrackedStorage(); 389 } 390 391 @NonNull 392 @Override 393 public ArraySet<? extends PackageStateInternal> getDisabledPackageStates() { 394 return mDisabledPackages.untrackedStorage(); 395 } 396 397 @NonNull 398 @Override 399 public SigningDetails getSigningDetails() { 400 return signatures.mSigningDetails; 401 } 402 403 @NonNull 404 @Override 405 public ArrayMap<String, ParsedProcess> getProcesses() { 406 return processes; 407 } 408 409 @NonNull 410 @Override 411 public LegacyPermissionState getSharedUserLegacyPermissionState() { 412 return super.getLegacyPermissionState(); 413 } 414 } 415