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