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