diff options
| author | 2017-01-27 20:57:30 +0000 | |
|---|---|---|
| committer | 2017-01-27 20:57:33 +0000 | |
| commit | 6fd52cd04bb2b76fdd522bca5b51acb3d86ced48 (patch) | |
| tree | 721451f6e2f55d929dbc1cee32fa243a3e7ae97b | |
| parent | e3eb296cb4049431fccec87461fa074a7712ddc5 (diff) | |
| parent | 5c0ecfdb37b082bd6bd490270193b676ecb481c2 (diff) | |
Merge "Introduced UserDataPreparer class"
3 files changed, 154 insertions, 106 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2e4e30377e04..b0512d4f3177 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -831,6 +831,7 @@ public class PackageManagerService extends IPackageManager.Stub { private List<String> mKeepUninstalledPackages; private UserManagerInternal mUserManagerInternal; + private final UserDataPreparer mUserDataPreparer; private File mCacheDir; @@ -2262,8 +2263,8 @@ public class PackageManagerService extends IPackageManager.Stub { mEphemeralInstallDir = new File(dataDir, "app-ephemeral"); mAsecInternalPath = new File(dataDir, "app-asec").getPath(); mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); - - sUserManager = new UserManagerService(context, this, mPackages); + mUserDataPreparer = new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore); + sUserManager = new UserManagerService(context, this, mUserDataPreparer, mPackages); // Propagate permission configuration in to package manager. ArrayMap<String, SystemConfig.PermissionEntry> permConfig @@ -21256,101 +21257,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } /** - * Prepare storage areas for given user on all mounted devices. - */ - void prepareUserData(int userId, int userSerial, int flags) { - synchronized (mInstallLock) { - final StorageManager storage = mContext.getSystemService(StorageManager.class); - for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { - final String volumeUuid = vol.getFsUuid(); - prepareUserDataLI(volumeUuid, userId, userSerial, flags, true); - } - } - } - - private void prepareUserDataLI(String volumeUuid, int userId, int userSerial, int flags, - boolean allowRecover) { - // Prepare storage and verify that serial numbers are consistent; if - // there's a mismatch we need to destroy to avoid leaking data - final StorageManager storage = mContext.getSystemService(StorageManager.class); - try { - storage.prepareUserStorage(volumeUuid, userId, userSerial, flags); - - if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && !mOnlyCore) { - UserManagerService.enforceSerialNumber( - Environment.getDataUserDeDirectory(volumeUuid, userId), userSerial); - if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) { - UserManagerService.enforceSerialNumber( - Environment.getDataSystemDeDirectory(userId), userSerial); - } - } - if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && !mOnlyCore) { - UserManagerService.enforceSerialNumber( - Environment.getDataUserCeDirectory(volumeUuid, userId), userSerial); - if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) { - UserManagerService.enforceSerialNumber( - Environment.getDataSystemCeDirectory(userId), userSerial); - } - } - - synchronized (mInstallLock) { - mInstaller.createUserData(volumeUuid, userId, userSerial, flags); - } - } catch (Exception e) { - logCriticalInfo(Log.WARN, "Destroying user " + userId + " on volume " + volumeUuid - + " because we failed to prepare: " + e); - destroyUserDataLI(volumeUuid, userId, - StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); - - if (allowRecover) { - // Try one last time; if we fail again we're really in trouble - prepareUserDataLI(volumeUuid, userId, userSerial, flags, false); - } - } - } - - /** - * Destroy storage areas for given user on all mounted devices. - */ - void destroyUserData(int userId, int flags) { - synchronized (mInstallLock) { - final StorageManager storage = mContext.getSystemService(StorageManager.class); - for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { - final String volumeUuid = vol.getFsUuid(); - destroyUserDataLI(volumeUuid, userId, flags); - } - } - } - - private void destroyUserDataLI(String volumeUuid, int userId, int flags) { - final StorageManager storage = mContext.getSystemService(StorageManager.class); - try { - // Clean up app data, profile data, and media data - mInstaller.destroyUserData(volumeUuid, userId, flags); - - // Clean up system data - if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) { - if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) { - FileUtils.deleteContentsAndDir(Environment.getUserSystemDirectory(userId)); - FileUtils.deleteContentsAndDir(Environment.getDataSystemDeDirectory(userId)); - FileUtils.deleteContentsAndDir(Environment.getDataMiscDeDirectory(userId)); - } - if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { - FileUtils.deleteContentsAndDir(Environment.getDataSystemCeDirectory(userId)); - FileUtils.deleteContentsAndDir(Environment.getDataMiscCeDirectory(userId)); - } - } - - // Data with special labels is now gone, so finish the job - storage.destroyUserStorage(volumeUuid, userId, flags); - - } catch (Exception e) { - logCriticalInfo(Log.WARN, - "Failed to destroy user " + userId + " on volume " + volumeUuid + ": " + e); - } - } - - /** * Examine all users present on given mounted volume, and destroy data * belonging to users that are no longer valid, or whose user ID has been * recycled. @@ -21397,7 +21303,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); if (destroyUser) { synchronized (mInstallLock) { - destroyUserDataLI(volumeUuid, userId, + mUserDataPreparer.destroyUserDataLI(volumeUuid, userId, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); } } diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java new file mode 100644 index 000000000000..52599fd031c9 --- /dev/null +++ b/services/core/java/com/android/server/pm/UserDataPreparer.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.pm; + +import android.content.Context; +import android.os.Environment; +import android.os.FileUtils; +import android.os.storage.StorageManager; +import android.os.storage.VolumeInfo; +import android.util.Log; + +import java.util.Objects; + +import static com.android.server.pm.PackageManagerService.logCriticalInfo; + +/** + * Helper class for preparing and destroying user storage + */ +class UserDataPreparer { + private final Object mInstallLock; + private final Context mContext; + private final boolean mOnlyCore; + private final Installer mInstaller; + + UserDataPreparer(Installer installer, Object installLock, Context context, boolean onlyCore) { + mInstallLock = installLock; + mContext = context; + mOnlyCore = onlyCore; + mInstaller = installer; + } + + /** + * Prepare storage areas for given user on all mounted devices. + */ + void prepareUserData(int userId, int userSerial, int flags) { + synchronized (mInstallLock) { + final StorageManager storage = mContext.getSystemService(StorageManager.class); + for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { + final String volumeUuid = vol.getFsUuid(); + prepareUserDataLI(volumeUuid, userId, userSerial, flags, true); + } + } + } + + private void prepareUserDataLI(String volumeUuid, int userId, int userSerial, int flags, + boolean allowRecover) { + // Prepare storage and verify that serial numbers are consistent; if + // there's a mismatch we need to destroy to avoid leaking data + final StorageManager storage = mContext.getSystemService(StorageManager.class); + try { + storage.prepareUserStorage(volumeUuid, userId, userSerial, flags); + + if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && !mOnlyCore) { + UserManagerService.enforceSerialNumber( + Environment.getDataUserDeDirectory(volumeUuid, userId), userSerial); + if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) { + UserManagerService.enforceSerialNumber( + Environment.getDataSystemDeDirectory(userId), userSerial); + } + } + if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && !mOnlyCore) { + UserManagerService.enforceSerialNumber( + Environment.getDataUserCeDirectory(volumeUuid, userId), userSerial); + if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) { + UserManagerService.enforceSerialNumber( + Environment.getDataSystemCeDirectory(userId), userSerial); + } + } + + mInstaller.createUserData(volumeUuid, userId, userSerial, flags); + } catch (Exception e) { + logCriticalInfo(Log.WARN, "Destroying user " + userId + " on volume " + volumeUuid + + " because we failed to prepare: " + e); + destroyUserDataLI(volumeUuid, userId, + StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); + + if (allowRecover) { + // Try one last time; if we fail again we're really in trouble + prepareUserDataLI(volumeUuid, userId, userSerial, flags, false); + } + } + } + + /** + * Destroy storage areas for given user on all mounted devices. + */ + void destroyUserData(int userId, int flags) { + synchronized (mInstallLock) { + final StorageManager storage = mContext.getSystemService(StorageManager.class); + for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { + final String volumeUuid = vol.getFsUuid(); + destroyUserDataLI(volumeUuid, userId, flags); + } + } + } + + void destroyUserDataLI(String volumeUuid, int userId, int flags) { + final StorageManager storage = mContext.getSystemService(StorageManager.class); + try { + // Clean up app data, profile data, and media data + mInstaller.destroyUserData(volumeUuid, userId, flags); + + // Clean up system data + if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) { + if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) { + FileUtils.deleteContentsAndDir(Environment.getUserSystemDirectory(userId)); + FileUtils.deleteContentsAndDir(Environment.getDataSystemDeDirectory(userId)); + FileUtils.deleteContentsAndDir(Environment.getDataMiscDeDirectory(userId)); + } + if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { + FileUtils.deleteContentsAndDir(Environment.getDataSystemCeDirectory(userId)); + FileUtils.deleteContentsAndDir(Environment.getDataMiscCeDirectory(userId)); + } + } + + // Data with special labels is now gone, so finish the job + storage.destroyUserStorage(volumeUuid, userId, flags); + + } catch (Exception e) { + logCriticalInfo(Log.WARN, + "Failed to destroy user " + userId + " on volume " + volumeUuid + ": " + e); + } + } + +} diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 9d2d9e5bf5d2..455d3e4f0820 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -227,6 +227,7 @@ public class UserManagerService extends IUserManager.Stub { private final Context mContext; private final PackageManagerService mPm; private final Object mPackagesLock; + private final UserDataPreparer mUserDataPreparer; // Short-term lock for internal state, when interaction/sync with PM is not required private final Object mUsersLock = new Object(); private final Object mRestrictionsLock = new Object(); @@ -433,7 +434,7 @@ public class UserManagerService extends IUserManager.Stub { // TODO b/28848102 Add support for test dependencies injection @VisibleForTesting UserManagerService(Context context) { - this(context, null, new Object(), context.getCacheDir()); + this(context, null, null, new Object(), context.getCacheDir()); } /** @@ -441,16 +442,18 @@ public class UserManagerService extends IUserManager.Stub { * associated with the package manager, and the given lock is the * package manager's own lock. */ - UserManagerService(Context context, PackageManagerService pm, Object packagesLock) { - this(context, pm, packagesLock, Environment.getDataDirectory()); + UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer, + Object packagesLock) { + this(context, pm, userDataPreparer, packagesLock, Environment.getDataDirectory()); } private UserManagerService(Context context, PackageManagerService pm, - Object packagesLock, File dataDir) { + UserDataPreparer userDataPreparer, Object packagesLock, File dataDir) { mContext = context; mPm = pm; mPackagesLock = packagesLock; mHandler = new MainHandler(); + mUserDataPreparer = userDataPreparer; synchronized (mPackagesLock) { mUsersDir = new File(dataDir, USER_INFO_DIR); mUsersDir.mkdirs(); @@ -2494,7 +2497,7 @@ public class UserManagerService extends IUserManager.Stub { } final StorageManager storage = mContext.getSystemService(StorageManager.class); storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral()); - mPm.prepareUserData(userId, userInfo.serialNumber, + mUserDataPreparer.prepareUserData(userId, userInfo.serialNumber, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); mPm.createNewUser(userId, disallowedPackages); userInfo.partial = false; @@ -2788,7 +2791,7 @@ public class UserManagerService extends IUserManager.Stub { mPm.cleanUpUser(this, userHandle); // Clean up all data before removing metadata - mPm.destroyUserData(userHandle, + mUserDataPreparer.destroyUserData(userHandle, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); // Remove this user from the list @@ -3129,7 +3132,7 @@ public class UserManagerService extends IUserManager.Stub { final int userSerial = userInfo.serialNumber; // Migrate only if build fingerprints mismatch boolean migrateAppsData = !Build.FINGERPRINT.equals(userInfo.lastLoggedInFingerprint); - mPm.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_DE); + mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_DE); mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE, migrateAppsData); if (userId != UserHandle.USER_SYSTEM) { @@ -3151,7 +3154,7 @@ public class UserManagerService extends IUserManager.Stub { final int userSerial = userInfo.serialNumber; // Migrate only if build fingerprints mismatch boolean migrateAppsData = !Build.FINGERPRINT.equals(userInfo.lastLoggedInFingerprint); - mPm.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_CE); + mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_CE); mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE, migrateAppsData); } |