1 /* 2 * Copyright (C) 2019 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 android.app.admin; 18 19 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 20 import static org.xmlpull.v1.XmlPullParser.END_TAG; 21 import static org.xmlpull.v1.XmlPullParser.TEXT; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.content.ComponentName; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.util.Log; 29 import android.util.TypedXmlPullParser; 30 import android.util.TypedXmlSerializer; 31 32 import org.xmlpull.v1.XmlPullParserException; 33 34 import java.io.IOException; 35 import java.util.ArrayList; 36 import java.util.List; 37 38 /** 39 * The factory reset protection policy determines which accounts can unlock a device that 40 * has gone through untrusted factory reset. 41 * <p> 42 * Only a device owner or profile owner of an organization-owned device can set a factory 43 * reset protection policy for the device by calling the {@code DevicePolicyManager} method 44 * {@link DevicePolicyManager#setFactoryResetProtectionPolicy(ComponentName, 45 * FactoryResetProtectionPolicy)}}. 46 * <p> 47 * Normally factory reset protection does not kick in if the device is factory reset via Settings. 48 * This is also the case when a device owner sets factory reset protection policy. However, 49 * when a profile owner of an organization-owned device sets factory reset protection policy that 50 * locks the device to specific accounts, the policy will take effect even if factory reset is 51 * performed from Settings. 52 * 53 * @see DevicePolicyManager#setFactoryResetProtectionPolicy 54 * @see DevicePolicyManager#getFactoryResetProtectionPolicy 55 */ 56 public final class FactoryResetProtectionPolicy implements Parcelable { 57 58 private static final String LOG_TAG = "FactoryResetProtectionPolicy"; 59 60 private static final String KEY_FACTORY_RESET_PROTECTION_ACCOUNT = 61 "factory_reset_protection_account"; 62 private static final String KEY_FACTORY_RESET_PROTECTION_ENABLED = 63 "factory_reset_protection_enabled"; 64 private static final String ATTR_VALUE = "value"; 65 66 private final List<String> mFactoryResetProtectionAccounts; 67 private final boolean mFactoryResetProtectionEnabled; 68 FactoryResetProtectionPolicy(List<String> factoryResetProtectionAccounts, boolean factoryResetProtectionEnabled)69 private FactoryResetProtectionPolicy(List<String> factoryResetProtectionAccounts, 70 boolean factoryResetProtectionEnabled) { 71 mFactoryResetProtectionAccounts = factoryResetProtectionAccounts; 72 mFactoryResetProtectionEnabled = factoryResetProtectionEnabled; 73 } 74 75 /** 76 * Get the list of accounts that can provision a device which has been factory reset. 77 */ getFactoryResetProtectionAccounts()78 public @NonNull List<String> getFactoryResetProtectionAccounts() { 79 return mFactoryResetProtectionAccounts; 80 } 81 82 /** 83 * Return whether factory reset protection for the device is enabled or not. 84 */ isFactoryResetProtectionEnabled()85 public boolean isFactoryResetProtectionEnabled() { 86 return mFactoryResetProtectionEnabled; 87 } 88 89 /** 90 * Builder class for {@link FactoryResetProtectionPolicy} objects. 91 */ 92 public static class Builder { 93 private List<String> mFactoryResetProtectionAccounts; 94 private boolean mFactoryResetProtectionEnabled; 95 96 /** 97 * Initialize a new Builder to construct a {@link FactoryResetProtectionPolicy}. 98 */ Builder()99 public Builder() { 100 mFactoryResetProtectionEnabled = true; 101 }; 102 103 /** 104 * Sets which accounts can unlock a device that has been factory reset. 105 * <p> 106 * Once set, the consumer unlock flow will be disabled and only accounts in this list 107 * can unlock factory reset protection after untrusted factory reset. 108 * <p> 109 * It's up to the FRP management agent to interpret the {@code String} as account it 110 * supports. Please consult their relevant documentation for details. 111 * 112 * @param factoryResetProtectionAccounts list of accounts. 113 * @return the same Builder instance. 114 */ 115 @NonNull setFactoryResetProtectionAccounts( @onNull List<String> factoryResetProtectionAccounts)116 public Builder setFactoryResetProtectionAccounts( 117 @NonNull List<String> factoryResetProtectionAccounts) { 118 mFactoryResetProtectionAccounts = new ArrayList<>(factoryResetProtectionAccounts); 119 return this; 120 } 121 122 /** 123 * Sets whether factory reset protection is enabled or not. 124 * <p> 125 * Once disabled, factory reset protection will not kick in all together when the device 126 * goes through untrusted factory reset. This applies to both the consumer unlock flow and 127 * the admin account overrides via {@link #setFactoryResetProtectionAccounts}. By default, 128 * factory reset protection is enabled. 129 * 130 * @param factoryResetProtectionEnabled Whether the policy is enabled or not. 131 * @return the same Builder instance. 132 */ 133 @NonNull setFactoryResetProtectionEnabled(boolean factoryResetProtectionEnabled)134 public Builder setFactoryResetProtectionEnabled(boolean factoryResetProtectionEnabled) { 135 mFactoryResetProtectionEnabled = factoryResetProtectionEnabled; 136 return this; 137 } 138 139 /** 140 * Combines all of the attributes that have been set on this {@code Builder} 141 * 142 * @return a new {@link FactoryResetProtectionPolicy} object. 143 */ 144 @NonNull build()145 public FactoryResetProtectionPolicy build() { 146 return new FactoryResetProtectionPolicy(mFactoryResetProtectionAccounts, 147 mFactoryResetProtectionEnabled); 148 } 149 } 150 151 @Override toString()152 public String toString() { 153 return "FactoryResetProtectionPolicy{" 154 + "mFactoryResetProtectionAccounts=" + mFactoryResetProtectionAccounts 155 + ", mFactoryResetProtectionEnabled=" + mFactoryResetProtectionEnabled 156 + '}'; 157 } 158 159 @Override writeToParcel(@onNull Parcel dest, @Nullable int flags)160 public void writeToParcel(@NonNull Parcel dest, @Nullable int flags) { 161 int accountsCount = mFactoryResetProtectionAccounts.size(); 162 dest.writeInt(accountsCount); 163 for (String account: mFactoryResetProtectionAccounts) { 164 dest.writeString(account); 165 } 166 dest.writeBoolean(mFactoryResetProtectionEnabled); 167 } 168 169 @Override describeContents()170 public int describeContents() { 171 return 0; 172 } 173 174 public static final @NonNull Creator<FactoryResetProtectionPolicy> CREATOR = 175 new Creator<FactoryResetProtectionPolicy>() { 176 177 @Override 178 public FactoryResetProtectionPolicy createFromParcel(Parcel in) { 179 List<String> factoryResetProtectionAccounts = new ArrayList<>(); 180 int accountsCount = in.readInt(); 181 for (int i = 0; i < accountsCount; i++) { 182 factoryResetProtectionAccounts.add(in.readString()); 183 } 184 boolean factoryResetProtectionEnabled = in.readBoolean(); 185 186 return new FactoryResetProtectionPolicy(factoryResetProtectionAccounts, 187 factoryResetProtectionEnabled); 188 } 189 190 @Override 191 public FactoryResetProtectionPolicy[] newArray(int size) { 192 return new FactoryResetProtectionPolicy[size]; 193 } 194 }; 195 196 /** 197 * Restore a previously saved FactoryResetProtectionPolicy from XML. 198 * <p> 199 * No validation is required on the reconstructed policy since the XML was previously 200 * created by the system server from a validated policy. 201 * @hide 202 */ 203 @Nullable readFromXml(@onNull TypedXmlPullParser parser)204 public static FactoryResetProtectionPolicy readFromXml(@NonNull TypedXmlPullParser parser) { 205 try { 206 boolean factoryResetProtectionEnabled = parser.getAttributeBoolean(null, 207 KEY_FACTORY_RESET_PROTECTION_ENABLED, false); 208 209 List<String> factoryResetProtectionAccounts = new ArrayList<>(); 210 int outerDepth = parser.getDepth(); 211 int type; 212 while ((type = parser.next()) != END_DOCUMENT 213 && (type != END_TAG || parser.getDepth() > outerDepth)) { 214 if (type == END_TAG || type == TEXT) { 215 continue; 216 } 217 if (!parser.getName().equals(KEY_FACTORY_RESET_PROTECTION_ACCOUNT)) { 218 continue; 219 } 220 factoryResetProtectionAccounts.add( 221 parser.getAttributeValue(null, ATTR_VALUE)); 222 } 223 224 return new FactoryResetProtectionPolicy(factoryResetProtectionAccounts, 225 factoryResetProtectionEnabled); 226 } catch (XmlPullParserException | IOException e) { 227 Log.w(LOG_TAG, "Reading from xml failed", e); 228 } 229 return null; 230 } 231 232 /** 233 * @hide 234 */ writeToXml(@onNull TypedXmlSerializer out)235 public void writeToXml(@NonNull TypedXmlSerializer out) throws IOException { 236 out.attributeBoolean(null, KEY_FACTORY_RESET_PROTECTION_ENABLED, 237 mFactoryResetProtectionEnabled); 238 for (String account : mFactoryResetProtectionAccounts) { 239 out.startTag(null, KEY_FACTORY_RESET_PROTECTION_ACCOUNT); 240 out.attribute(null, ATTR_VALUE, account); 241 out.endTag(null, KEY_FACTORY_RESET_PROTECTION_ACCOUNT); 242 } 243 } 244 245 /** 246 * Returns if the policy will result in factory reset protection being locked to 247 * admin-specified accounts. 248 * <p> 249 * When a device has a non-empty factory reset protection policy, trusted factory reset 250 * via Settings will no longer remove factory reset protection from the device. 251 * @hide 252 */ isNotEmpty()253 public boolean isNotEmpty() { 254 return !mFactoryResetProtectionAccounts.isEmpty() && mFactoryResetProtectionEnabled; 255 } 256 257 } 258