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