diff options
| author | 2016-04-18 19:43:16 +0000 | |
|---|---|---|
| committer | 2016-04-18 19:43:18 +0000 | |
| commit | ad14b884f4110e03ec7b5ba7b913be25d19aa95c (patch) | |
| tree | e1daadae964ee39c8f7ab010123f72cf8bf02cd5 | |
| parent | c79c3246c9a3e0d2aa34afd18fddc95a6aff0f30 (diff) | |
| parent | fcf1e55821b694df3b8434f40aa3b6d3c3e7ea50 (diff) | |
Merge "Consistent creation/destruction of user data." into nyc-dev
7 files changed, 170 insertions, 67 deletions
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index dd73e53f65e6..7d74a1234c26 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -437,6 +437,14 @@ public class FileUtils { return filePath.startsWith(dirPath); } + public static boolean deleteContentsAndDir(File dir) { + if (deleteContents(dir)) { + return dir.delete(); + } else { + return false; + } + } + public static boolean deleteContents(File dir) { File[] files = dir.listFiles(); boolean success = true; diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index c21c65a706a3..3915b0257493 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -1325,6 +1325,24 @@ public interface IMountService extends IInterface { } @Override + public void destroyUserStorage(String volumeUuid, int userId, int flags) + throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(volumeUuid); + _data.writeInt(userId); + _data.writeInt(flags); + mRemote.transact(Stub.TRANSACTION_destroyUserStorage, _data, _reply, 0); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } + + @Override public ParcelFileDescriptor mountAppFuse(String name) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); @@ -1465,6 +1483,7 @@ public interface IMountService extends IInterface { static final int TRANSACTION_isUserKeyUnlocked = IBinder.FIRST_CALL_TRANSACTION + 65; static final int TRANSACTION_prepareUserStorage = IBinder.FIRST_CALL_TRANSACTION + 66; + static final int TRANSACTION_destroyUserStorage = IBinder.FIRST_CALL_TRANSACTION + 67; static final int TRANSACTION_isConvertibleToFBE = IBinder.FIRST_CALL_TRANSACTION + 68; @@ -2096,6 +2115,15 @@ public interface IMountService extends IInterface { reply.writeNoException(); return true; } + case TRANSACTION_destroyUserStorage: { + data.enforceInterface(DESCRIPTOR); + String volumeUuid = data.readString(); + int userId = data.readInt(); + int _flags = data.readInt(); + destroyUserStorage(volumeUuid, userId, _flags); + reply.writeNoException(); + return true; + } case TRANSACTION_mountAppFuse: { data.enforceInterface(DESCRIPTOR); String name = data.readString(); @@ -2434,6 +2462,7 @@ public interface IMountService extends IInterface { public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) throws RemoteException; + public void destroyUserStorage(String volumeUuid, int userId, int flags) throws RemoteException; public ParcelFileDescriptor mountAppFuse(String name) throws RemoteException; } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 0a8fdd9fac3b..f68e227a32a3 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -1053,6 +1053,15 @@ public class StorageManager { } /** {@hide} */ + public void destroyUserStorage(String volumeUuid, int userId, int flags) { + try { + mMountService.destroyUserStorage(volumeUuid, userId, flags); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** {@hide} */ public boolean isUserKeyUnlocked(int userId) { try { return mMountService.isUserKeyUnlocked(userId); diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 229a3f4dd835..ec05dae68a85 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -2875,6 +2875,19 @@ class MountService extends IMountService.Stub } @Override + public void destroyUserStorage(String volumeUuid, int userId, int flags) { + enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); + waitForReady(); + + try { + mCryptConnector.execute("cryptfs", "destroy_user_storage", escapeNull(volumeUuid), + userId, flags); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException { try { final int uid = Binder.getCallingUid(); diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index a11ee74b97f8..66c1a53f587a 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -174,12 +174,13 @@ public final class Installer extends SystemService { mInstaller.execute("destroy_app_profiles", pkgName); } - public void createUserConfig(int userid) throws InstallerException { - mInstaller.execute("mkuserconfig", userid); + public void createUserData(String uuid, int userId, int userSerial, int flags) + throws InstallerException { + mInstaller.execute("create_user_data", uuid, userId, userSerial, flags); } - public void removeUserDataDirs(String uuid, int userid) throws InstallerException { - mInstaller.execute("rmuser", uuid, userid); + public void destroyUserData(String uuid, int userId, int flags) throws InstallerException { + mInstaller.execute("destroy_user_data", uuid, userId, flags); } public void markBootComplete(String instructionSet) throws InstallerException { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index dc81c6561d2a..435f48c28a84 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -109,7 +109,6 @@ import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.IDevicePolicyManager; import android.app.admin.SecurityLog; import android.app.backup.IBackupManager; -import android.app.usage.UsageStatsManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -17421,6 +17420,10 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); return true; } }); + + // Now that we're mostly running, clean up stale users and apps + reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL); + reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL); } @Override @@ -18653,14 +18656,100 @@ 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) { + UserManagerService.enforceSerialNumber( + Environment.getDataUserDeDirectory(volumeUuid, userId), userSerial); + } + if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { + UserManagerService.enforceSerialNumber( + Environment.getDataUserCeDirectory(volumeUuid, 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, flags); + + 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)); + } + if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { + FileUtils.deleteContentsAndDir(Environment.getDataSystemCeDirectory(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. */ private void reconcileUsers(String volumeUuid) { - // TODO: also reconcile DE directories - final File[] files = FileUtils - .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid)); + final List<File> files = new ArrayList<>(); + Collections.addAll(files, FileUtils + .listFilesOrEmpty(Environment.getDataUserDeDirectory(volumeUuid))); + Collections.addAll(files, FileUtils + .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid))); for (File file : files) { if (!file.isDirectory()) continue; @@ -18691,11 +18780,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); if (destroyUser) { synchronized (mInstallLock) { - try { - mInstaller.removeUserDataDirs(volumeUuid, userId); - } catch (InstallerException e) { - Slog.w(TAG, "Failed to clean up user dirs", e); - } + destroyUserDataLI(volumeUuid, userId, + StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); } } } @@ -19490,21 +19576,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); mSettings.removeUserLPw(userHandle); mPendingBroadcasts.remove(userHandle); mEphemeralApplicationRegistry.onUserRemovedLPw(userHandle); - } - synchronized (mInstallLock) { - final StorageManager storage = mContext.getSystemService(StorageManager.class); - for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { - final String volumeUuid = vol.getFsUuid(); - if (DEBUG_INSTALL) Slog.d(TAG, "Removing user data on volume " + volumeUuid); - try { - mInstaller.removeUserDataDirs(volumeUuid, userHandle); - } catch (InstallerException e) { - Slog.w(TAG, "Failed to remove user data", e); - } - } - synchronized (mPackages) { - removeUnusedPackagesLILPw(userManager, userHandle); - } + removeUnusedPackagesLPw(userManager, userHandle); } } @@ -19513,7 +19585,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); * that are no longer in use by any other user. * @param userHandle the user being removed */ - private void removeUnusedPackagesLILPw(UserManagerService userManager, final int userHandle) { + private void removeUnusedPackagesLPw(UserManagerService userManager, final int userHandle) { final boolean DEBUG_CLEAN_APKS = false; int [] users = userManager.getUserIds(); Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator(); @@ -19563,11 +19635,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); /** Called by UserManagerService */ void createNewUser(int userHandle) { synchronized (mInstallLock) { - try { - mInstaller.createUserConfig(userHandle); - } catch (InstallerException e) { - Slog.w(TAG, "Failed to create user config", e); - } mSettings.createNewUserLI(this, mInstaller, userHandle); } synchronized (mPackages) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 9b918f3fb993..42f7166fb7ca 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -65,7 +65,6 @@ import android.os.UserManager; import android.os.UserManagerInternal; import android.os.UserManagerInternal.UserRestrictionsListener; import android.os.storage.StorageManager; -import android.os.storage.VolumeInfo; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; @@ -2060,7 +2059,7 @@ public class UserManagerService extends IUserManager.Stub { } final StorageManager storage = mContext.getSystemService(StorageManager.class); storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral()); - prepareUserStorage(userId, userInfo.serialNumber, + mPm.prepareUserData(userId, userInfo.serialNumber, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); mPm.createNewUser(userId); userInfo.partial = false; @@ -2300,9 +2299,9 @@ public class UserManagerService extends IUserManager.Stub { Slog.i(LOG_TAG, "Destroying key for user " + userHandle + " failed, continuing anyway", e); } + // Cleanup package manager settings mPm.cleanUpUser(this, userHandle); - // Remove this user from the list synchronized (mUsersLock) { mUsers.remove(userHandle); @@ -2322,24 +2321,12 @@ public class UserManagerService extends IUserManager.Stub { AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX)); userFile.delete(); updateUserIds(); - File userDir = Environment.getUserSystemDirectory(userHandle); - File renamedUserDir = Environment.getUserSystemDirectory(UserHandle.USER_NULL - userHandle); - if (userDir.renameTo(renamedUserDir)) { - removeDirectoryRecursive(renamedUserDir); - } else { - removeDirectoryRecursive(userDir); - } - } - private void removeDirectoryRecursive(File parent) { - if (parent.isDirectory()) { - String[] files = parent.list(); - for (String filename : files) { - File child = new File(parent, filename); - removeDirectoryRecursive(child); - } - } - parent.delete(); + // Now that we've purged all the metadata above, destroy the actual data + // on disk; if we battery pull in here we'll finish cleaning up when + // reconciling after reboot. + mPm.destroyUserData(userHandle, + StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); } private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) { @@ -2634,23 +2621,12 @@ public class UserManagerService extends IUserManager.Stub { } /** - * Prepare storage areas for given user on all mounted devices. - */ - private void prepareUserStorage(int userId, int userSerial, int flags) { - final StorageManager storage = mContext.getSystemService(StorageManager.class); - for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { - final String volumeUuid = vol.getFsUuid(); - storage.prepareUserStorage(volumeUuid, userId, userSerial, flags); - } - } - - /** * Called right before a user is started. This gives us a chance to prepare * app storage and apply any user restrictions. */ public void onBeforeStartUser(int userId) { final int userSerial = getUserSerialNumber(userId); - prepareUserStorage(userId, userSerial, StorageManager.FLAG_STORAGE_DE); + mPm.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_DE); mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE); if (userId != UserHandle.USER_SYSTEM) { @@ -2666,7 +2642,7 @@ public class UserManagerService extends IUserManager.Stub { */ public void onBeforeUnlockUser(@UserIdInt int userId) { final int userSerial = getUserSerialNumber(userId); - prepareUserStorage(userId, userSerial, StorageManager.FLAG_STORAGE_CE); + mPm.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_CE); mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE); } |