• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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