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.PackageManager.UNINSTALL_REASON_UNKNOWN;
20 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
21 import static android.os.incremental.IncrementalManager.isIncrementalPath;
22 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
23 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
24 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
25 
26 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
27 import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
28 import static com.android.server.pm.PackageManagerService.RANDOM_DIR_PREFIX;
29 import static com.android.server.pm.PackageManagerService.TAG;
30 
31 import android.annotation.NonNull;
32 import android.annotation.Nullable;
33 import android.content.pm.PackageManager;
34 import android.content.pm.parsing.ApkLiteParseUtils;
35 import android.content.pm.parsing.PackageLite;
36 import android.content.pm.parsing.result.ParseResult;
37 import android.content.pm.parsing.result.ParseTypeImpl;
38 import android.os.Environment;
39 import android.os.Trace;
40 import android.os.UserHandle;
41 import android.os.incremental.IncrementalManager;
42 import android.util.Log;
43 import android.util.Slog;
44 import android.util.SparseBooleanArray;
45 
46 import com.android.internal.annotations.GuardedBy;
47 import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
48 import com.android.internal.pm.parsing.pkg.PackageImpl;
49 import com.android.internal.pm.pkg.component.ParsedInstrumentation;
50 import com.android.internal.util.ArrayUtils;
51 import com.android.server.pm.parsing.PackageCacher;
52 import com.android.server.pm.permission.PermissionManagerServiceInternal;
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.util.Collections;
58 import java.util.List;
59 
60 /**
61  * Removes a package from internal data structures, deletes it data directories if requested,
62  * and clears its app profiles
63  */
64 final class RemovePackageHelper {
65     private final PackageManagerService mPm;
66     private final IncrementalManager mIncrementalManager;
67     private final Installer mInstaller;
68     private final PermissionManagerServiceInternal mPermissionManager;
69     private final SharedLibrariesImpl mSharedLibraries;
70     private final AppDataHelper mAppDataHelper;
71     private final BroadcastHelper mBroadcastHelper;
72 
73     // TODO(b/198166813): remove PMS dependency
RemovePackageHelper(PackageManagerService pm, AppDataHelper appDataHelper, BroadcastHelper broadcastHelper)74     RemovePackageHelper(PackageManagerService pm, AppDataHelper appDataHelper,
75                         BroadcastHelper broadcastHelper) {
76         mPm = pm;
77         mIncrementalManager = mPm.mInjector.getIncrementalManager();
78         mInstaller = mPm.mInjector.getInstaller();
79         mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
80         mSharedLibraries = mPm.mInjector.getSharedLibrariesImpl();
81         mAppDataHelper = appDataHelper;
82         mBroadcastHelper = broadcastHelper;
83     }
84 
removeCodePath(File codePath)85     public void removeCodePath(File codePath) {
86         try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) {
87             removeCodePathLI(codePath);
88         }
89     }
90 
91     @GuardedBy("mPm.mInstallLock")
removeCodePathLI(File codePath)92     private void removeCodePathLI(File codePath) {
93         if (codePath == null || !codePath.exists()) {
94             return;
95         }
96         if (codePath.isDirectory()) {
97             final File codePathParent = codePath.getParentFile();
98             final boolean needRemoveParent = codePathParent.getName().startsWith(RANDOM_DIR_PREFIX);
99             try {
100                 final boolean isIncremental = (mIncrementalManager != null && isIncrementalPath(
101                         codePath.getAbsolutePath()));
102                 if (isIncremental) {
103                     if (needRemoveParent) {
104                         mIncrementalManager.rmPackageDir(codePathParent);
105                     } else {
106                         mIncrementalManager.rmPackageDir(codePath);
107                     }
108                 }
109 
110                 final String packageName = codePath.getName();
111                 mInstaller.rmPackageDir(packageName, codePath.getAbsolutePath());
112                 if (needRemoveParent) {
113                     mInstaller.rmPackageDir(packageName, codePathParent.getAbsolutePath());
114                     removeCachedResult(codePathParent);
115                 }
116             } catch (Installer.InstallerException e) {
117                 Slog.w(TAG, "Failed to remove code path", e);
118             }
119         } else {
120             codePath.delete();
121         }
122     }
123 
removeCachedResult(@onNull File codePath)124     private void removeCachedResult(@NonNull File codePath) {
125         if (mPm.getCacheDir() == null) {
126             return;
127         }
128 
129         final PackageCacher cacher = new PackageCacher(mPm.getCacheDir());
130         // Find and delete the cached result belong to the given codePath.
131         cacher.cleanCachedResult(codePath);
132     }
133 
134     // Used for system apps only
removePackage(AndroidPackage pkg, boolean chatty)135     public void removePackage(AndroidPackage pkg, boolean chatty) {
136         try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) {
137             removePackageLI(pkg, chatty);
138         }
139     }
140 
141     @GuardedBy("mPm.mInstallLock")
removePackageLI(AndroidPackage pkg, boolean chatty)142     private void removePackageLI(AndroidPackage pkg, boolean chatty) {
143         // Remove the parent package setting
144         PackageStateInternal ps = mPm.snapshotComputer()
145                 .getPackageStateInternal(pkg.getPackageName());
146         if (ps != null) {
147             removePackageLI(ps.getPackageName(), chatty);
148         } else if (DEBUG_REMOVE && chatty) {
149             Log.d(TAG, "Not removing package " + pkg.getPackageName() + "; mExtras == null");
150         }
151     }
152 
153     @GuardedBy("mPm.mInstallLock")
removePackageLI(String packageName, boolean chatty)154     private void removePackageLI(String packageName, boolean chatty) {
155         if (DEBUG_INSTALL) {
156             if (chatty) {
157                 Log.d(TAG, "Removing package " + packageName);
158             }
159         }
160 
161         // writer
162         synchronized (mPm.mLock) {
163             final AndroidPackage removedPackage = mPm.mPackages.remove(packageName);
164             if (removedPackage != null) {
165                 // TODO: Use PackageState for isSystem
166                 cleanPackageDataStructuresLILPw(removedPackage,
167                         AndroidPackageLegacyUtils.isSystem(removedPackage), chatty);
168             }
169         }
170     }
171 
172     @GuardedBy("mPm.mLock")
cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean isSystemApp, boolean chatty)173     private void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean isSystemApp,
174             boolean chatty) {
175         mPm.mComponentResolver.removeAllComponents(pkg, chatty);
176         mPermissionManager.onPackageRemoved(pkg);
177         mPm.getPackageProperty().removeAllProperties(pkg);
178 
179         final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations());
180         StringBuilder r = null;
181         int i;
182         for (i = 0; i < instrumentationSize; i++) {
183             ParsedInstrumentation a = pkg.getInstrumentations().get(i);
184             mPm.getInstrumentation().remove(a.getComponentName());
185             if (DEBUG_REMOVE && chatty) {
186                 if (r == null) {
187                     r = new StringBuilder(256);
188                 } else {
189                     r.append(' ');
190                 }
191                 r.append(a.getName());
192             }
193         }
194         if (r != null) {
195             if (DEBUG_REMOVE) Log.d(TAG, "  Instrumentation: " + r);
196         }
197 
198         r = null;
199         if (isSystemApp) {
200             // Only system apps can hold shared libraries.
201             final int libraryNamesSize = pkg.getLibraryNames().size();
202             for (i = 0; i < libraryNamesSize; i++) {
203                 String name = pkg.getLibraryNames().get(i);
204                 if (mSharedLibraries.removeSharedLibrary(name, 0)) {
205                     if (DEBUG_REMOVE && chatty) {
206                         if (r == null) {
207                             r = new StringBuilder(256);
208                         } else {
209                             r.append(' ');
210                         }
211                         r.append(name);
212                     }
213                 }
214             }
215         }
216 
217         r = null;
218 
219         // Any package can hold SDK or static shared libraries.
220         if (pkg.getSdkLibraryName() != null) {
221             if (mSharedLibraries.removeSharedLibrary(
222                     pkg.getSdkLibraryName(), pkg.getSdkLibVersionMajor())) {
223                 if (DEBUG_REMOVE && chatty) {
224                     if (r == null) {
225                         r = new StringBuilder(256);
226                     } else {
227                         r.append(' ');
228                     }
229                     r.append(pkg.getSdkLibraryName());
230                 }
231             }
232         }
233         if (pkg.getStaticSharedLibraryName() != null) {
234             if (mSharedLibraries.removeSharedLibrary(pkg.getStaticSharedLibraryName(),
235                     pkg.getStaticSharedLibraryVersion())) {
236                 if (DEBUG_REMOVE && chatty) {
237                     if (r == null) {
238                         r = new StringBuilder(256);
239                     } else {
240                         r.append(' ');
241                     }
242                     r.append(pkg.getStaticSharedLibraryName());
243                 }
244             }
245         }
246 
247         if (r != null) {
248             if (DEBUG_REMOVE) Log.d(TAG, "  Libraries: " + r);
249         }
250     }
251 
252     /**
253      * This method clears the data and states stored in the system that are related to the
254      * package being deleted and the target user, including the data directory.
255      * If the DELETE_KEEP_DATA flag is set, everything is preserved except ART profiles.
256      * Make sure this flag is set for partially installed apps. If not it's meaningless to
257      * delete a partially installed application.
258      */
clearPackageStateForUserLIF(PackageSetting ps, int userId, int flags)259     public void clearPackageStateForUserLIF(PackageSetting ps, int userId, int flags) {
260         final String packageName = ps.getPackageName();
261         // Step 1: always destroy app profiles.
262         mAppDataHelper.destroyAppProfilesLIF(packageName);
263 
264         final AndroidPackage pkg;
265         final SharedUserSetting sus;
266         synchronized (mPm.mLock) {
267             pkg = mPm.mPackages.get(packageName);
268             sus = mPm.mSettings.getSharedUserSettingLPr(ps);
269         }
270 
271         final AndroidPackage resolvedPkg;
272         if (pkg != null) {
273             resolvedPkg = pkg;
274         } else {
275             // We don't have a parsed package when it lives on an ejected
276             // adopted storage device, so fake something together
277             resolvedPkg = PackageImpl.buildFakeForDeletion(packageName, ps.getVolumeUuid());
278         }
279 
280         int appDataDeletionFlags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL;
281         // Personal data is preserved if the DELETE_KEEP_DATA flag is on
282         if ((flags & PackageManager.DELETE_KEEP_DATA) != 0) {
283             if ((flags & PackageManager.DELETE_ARCHIVE) != 0) {
284                 mAppDataHelper.clearAppDataLIF(resolvedPkg, userId,
285                         appDataDeletionFlags | Installer.FLAG_CLEAR_CACHE_ONLY);
286                 mAppDataHelper.clearAppDataLIF(resolvedPkg, userId,
287                         appDataDeletionFlags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
288             }
289             return;
290         }
291 
292         // Step 2: destroy app data.
293         mAppDataHelper.destroyAppDataLIF(resolvedPkg, userId, appDataDeletionFlags);
294         if (userId != UserHandle.USER_ALL) {
295             ps.setCeDataInode(-1, userId);
296             ps.setDeDataInode(-1, userId);
297         }
298 
299         final PreferredActivityHelper preferredActivityHelper = new PreferredActivityHelper(mPm,
300                 mBroadcastHelper);
301         if (userId == UserHandle.USER_ALL) {
302             if (DEBUG_REMOVE) {
303                 Slog.d(TAG, "Clear package:" + packageName + " state for all users");
304             }
305             // Step 3: inform DomainVerificationManager.
306             mPm.mDomainVerificationManager.clearPackage(packageName);
307             synchronized (mPm.mLock) {
308                 // Step 3.1 (only for USER_ALL): notify KeySetManagerService.
309                 mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
310                 // Step 3.2 (only for USER_ALL): update installer ownership.
311                 mPm.mInjector.getUpdateOwnershipHelper().removeUpdateOwnerDenyList(packageName);
312                 // Step 3.3 (only for USER_ALL): update AppsFilter.
313                 final Computer snapshot = mPm.snapshotComputer();
314                 mPm.mAppsFilter.removePackage(snapshot,
315                         snapshot.getPackageStateInternal(packageName));
316                 // Step 4: clear perferred activities.
317                 final SparseBooleanArray changedUsers = new SparseBooleanArray();
318                 mPm.clearPackagePreferredActivitiesLPw(
319                         packageName, changedUsers, UserHandle.USER_ALL);
320                 mPm.mInjector.getBackgroundHandler().post(() -> {
321                     if (changedUsers.size() > 0) {
322                         preferredActivityHelper.updateDefaultHomeNotLocked(mPm.snapshotComputer(),
323                                 changedUsers);
324                         mBroadcastHelper.sendPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
325                     }
326                 });
327                 // Step 5: inform PermissionManager.
328                 // This has to be done after the removal from mSettings in removePackageDataLIF.
329             }
330         } else {
331             if (DEBUG_REMOVE) {
332                 Slog.d(TAG, "Clear package:" + packageName + " state for user:" + userId);
333             }
334             // Step 3: inform DomainVerificationManager.
335             mPm.mDomainVerificationManager.clearPackageForUser(packageName, userId);
336             // Step 4: clear perferred activities.
337             preferredActivityHelper.clearPackagePreferredActivities(packageName, userId);
338             // Step 5: inform PermissionManager.
339             List<AndroidPackage> sharedUserPkgs =
340                     sus != null ? sus.getPackages() : Collections.emptyList();
341             mPermissionManager.onPackageUninstalled(packageName, ps.getAppId(), ps, pkg,
342                     sharedUserPkgs, userId);
343         }
344 
345         // Step 6: detroy keystore data.
346         mPm.mInjector.getBackgroundHandler().post(() -> {
347             try {
348                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
349                         "clearKeystoreData:" + ps.getAppId() + " for user: " + userId);
350                 mAppDataHelper.clearKeystoreData(userId, ps.getAppId());
351             } finally {
352                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
353             }
354         });
355     }
356 
357     // Called to clean up disabled system packages
removePackageData(final PackageSetting deletedPs, @NonNull int[] allUserHandles)358     public void removePackageData(final PackageSetting deletedPs, @NonNull int[] allUserHandles) {
359         try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) {
360             removePackageDataLIF(deletedPs, UserHandle.USER_ALL, allUserHandles,
361                     new PackageRemovedInfo(), /* flags= */ 0, /* writeSettings= */ false);
362         }
363     }
364 
365     /**
366      * This method deletes the package from internal data structures such as mPackages / mSettings.
367      *
368      * @param targetUserId indicates the target user of the deletion. It equals to
369      *                     {@link UserHandle.USER_ALL} if the deletion was initiated for all users,
370      *                     otherwise it equals to the specific user id that the deletion was meant
371      *                     for.
372      */
373     @GuardedBy("mPm.mInstallLock")
removePackageDataLIF(final PackageSetting deletedPs, int targetUserId, @NonNull int[] allUserHandles, @NonNull PackageRemovedInfo outInfo, int flags, boolean writeSettings)374     public void removePackageDataLIF(final PackageSetting deletedPs, int targetUserId,
375             @NonNull int[] allUserHandles,
376             @NonNull PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
377         String packageName = deletedPs.getPackageName();
378         if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
379         final boolean shouldDeletePackageSetting =
380                 shouldDeletePackageSetting(deletedPs, targetUserId, allUserHandles, flags);
381         // Retrieve object to delete permissions for shared user later on
382         final AndroidPackage deletedPkg = deletedPs.getPkg();
383 
384         // Delete all the data and states related to this package.
385         clearPackageStateForUserLIF(deletedPs,
386                 shouldDeletePackageSetting ? UserHandle.USER_ALL : targetUserId, flags);
387 
388         // Delete from mPackages
389         removePackageLI(packageName, (flags & PackageManager.DELETE_CHATTY) != 0);
390         if (!deletedPs.isSystem()) {
391             // A non-system app's AndroidPackage object has been removed from the service.
392             // Explicitly nullify the corresponding app's PackageSetting's pkg object to
393             // prevent any future usage of it, in case the PackageSetting object will remain because
394             // of DELETE_KEEP_DATA.
395             deletedPs.setPkg(null);
396         }
397 
398         if (shouldDeletePackageSetting) {
399             // Delete from mSettings
400             final SparseBooleanArray changedUsers = new SparseBooleanArray();
401             synchronized (mPm.mLock) {
402                 outInfo.mIsAppIdRemoved = mPm.mSettings.removePackageAndAppIdLPw(packageName);
403                 if (!mPm.mSettings.isDisabledSystemPackageLPr(packageName)) {
404                     final SharedUserSetting sus = mPm.mSettings.getSharedUserSettingLPr(deletedPs);
405                     // If we don't have a disabled system package to reinstall, the package is
406                     // really gone and its permission state should be removed.
407                     final List<AndroidPackage> sharedUserPkgs =
408                             sus != null ? sus.getPackages() : Collections.emptyList();
409                     mPermissionManager.onPackageUninstalled(packageName, deletedPs.getAppId(),
410                             deletedPs, deletedPkg, sharedUserPkgs, UserHandle.USER_ALL);
411                     // After permissions are handled, check if the shared user can be migrated
412                     if (sus != null) {
413                         mPm.mSettings.checkAndConvertSharedUserSettingsLPw(sus);
414                     }
415                 }
416                 mPm.mSettings.removeRenamedPackageLPw(deletedPs.getRealName());
417             }
418         } else if (!deletedPs.isSystem() && !outInfo.mIsUpdate
419                 && outInfo.mRemovedUsers != null && !deletedPs.isExternalStorage()) {
420             // For non-system uninstalls with DELETE_KEEP_DATA, set the installed state to false
421             // for affected users. This does not apply to app updates where the old apk is replaced
422             // but the old data remains.
423             if (DEBUG_REMOVE) {
424                 Slog.d(TAG, "Updating installed state to false because of DELETE_KEEP_DATA");
425             }
426             final boolean isArchive = (flags & PackageManager.DELETE_ARCHIVE) != 0;
427             final long currentTimeMillis = System.currentTimeMillis();
428             for (int userId : outInfo.mRemovedUsers) {
429                 if (DEBUG_REMOVE) {
430                     final boolean wasInstalled = deletedPs.getInstalled(userId);
431                     Slog.d(TAG, "    user " + userId + ": " + wasInstalled + " => " + false);
432                 }
433                 deletedPs.setInstalled(/* installed= */ false, userId);
434             }
435         }
436 
437         // make sure to preserve per-user installed state if this removal was just
438         // a downgrade of a system app to the factory package
439         boolean installedStateChanged = false;
440         if (outInfo.mOrigUsers != null && deletedPs.isSystem()) {
441             if (DEBUG_REMOVE) {
442                 Slog.d(TAG, "Propagating install state across downgrade");
443             }
444             for (int userId : allUserHandles) {
445                 final boolean installed = ArrayUtils.contains(outInfo.mOrigUsers, userId);
446                 if (DEBUG_REMOVE) {
447                     Slog.d(TAG, "    user " + userId + " => " + installed);
448                 }
449                 if (installed != deletedPs.getInstalled(userId)) {
450                     installedStateChanged = true;
451                 }
452                 deletedPs.setInstalled(installed, userId);
453                 if (installed) {
454                     deletedPs.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
455                 }
456             }
457         }
458         synchronized (mPm.mLock) {
459             // can downgrade to reader
460             if (writeSettings) {
461                 // Save settings now
462                 mPm.writeSettingsLPrTEMP();
463             }
464             if (installedStateChanged) {
465                 mPm.mSettings.writeKernelMappingLPr(deletedPs);
466             }
467         }
468     }
469 
shouldDeletePackageSetting(PackageSetting deletedPs, int userId, int[] allUserHandles, int flags)470     private static boolean shouldDeletePackageSetting(PackageSetting deletedPs, int userId,
471                                                       int[] allUserHandles, int flags) {
472         if ((flags & PackageManager.DELETE_KEEP_DATA) != 0) {
473             return false;
474         }
475         if (userId == UserHandle.USER_ALL) {
476             // Deleting for ALL. Let's wipe the PackageSetting.
477             return true;
478         }
479         if (deletedPs.hasDataOnAnyOtherUser(allUserHandles, userId)) {
480             // We arrived here because we are uninstalling the package for a specified user, and the
481             // package isn't installed on any other user. Before we proceed to completely delete the
482             // PackageSetting from mSettings, let's first check if data exists on any other user.
483             // If so, do not wipe the PackageSetting.
484             return false;
485         }
486         return true;
487     }
488 
cleanUpResources(@ullable String packageName, @Nullable File codeFile, @Nullable String[] instructionSets)489     void cleanUpResources(@Nullable String packageName, @Nullable File codeFile,
490                           @Nullable String[] instructionSets) {
491         try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) {
492             cleanUpResourcesLI(codeFile, instructionSets);
493         }
494         if (packageName == null) {
495             return;
496         }
497         synchronized (mPm.mLock) {
498             PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
499             if (ps != null) {
500                 ps.removeOldPath(codeFile);
501             }
502         }
503     }
504 
505     // Need installer lock especially for dex file removal.
506     @GuardedBy("mPm.mInstallLock")
cleanUpResourcesLI(@ullable File codeFile, @Nullable String[] instructionSets)507     private void cleanUpResourcesLI(@Nullable File codeFile, @Nullable String[] instructionSets) {
508         // Try enumerating all code paths before deleting
509         List<String> allCodePaths = Collections.EMPTY_LIST;
510         if (codeFile != null && codeFile.exists()) {
511             final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
512             final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
513                     input.reset(), codeFile, /* flags */ 0);
514             if (result.isSuccess()) {
515                 // Ignore error; we tried our best
516                 allCodePaths = result.getResult().getAllApkPaths();
517             }
518         }
519 
520         removeCodePathLI(codeFile);
521 
522         // TODO(b/265813358): ART Service currently doesn't support deleting optimized artifacts
523         // relative to an arbitrary APK path. Skip this and rely on its file GC instead.
524     }
525 
cleanUpForMoveInstall(String volumeUuid, String packageName, String fromCodePath)526     void cleanUpForMoveInstall(String volumeUuid, String packageName, String fromCodePath) {
527         final String toPathName = new File(fromCodePath).getName();
528         final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid), toPathName);
529         Slog.d(TAG, "Cleaning up " + packageName + " on " + volumeUuid);
530         final int[] userIds = mPm.mUserManager.getUserIds();
531         try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) {
532             // Clean up both app data and code
533             // All package moves are frozen until finished
534 
535             // We purposefully exclude FLAG_STORAGE_EXTERNAL here, since
536             // this task was only focused on moving data on internal storage.
537             // We don't want ART profiles cleared, because they don't move,
538             // so we would be deleting the only copy (b/149200535).
539             final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE
540                     | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
541             for (int userId : userIds) {
542                 try {
543                     mPm.mInstaller.destroyAppData(volumeUuid, packageName, userId, flags,
544                             0);
545                 } catch (Installer.InstallerException e) {
546                     Slog.w(TAG, String.valueOf(e));
547                 }
548             }
549             removeCodePathLI(codeFile);
550         }
551     }
552 }
553