1 /* 2 * Copyright (C) 2021 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 17 package com.android.server.devicepolicy; 18 19 import android.os.UserHandle; 20 import android.util.Slog; 21 import android.util.SparseArray; 22 23 import com.android.internal.util.JournaledFile; 24 25 import java.io.File; 26 import java.io.IOException; 27 import java.nio.charset.Charset; 28 import java.nio.file.Files; 29 30 /** 31 * Class for dealing with Device Policy Manager Service version upgrades. 32 * Initially, this class is responsible for upgrading the "device_policies.xml" file upon 33 * platform version upgrade. 34 * 35 * It is useful for policies which have a different default for an upgrading device than a 36 * newly-configured device (for example, the admin can grant sensors-related permissions by 37 * default on existing fully-managed devices that upgrade to Android S, but on devices set up 38 * with Android S the value of the policy is set explicitly during set-up). 39 * 40 * Practically, it's useful for changes to the data model of the {@code DevicePolicyData} and 41 * {@code ActiveAdmin} classes. 42 * 43 * To add a new upgrade step: 44 * (1) Increase the {@code DPMS_VERSION} constant in {@code DevicePolicyManagerService} by one. 45 * (2) Add an if statement in {@code upgradePolicy} comparing the version, performing the upgrade 46 * step and setting the value of {@code currentVersion} to the newly-incremented version. 47 * (3) Add a test in {@code PolicyVersionUpgraderTest}. 48 */ 49 public class PolicyVersionUpgrader { 50 private static final String LOG_TAG = "DevicePolicyManager"; 51 private static final boolean VERBOSE_LOG = DevicePolicyManagerService.VERBOSE_LOG; 52 private final PolicyUpgraderDataProvider mProvider; 53 PolicyVersionUpgrader(PolicyUpgraderDataProvider provider)54 public PolicyVersionUpgrader(PolicyUpgraderDataProvider provider) { 55 mProvider = provider; 56 } 57 58 /** 59 * Performs the upgrade steps for all users on the system. 60 * 61 * @param allUsers List of all user IDs on the system, including disabled users, as well as 62 * managed profile user IDs. 63 * @param dpmsVersion The version to upgrade to. 64 */ upgradePolicy(int dpmsVersion)65 public void upgradePolicy(int dpmsVersion) { 66 int oldVersion = readVersion(); 67 if (oldVersion >= dpmsVersion) { 68 Slog.i(LOG_TAG, String.format("Current version %d, latest version %d, not upgrading.", 69 oldVersion, dpmsVersion)); 70 return; 71 } 72 73 final int[] allUsers = mProvider.getUsersForUpgrade(); 74 75 //NOTE: The current version is provided in case the XML file format changes in a 76 // non-backwards-compatible way, so that DeviceAdminData could load it with 77 // old tags, for example. 78 final SparseArray<DevicePolicyData> allUsersData = loadAllUsersData(allUsers, oldVersion); 79 80 int currentVersion = oldVersion; 81 if (currentVersion == 0) { 82 Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion)); 83 // The first upgrade (from no version to version 1) is to overwrite 84 // the "active-password" tag in case it was left around. 85 currentVersion = 1; 86 } 87 88 if (currentVersion == 1) { 89 Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion)); 90 // This upgrade step is for Device Owner scenario only: For devices upgrading to S, 91 // if there is a device owner, it retains the ability to control sensors-related 92 // permission grants. 93 for (int userId : allUsers) { 94 DevicePolicyData userData = allUsersData.get(userId); 95 if (userData == null) { 96 continue; 97 } 98 for (ActiveAdmin admin : userData.mAdminList) { 99 if (mProvider.isDeviceOwner(userId, admin.info.getComponent())) { 100 Slog.i(LOG_TAG, String.format( 101 "Marking Device Owner in user %d for permission grant ", userId)); 102 admin.mAdminCanGrantSensorsPermissions = true; 103 } 104 } 105 } 106 currentVersion = 2; 107 } 108 109 writePoliciesAndVersion(allUsers, allUsersData, currentVersion); 110 } 111 writePoliciesAndVersion(int[] allUsers, SparseArray<DevicePolicyData> allUsersData, int currentVersion)112 private void writePoliciesAndVersion(int[] allUsers, SparseArray<DevicePolicyData> allUsersData, 113 int currentVersion) { 114 boolean allWritesSuccessful = true; 115 for (int user : allUsers) { 116 allWritesSuccessful = allWritesSuccessful && writeDataForUser(user, 117 allUsersData.get(user)); 118 } 119 120 if (allWritesSuccessful) { 121 writeVersion(currentVersion); 122 } else { 123 Slog.e(LOG_TAG, String.format("Error: Failed upgrading policies to version %d", 124 currentVersion)); 125 } 126 } 127 loadAllUsersData(int[] allUsers, int loadVersion)128 private SparseArray<DevicePolicyData> loadAllUsersData(int[] allUsers, int loadVersion) { 129 final SparseArray<DevicePolicyData> allUsersData = new SparseArray<>(); 130 for (int user: allUsers) { 131 allUsersData.append(user, loadDataForUser(user, loadVersion)); 132 } 133 return allUsersData; 134 } 135 loadDataForUser(int userId, int loadVersion)136 private DevicePolicyData loadDataForUser(int userId, int loadVersion) { 137 DevicePolicyData policy = new DevicePolicyData(userId); 138 DevicePolicyData.load(policy, 139 !mProvider.storageManagerIsFileBasedEncryptionEnabled(), 140 mProvider.makeDevicePoliciesJournaledFile(userId), 141 mProvider.getAdminInfoSupplier(userId), 142 mProvider.getOwnerComponent(userId)); 143 return policy; 144 } 145 writeDataForUser(int userId, DevicePolicyData policy)146 private boolean writeDataForUser(int userId, DevicePolicyData policy) { 147 return DevicePolicyData.store( 148 policy, 149 mProvider.makeDevicePoliciesJournaledFile(userId), 150 !mProvider.storageManagerIsFileBasedEncryptionEnabled()); 151 } 152 getVersionFile()153 private JournaledFile getVersionFile() { 154 return mProvider.makePoliciesVersionJournaledFile(UserHandle.USER_SYSTEM); 155 } 156 readVersion()157 private int readVersion() { 158 JournaledFile versionFile = getVersionFile(); 159 160 File file = versionFile.chooseForRead(); 161 if (VERBOSE_LOG) { 162 Slog.v(LOG_TAG, "Loading version from " + file); 163 } 164 try { 165 String versionString = Files.readAllLines( 166 file.toPath(), Charset.defaultCharset()).get(0); 167 return Integer.parseInt(versionString); 168 } catch (IOException | NumberFormatException | IndexOutOfBoundsException e) { 169 Slog.e(LOG_TAG, "Error reading version", e); 170 return 0; 171 } 172 } 173 writeVersion(int version)174 private void writeVersion(int version) { 175 JournaledFile versionFile = getVersionFile(); 176 177 File file = versionFile.chooseForWrite(); 178 if (VERBOSE_LOG) { 179 Slog.v(LOG_TAG, String.format("Writing new version to: %s", file)); 180 } 181 182 try { 183 byte[] versionBytes = String.format("%d", version).getBytes(); 184 Files.write(file.toPath(), versionBytes); 185 versionFile.commit(); 186 } catch (IOException e) { 187 Slog.e(LOG_TAG, String.format("Writing version %d failed: %s", version), e); 188 versionFile.rollback(); 189 } 190 } 191 } 192