1/*
2 * Copyright (C) 2015 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
17package android.app.admin;
18
19import android.annotation.IntDef;
20import android.os.Parcel;
21import android.os.Parcelable;
22import android.os.PersistableBundle;
23
24import org.xmlpull.v1.XmlPullParser;
25import org.xmlpull.v1.XmlPullParserException;
26import org.xmlpull.v1.XmlSerializer;
27
28import java.io.IOException;
29import java.lang.annotation.Retention;
30import java.lang.annotation.RetentionPolicy;
31
32/**
33 * A class that represents a local system update policy set by the device owner.
34 *
35 * @see DevicePolicyManager#setSystemUpdatePolicy
36 * @see DevicePolicyManager#getSystemUpdatePolicy
37 */
38public class SystemUpdatePolicy implements Parcelable {
39
40    /** @hide */
41    @IntDef({
42        TYPE_INSTALL_AUTOMATIC,
43        TYPE_INSTALL_WINDOWED,
44        TYPE_POSTPONE})
45    @Retention(RetentionPolicy.SOURCE)
46    @interface SystemUpdatePolicyType {}
47
48    /**
49     * Unknown policy type, used only internally.
50     */
51    private static final int TYPE_UNKNOWN = -1;
52    /**
53     * Install system update automatically as soon as one is available.
54     */
55    public static final int TYPE_INSTALL_AUTOMATIC = 1;
56
57    /**
58     * Install system update automatically within a daily maintenance window, for a maximum of 30
59     * days. After the expiration the policy will no longer be effective and the system should
60     * revert back to its normal behavior as if no policy were set. The only exception is
61     * {@link #TYPE_INSTALL_AUTOMATIC} which should still take effect to install system update
62     * immediately.
63     */
64    public static final int TYPE_INSTALL_WINDOWED = 2;
65
66    /**
67     * Incoming system update will be blocked for a maximum of 30 days, after which the system
68     * should revert back to its normal behavior as if no policy were set. The only exception is
69     * {@link #TYPE_INSTALL_AUTOMATIC} which should still take effect to install system update
70     * immediately.
71     */
72    public static final int TYPE_POSTPONE = 3;
73
74    private static final String KEY_POLICY_TYPE = "policy_type";
75    private static final String KEY_INSTALL_WINDOW_START = "install_window_start";
76    private static final String KEY_INSTALL_WINDOW_END = "install_window_end";
77    /**
78     * The upper boundary of the daily maintenance window: 24 * 60 minutes.
79     */
80    private static final int WINDOW_BOUNDARY = 24 * 60;
81
82    @SystemUpdatePolicyType
83    private int mPolicyType;
84
85    private int mMaintenanceWindowStart;
86    private int mMaintenanceWindowEnd;
87
88
89    private SystemUpdatePolicy() {
90        mPolicyType = TYPE_UNKNOWN;
91    }
92
93    /**
94     * Create a policy object and set it to install update automatically as soon as one is
95     * available.
96     *
97     * @see #TYPE_INSTALL_AUTOMATIC
98     */
99    public static SystemUpdatePolicy createAutomaticInstallPolicy() {
100        SystemUpdatePolicy policy = new SystemUpdatePolicy();
101        policy.mPolicyType = TYPE_INSTALL_AUTOMATIC;
102        return policy;
103    }
104
105    /**
106     * Create a policy object and set it to: new system update will only be installed automatically
107     * when the system clock is inside a daily maintenance window. If the start and end times are
108     * the same, the window is considered to include the WHOLE 24 hours, that is, updates can
109     * install at any time. If the given window in invalid, a {@link IllegalArgumentException} will
110     * be thrown. If start time is later than end time, the window is considered spanning midnight,
111     * i.e. end time donates a time on the next day. The maintenance window will last for 30 days,
112     * after which the system should revert back to its normal behavior as if no policy were set.
113     *
114     * @param startTime the start of the maintenance window, measured as the number of minutes from
115     *            midnight in the device's local time. Must be in the range of [0, 1440).
116     * @param endTime the end of the maintenance window, measured as the number of minutes from
117     *            midnight in the device's local time. Must be in the range of [0, 1440).
118     * @see #TYPE_INSTALL_WINDOWED
119     */
120    public static SystemUpdatePolicy createWindowedInstallPolicy(int startTime, int endTime) {
121        if (startTime < 0 || startTime >= WINDOW_BOUNDARY
122                || endTime < 0 || endTime >= WINDOW_BOUNDARY) {
123            throw new IllegalArgumentException("startTime and endTime must be inside [0, 1440)");
124        }
125        SystemUpdatePolicy policy = new SystemUpdatePolicy();
126        policy.mPolicyType = TYPE_INSTALL_WINDOWED;
127        policy.mMaintenanceWindowStart = startTime;
128        policy.mMaintenanceWindowEnd = endTime;
129        return policy;
130    }
131
132    /**
133     * Create a policy object and set it to block installation for a maximum period of 30 days.
134     * After expiration the system should revert back to its normal behavior as if no policy were
135     * set.
136     *
137     * @see #TYPE_POSTPONE
138     */
139    public static SystemUpdatePolicy createPostponeInstallPolicy() {
140        SystemUpdatePolicy policy = new SystemUpdatePolicy();
141        policy.mPolicyType = TYPE_POSTPONE;
142        return policy;
143    }
144
145    /**
146     * Returns the type of system update policy.
147     *
148     * @return an integer, either one of {@link #TYPE_INSTALL_AUTOMATIC},
149     * {@link #TYPE_INSTALL_WINDOWED} and {@link #TYPE_POSTPONE}, or -1 if no policy has been set.
150     */
151    @SystemUpdatePolicyType
152    public int getPolicyType() {
153        return mPolicyType;
154    }
155
156    /**
157     * Get the start of the maintenance window.
158     *
159     * @return the start of the maintenance window measured as the number of minutes from midnight,
160     * or -1 if the policy does not have a maintenance window.
161     */
162    public int getInstallWindowStart() {
163        if (mPolicyType == TYPE_INSTALL_WINDOWED) {
164            return mMaintenanceWindowStart;
165        } else {
166            return -1;
167        }
168    }
169
170    /**
171     * Get the end of the maintenance window.
172     *
173     * @return the end of the maintenance window measured as the number of minutes from midnight,
174     * or -1 if the policy does not have a maintenance window.
175     */
176    public int getInstallWindowEnd() {
177        if (mPolicyType == TYPE_INSTALL_WINDOWED) {
178            return mMaintenanceWindowEnd;
179        } else {
180            return -1;
181        }
182    }
183
184    /**
185     * Return if this object represents a valid policy.
186     * @hide
187     */
188    public boolean isValid() {
189        if (mPolicyType == TYPE_INSTALL_AUTOMATIC || mPolicyType == TYPE_POSTPONE) {
190            return true;
191        } else if (mPolicyType == TYPE_INSTALL_WINDOWED) {
192            return mMaintenanceWindowStart >= 0 && mMaintenanceWindowStart < WINDOW_BOUNDARY
193                    && mMaintenanceWindowEnd >= 0 && mMaintenanceWindowEnd < WINDOW_BOUNDARY;
194        } else {
195            return false;
196        }
197    }
198
199    @Override
200    public String toString() {
201        return String.format("SystemUpdatePolicy (type: %d, windowStart: %d, windowEnd: %d)",
202                mPolicyType, mMaintenanceWindowStart, mMaintenanceWindowEnd);
203    }
204
205    @Override
206    public int describeContents() {
207        return 0;
208    }
209
210    @Override
211    public void writeToParcel(Parcel dest, int flags) {
212        dest.writeInt(mPolicyType);
213        dest.writeInt(mMaintenanceWindowStart);
214        dest.writeInt(mMaintenanceWindowEnd);
215    }
216
217    public static final Parcelable.Creator<SystemUpdatePolicy> CREATOR =
218            new Parcelable.Creator<SystemUpdatePolicy>() {
219
220                @Override
221                public SystemUpdatePolicy createFromParcel(Parcel source) {
222                    SystemUpdatePolicy policy = new SystemUpdatePolicy();
223                    policy.mPolicyType = source.readInt();
224                    policy.mMaintenanceWindowStart = source.readInt();
225                    policy.mMaintenanceWindowEnd = source.readInt();
226                    return policy;
227                }
228
229                @Override
230                public SystemUpdatePolicy[] newArray(int size) {
231                    return new SystemUpdatePolicy[size];
232                }
233    };
234
235
236    /**
237     * @hide
238     */
239    public static SystemUpdatePolicy restoreFromXml(XmlPullParser parser) {
240        try {
241            SystemUpdatePolicy policy = new SystemUpdatePolicy();
242            String value = parser.getAttributeValue(null, KEY_POLICY_TYPE);
243            if (value != null) {
244                policy.mPolicyType = Integer.parseInt(value);
245
246                value = parser.getAttributeValue(null, KEY_INSTALL_WINDOW_START);
247                if (value != null) {
248                    policy.mMaintenanceWindowStart = Integer.parseInt(value);
249                }
250                value = parser.getAttributeValue(null, KEY_INSTALL_WINDOW_END);
251                if (value != null) {
252                    policy.mMaintenanceWindowEnd = Integer.parseInt(value);
253                }
254                return policy;
255            }
256        } catch (NumberFormatException e) {
257            // Fail through
258        }
259        return null;
260    }
261
262    /**
263     * @hide
264     */
265    public void saveToXml(XmlSerializer out) throws IOException {
266        out.attribute(null, KEY_POLICY_TYPE, Integer.toString(mPolicyType));
267        out.attribute(null, KEY_INSTALL_WINDOW_START, Integer.toString(mMaintenanceWindowStart));
268        out.attribute(null, KEY_INSTALL_WINDOW_END, Integer.toString(mMaintenanceWindowEnd));
269    }
270}
271
272