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.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
20 
21 import static com.android.server.pm.PackageManagerService.TAG;
22 import static com.android.server.pm.PackageManagerServiceUtils.getPackageManagerLocal;
23 import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
24 
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.annotation.UserIdInt;
28 import android.content.pm.PackageManager;
29 import android.os.CreateAppDataArgs;
30 import android.os.Environment;
31 import android.os.FileUtils;
32 import android.os.Process;
33 import android.os.Trace;
34 import android.os.UserHandle;
35 import android.os.storage.StorageManager;
36 import android.os.storage.StorageManagerInternal;
37 import android.os.storage.VolumeInfo;
38 import android.security.AndroidKeyStoreMaintenance;
39 import android.system.keystore2.Domain;
40 import android.text.TextUtils;
41 import android.util.Log;
42 import android.util.Slog;
43 import android.util.TimingsTraceLog;
44 
45 import com.android.internal.annotations.GuardedBy;
46 import com.android.internal.util.Preconditions;
47 import com.android.server.SystemServerInitThreadPool;
48 import com.android.server.pm.dex.ArtManagerService;
49 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
50 import com.android.server.pm.pkg.AndroidPackage;
51 import com.android.server.pm.pkg.PackageStateInternal;
52 import com.android.server.pm.pkg.PackageUserStateInternal;
53 import com.android.server.pm.pkg.SELinuxUtil;
54 
55 import dalvik.system.VMRuntime;
56 
57 import java.io.File;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.List;
61 import java.util.concurrent.CompletableFuture;
62 import java.util.concurrent.Future;
63 
64 /**
65  * Prepares app data for users
66  */
67 public class AppDataHelper {
68     private static final boolean DEBUG_APP_DATA = false;
69 
70     private final PackageManagerService mPm;
71     private final Installer mInstaller;
72     private final ArtManagerService mArtManagerService;
73     private final PackageManagerServiceInjector mInjector;
74 
75     // TODO(b/198166813): remove PMS dependency
AppDataHelper(PackageManagerService pm)76     AppDataHelper(PackageManagerService pm) {
77         mPm = pm;
78         mInjector = mPm.mInjector;
79         mInstaller = mInjector.getInstaller();
80         mArtManagerService = mInjector.getArtManagerService();
81     }
82 
83     /**
84      * Prepare app data for the given app just after it was installed or
85      * upgraded. This method carefully only touches users that it's installed
86      * for, and it forces a restorecon to handle any seinfo changes.
87      * <p>
88      * Verifies that directories exist and that ownership and labeling is
89      * correct for all installed apps. If there is an ownership mismatch, it
90      * will wipe and recreate the data.
91      * <p>
92      * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em>
93      */
94     @GuardedBy("mPm.mInstallLock")
prepareAppDataAfterInstallLIF(AndroidPackage pkg)95     public void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
96         final PackageSetting ps;
97         synchronized (mPm.mLock) {
98             ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
99         }
100 
101         prepareAppDataPostCommitLIF(ps, 0 /* previousAppId */, getInstalledUsersForPackage(ps));
102     }
103 
getInstalledUsersForPackage(PackageSetting ps)104     private int[] getInstalledUsersForPackage(PackageSetting ps) {
105         UserManagerInternal umInternal = mInjector.getUserManagerInternal();
106         var users = umInternal.getUsers(false /*excludeDying*/);
107         int[] userIds = new int[users.size()];
108         int userIdsCount = 0;
109         for (int i = 0, size = users.size(); i < size; ++i) {
110             int userId = users.get(i).id;
111             if (ps.getInstalled(userId)) {
112                 userIds[userIdsCount++] = userId;
113             }
114         }
115         return Arrays.copyOf(userIds, userIdsCount);
116     }
117 
118     /**
119      * For more details about data verification and previousAppId, check
120      * {@link #prepareAppData}
121      * @see #prepareAppDataAfterInstallLIF
122      */
123     @GuardedBy("mPm.mInstallLock")
prepareAppDataPostCommitLIF(PackageSetting ps, int previousAppId, int[] userIds)124     public void prepareAppDataPostCommitLIF(PackageSetting ps, int previousAppId, int[] userIds) {
125         synchronized (mPm.mLock) {
126             mPm.mSettings.writeKernelMappingLPr(ps);
127         }
128 
129         // TODO(b/211761016): should we still create the profile dirs?
130         if (ps.getPkg() != null && !shouldHaveAppStorage(ps.getPkg())) {
131             Slog.w(TAG, "Skipping preparing app data for " + ps.getPackageName());
132             return;
133         }
134 
135         Installer.Batch batch = new Installer.Batch();
136         UserManagerInternal umInternal = mInjector.getUserManagerInternal();
137         StorageManagerInternal smInternal = mInjector.getLocalService(
138                 StorageManagerInternal.class);
139         for (int userId : userIds) {
140             final int flags;
141             if (StorageManager.isCeStorageUnlocked(userId)
142                     && smInternal.isCeStoragePrepared(userId)) {
143                 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
144             } else if (umInternal.isUserRunning(userId)) {
145                 flags = StorageManager.FLAG_STORAGE_DE;
146             } else {
147                 continue;
148             }
149 
150             // TODO: when user data is locked, mark that we're still dirty
151             prepareAppData(batch, ps, previousAppId, userId, flags).thenRun(() -> {
152                 // Note: this code block is executed with the Installer lock
153                 // already held, since it's invoked as a side-effect of
154                 // executeBatchLI()
155                 if (umInternal.isUserUnlockingOrUnlocked(userId)) {
156                     // Prepare app data on external storage; currently this is used to
157                     // setup any OBB dirs that were created by the installer correctly.
158                     int uid = UserHandle.getUid(userId, ps.getAppId());
159                     smInternal.prepareAppDataAfterInstall(ps.getPackageName(), uid);
160                 }
161             });
162         }
163         executeBatchLI(batch);
164     }
165 
executeBatchLI(@onNull Installer.Batch batch)166     private void executeBatchLI(@NonNull Installer.Batch batch) {
167         try {
168             batch.execute(mInstaller);
169         } catch (Installer.InstallerException e) {
170             Slog.w(TAG, "Failed to execute pending operations", e);
171         }
172     }
173 
prepareAppDataAndMigrate(@onNull Installer.Batch batch, @NonNull AndroidPackage pkg, @UserIdInt int userId, @StorageManager.StorageFlags int flags, boolean maybeMigrateAppData)174     private void prepareAppDataAndMigrate(@NonNull Installer.Batch batch,
175             @NonNull AndroidPackage pkg, @UserIdInt int userId,
176             @StorageManager.StorageFlags int flags, boolean maybeMigrateAppData) {
177         if (pkg == null) {
178             Slog.wtf(TAG, "Package was null!", new Throwable());
179             return;
180         }
181         if (!shouldHaveAppStorage(pkg)) {
182             Slog.w(TAG, "Skipping preparing app data for " + pkg.getPackageName());
183             return;
184         }
185         final PackageSetting ps;
186         synchronized (mPm.mLock) {
187             ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
188         }
189         prepareAppData(batch, ps, Process.INVALID_UID, userId, flags).thenRun(() -> {
190             // Note: this code block is executed with the Installer lock
191             // already held, since it's invoked as a side-effect of
192             // executeBatchLI()
193             if (maybeMigrateAppData && maybeMigrateAppDataLIF(ps, userId)) {
194                 // We may have just shuffled around app data directories, so
195                 // prepare them one more time
196                 final Installer.Batch batchInner = new Installer.Batch();
197                 prepareAppData(batchInner, ps, Process.INVALID_UID, userId, flags);
198                 executeBatchLI(batchInner);
199             }
200         });
201     }
202 
203     /**
204      * Prepare app data for the given app.
205      * <p>
206      * Verifies that directories exist and that ownership and labeling is
207      * correct for all installed apps. If there is an ownership mismatch:
208      * <ul>
209      * <li>If previousAppId < 0, app data will be migrated to the new app ID
210      * <li>If previousAppId == 0, no migration will happen and data will be wiped and recreated
211      * <li>If previousAppId > 0, app data owned by previousAppId will be migrated to the new app ID
212      * </ul>
213      */
prepareAppData(@onNull Installer.Batch batch, @NonNull PackageSetting ps, int previousAppId, int userId, int flags)214     private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch,
215             @NonNull PackageSetting ps, int previousAppId, int userId, int flags) {
216         final String packageName = ps.getPackageName();
217 
218         if (DEBUG_APP_DATA) {
219             Slog.v(TAG, "prepareAppData for " + packageName + " u" + userId + " 0x"
220                     + Integer.toHexString(flags));
221         }
222 
223         final String seInfoUser;
224         synchronized (mPm.mLock) {
225             seInfoUser = SELinuxUtil.getSeinfoUser(ps.readUserState(userId));
226         }
227 
228         final AndroidPackage pkg = ps.getPkg();
229         final String volumeUuid = ps.getVolumeUuid();
230         final int appId = ps.getAppId();
231 
232         String pkgSeInfo = ps.getSeInfo();
233         Preconditions.checkNotNull(pkgSeInfo);
234 
235         final String seInfo = pkgSeInfo + seInfoUser;
236         final int targetSdkVersion = ps.getTargetSdkVersion();
237         final boolean usesSdk = ps.getUsesSdkLibraries().length > 0;
238         final CreateAppDataArgs args = Installer.buildCreateAppDataArgs(volumeUuid, packageName,
239                 userId, flags, appId, seInfo, targetSdkVersion, usesSdk);
240         args.previousAppId = previousAppId;
241 
242         return batch.createAppData(args).whenComplete((createAppDataResult, e) -> {
243             // Note: this code block is executed with the Installer lock
244             // already held, since it's invoked as a side-effect of
245             // executeBatchLI()
246             if (e != null) {
247                 logCriticalInfo(Log.WARN, "Failed to create app data for " + packageName
248                         + ", but trying to recover: " + e);
249                 destroyAppDataLeafLIF(packageName, volumeUuid, userId, flags);
250                 try {
251                     createAppDataResult = mInstaller.createAppData(args);
252                     logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
253                 } catch (Installer.InstallerException e2) {
254                     logCriticalInfo(Log.DEBUG, "Recovery failed!");
255                 }
256             }
257 
258             final long ceDataInode = createAppDataResult.ceDataInode;
259             final long deDataInode = createAppDataResult.deDataInode;
260 
261             if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
262                 synchronized (mPm.mLock) {
263                     ps.setCeDataInode(ceDataInode, userId);
264                 }
265             }
266             if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && deDataInode != -1) {
267                 synchronized (mPm.mLock) {
268                     ps.setDeDataInode(deDataInode, userId);
269                 }
270             }
271 
272             if (pkg != null) {
273                 prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
274             }
275         });
276     }
277 
278     public void prepareAppDataContentsLIF(AndroidPackage pkg,
279             @Nullable PackageStateInternal pkgSetting, int userId, int flags) {
280         if (pkg == null) {
281             Slog.wtf(TAG, "Package was null!", new Throwable());
282             return;
283         }
284         prepareAppDataContentsLeafLIF(pkg, pkgSetting, userId, flags);
285     }
286 
287     private void prepareAppDataContentsLeafLIF(AndroidPackage pkg,
288             @Nullable PackageStateInternal pkgSetting, int userId, int flags) {
289         final String volumeUuid = pkg.getVolumeUuid();
290         final String packageName = pkg.getPackageName();
291 
292         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
293             // Create a native library symlink only if we have native libraries
294             // and if the native libraries are 32 bit libraries. We do not provide
295             // this symlink for 64 bit libraries.
296             String primaryCpuAbi = pkgSetting == null
297                     ? AndroidPackageUtils.getRawPrimaryCpuAbi(pkg) : pkgSetting.getPrimaryCpuAbi();
298             if (primaryCpuAbi != null && !VMRuntime.is64BitAbi(primaryCpuAbi)) {
299                 final String nativeLibPath = pkg.getNativeLibraryDir();
300                 if (!(new File(nativeLibPath).exists())) {
301                     return;
302                 }
303                 try {
304                     mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName,
305                             nativeLibPath, userId);
306                 } catch (Installer.InstallerException e) {
307                     Slog.e(TAG, "Failed to link native for " + packageName + ": " + e);
308                 }
309             }
310         }
311     }
312 
313     /**
314      * For system apps on non-FBE devices, this method migrates any existing
315      * CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag
316      * requested by the app.
317      */
318     private boolean maybeMigrateAppDataLIF(@NonNull PackageSetting ps, @UserIdInt int userId) {
319         if (ps.isSystem() && !StorageManager.isFileEncrypted()
320                 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
321             final int storageTarget = ps.isDefaultToDeviceProtectedStorage()
322                     ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
323             try {
324                 mInstaller.migrateAppData(ps.getVolumeUuid(), ps.getPackageName(), userId,
325                         storageTarget);
326             } catch (Installer.InstallerException e) {
327                 logCriticalInfo(Log.WARN,
328                         "Failed to migrate " + ps.getPackageName() + ": " + e.getMessage());
329             }
330             return true;
331         } else {
332             return false;
333         }
334     }
335 
336     /**
337      * Reconcile all app data for the given user.
338      * <p>
339      * Verifies that directories exist and that ownership and labeling is
340      * correct for all installed apps on all mounted volumes.
341      */
342     @NonNull
343     public void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags,
344             boolean migrateAppsData) {
345         final StorageManager storage = mInjector.getSystemService(StorageManager.class);
346         for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
347             final String volumeUuid = vol.getFsUuid();
348             try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) {
349                 reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppsData);
350             }
351         }
352     }
353 
354     @GuardedBy("mPm.mInstallLock")
355     void reconcileAppsDataLI(String volumeUuid, int userId, @StorageManager.StorageFlags int flags,
356             boolean migrateAppData) {
357         reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppData, false /* onlyCoreApps */);
358     }
359 
360     /**
361      * Reconcile all app data on given mounted volume.
362      * <p>
363      * Destroys app data that isn't expected, either due to uninstallation or
364      * reinstallation on another volume.
365      * <p>
366      * Verifies that directories exist and that ownership and labeling is
367      * correct for all installed apps.
368      *
369      * @return list of skipped non-core packages (if {@code onlyCoreApps} is true)
370      */
371     @GuardedBy("mPm.mInstallLock")
372     private List<String> reconcileAppsDataLI(String volumeUuid, int userId,
373             @StorageManager.StorageFlags int flags, boolean migrateAppData, boolean onlyCoreApps) {
374         Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
375                 + Integer.toHexString(flags) + " migrateAppData=" + migrateAppData);
376         List<String> result = onlyCoreApps ? new ArrayList<>() : null;
377 
378         try {
379             mInstaller.cleanupInvalidPackageDirs(volumeUuid, userId, flags);
380         } catch (Installer.InstallerException e) {
381             logCriticalInfo(Log.WARN, "Failed to cleanup deleted dirs: " + e);
382         }
383 
384         final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
385         final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
386 
387         final Computer snapshot = mPm.snapshotComputer();
388         // First look for stale data that doesn't belong, and check if things
389         // have changed since we did our last restorecon
390         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
391             if (StorageManager.isFileEncrypted() && !StorageManager.isCeStorageUnlocked(userId)) {
392                 throw new RuntimeException(
393                         "Yikes, someone asked us to reconcile CE storage while " + userId
394                                 + " was still locked; this would have caused massive data loss!");
395             }
396 
397             final File[] files = FileUtils.listFilesOrEmpty(ceDir);
398             for (File file : files) {
399                 final String packageName = file.getName();
400                 try {
401                     assertPackageStorageValid(snapshot, volumeUuid, packageName, userId);
402                 } catch (PackageManagerException e) {
403                     logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
404                     try {
405                         mInstaller.destroyAppData(volumeUuid, packageName, userId,
406                                 StorageManager.FLAG_STORAGE_CE, 0);
407                     } catch (Installer.InstallerException e2) {
408                         logCriticalInfo(Log.WARN, "Failed to destroy: " + e2);
409                     }
410                 }
411             }
412         }
413         if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
414             final File[] files = FileUtils.listFilesOrEmpty(deDir);
415             for (File file : files) {
416                 final String packageName = file.getName();
417                 try {
418                     assertPackageStorageValid(snapshot, volumeUuid, packageName, userId);
419                 } catch (PackageManagerException e) {
420                     logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
421                     try {
422                         mInstaller.destroyAppData(volumeUuid, packageName, userId,
423                                 StorageManager.FLAG_STORAGE_DE, 0);
424                     } catch (Installer.InstallerException e2) {
425                         logCriticalInfo(Log.WARN, "Failed to destroy: " + e2);
426                     }
427                 }
428             }
429         }
430 
431         // Ensure that data directories are ready to roll for all packages
432         // installed for this volume and user
433         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "prepareAppDataAndMigrate");
434         Installer.Batch batch = new Installer.Batch();
435         List<? extends PackageStateInternal> packages = snapshot.getVolumePackages(volumeUuid);
436         int preparedCount = 0;
437         for (PackageStateInternal ps : packages) {
438             final String packageName = ps.getPackageName();
439             if (ps.getPkg() == null) {
440                 Slog.w(TAG, "Odd, missing scanned package " + packageName);
441                 // TODO: might be due to legacy ASEC apps; we should circle back
442                 // and reconcile again once they're scanned
443                 continue;
444             }
445             // Skip non-core apps if requested
446             if (onlyCoreApps && !ps.getPkg().isCoreApp()) {
447                 result.add(packageName);
448                 continue;
449             }
450 
451             if (ps.getUserStateOrDefault(userId).isInstalled()) {
452                 prepareAppDataAndMigrate(batch, ps.getPkg(), userId, flags, migrateAppData);
453                 preparedCount++;
454             }
455         }
456         executeBatchLI(batch);
457         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
458 
459         Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages");
460         return result;
461     }
462 
463     /**
464      * Asserts that storage path is valid by checking that {@code packageName} is present,
465      * installed for the given {@code userId} and can have app data.
466      */
467     private void assertPackageStorageValid(@NonNull Computer snapshot, String volumeUuid,
468             String packageName, int userId) throws PackageManagerException {
469         final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
470         if (packageState == null) {
471             throw PackageManagerException.ofInternalError("Package " + packageName + " is unknown",
472                     PackageManagerException.INTERNAL_ERROR_STORAGE_INVALID_PACKAGE_UNKNOWN);
473         }
474         if (!TextUtils.equals(volumeUuid, packageState.getVolumeUuid())) {
475             throw PackageManagerException.ofInternalError(
476                     "Package " + packageName + " found on unknown volume " + volumeUuid
477                             + "; expected volume " + packageState.getVolumeUuid(),
478                     PackageManagerException.INTERNAL_ERROR_STORAGE_INVALID_VOLUME_UNKNOWN);
479         }
480         final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId);
481         if (!userState.isInstalled() && !userState.dataExists()) {
482             throw PackageManagerException.ofInternalError(
483                     "Package " + packageName + " not installed for user " + userId
484                             + " or was deleted without DELETE_KEEP_DATA",
485                     PackageManagerException.INTERNAL_ERROR_STORAGE_INVALID_NOT_INSTALLED_FOR_USER);
486         }
487         if (packageState.getPkg() != null
488                 && !shouldHaveAppStorage(packageState.getPkg())) {
489             throw PackageManagerException.ofInternalError(
490                     "Package " + packageName + " shouldn't have storage",
491                     PackageManagerException.INTERNAL_ERROR_STORAGE_INVALID_SHOULD_NOT_HAVE_STORAGE);
492         }
493     }
494 
495     /**
496      * Prepare storage for system user really early during boot,
497      * since core system apps like SettingsProvider and SystemUI
498      * can't wait for user to start
499      */
500     public Future<?> fixAppsDataOnBoot() {
501         final @StorageManager.StorageFlags int storageFlags;
502         if (StorageManager.isFileEncrypted()) {
503             storageFlags = StorageManager.FLAG_STORAGE_DE;
504         } else {
505             storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
506         }
507         final List<String> deferPackages;
508         try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) {
509             deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,
510                     UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
511                     true /* onlyCoreApps */);
512         }
513         Future<?> prepareAppDataFuture = SystemServerInitThreadPool.submit(() -> {
514             TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync",
515                     Trace.TRACE_TAG_PACKAGE_MANAGER);
516             traceLog.traceBegin("AppDataFixup");
517             try {
518                 mInstaller.fixupAppData(StorageManager.UUID_PRIVATE_INTERNAL,
519                         StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
520             } catch (Installer.InstallerException e) {
521                 Slog.w(TAG, "Trouble fixing GIDs", e);
522             }
523             traceLog.traceEnd();
524 
525             traceLog.traceBegin("AppDataPrepare");
526             if (deferPackages == null || deferPackages.isEmpty()) {
527                 return;
528             }
529             int count = 0;
530             final Installer.Batch batch = new Installer.Batch();
531             for (String pkgName : deferPackages) {
532                 final Computer snapshot = mPm.snapshotComputer();
533                 final PackageStateInternal packageStateInternal = snapshot.getPackageStateInternal(
534                         pkgName);
535                 if (packageStateInternal != null
536                         && packageStateInternal.getUserStateOrDefault(
537                                 UserHandle.USER_SYSTEM).isInstalled()) {
538                     AndroidPackage pkg = packageStateInternal.getPkg();
539                     prepareAppDataAndMigrate(batch, pkg,
540                             UserHandle.USER_SYSTEM, storageFlags, true /* maybeMigrateAppData */);
541                     count++;
542                 }
543             }
544             try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) {
545                 executeBatchLI(batch);
546             }
547             traceLog.traceEnd();
548             Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages");
549         }, "prepareAppData");
550         return prepareAppDataFuture;
551     }
552 
553     void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
554         if (pkg == null) {
555             return;
556         }
557         clearAppDataLeafLIF(pkg.getPackageName(), pkg.getVolumeUuid(), userId, flags);
558 
559         if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
560             clearAppProfilesLIF(pkg);
561         }
562     }
563 
564     void clearAppDataLeafLIF(String packageName, String volumeUuid, int userId, int flags) {
565         final Computer snapshot = mPm.snapshotComputer();
566         final PackageStateInternal packageStateInternal =
567                 snapshot.getPackageStateInternal(packageName);
568         for (int realUserId : mPm.resolveUserIds(userId)) {
569             final long ceDataInode = (packageStateInternal != null)
570                     ? packageStateInternal.getUserStateOrDefault(realUserId).getCeDataInode() : 0;
571             try {
572                 mInstaller.clearAppData(volumeUuid, packageName, realUserId,
573                         flags, ceDataInode);
574             } catch (Installer.InstallerException e) {
575                 Slog.w(TAG, String.valueOf(e));
576             }
577         }
578     }
579 
580     void clearAppProfilesLIF(AndroidPackage pkg) {
581         if (pkg == null) {
582             Slog.wtf(TAG, "Package was null!", new Throwable());
583             return;
584         }
585         destroyAppProfilesLIF(pkg.getPackageName());
586     }
587 
588     public void destroyAppDataLIF(AndroidPackage pkg, int userId, int flags) {
589         if (pkg == null) {
590             Slog.wtf(TAG, "Package was null!", new Throwable());
591             return;
592         }
593         destroyAppDataLeafLIF(pkg.getPackageName(), pkg.getVolumeUuid(), userId, flags);
594     }
595 
596     private void destroyAppDataLeafLIF(
597             String packageName, String volumeUuid, int userId, int flags) {
598         final Computer snapshot = mPm.snapshotComputer();
599         final PackageStateInternal packageStateInternal =
600                 snapshot.getPackageStateInternal(packageName);
601         for (int realUserId : mPm.resolveUserIds(userId)) {
602             final long ceDataInode = (packageStateInternal != null)
603                     ? packageStateInternal.getUserStateOrDefault(realUserId).getCeDataInode() : 0;
604             try {
605                 mInstaller.destroyAppData(volumeUuid, packageName, realUserId,
606                         flags, ceDataInode);
607             } catch (Installer.InstallerException e) {
608                 Slog.w(TAG, String.valueOf(e));
609             }
610             mPm.getDexManager().notifyPackageDataDestroyed(packageName, userId);
611             mPm.getDynamicCodeLogger().notifyPackageDataDestroyed(packageName, userId);
612         }
613     }
614 
615     /**
616      * Destroy ART app profiles for the package.
617      */
618     void destroyAppProfilesLIF(String packageName) {
619         if (!DexOptHelper.artManagerLocalIsInitialized()) {
620             // This function may get called while PackageManagerService is constructed (via e.g.
621             // InitAppsHelper.initSystemApps), and ART Service hasn't yet been started then (it
622             // requires a registered PackageManagerLocal instance). We can skip clearing any stale
623             // app profiles in this case, because ART Service and the runtime will ignore stale or
624             // otherwise invalid ref and cur profiles.
625             return;
626         }
627 
628         try (PackageManagerLocal.FilteredSnapshot snapshot =
629                         getPackageManagerLocal().withFilteredSnapshot()) {
630             try {
631                 DexOptHelper.getArtManagerLocal().clearAppProfiles(snapshot, packageName);
632             } catch (IllegalArgumentException e) {
633                 // Package isn't found, but that should only happen due to race.
634                 Slog.w(TAG, e);
635             }
636         }
637     }
638 
639     /**
640      * Returns {@code true} if app's internal storage should be created for this {@code pkg}.
641      */
642     private boolean shouldHaveAppStorage(AndroidPackage pkg) {
643         PackageManager.Property noAppDataProp =
644                 pkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
645         return (noAppDataProp == null || !noAppDataProp.getBoolean()) && pkg.getUid() >= 0;
646     }
647 
648     /**
649      * Remove entries from the keystore daemon. Will only remove if the {@code appId} is valid.
650      */
651     public void clearKeystoreData(int userId, int appId) {
652         if (appId < 0) {
653             return;
654         }
655 
656         for (int realUserId : mPm.resolveUserIds(userId)) {
657             AndroidKeyStoreMaintenance.clearNamespace(
658                     Domain.APP, UserHandle.getUid(realUserId, appId));
659         }
660     }
661 }
662