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 
30 import org.xmlpull.v1.XmlPullParser;
31 import org.xmlpull.v1.XmlPullParserException;
32 import org.xmlpull.v1.XmlSerializer;
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 XmlPullParser parser)204     public static FactoryResetProtectionPolicy readFromXml(@NonNull XmlPullParser parser) {
205         try {
206             boolean factoryResetProtectionEnabled = Boolean.parseBoolean(
207                     parser.getAttributeValue(null, KEY_FACTORY_RESET_PROTECTION_ENABLED));
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 XmlSerializer out)235     public void writeToXml(@NonNull XmlSerializer out) throws IOException {
236         out.attribute(null, KEY_FACTORY_RESET_PROTECTION_ENABLED,
237                 Boolean.toString(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