15c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov/*
25c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov * Copyright (C) 2017 The Android Open Source Project
35c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov *
45c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov * Licensed under the Apache License, Version 2.0 (the "License");
55c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov * you may not use this file except in compliance with the License.
65c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov * You may obtain a copy of the License at
75c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov *
85c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov *      http://www.apache.org/licenses/LICENSE-2.0
95c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov *
105c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov * Unless required by applicable law or agreed to in writing, software
115c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov * distributed under the License is distributed on an "AS IS" BASIS,
125c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov * See the License for the specific language governing permissions and
145c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov * limitations under the License
155c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov */
165c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
175c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolovpackage com.android.server.pm;
185c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
195c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolovimport android.content.Context;
2050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport android.content.pm.UserInfo;
215c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolovimport android.os.Environment;
225c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolovimport android.os.FileUtils;
235c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolovimport android.os.storage.StorageManager;
245c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolovimport android.os.storage.VolumeInfo;
2550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport android.system.ErrnoException;
2650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport android.system.Os;
2750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport android.system.OsConstants;
285c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolovimport android.util.Log;
2950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport android.util.Slog;
3050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport android.util.SparseArray;
315c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
3250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport com.android.internal.annotations.VisibleForTesting;
3350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
3450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport java.io.File;
3550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport java.io.IOException;
3650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport java.nio.charset.StandardCharsets;
3750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport java.util.ArrayList;
3850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport java.util.Collections;
3950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport java.util.List;
405c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolovimport java.util.Objects;
4150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolovimport java.util.Set;
425c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
435c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolovimport static com.android.server.pm.PackageManagerService.logCriticalInfo;
445c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
455c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov/**
465c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov * Helper class for preparing and destroying user storage
475c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov */
485c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolovclass UserDataPreparer {
4950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    private static final String TAG = "UserDataPreparer";
5050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    private static final String XATTR_SERIAL = "user.serial";
5150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
525c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    private final Object mInstallLock;
535c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    private final Context mContext;
545c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    private final boolean mOnlyCore;
555c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    private final Installer mInstaller;
565c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
575c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    UserDataPreparer(Installer installer, Object installLock, Context context, boolean onlyCore) {
585c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        mInstallLock = installLock;
595c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        mContext = context;
605c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        mOnlyCore = onlyCore;
615c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        mInstaller = installer;
625c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    }
635c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
645c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    /**
655c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov     * Prepare storage areas for given user on all mounted devices.
665c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov     */
675c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    void prepareUserData(int userId, int userSerial, int flags) {
685c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        synchronized (mInstallLock) {
695c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            final StorageManager storage = mContext.getSystemService(StorageManager.class);
705c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
715c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                final String volumeUuid = vol.getFsUuid();
725c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                prepareUserDataLI(volumeUuid, userId, userSerial, flags, true);
735c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            }
745c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        }
755c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    }
765c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
775c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    private void prepareUserDataLI(String volumeUuid, int userId, int userSerial, int flags,
785c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            boolean allowRecover) {
795c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        // Prepare storage and verify that serial numbers are consistent; if
805c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        // there's a mismatch we need to destroy to avoid leaking data
815c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        final StorageManager storage = mContext.getSystemService(StorageManager.class);
825c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        try {
835c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            storage.prepareUserStorage(volumeUuid, userId, userSerial, flags);
845c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
855c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && !mOnlyCore) {
8650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                enforceSerialNumber(getDataUserDeDirectory(volumeUuid, userId), userSerial);
875c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
8850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    enforceSerialNumber(getDataSystemDeDirectory(userId), userSerial);
895c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                }
905c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            }
915c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && !mOnlyCore) {
9250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                enforceSerialNumber(getDataUserCeDirectory(volumeUuid, userId), userSerial);
935c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
9450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    enforceSerialNumber(getDataSystemCeDirectory(userId), userSerial);
955c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                }
965c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            }
975c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
985c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            mInstaller.createUserData(volumeUuid, userId, userSerial, flags);
995c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        } catch (Exception e) {
1005c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            logCriticalInfo(Log.WARN, "Destroying user " + userId + " on volume " + volumeUuid
1015c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                    + " because we failed to prepare: " + e);
1025c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            destroyUserDataLI(volumeUuid, userId,
1035c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                    StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
1045c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
1055c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            if (allowRecover) {
1065c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                // Try one last time; if we fail again we're really in trouble
1075c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                prepareUserDataLI(volumeUuid, userId, userSerial, flags, false);
1085c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            }
1095c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        }
1105c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    }
1115c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
1125c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    /**
1135c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov     * Destroy storage areas for given user on all mounted devices.
1145c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov     */
1155c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    void destroyUserData(int userId, int flags) {
1165c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        synchronized (mInstallLock) {
1175c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            final StorageManager storage = mContext.getSystemService(StorageManager.class);
1185c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
1195c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                final String volumeUuid = vol.getFsUuid();
1205c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                destroyUserDataLI(volumeUuid, userId, flags);
1215c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            }
1225c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        }
1235c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    }
1245c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
1255c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    void destroyUserDataLI(String volumeUuid, int userId, int flags) {
1265c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        final StorageManager storage = mContext.getSystemService(StorageManager.class);
1275c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        try {
1285c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            // Clean up app data, profile data, and media data
1295c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            mInstaller.destroyUserData(volumeUuid, userId, flags);
1305c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
1315c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            // Clean up system data
1325c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
1335c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
13450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    FileUtils.deleteContentsAndDir(getUserSystemDirectory(userId));
13550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    FileUtils.deleteContentsAndDir(getDataSystemDeDirectory(userId));
13650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    FileUtils.deleteContentsAndDir(getDataMiscDeDirectory(userId));
1375c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                }
1385c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
13950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    FileUtils.deleteContentsAndDir(getDataSystemCeDirectory(userId));
14050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    FileUtils.deleteContentsAndDir(getDataMiscCeDirectory(userId));
1415c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                }
1425c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            }
1435c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
1445c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            // Data with special labels is now gone, so finish the job
1455c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            storage.destroyUserStorage(volumeUuid, userId, flags);
1465c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
1475c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        } catch (Exception e) {
1485c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov            logCriticalInfo(Log.WARN,
1495c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov                    "Failed to destroy user " + userId + " on volume " + volumeUuid + ": " + e);
1505c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov        }
1515c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov    }
1525c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov
15350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    /**
15450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * Examine all users present on given mounted volume, and destroy data
15550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * belonging to users that are no longer valid, or whose user ID has been
15650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * recycled.
15750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     */
15850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    void reconcileUsers(String volumeUuid, List<UserInfo> validUsersList) {
15950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        final List<File> files = new ArrayList<>();
16050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        Collections.addAll(files, FileUtils
16150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                .listFilesOrEmpty(Environment.getDataUserDeDirectory(volumeUuid)));
16250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        Collections.addAll(files, FileUtils
16350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid)));
16450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        Collections.addAll(files, FileUtils
16550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                .listFilesOrEmpty(Environment.getDataSystemDeDirectory()));
16650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        Collections.addAll(files, FileUtils
16750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                .listFilesOrEmpty(Environment.getDataSystemCeDirectory()));
16850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        Collections.addAll(files, FileUtils
16950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                .listFilesOrEmpty(Environment.getDataMiscCeDirectory()));
17050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        reconcileUsers(volumeUuid, validUsersList, files);
17150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
17250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
17350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    @VisibleForTesting
17450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    void reconcileUsers(String volumeUuid, List<UserInfo> validUsersList, List<File> files) {
17550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        final int userCount = validUsersList.size();
17650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        SparseArray<UserInfo> users = new SparseArray<>(userCount);
17750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        for (int i = 0; i < userCount; i++) {
17850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            UserInfo user = validUsersList.get(i);
17950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            users.put(user.id, user);
18050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        }
18150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        for (File file : files) {
18250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            if (!file.isDirectory()) {
18350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                continue;
18450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            }
18550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
18650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            final int userId;
18750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            final UserInfo info;
18850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            try {
18950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                userId = Integer.parseInt(file.getName());
19050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                info = users.get(userId);
19150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            } catch (NumberFormatException e) {
19250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                Slog.w(TAG, "Invalid user directory " + file);
19350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                continue;
19450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            }
19550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
19650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            boolean destroyUser = false;
19750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            if (info == null) {
19850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                logCriticalInfo(Log.WARN, "Destroying user directory " + file
19950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                        + " because no matching user was found");
20050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                destroyUser = true;
20150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            } else if (!mOnlyCore) {
20250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                try {
20350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    enforceSerialNumber(file, info.serialNumber);
20450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                } catch (IOException e) {
20550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    logCriticalInfo(Log.WARN, "Destroying user directory " + file
20650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                            + " because we failed to enforce serial number: " + e);
20750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    destroyUser = true;
20850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                }
20950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            }
21050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
21150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            if (destroyUser) {
21250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                synchronized (mInstallLock) {
21350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    destroyUserDataLI(volumeUuid, userId,
21450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                            StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
21550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                }
21650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            }
21750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        }
21850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
21950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
22050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    @VisibleForTesting
22150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    protected File getDataMiscCeDirectory(int userId) {
22250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        return Environment.getDataMiscCeDirectory(userId);
22350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
22450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
22550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    @VisibleForTesting
22650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    protected File getDataSystemCeDirectory(int userId) {
22750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        return Environment.getDataSystemCeDirectory(userId);
22850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
22950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
23050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    @VisibleForTesting
23150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    protected File getDataMiscDeDirectory(int userId) {
23250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        return Environment.getDataMiscDeDirectory(userId);
23350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
23450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
23550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    @VisibleForTesting
23650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    protected File getUserSystemDirectory(int userId) {
23750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        return Environment.getUserSystemDirectory(userId);
23850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
23950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
24050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    @VisibleForTesting
24150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    protected File getDataUserCeDirectory(String volumeUuid, int userId) {
24250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        return Environment.getDataUserCeDirectory(volumeUuid, userId);
24350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
24450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
24550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    @VisibleForTesting
24650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    protected File getDataSystemDeDirectory(int userId) {
24750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        return Environment.getDataSystemDeDirectory(userId);
24850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
24950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
25050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    @VisibleForTesting
25150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    protected File getDataUserDeDirectory(String volumeUuid, int userId) {
25250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        return Environment.getDataUserDeDirectory(volumeUuid, userId);
25350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
25450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
25550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    @VisibleForTesting
25650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    protected boolean isFileEncryptedEmulatedOnly() {
25750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        return StorageManager.isFileEncryptedEmulatedOnly();
25850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
25950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
26050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    /**
26150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * Enforce that serial number stored in user directory inode matches the
26250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * given expected value. Gracefully sets the serial number if currently
26350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * undefined.
26450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     *
26550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * @throws IOException when problem extracting serial number, or serial
26650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     *             number is mismatched.
26750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     */
26850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    void enforceSerialNumber(File file, int serialNumber) throws IOException {
26950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        if (isFileEncryptedEmulatedOnly()) {
27050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            // When we're emulating FBE, the directory may have been chmod
27150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            // 000'ed, meaning we can't read the serial number to enforce it;
27250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            // instead of destroying the user, just log a warning.
27350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            Slog.w(TAG, "Device is emulating FBE; assuming current serial number is valid");
27450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            return;
27550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        }
27650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
27750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        final int foundSerial = getSerialNumber(file);
27850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        Slog.v(TAG, "Found " + file + " with serial number " + foundSerial);
27950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
28050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        if (foundSerial == -1) {
28150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            Slog.d(TAG, "Serial number missing on " + file + "; assuming current is valid");
28250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            try {
28350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                setSerialNumber(file, serialNumber);
28450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            } catch (IOException e) {
28550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                Slog.w(TAG, "Failed to set serial number on " + file, e);
28650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            }
28750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
28850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        } else if (foundSerial != serialNumber) {
28950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            throw new IOException("Found serial number " + foundSerial
29050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                    + " doesn't match expected " + serialNumber);
29150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        }
29250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
29350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
29450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    /**
29550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * Set serial number stored in user directory inode.
29650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     *
29750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * @throws IOException if serial number was already set
29850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     */
29950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    private static void setSerialNumber(File file, int serialNumber) throws IOException {
30050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        try {
30150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            final byte[] buf = Integer.toString(serialNumber).getBytes(StandardCharsets.UTF_8);
30250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            Os.setxattr(file.getAbsolutePath(), XATTR_SERIAL, buf, OsConstants.XATTR_CREATE);
30350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        } catch (ErrnoException e) {
30450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            throw e.rethrowAsIOException();
30550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        }
30650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
30750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
30850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    /**
30950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * Return serial number stored in user directory inode.
31050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     *
31150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     * @return parsed serial number, or -1 if not set
31250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov     */
31350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    @VisibleForTesting
31450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    static int getSerialNumber(File file) throws IOException {
31550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        try {
31650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            final byte[] buf = Os.getxattr(file.getAbsolutePath(), XATTR_SERIAL);
31750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            final String serial = new String(buf);
31850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            try {
31950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                return Integer.parseInt(serial);
32050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            } catch (NumberFormatException e) {
32150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                throw new IOException("Bad serial number: " + serial);
32250979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            }
32350979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        } catch (ErrnoException e) {
32450979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            if (e.errno == OsConstants.ENODATA) {
32550979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                return -1;
32650979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            } else {
32750979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov                throw e.rethrowAsIOException();
32850979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov            }
32950979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov        }
33050979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov    }
33150979d14f913b97852c9e39b3b85c555988760f5Fyodor Kupolov
3325c0ecfdb37b082bd6bd490270193b676ecb481c2Fyodor Kupolov}
333