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