Loading services/core/java/com/android/server/pm/Installer.java +129 −21 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.PackageStats; import android.os.Build; import android.os.CreateAppDataArgs; import android.os.CreateAppDataResult; import android.os.IBinder; import android.os.IBinder.DeathRecipient; import android.os.IInstalld; Loading @@ -39,7 +41,10 @@ import dalvik.system.BlockGuard; import dalvik.system.VMRuntime; import java.io.FileDescriptor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; public class Installer extends SystemService { private static final String TAG = "Installer"; Loading Loading @@ -176,39 +181,142 @@ public class Installer extends SystemService { } } private static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion) { final CreateAppDataArgs args = new CreateAppDataArgs(); args.uuid = uuid; args.packageName = packageName; args.userId = userId; args.flags = flags; args.appId = appId; args.seInfo = seInfo; args.targetSdkVersion = targetSdkVersion; return args; } private static CreateAppDataResult buildPlaceholderCreateAppDataResult() { final CreateAppDataResult result = new CreateAppDataResult(); result.ceDataInode = -1; result.exceptionCode = 0; result.exceptionMessage = null; return result; } /** * @deprecated callers are encouraged to migrate to using {@link Batch} to * more efficiently handle operations in bulk. */ @Deprecated public long createAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion) throws InstallerException { if (!checkBeforeRemote()) return -1; final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags, appId, seInfo, targetSdkVersion); final CreateAppDataResult result = createAppData(args); if (result.exceptionCode == 0) { return result.ceDataInode; } else { throw new InstallerException(result.exceptionMessage); } } public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args) throws InstallerException { if (!checkBeforeRemote()) { return buildPlaceholderCreateAppDataResult(); } try { return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo, targetSdkVersion); return mInstalld.createAppData(args); } catch (Exception e) { throw InstallerException.from(e); } } /** * Batched version of createAppData for use with multiple packages. */ public void createAppDataBatched(String[] uuids, String[] packageNames, int userId, int flags, int[] appIds, String[] seInfos, int[] targetSdkVersions) throws InstallerException { if (!checkBeforeRemote()) return; final int batchSize = 256; for (int i = 0; i < uuids.length; i += batchSize) { int to = i + batchSize; if (to > uuids.length) { to = uuids.length; public @NonNull CreateAppDataResult[] createAppDataBatched(@NonNull CreateAppDataArgs[] args) throws InstallerException { if (!checkBeforeRemote()) { final CreateAppDataResult[] results = new CreateAppDataResult[args.length]; Arrays.fill(results, buildPlaceholderCreateAppDataResult()); return results; } try { mInstalld.createAppDataBatched(Arrays.copyOfRange(uuids, i, to), Arrays.copyOfRange(packageNames, i, to), userId, flags, Arrays.copyOfRange(appIds, i, to), Arrays.copyOfRange(seInfos, i, to), Arrays.copyOfRange(targetSdkVersions, i, to)); return mInstalld.createAppDataBatched(args); } catch (Exception e) { throw InstallerException.from(e); } } /** * Class that collects multiple {@code installd} operations together in an * attempt to more efficiently execute them in bulk. * <p> * Instead of returning results immediately, {@link CompletableFuture} * instances are returned which can be used to chain follow-up work for each * request. * <p> * The creator of this object <em>must</em> invoke {@link #execute()} * exactly once to begin execution of all pending operations. Once execution * has been kicked off, no additional events can be enqueued into this * instance, but multiple instances can safely exist in parallel. */ public static class Batch { private static final int CREATE_APP_DATA_BATCH_SIZE = 256; private boolean mExecuted; private final List<CreateAppDataArgs> mArgs = new ArrayList<>(); private final List<CompletableFuture<Long>> mFutures = new ArrayList<>(); /** * Enqueue the given {@code installd} operation to be executed in the * future when {@link #execute(Installer)} is invoked. * <p> * Callers of this method are not required to hold a monitor lock on an * {@link Installer} object. */ public synchronized @NonNull CompletableFuture<Long> createAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion) { if (mExecuted) throw new IllegalStateException(); final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags, appId, seInfo, targetSdkVersion); final CompletableFuture<Long> future = new CompletableFuture<>(); mArgs.add(args); mFutures.add(future); return future; } /** * Execute all pending {@code installd} operations that have been * collected by this batch in a blocking fashion. * <p> * Callers of this method <em>must</em> hold a monitor lock on the given * {@link Installer} object. */ public synchronized void execute(@NonNull Installer installer) throws InstallerException { if (mExecuted) throw new IllegalStateException(); mExecuted = true; final int size = mArgs.size(); for (int i = 0; i < size; i += CREATE_APP_DATA_BATCH_SIZE) { final CreateAppDataArgs[] args = new CreateAppDataArgs[Math.min(size - i, CREATE_APP_DATA_BATCH_SIZE)]; for (int j = 0; j < args.length; j++) { args[j] = mArgs.get(i + j); } final CreateAppDataResult[] results = installer.createAppDataBatched(args); for (int j = 0; j < args.length; j++) { final CreateAppDataResult result = results[j]; final CompletableFuture<Long> future = mFutures.get(i + j); if (result.exceptionCode == 0) { future.complete(result.ceDataInode); } else { future.completeExceptionally( new InstallerException(result.exceptionMessage)); } } } } } public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, Loading services/core/java/com/android/server/pm/PackageManagerService.java +112 −75 Original line number Diff line number Diff line Loading @@ -418,6 +418,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; Loading Loading @@ -3481,6 +3482,7 @@ public class PackageManagerService extends IPackageManager.Stub return; } int count = 0; final Installer.Batch batch = new Installer.Batch(); for (String pkgName : deferPackages) { AndroidPackage pkg = null; synchronized (mLock) { Loading @@ -3490,13 +3492,14 @@ public class PackageManagerService extends IPackageManager.Stub } } if (pkg != null) { synchronized (mInstallLock) { prepareAppDataAndMigrateLIF(pkg, UserHandle.USER_SYSTEM, storageFlags, prepareAppDataAndMigrate(batch, pkg, UserHandle.USER_SYSTEM, storageFlags, true /* maybeMigrateAppData */); } count++; } } synchronized (mInstallLock) { executeBatchLI(batch); } traceLog.traceEnd(); Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages"); }, "prepareAppData"); Loading Loading @@ -22743,6 +22746,14 @@ public class PackageManagerService extends IPackageManager.Stub } } private void executeBatchLI(@NonNull Installer.Batch batch) { try { batch.execute(mInstaller); } catch (InstallerException e) { Slog.w(TAG, "Failed to execute pending operations", e); } } /** * Examine all apps present on given mounted volume, and destroy apps that * aren't expected, either due to uninstallation or reinstallation on Loading Loading @@ -22882,6 +22893,8 @@ public class PackageManagerService extends IPackageManager.Stub // Ensure that data directories are ready to roll for all packages // installed for this volume and user Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "prepareAppDataAndMigrate"); Installer.Batch batch = new Installer.Batch(); final List<PackageSetting> packages; synchronized (mLock) { packages = mSettings.getVolumePackagesLPr(volumeUuid); Loading @@ -22902,10 +22915,12 @@ public class PackageManagerService extends IPackageManager.Stub } if (ps.getInstalled(userId)) { prepareAppDataAndMigrateLIF(ps.pkg, userId, flags, migrateAppData); prepareAppDataAndMigrate(batch, ps.pkg, userId, flags, migrateAppData); preparedCount++; } } executeBatchLI(batch); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages"); return result; Loading @@ -22930,6 +22945,7 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeKernelMappingLPr(ps); } Installer.Batch batch = new Installer.Batch(); UserManagerInternal umInternal = mInjector.getUserManagerInternal(); StorageManagerInternal smInternal = mInjector.getStorageManagerInternal(); for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) { Loading @@ -22944,16 +22960,20 @@ public class PackageManagerService extends IPackageManager.Stub if (ps.getInstalled(user.id)) { // TODO: when user data is locked, mark that we're still dirty prepareAppDataLIF(pkg, user.id, flags); prepareAppData(batch, pkg, user.id, flags).thenRun(() -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() if (umInternal.isUserUnlockingOrUnlocked(user.id)) { // Prepare app data on external storage; currently this is used to // setup any OBB dirs that were created by the installer correctly. int uid = UserHandle.getUid(user.id, UserHandle.getAppId(pkg.getUid())); smInternal.prepareAppDataAfterInstall(pkg.getPackageName(), uid); } }); } } executeBatchLI(batch); } /** Loading @@ -22964,26 +22984,33 @@ public class PackageManagerService extends IPackageManager.Stub * will try recovering system apps by wiping data; third-party app data is * left intact. */ private void prepareAppDataLIF(AndroidPackage pkg, int userId, int flags) { private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch, @Nullable AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; return CompletableFuture.completedFuture(null); } prepareAppDataLeafLIF(pkg, userId, flags); return prepareAppDataLeaf(batch, pkg, userId, flags); } private void prepareAppDataAndMigrateLIF(AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) { prepareAppDataLIF(pkg, userId, flags); private @NonNull CompletableFuture<?> prepareAppDataAndMigrate(@NonNull Installer.Batch batch, @NonNull AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) { return prepareAppData(batch, pkg, userId, flags).thenRun(() -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() if (maybeMigrateAppData && maybeMigrateAppDataLIF(pkg, userId)) { // We may have just shuffled around app data directories, so // prepare them one more time prepareAppDataLIF(pkg, userId, flags); final Installer.Batch batchInner = new Installer.Batch(); prepareAppData(batchInner, pkg, userId, flags); executeBatchLI(batchInner); } }); } private void prepareAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) { private @NonNull CompletableFuture<?> prepareAppDataLeaf(@NonNull Installer.Batch batch, @NonNull AndroidPackage pkg, int userId, int flags) { if (DEBUG_APP_DATA) { Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x" + Integer.toHexString(flags)); Loading @@ -23003,42 +23030,51 @@ public class PackageManagerService extends IPackageManager.Stub Preconditions.checkNotNull(pkgSeInfo); final String seInfo = pkgSeInfo + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : ""); long ceDataInode = -1; try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); } catch (InstallerException e) { if (pkg.isSystem()) { final int targetSdkVersion = pkg.getTargetSdkVersion(); return batch.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, targetSdkVersion).whenComplete((ceDataInode, e) -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() if ((e != null) && pkg.isSystem()) { logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName + ", but trying to recover: " + e); destroyAppDataLeafLIF(pkg, userId, flags); try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); logCriticalInfo(Log.DEBUG, "Recovery succeeded!"); } catch (InstallerException e2) { logCriticalInfo(Log.DEBUG, "Recovery failed!"); } } else { } else if (e != null) { Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e); } } // Prepare the application profiles only for upgrades and first boot (so that we don't // repeat the same operation at each boot). // We only have to cover the upgrade and first boot here because for app installs we // prepare the profiles before invoking dexopt (in installPackageLI). // Prepare the application profiles only for upgrades and // first boot (so that we don't repeat the same operation at // each boot). // // We only have to cover the upgrade and first boot here // because for app installs we prepare the profiles before // invoking dexopt (in installPackageLI). // // We also have to cover non system users because we do not call the usual install package // methods for them. // We also have to cover non system users because we do not // call the usual install package methods for them. // // NOTE: in order to speed up first boot time we only create the current profile and do not // update the content of the reference profile. A system image should already be configured // with the right profile keys and the profiles for the speed-profile prebuilds should // already be copied. That's done in #performDexOptUpgrade. // NOTE: in order to speed up first boot time we only create // the current profile and do not update the content of the // reference profile. A system image should already be // configured with the right profile keys and the profiles // for the speed-profile prebuilds should already be copied. // That's done in #performDexOptUpgrade. // // TODO(calin, mathieuc): We should use .dm files for prebuilds profiles instead of // manually copying them in #performDexOptUpgrade. When we do that we should have a more // granular check here and only update the existing profiles. // TODO(calin, mathieuc): We should use .dm files for // prebuilds profiles instead of manually copying them in // #performDexOptUpgrade. When we do that we should have a // more granular check here and only update the existing // profiles. if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) { mArtManagerService.prepareAppProfiles(pkg, userId, /* updateReferenceProfileContent= */ false); Loading @@ -23054,6 +23090,7 @@ public class PackageManagerService extends IPackageManager.Stub } prepareAppDataContentsLeafLIF(pkg, ps, userId, flags); }); } private void prepareAppDataContentsLIF(AndroidPackage pkg, @Nullable PackageSetting pkgSetting, services/core/java/com/android/server/pm/Settings.java +10 −24 Original line number Diff line number Diff line Loading @@ -102,6 +102,7 @@ import com.android.internal.util.XmlUtils; import com.android.permission.persistence.RuntimePermissionsPersistence; import com.android.permission.persistence.RuntimePermissionsState; import com.android.server.LocalServices; import com.android.server.pm.Installer.Batch; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; Loading Loading @@ -4148,24 +4149,12 @@ public final class Settings { final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", Trace.TRACE_TAG_PACKAGE_MANAGER); t.traceBegin("createNewUser-" + userHandle); String[] volumeUuids; String[] names; int[] appIds; String[] seinfos; int[] targetSdkVersions; int packagesCount; Installer.Batch batch = new Installer.Batch(); final boolean skipPackageWhitelist = userTypeInstallablePackages == null; synchronized (mLock) { Collection<PackageSetting> packages = mPackages.values(); packagesCount = packages.size(); volumeUuids = new String[packagesCount]; names = new String[packagesCount]; appIds = new int[packagesCount]; seinfos = new String[packagesCount]; targetSdkVersions = new int[packagesCount]; Iterator<PackageSetting> packagesIterator = packages.iterator(); for (int i = 0; i < packagesCount; i++) { PackageSetting ps = packagesIterator.next(); final int size = mPackages.size(); for (int i = 0; i < size; i++) { final PackageSetting ps = mPackages.valueAt(i); if (ps.pkg == null) { continue; } Loading @@ -4187,18 +4176,15 @@ public final class Settings { } // Need to create a data directory for all apps under this user. Accumulate all // required args and call the installer after mPackages lock has been released volumeUuids[i] = ps.volumeUuid; names[i] = ps.name; appIds[i] = ps.appId; seinfos[i] = AndroidPackageUtils.getSeInfo(ps.pkg, ps); targetSdkVersions[i] = ps.pkg.getTargetSdkVersion(); final String seInfo = AndroidPackageUtils.getSeInfo(ps.pkg, ps); batch.createAppData(ps.volumeUuid, ps.name, userHandle, StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE, ps.appId, seInfo, ps.pkg.getTargetSdkVersion()); } } t.traceBegin("createAppData"); final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE; try { installer.createAppDataBatched(volumeUuids, names, userHandle, flags, appIds, seinfos, targetSdkVersions); batch.execute(installer); } catch (InstallerException e) { Slog.w(TAG, "Failed to prepare app data", e); } Loading Loading
services/core/java/com/android/server/pm/Installer.java +129 −21 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.PackageStats; import android.os.Build; import android.os.CreateAppDataArgs; import android.os.CreateAppDataResult; import android.os.IBinder; import android.os.IBinder.DeathRecipient; import android.os.IInstalld; Loading @@ -39,7 +41,10 @@ import dalvik.system.BlockGuard; import dalvik.system.VMRuntime; import java.io.FileDescriptor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; public class Installer extends SystemService { private static final String TAG = "Installer"; Loading Loading @@ -176,39 +181,142 @@ public class Installer extends SystemService { } } private static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion) { final CreateAppDataArgs args = new CreateAppDataArgs(); args.uuid = uuid; args.packageName = packageName; args.userId = userId; args.flags = flags; args.appId = appId; args.seInfo = seInfo; args.targetSdkVersion = targetSdkVersion; return args; } private static CreateAppDataResult buildPlaceholderCreateAppDataResult() { final CreateAppDataResult result = new CreateAppDataResult(); result.ceDataInode = -1; result.exceptionCode = 0; result.exceptionMessage = null; return result; } /** * @deprecated callers are encouraged to migrate to using {@link Batch} to * more efficiently handle operations in bulk. */ @Deprecated public long createAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion) throws InstallerException { if (!checkBeforeRemote()) return -1; final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags, appId, seInfo, targetSdkVersion); final CreateAppDataResult result = createAppData(args); if (result.exceptionCode == 0) { return result.ceDataInode; } else { throw new InstallerException(result.exceptionMessage); } } public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args) throws InstallerException { if (!checkBeforeRemote()) { return buildPlaceholderCreateAppDataResult(); } try { return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo, targetSdkVersion); return mInstalld.createAppData(args); } catch (Exception e) { throw InstallerException.from(e); } } /** * Batched version of createAppData for use with multiple packages. */ public void createAppDataBatched(String[] uuids, String[] packageNames, int userId, int flags, int[] appIds, String[] seInfos, int[] targetSdkVersions) throws InstallerException { if (!checkBeforeRemote()) return; final int batchSize = 256; for (int i = 0; i < uuids.length; i += batchSize) { int to = i + batchSize; if (to > uuids.length) { to = uuids.length; public @NonNull CreateAppDataResult[] createAppDataBatched(@NonNull CreateAppDataArgs[] args) throws InstallerException { if (!checkBeforeRemote()) { final CreateAppDataResult[] results = new CreateAppDataResult[args.length]; Arrays.fill(results, buildPlaceholderCreateAppDataResult()); return results; } try { mInstalld.createAppDataBatched(Arrays.copyOfRange(uuids, i, to), Arrays.copyOfRange(packageNames, i, to), userId, flags, Arrays.copyOfRange(appIds, i, to), Arrays.copyOfRange(seInfos, i, to), Arrays.copyOfRange(targetSdkVersions, i, to)); return mInstalld.createAppDataBatched(args); } catch (Exception e) { throw InstallerException.from(e); } } /** * Class that collects multiple {@code installd} operations together in an * attempt to more efficiently execute them in bulk. * <p> * Instead of returning results immediately, {@link CompletableFuture} * instances are returned which can be used to chain follow-up work for each * request. * <p> * The creator of this object <em>must</em> invoke {@link #execute()} * exactly once to begin execution of all pending operations. Once execution * has been kicked off, no additional events can be enqueued into this * instance, but multiple instances can safely exist in parallel. */ public static class Batch { private static final int CREATE_APP_DATA_BATCH_SIZE = 256; private boolean mExecuted; private final List<CreateAppDataArgs> mArgs = new ArrayList<>(); private final List<CompletableFuture<Long>> mFutures = new ArrayList<>(); /** * Enqueue the given {@code installd} operation to be executed in the * future when {@link #execute(Installer)} is invoked. * <p> * Callers of this method are not required to hold a monitor lock on an * {@link Installer} object. */ public synchronized @NonNull CompletableFuture<Long> createAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion) { if (mExecuted) throw new IllegalStateException(); final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags, appId, seInfo, targetSdkVersion); final CompletableFuture<Long> future = new CompletableFuture<>(); mArgs.add(args); mFutures.add(future); return future; } /** * Execute all pending {@code installd} operations that have been * collected by this batch in a blocking fashion. * <p> * Callers of this method <em>must</em> hold a monitor lock on the given * {@link Installer} object. */ public synchronized void execute(@NonNull Installer installer) throws InstallerException { if (mExecuted) throw new IllegalStateException(); mExecuted = true; final int size = mArgs.size(); for (int i = 0; i < size; i += CREATE_APP_DATA_BATCH_SIZE) { final CreateAppDataArgs[] args = new CreateAppDataArgs[Math.min(size - i, CREATE_APP_DATA_BATCH_SIZE)]; for (int j = 0; j < args.length; j++) { args[j] = mArgs.get(i + j); } final CreateAppDataResult[] results = installer.createAppDataBatched(args); for (int j = 0; j < args.length; j++) { final CreateAppDataResult result = results[j]; final CompletableFuture<Long> future = mFutures.get(i + j); if (result.exceptionCode == 0) { future.complete(result.ceDataInode); } else { future.completeExceptionally( new InstallerException(result.exceptionMessage)); } } } } } public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, Loading
services/core/java/com/android/server/pm/PackageManagerService.java +112 −75 Original line number Diff line number Diff line Loading @@ -418,6 +418,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; Loading Loading @@ -3481,6 +3482,7 @@ public class PackageManagerService extends IPackageManager.Stub return; } int count = 0; final Installer.Batch batch = new Installer.Batch(); for (String pkgName : deferPackages) { AndroidPackage pkg = null; synchronized (mLock) { Loading @@ -3490,13 +3492,14 @@ public class PackageManagerService extends IPackageManager.Stub } } if (pkg != null) { synchronized (mInstallLock) { prepareAppDataAndMigrateLIF(pkg, UserHandle.USER_SYSTEM, storageFlags, prepareAppDataAndMigrate(batch, pkg, UserHandle.USER_SYSTEM, storageFlags, true /* maybeMigrateAppData */); } count++; } } synchronized (mInstallLock) { executeBatchLI(batch); } traceLog.traceEnd(); Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages"); }, "prepareAppData"); Loading Loading @@ -22743,6 +22746,14 @@ public class PackageManagerService extends IPackageManager.Stub } } private void executeBatchLI(@NonNull Installer.Batch batch) { try { batch.execute(mInstaller); } catch (InstallerException e) { Slog.w(TAG, "Failed to execute pending operations", e); } } /** * Examine all apps present on given mounted volume, and destroy apps that * aren't expected, either due to uninstallation or reinstallation on Loading Loading @@ -22882,6 +22893,8 @@ public class PackageManagerService extends IPackageManager.Stub // Ensure that data directories are ready to roll for all packages // installed for this volume and user Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "prepareAppDataAndMigrate"); Installer.Batch batch = new Installer.Batch(); final List<PackageSetting> packages; synchronized (mLock) { packages = mSettings.getVolumePackagesLPr(volumeUuid); Loading @@ -22902,10 +22915,12 @@ public class PackageManagerService extends IPackageManager.Stub } if (ps.getInstalled(userId)) { prepareAppDataAndMigrateLIF(ps.pkg, userId, flags, migrateAppData); prepareAppDataAndMigrate(batch, ps.pkg, userId, flags, migrateAppData); preparedCount++; } } executeBatchLI(batch); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages"); return result; Loading @@ -22930,6 +22945,7 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeKernelMappingLPr(ps); } Installer.Batch batch = new Installer.Batch(); UserManagerInternal umInternal = mInjector.getUserManagerInternal(); StorageManagerInternal smInternal = mInjector.getStorageManagerInternal(); for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) { Loading @@ -22944,16 +22960,20 @@ public class PackageManagerService extends IPackageManager.Stub if (ps.getInstalled(user.id)) { // TODO: when user data is locked, mark that we're still dirty prepareAppDataLIF(pkg, user.id, flags); prepareAppData(batch, pkg, user.id, flags).thenRun(() -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() if (umInternal.isUserUnlockingOrUnlocked(user.id)) { // Prepare app data on external storage; currently this is used to // setup any OBB dirs that were created by the installer correctly. int uid = UserHandle.getUid(user.id, UserHandle.getAppId(pkg.getUid())); smInternal.prepareAppDataAfterInstall(pkg.getPackageName(), uid); } }); } } executeBatchLI(batch); } /** Loading @@ -22964,26 +22984,33 @@ public class PackageManagerService extends IPackageManager.Stub * will try recovering system apps by wiping data; third-party app data is * left intact. */ private void prepareAppDataLIF(AndroidPackage pkg, int userId, int flags) { private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch, @Nullable AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; return CompletableFuture.completedFuture(null); } prepareAppDataLeafLIF(pkg, userId, flags); return prepareAppDataLeaf(batch, pkg, userId, flags); } private void prepareAppDataAndMigrateLIF(AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) { prepareAppDataLIF(pkg, userId, flags); private @NonNull CompletableFuture<?> prepareAppDataAndMigrate(@NonNull Installer.Batch batch, @NonNull AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) { return prepareAppData(batch, pkg, userId, flags).thenRun(() -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() if (maybeMigrateAppData && maybeMigrateAppDataLIF(pkg, userId)) { // We may have just shuffled around app data directories, so // prepare them one more time prepareAppDataLIF(pkg, userId, flags); final Installer.Batch batchInner = new Installer.Batch(); prepareAppData(batchInner, pkg, userId, flags); executeBatchLI(batchInner); } }); } private void prepareAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) { private @NonNull CompletableFuture<?> prepareAppDataLeaf(@NonNull Installer.Batch batch, @NonNull AndroidPackage pkg, int userId, int flags) { if (DEBUG_APP_DATA) { Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x" + Integer.toHexString(flags)); Loading @@ -23003,42 +23030,51 @@ public class PackageManagerService extends IPackageManager.Stub Preconditions.checkNotNull(pkgSeInfo); final String seInfo = pkgSeInfo + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : ""); long ceDataInode = -1; try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); } catch (InstallerException e) { if (pkg.isSystem()) { final int targetSdkVersion = pkg.getTargetSdkVersion(); return batch.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, targetSdkVersion).whenComplete((ceDataInode, e) -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() if ((e != null) && pkg.isSystem()) { logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName + ", but trying to recover: " + e); destroyAppDataLeafLIF(pkg, userId, flags); try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); logCriticalInfo(Log.DEBUG, "Recovery succeeded!"); } catch (InstallerException e2) { logCriticalInfo(Log.DEBUG, "Recovery failed!"); } } else { } else if (e != null) { Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e); } } // Prepare the application profiles only for upgrades and first boot (so that we don't // repeat the same operation at each boot). // We only have to cover the upgrade and first boot here because for app installs we // prepare the profiles before invoking dexopt (in installPackageLI). // Prepare the application profiles only for upgrades and // first boot (so that we don't repeat the same operation at // each boot). // // We only have to cover the upgrade and first boot here // because for app installs we prepare the profiles before // invoking dexopt (in installPackageLI). // // We also have to cover non system users because we do not call the usual install package // methods for them. // We also have to cover non system users because we do not // call the usual install package methods for them. // // NOTE: in order to speed up first boot time we only create the current profile and do not // update the content of the reference profile. A system image should already be configured // with the right profile keys and the profiles for the speed-profile prebuilds should // already be copied. That's done in #performDexOptUpgrade. // NOTE: in order to speed up first boot time we only create // the current profile and do not update the content of the // reference profile. A system image should already be // configured with the right profile keys and the profiles // for the speed-profile prebuilds should already be copied. // That's done in #performDexOptUpgrade. // // TODO(calin, mathieuc): We should use .dm files for prebuilds profiles instead of // manually copying them in #performDexOptUpgrade. When we do that we should have a more // granular check here and only update the existing profiles. // TODO(calin, mathieuc): We should use .dm files for // prebuilds profiles instead of manually copying them in // #performDexOptUpgrade. When we do that we should have a // more granular check here and only update the existing // profiles. if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) { mArtManagerService.prepareAppProfiles(pkg, userId, /* updateReferenceProfileContent= */ false); Loading @@ -23054,6 +23090,7 @@ public class PackageManagerService extends IPackageManager.Stub } prepareAppDataContentsLeafLIF(pkg, ps, userId, flags); }); } private void prepareAppDataContentsLIF(AndroidPackage pkg, @Nullable PackageSetting pkgSetting,
services/core/java/com/android/server/pm/Settings.java +10 −24 Original line number Diff line number Diff line Loading @@ -102,6 +102,7 @@ import com.android.internal.util.XmlUtils; import com.android.permission.persistence.RuntimePermissionsPersistence; import com.android.permission.persistence.RuntimePermissionsState; import com.android.server.LocalServices; import com.android.server.pm.Installer.Batch; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; Loading Loading @@ -4148,24 +4149,12 @@ public final class Settings { final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", Trace.TRACE_TAG_PACKAGE_MANAGER); t.traceBegin("createNewUser-" + userHandle); String[] volumeUuids; String[] names; int[] appIds; String[] seinfos; int[] targetSdkVersions; int packagesCount; Installer.Batch batch = new Installer.Batch(); final boolean skipPackageWhitelist = userTypeInstallablePackages == null; synchronized (mLock) { Collection<PackageSetting> packages = mPackages.values(); packagesCount = packages.size(); volumeUuids = new String[packagesCount]; names = new String[packagesCount]; appIds = new int[packagesCount]; seinfos = new String[packagesCount]; targetSdkVersions = new int[packagesCount]; Iterator<PackageSetting> packagesIterator = packages.iterator(); for (int i = 0; i < packagesCount; i++) { PackageSetting ps = packagesIterator.next(); final int size = mPackages.size(); for (int i = 0; i < size; i++) { final PackageSetting ps = mPackages.valueAt(i); if (ps.pkg == null) { continue; } Loading @@ -4187,18 +4176,15 @@ public final class Settings { } // Need to create a data directory for all apps under this user. Accumulate all // required args and call the installer after mPackages lock has been released volumeUuids[i] = ps.volumeUuid; names[i] = ps.name; appIds[i] = ps.appId; seinfos[i] = AndroidPackageUtils.getSeInfo(ps.pkg, ps); targetSdkVersions[i] = ps.pkg.getTargetSdkVersion(); final String seInfo = AndroidPackageUtils.getSeInfo(ps.pkg, ps); batch.createAppData(ps.volumeUuid, ps.name, userHandle, StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE, ps.appId, seInfo, ps.pkg.getTargetSdkVersion()); } } t.traceBegin("createAppData"); final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE; try { installer.createAppDataBatched(volumeUuids, names, userHandle, flags, appIds, seinfos, targetSdkVersions); batch.execute(installer); } catch (InstallerException e) { Slog.w(TAG, "Failed to prepare app data", e); } Loading