Merge "Introduced UserDataPreparer class"

This commit is contained in:
TreeHugger Robot
2017-01-27 20:57:30 +00:00
committed by Android (Google) Code Review
3 changed files with 154 additions and 106 deletions

View File

@@ -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
@@ -21255,101 +21256,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
@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}