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.policy.AttributeCache; 51 import com.android.internal.util.IndentingPrintWriter; 52 import com.android.server.pm.pkg.AndroidPackage; 53 import com.android.server.pm.pkg.PackageStateInternal; 54 import com.android.server.pm.pkg.parsing.ParsingPackageUtils; 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 final InstallPackageHelper installPackageHelper = new InstallPackageHelper(mPm); 151 synchronized (mPm.mLock) { 152 ver = mPm.mSettings.findOrCreateVersion(volumeUuid); 153 packages = mPm.mSettings.getVolumePackagesLPr(volumeUuid); 154 } 155 156 for (PackageStateInternal ps : packages) { 157 freezers.add(mPm.freezePackage(ps.getPackageName(), UserHandle.USER_ALL, 158 "loadPrivatePackagesInner", ApplicationExitInfo.REASON_OTHER)); 159 synchronized (mPm.mInstallLock) { 160 final AndroidPackage pkg; 161 try { 162 pkg = installPackageHelper.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.isUserKeyUnlocked(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, user.serialNumber, flags); 197 synchronized (mPm.mInstallLock) { 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 sendResourcesChangedBroadcast(true /* mediaStatus */, false /* replacing */, loaded); 231 synchronized (mLoadedVolumes) { 232 mLoadedVolumes.add(vol.getId()); 233 } 234 } 235 unloadPrivatePackages(final VolumeInfo vol)236 private void unloadPrivatePackages(final VolumeInfo vol) { 237 mPm.mHandler.post(() -> unloadPrivatePackagesInner(vol)); 238 } 239 unloadPrivatePackagesInner(VolumeInfo vol)240 private void unloadPrivatePackagesInner(VolumeInfo vol) { 241 final String volumeUuid = vol.fsUuid; 242 if (TextUtils.isEmpty(volumeUuid)) { 243 Slog.e(TAG, "Unloading internal storage is probably a mistake; ignoring"); 244 return; 245 } 246 247 final int[] userIds = mPm.mUserManager.getUserIds(); 248 final ArrayList<AndroidPackage> unloaded = new ArrayList<>(); 249 synchronized (mPm.mInstallLock) { 250 synchronized (mPm.mLock) { 251 final List<? extends PackageStateInternal> packages = 252 mPm.mSettings.getVolumePackagesLPr(volumeUuid); 253 for (PackageStateInternal ps : packages) { 254 if (ps.getPkg() == null) continue; 255 256 final AndroidPackage pkg = ps.getPkg(); 257 final int deleteFlags = PackageManager.DELETE_KEEP_DATA; 258 final PackageRemovedInfo outInfo = new PackageRemovedInfo(mPm); 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, outInfo, 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 sendResourcesChangedBroadcast(false /* mediaStatus */, false /* replacing */, unloaded); 283 synchronized (mLoadedVolumes) { 284 mLoadedVolumes.remove(vol.getId()); 285 } 286 287 // Try very hard to release any references to this path so we don't risk 288 // the system server being killed due to open FDs 289 ResourcesManager.getInstance().invalidatePath(vol.getPath().getAbsolutePath()); 290 291 for (int i = 0; i < 3; i++) { 292 System.gc(); 293 System.runFinalization(); 294 } 295 } 296 sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, ArrayList<AndroidPackage> packages)297 private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, 298 ArrayList<AndroidPackage> packages) { 299 final int size = packages.size(); 300 final String[] packageNames = new String[size]; 301 final int[] packageUids = new int[size]; 302 for (int i = 0; i < size; i++) { 303 final AndroidPackage pkg = packages.get(i); 304 packageNames[i] = pkg.getPackageName(); 305 packageUids[i] = pkg.getUid(); 306 } 307 mBroadcastHelper.sendResourcesChangedBroadcast(mPm::snapshotComputer, mediaStatus, 308 replacing, packageNames, packageUids); 309 } 310 311 /** 312 * Examine all apps present on given mounted volume, and destroy apps that 313 * aren't expected, either due to uninstallation or reinstallation on 314 * another volume. 315 */ reconcileApps(@onNull Computer snapshot, String volumeUuid)316 public void reconcileApps(@NonNull Computer snapshot, String volumeUuid) { 317 List<String> absoluteCodePaths = collectAbsoluteCodePaths(snapshot); 318 List<File> filesToDelete = null; 319 320 final File[] files = FileUtils.listFilesOrEmpty( 321 Environment.getDataAppDirectory(volumeUuid)); 322 for (File file : files) { 323 final boolean isPackage = (isApkFile(file) || file.isDirectory()) 324 && !PackageInstallerService.isStageName(file.getName()); 325 if (!isPackage) { 326 // Ignore entries which are not packages 327 continue; 328 } 329 330 String absolutePath = file.getAbsolutePath(); 331 332 boolean pathValid = false; 333 final int absoluteCodePathCount = absoluteCodePaths.size(); 334 for (int i = 0; i < absoluteCodePathCount; i++) { 335 String absoluteCodePath = absoluteCodePaths.get(i); 336 if (absoluteCodePath.startsWith(absolutePath)) { 337 pathValid = true; 338 break; 339 } 340 } 341 342 if (!pathValid) { 343 if (filesToDelete == null) { 344 filesToDelete = new ArrayList<>(); 345 } 346 filesToDelete.add(file); 347 } 348 } 349 350 if (filesToDelete != null) { 351 final int fileToDeleteCount = filesToDelete.size(); 352 for (int i = 0; i < fileToDeleteCount; i++) { 353 File fileToDelete = filesToDelete.get(i); 354 logCriticalInfo(Log.WARN, "Destroying orphaned at " + fileToDelete); 355 mRemovePackageHelper.removeCodePath(fileToDelete); 356 } 357 } 358 } 359 collectAbsoluteCodePaths(@onNull Computer snapshot)360 private List<String> collectAbsoluteCodePaths(@NonNull Computer snapshot) { 361 List<String> codePaths = new ArrayList<>(); 362 final ArrayMap<String, ? extends PackageStateInternal> packageStates = 363 snapshot.getPackageStates(); 364 final int packageCount = packageStates.size(); 365 for (int i = 0; i < packageCount; i++) { 366 final PackageStateInternal ps = packageStates.valueAt(i); 367 codePaths.add(ps.getPath().getAbsolutePath()); 368 } 369 return codePaths; 370 } 371 dumpLoadedVolumes(@onNull PrintWriter pw, @NonNull DumpState dumpState)372 public void dumpLoadedVolumes(@NonNull PrintWriter pw, @NonNull DumpState dumpState) { 373 if (dumpState.onTitlePrinted()) { 374 pw.println(); 375 } 376 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); 377 ipw.println(); 378 ipw.println("Loaded volumes:"); 379 ipw.increaseIndent(); 380 synchronized (mLoadedVolumes) { 381 if (mLoadedVolumes.size() == 0) { 382 ipw.println("(none)"); 383 } else { 384 for (int i = 0; i < mLoadedVolumes.size(); i++) { 385 ipw.println(mLoadedVolumes.valueAt(i)); 386 } 387 } 388 } 389 ipw.decreaseIndent(); 390 } 391 } 392