Merge "Introduced UserDataPreparer class"
This commit is contained in:
committed by
Android (Google) Code Review
commit
6fd52cd04b
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
139
services/core/java/com/android/server/pm/UserDataPreparer.java
Normal file
139
services/core/java/com/android/server/pm/UserDataPreparer.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user