1 /* 2 * Copyright (C) 2021 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.content.pm.parsing.ApkLiteParseUtils.isApkFile; 20 import static android.os.storage.StorageManager.FLAG_STORAGE_CE; 21 import static android.os.storage.StorageManager.FLAG_STORAGE_DE; 22 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL; 23 24 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; 25 import static com.android.server.pm.PackageManagerService.SCAN_INITIAL; 26 import static com.android.server.pm.PackageManagerService.TAG; 27 import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo; 28 29 import android.annotation.NonNull; 30 import android.app.ApplicationExitInfo; 31 import android.app.ResourcesManager; 32 import android.content.pm.PackageManager; 33 import android.content.pm.PackagePartitions; 34 import android.content.pm.UserInfo; 35 import android.content.pm.VersionedPackage; 36 import android.os.Environment; 37 import android.os.FileUtils; 38 import android.os.UserHandle; 39 import android.os.storage.StorageEventListener; 40 import android.os.storage.StorageManager; 41 import android.os.storage.StorageManagerInternal; 42 import android.os.storage.VolumeInfo; 43 import android.text.TextUtils; 44 import android.util.ArrayMap; 45 import android.util.ArraySet; 46 import android.util.Log; 47 import android.util.Slog; 48 49 import com.android.internal.annotations.GuardedBy; 50 import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; 51 import com.android.internal.policy.AttributeCache; 52 import com.android.internal.util.IndentingPrintWriter; 53 import com.android.server.pm.pkg.AndroidPackage; 54 import com.android.server.pm.pkg.PackageStateInternal; 55 56 import java.io.File; 57 import java.io.PrintWriter; 58 import java.util.ArrayList; 59 import java.util.List; 60 61 /** Helper class to handle storage events and private apps loading */ 62 public final class StorageEventHelper extends StorageEventListener { 63 private final PackageManagerService mPm; 64 private final BroadcastHelper mBroadcastHelper; 65 private final DeletePackageHelper mDeletePackageHelper; 66 private final RemovePackageHelper mRemovePackageHelper; 67 68 @GuardedBy("mLoadedVolumes") 69 final ArraySet<String> mLoadedVolumes = new ArraySet<>(); 70 71 // TODO(b/198166813): remove PMS dependency StorageEventHelper(PackageManagerService pm, DeletePackageHelper deletePackageHelper, RemovePackageHelper removePackageHelper)72 public StorageEventHelper(PackageManagerService pm, DeletePackageHelper deletePackageHelper, 73 RemovePackageHelper removePackageHelper) { 74 mPm = pm; 75 mBroadcastHelper = new BroadcastHelper(mPm.mInjector); 76 mDeletePackageHelper = deletePackageHelper; 77 mRemovePackageHelper = removePackageHelper; 78 } 79 80 @Override onVolumeStateChanged(VolumeInfo vol, int oldState, int newState)81 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { 82 if (vol.type == VolumeInfo.TYPE_PRIVATE) { 83 if (vol.state == VolumeInfo.STATE_MOUNTED) { 84 final String volumeUuid = vol.getFsUuid(); 85 86 // Clean up any users or apps that were removed or recreated 87 // while this volume was missing 88 mPm.mUserManager.reconcileUsers(volumeUuid); 89 reconcileApps(mPm.snapshotComputer(), volumeUuid); 90 91 // Clean up any install sessions that expired or were 92 // cancelled while this volume was missing 93 mPm.mInstallerService.onPrivateVolumeMounted(volumeUuid); 94 95 loadPrivatePackages(vol); 96 97 } else if (vol.state == VolumeInfo.STATE_EJECTING) { 98 unloadPrivatePackages(vol); 99 } 100 } 101 } 102 103 @Override onVolumeForgotten(String fsUuid)104 public void onVolumeForgotten(String fsUuid) { 105 if (TextUtils.isEmpty(fsUuid)) { 106 Slog.e(TAG, "Forgetting internal storage is probably a mistake; ignoring"); 107 return; 108 } 109 110 // Remove any apps installed on the forgotten volume 111 synchronized (mPm.mLock) { 112 final List<? extends PackageStateInternal> packages = 113 mPm.mSettings.getVolumePackagesLPr(fsUuid); 114 for (PackageStateInternal ps : packages) { 115 Slog.d(TAG, "Destroying " + ps.getPackageName() 116 + " because volume was forgotten"); 117 mPm.deletePackageVersioned(new VersionedPackage(ps.getPackageName(), 118 PackageManager.VERSION_CODE_HIGHEST), 119 new PackageManager.LegacyPackageDeleteObserver(null).getBinder(), 120 UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS); 121 // Try very hard to release any references to this package 122 // so we don't risk the system server being killed due to 123 // open FDs 124 AttributeCache.instance().removePackage(ps.getPackageName()); 125 } 126 127 mPm.mSettings.onVolumeForgotten(fsUuid); 128 mPm.writeSettingsLPrTEMP(); 129 } 130 } 131 loadPrivatePackages(final VolumeInfo vol)132 private void loadPrivatePackages(final VolumeInfo vol) { 133 mPm.mHandler.post(() -> loadPrivatePackagesInner(vol)); 134 } 135 loadPrivatePackagesInner(VolumeInfo vol)136 private void loadPrivatePackagesInner(VolumeInfo vol) { 137 final String volumeUuid = vol.fsUuid; 138 if (TextUtils.isEmpty(volumeUuid)) { 139 Slog.e(TAG, "Loading internal storage is probably a mistake; ignoring"); 140 return; 141 } 142 143 final AppDataHelper appDataHelper = new AppDataHelper(mPm); 144 final ArrayList<PackageFreezer> freezers = new ArrayList<>(); 145 final ArrayList<AndroidPackage> loaded = new ArrayList<>(); 146 final int parseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_EXTERNAL_STORAGE; 147 148 final Settings.VersionInfo ver; 149 final List<? extends PackageStateInternal> packages; 150 synchronized (mPm.mLock) { 151 ver = mPm.mSettings.findOrCreateVersion(volumeUuid); 152 packages = mPm.mSettings.getVolumePackagesLPr(volumeUuid); 153 } 154 155 for (PackageStateInternal ps : packages) { 156 freezers.add(mPm.freezePackage(ps.getPackageName(), UserHandle.USER_ALL, 157 "loadPrivatePackagesInner", ApplicationExitInfo.REASON_OTHER, 158 null /* request */)); 159 try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) { 160 final AndroidPackage pkg; 161 try { 162 pkg = mPm.initPackageTracedLI( 163 ps.getPath(), parseFlags, SCAN_INITIAL); 164 loaded.add(pkg); 165 166 } catch (PackageManagerException e) { 167 Slog.w(TAG, "Failed to scan " + ps.getPath() + ": " + e.getMessage()); 168 } 169 170 if (!PackagePartitions.FINGERPRINT.equals(ver.fingerprint)) { 171 appDataHelper.clearAppDataLIF( 172 ps.getPkg(), UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE 173 | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY 174 | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES); 175 } 176 } 177 } 178 179 // Reconcile app data for all started/unlocked users 180 final StorageManager sm = mPm.mInjector.getSystemService(StorageManager.class); 181 UserManagerInternal umInternal = mPm.mInjector.getUserManagerInternal(); 182 StorageManagerInternal smInternal = mPm.mInjector.getLocalService( 183 StorageManagerInternal.class); 184 for (UserInfo user : mPm.mUserManager.getUsers(false /* includeDying */)) { 185 final int flags; 186 if (StorageManager.isCeStorageUnlocked(user.id) 187 && smInternal.isCeStoragePrepared(user.id)) { 188 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; 189 } else if (umInternal.isUserRunning(user.id)) { 190 flags = StorageManager.FLAG_STORAGE_DE; 191 } else { 192 continue; 193 } 194 195 try { 196 sm.prepareUserStorage(volumeUuid, user.id, flags); 197 try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) { 198 appDataHelper.reconcileAppsDataLI(volumeUuid, user.id, flags, 199 true /* migrateAppData */); 200 } 201 } catch (RuntimeException e) { 202 // The volume was probably already unmounted. We'll probably process the unmount 203 // event momentarily. TODO(b/256909937): ignoring errors from prepareUserStorage() 204 // is very dangerous. Instead, we should fix the race condition that allows this 205 // code to run on an unmounted volume in the first place. 206 Slog.w(TAG, "Failed to prepare storage: " + e); 207 } 208 } 209 210 synchronized (mPm.mLock) { 211 final boolean isUpgrade = !PackagePartitions.FINGERPRINT.equals(ver.fingerprint); 212 if (isUpgrade) { 213 logCriticalInfo(Log.INFO, "Partitions fingerprint changed from " + ver.fingerprint 214 + " to " + PackagePartitions.FINGERPRINT + "; regranting permissions for " 215 + volumeUuid); 216 } 217 mPm.mPermissionManager.onStorageVolumeMounted(volumeUuid, isUpgrade); 218 219 // Yay, everything is now upgraded 220 ver.forceCurrent(); 221 222 mPm.writeSettingsLPrTEMP(); 223 } 224 225 for (PackageFreezer freezer : freezers) { 226 freezer.close(); 227 } 228 229 if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded); 230 mBroadcastHelper.sendResourcesChangedBroadcastAndNotify(mPm.snapshotComputer(), 231 true /* mediaStatus */, false /* replacing */, loaded); 232 synchronized (mLoadedVolumes) { 233 mLoadedVolumes.add(vol.getId()); 234 } 235 } 236 unloadPrivatePackages(final VolumeInfo vol)237 private void unloadPrivatePackages(final VolumeInfo vol) { 238 mPm.mHandler.post(() -> unloadPrivatePackagesInner(vol)); 239 } 240 unloadPrivatePackagesInner(VolumeInfo vol)241 private void unloadPrivatePackagesInner(VolumeInfo vol) { 242 final String volumeUuid = vol.fsUuid; 243 if (TextUtils.isEmpty(volumeUuid)) { 244 Slog.e(TAG, "Unloading internal storage is probably a mistake; ignoring"); 245 return; 246 } 247 248 final int[] userIds = mPm.mUserManager.getUserIds(); 249 final ArrayList<AndroidPackage> unloaded = new ArrayList<>(); 250 try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) { 251 synchronized (mPm.mLock) { 252 final List<? extends PackageStateInternal> packages = 253 mPm.mSettings.getVolumePackagesLPr(volumeUuid); 254 for (PackageStateInternal ps : packages) { 255 if (ps.getPkg() == null) continue; 256 257 final AndroidPackage pkg = ps.getPkg(); 258 final int deleteFlags = PackageManager.DELETE_KEEP_DATA; 259 260 try (PackageFreezer freezer = mPm.freezePackageForDelete(ps.getPackageName(), 261 UserHandle.USER_ALL, deleteFlags, 262 "unloadPrivatePackagesInner", ApplicationExitInfo.REASON_OTHER)) { 263 if (mDeletePackageHelper.deletePackageLIF(ps.getPackageName(), null, false, 264 userIds, deleteFlags, new PackageRemovedInfo(), false)) { 265 unloaded.add(pkg); 266 } else { 267 Slog.w(TAG, "Failed to unload " + ps.getPath()); 268 } 269 } 270 271 // Try very hard to release any references to this package 272 // so we don't risk the system server being killed due to 273 // open FDs 274 AttributeCache.instance().removePackage(ps.getPackageName()); 275 } 276 277 mPm.writeSettingsLPrTEMP(); 278 } 279 } 280 281 if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded); 282 mBroadcastHelper.sendResourcesChangedBroadcastAndNotify(mPm.snapshotComputer(), 283 false /* mediaStatus */, false /* replacing */, unloaded); 284 synchronized (mLoadedVolumes) { 285 mLoadedVolumes.remove(vol.getId()); 286 } 287 288 // Try very hard to release any references to this path so we don't risk 289 // the system server being killed due to open FDs 290 ResourcesManager.getInstance().invalidatePath(vol.getPath().getAbsolutePath()); 291 292 for (int i = 0; i < 3; i++) { 293 System.gc(); 294 System.runFinalization(); 295 } 296 } 297 298 /** 299 * Examine all apps present on given mounted volume, and destroy apps that 300 * aren't expected, either due to uninstallation or reinstallation on 301 * another volume. 302 */ reconcileApps(@onNull Computer snapshot, String volumeUuid)303 public void reconcileApps(@NonNull Computer snapshot, String volumeUuid) { 304 List<String> absoluteCodePaths = collectAbsoluteCodePaths(snapshot); 305 List<File> filesToDelete = null; 306 307 final File[] files = FileUtils.listFilesOrEmpty( 308 Environment.getDataAppDirectory(volumeUuid)); 309 for (File file : files) { 310 final boolean isPackage = (isApkFile(file) || file.isDirectory()) 311 && !PackageInstallerService.isStageName(file.getName()); 312 if (!isPackage) { 313 // Ignore entries which are not packages 314 continue; 315 } 316 317 String absolutePath = file.getAbsolutePath(); 318 319 boolean pathValid = false; 320 final int absoluteCodePathCount = absoluteCodePaths.size(); 321 for (int i = 0; i < absoluteCodePathCount; i++) { 322 String absoluteCodePath = absoluteCodePaths.get(i); 323 if (absoluteCodePath.startsWith(absolutePath)) { 324 pathValid = true; 325 break; 326 } 327 } 328 329 if (!pathValid) { 330 if (filesToDelete == null) { 331 filesToDelete = new ArrayList<>(); 332 } 333 filesToDelete.add(file); 334 } 335 } 336 337 if (filesToDelete != null) { 338 final int fileToDeleteCount = filesToDelete.size(); 339 for (int i = 0; i < fileToDeleteCount; i++) { 340 File fileToDelete = filesToDelete.get(i); 341 logCriticalInfo(Log.WARN, "Destroying orphaned at " + fileToDelete); 342 mRemovePackageHelper.removeCodePath(fileToDelete); 343 } 344 } 345 } 346 collectAbsoluteCodePaths(@onNull Computer snapshot)347 private List<String> collectAbsoluteCodePaths(@NonNull Computer snapshot) { 348 List<String> codePaths = new ArrayList<>(); 349 final ArrayMap<String, ? extends PackageStateInternal> packageStates = 350 snapshot.getPackageStates(); 351 final int packageCount = packageStates.size(); 352 for (int i = 0; i < packageCount; i++) { 353 final PackageStateInternal ps = packageStates.valueAt(i); 354 codePaths.add(ps.getPath().getAbsolutePath()); 355 } 356 return codePaths; 357 } 358 dumpLoadedVolumes(@onNull PrintWriter pw, @NonNull DumpState dumpState)359 public void dumpLoadedVolumes(@NonNull PrintWriter pw, @NonNull DumpState dumpState) { 360 if (dumpState.onTitlePrinted()) { 361 pw.println(); 362 } 363 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); 364 ipw.println(); 365 ipw.println("Loaded volumes:"); 366 ipw.increaseIndent(); 367 synchronized (mLoadedVolumes) { 368 if (mLoadedVolumes.size() == 0) { 369 ipw.println("(none)"); 370 } else { 371 for (int i = 0; i < mLoadedVolumes.size(); i++) { 372 ipw.println(mLoadedVolumes.valueAt(i)); 373 } 374 } 375 } 376 ipw.decreaseIndent(); 377 } 378 } 379