UserDataPreparer.java revision 5c0ecfdb37b082bd6bd490270193b676ecb481c2
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.pm;
18
19import android.content.Context;
20import android.os.Environment;
21import android.os.FileUtils;
22import android.os.storage.StorageManager;
23import android.os.storage.VolumeInfo;
24import android.util.Log;
25
26import java.util.Objects;
27
28import static com.android.server.pm.PackageManagerService.logCriticalInfo;
29
30/**
31 * Helper class for preparing and destroying user storage
32 */
33class UserDataPreparer {
34    private final Object mInstallLock;
35    private final Context mContext;
36    private final boolean mOnlyCore;
37    private final Installer mInstaller;
38
39    UserDataPreparer(Installer installer, Object installLock, Context context, boolean onlyCore) {
40        mInstallLock = installLock;
41        mContext = context;
42        mOnlyCore = onlyCore;
43        mInstaller = installer;
44    }
45
46    /**
47     * Prepare storage areas for given user on all mounted devices.
48     */
49    void prepareUserData(int userId, int userSerial, int flags) {
50        synchronized (mInstallLock) {
51            final StorageManager storage = mContext.getSystemService(StorageManager.class);
52            for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
53                final String volumeUuid = vol.getFsUuid();
54                prepareUserDataLI(volumeUuid, userId, userSerial, flags, true);
55            }
56        }
57    }
58
59    private void prepareUserDataLI(String volumeUuid, int userId, int userSerial, int flags,
60            boolean allowRecover) {
61        // Prepare storage and verify that serial numbers are consistent; if
62        // there's a mismatch we need to destroy to avoid leaking data
63        final StorageManager storage = mContext.getSystemService(StorageManager.class);
64        try {
65            storage.prepareUserStorage(volumeUuid, userId, userSerial, flags);
66
67            if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && !mOnlyCore) {
68                UserManagerService.enforceSerialNumber(
69                        Environment.getDataUserDeDirectory(volumeUuid, userId), userSerial);
70                if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
71                    UserManagerService.enforceSerialNumber(
72                            Environment.getDataSystemDeDirectory(userId), userSerial);
73                }
74            }
75            if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && !mOnlyCore) {
76                UserManagerService.enforceSerialNumber(
77                        Environment.getDataUserCeDirectory(volumeUuid, userId), userSerial);
78                if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
79                    UserManagerService.enforceSerialNumber(
80                            Environment.getDataSystemCeDirectory(userId), userSerial);
81                }
82            }
83
84            mInstaller.createUserData(volumeUuid, userId, userSerial, flags);
85        } catch (Exception e) {
86            logCriticalInfo(Log.WARN, "Destroying user " + userId + " on volume " + volumeUuid
87                    + " because we failed to prepare: " + e);
88            destroyUserDataLI(volumeUuid, userId,
89                    StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
90
91            if (allowRecover) {
92                // Try one last time; if we fail again we're really in trouble
93                prepareUserDataLI(volumeUuid, userId, userSerial, flags, false);
94            }
95        }
96    }
97
98    /**
99     * Destroy storage areas for given user on all mounted devices.
100     */
101    void destroyUserData(int userId, int flags) {
102        synchronized (mInstallLock) {
103            final StorageManager storage = mContext.getSystemService(StorageManager.class);
104            for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
105                final String volumeUuid = vol.getFsUuid();
106                destroyUserDataLI(volumeUuid, userId, flags);
107            }
108        }
109    }
110
111    void destroyUserDataLI(String volumeUuid, int userId, int flags) {
112        final StorageManager storage = mContext.getSystemService(StorageManager.class);
113        try {
114            // Clean up app data, profile data, and media data
115            mInstaller.destroyUserData(volumeUuid, userId, flags);
116
117            // Clean up system data
118            if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
119                if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
120                    FileUtils.deleteContentsAndDir(Environment.getUserSystemDirectory(userId));
121                    FileUtils.deleteContentsAndDir(Environment.getDataSystemDeDirectory(userId));
122                    FileUtils.deleteContentsAndDir(Environment.getDataMiscDeDirectory(userId));
123                }
124                if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
125                    FileUtils.deleteContentsAndDir(Environment.getDataSystemCeDirectory(userId));
126                    FileUtils.deleteContentsAndDir(Environment.getDataMiscCeDirectory(userId));
127                }
128            }
129
130            // Data with special labels is now gone, so finish the job
131            storage.destroyUserStorage(volumeUuid, userId, flags);
132
133        } catch (Exception e) {
134            logCriticalInfo(Log.WARN,
135                    "Failed to destroy user " + userId + " on volume " + volumeUuid + ": " + e);
136        }
137    }
138
139}
140