1 /*
2  * Copyright (C) 2011 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.net;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 import android.util.BackupUtils;
23 import android.util.Range;
24 import android.util.RecurrenceRule;
25 
26 import com.android.internal.util.Preconditions;
27 
28 import java.io.ByteArrayOutputStream;
29 import java.io.DataInputStream;
30 import java.io.DataOutputStream;
31 import java.io.IOException;
32 import java.time.ZoneId;
33 import java.time.ZonedDateTime;
34 import java.util.Iterator;
35 import java.util.Objects;
36 
37 /**
38  * Policy for networks matching a {@link NetworkTemplate}, including usage cycle
39  * and limits to be enforced.
40  *
41  * @hide
42  */
43 public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
44     private static final int VERSION_INIT = 1;
45     private static final int VERSION_RULE = 2;
46     private static final int VERSION_RAPID = 3;
47 
48     public static final int CYCLE_NONE = -1;
49     public static final long WARNING_DISABLED = -1;
50     public static final long LIMIT_DISABLED = -1;
51     public static final long SNOOZE_NEVER = -1;
52 
53     @UnsupportedAppUsage
54     public NetworkTemplate template;
55     public RecurrenceRule cycleRule;
56     @UnsupportedAppUsage
57     public long warningBytes = WARNING_DISABLED;
58     @UnsupportedAppUsage
59     public long limitBytes = LIMIT_DISABLED;
60     public long lastWarningSnooze = SNOOZE_NEVER;
61     public long lastLimitSnooze = SNOOZE_NEVER;
62     public long lastRapidSnooze = SNOOZE_NEVER;
63     @UnsupportedAppUsage
64     @Deprecated public boolean metered = true;
65     @UnsupportedAppUsage
66     public boolean inferred = false;
67 
68     private static final long DEFAULT_MTU = 1500;
69 
buildRule(int cycleDay, ZoneId cycleTimezone)70     public static RecurrenceRule buildRule(int cycleDay, ZoneId cycleTimezone) {
71         if (cycleDay != NetworkPolicy.CYCLE_NONE) {
72             return RecurrenceRule.buildRecurringMonthly(cycleDay, cycleTimezone);
73         } else {
74             return RecurrenceRule.buildNever();
75         }
76     }
77 
78     @Deprecated
NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone, long warningBytes, long limitBytes, boolean metered)79     public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone,
80             long warningBytes, long limitBytes, boolean metered) {
81         this(template, cycleDay, cycleTimezone, warningBytes, limitBytes, SNOOZE_NEVER,
82                 SNOOZE_NEVER, metered, false);
83     }
84 
85     @Deprecated
86     @UnsupportedAppUsage
NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone, long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered, boolean inferred)87     public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone,
88             long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze,
89             boolean metered, boolean inferred) {
90         this(template, buildRule(cycleDay, ZoneId.of(cycleTimezone)), warningBytes,
91                 limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred);
92     }
93 
94     @Deprecated
NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered, boolean inferred)95     public NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes,
96             long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered,
97             boolean inferred) {
98         this(template, cycleRule, warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze,
99                 SNOOZE_NEVER, metered, inferred);
100     }
101 
NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze, long lastRapidSnooze, boolean metered, boolean inferred)102     public NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes,
103             long limitBytes, long lastWarningSnooze, long lastLimitSnooze, long lastRapidSnooze,
104             boolean metered, boolean inferred) {
105         this.template = Preconditions.checkNotNull(template, "missing NetworkTemplate");
106         this.cycleRule = Preconditions.checkNotNull(cycleRule, "missing RecurrenceRule");
107         this.warningBytes = warningBytes;
108         this.limitBytes = limitBytes;
109         this.lastWarningSnooze = lastWarningSnooze;
110         this.lastLimitSnooze = lastLimitSnooze;
111         this.lastRapidSnooze = lastRapidSnooze;
112         this.metered = metered;
113         this.inferred = inferred;
114     }
115 
NetworkPolicy(Parcel source)116     private NetworkPolicy(Parcel source) {
117         template = source.readParcelable(null);
118         cycleRule = source.readParcelable(null);
119         warningBytes = source.readLong();
120         limitBytes = source.readLong();
121         lastWarningSnooze = source.readLong();
122         lastLimitSnooze = source.readLong();
123         lastRapidSnooze = source.readLong();
124         metered = source.readInt() != 0;
125         inferred = source.readInt() != 0;
126     }
127 
128     @Override
writeToParcel(Parcel dest, int flags)129     public void writeToParcel(Parcel dest, int flags) {
130         dest.writeParcelable(template, flags);
131         dest.writeParcelable(cycleRule, flags);
132         dest.writeLong(warningBytes);
133         dest.writeLong(limitBytes);
134         dest.writeLong(lastWarningSnooze);
135         dest.writeLong(lastLimitSnooze);
136         dest.writeLong(lastRapidSnooze);
137         dest.writeInt(metered ? 1 : 0);
138         dest.writeInt(inferred ? 1 : 0);
139     }
140 
141     @Override
describeContents()142     public int describeContents() {
143         return 0;
144     }
145 
cycleIterator()146     public Iterator<Range<ZonedDateTime>> cycleIterator() {
147         return cycleRule.cycleIterator();
148     }
149 
150     /**
151      * Test if given measurement is over {@link #warningBytes}.
152      */
153     @UnsupportedAppUsage
isOverWarning(long totalBytes)154     public boolean isOverWarning(long totalBytes) {
155         return warningBytes != WARNING_DISABLED && totalBytes >= warningBytes;
156     }
157 
158     /**
159      * Test if given measurement is near enough to {@link #limitBytes} to be
160      * considered over-limit.
161      */
162     @UnsupportedAppUsage
isOverLimit(long totalBytes)163     public boolean isOverLimit(long totalBytes) {
164         // over-estimate, since kernel will trigger limit once first packet
165         // trips over limit.
166         totalBytes += 2 * DEFAULT_MTU;
167         return limitBytes != LIMIT_DISABLED && totalBytes >= limitBytes;
168     }
169 
170     /**
171      * Clear any existing snooze values, setting to {@link #SNOOZE_NEVER}.
172      */
173     @UnsupportedAppUsage
clearSnooze()174     public void clearSnooze() {
175         lastWarningSnooze = SNOOZE_NEVER;
176         lastLimitSnooze = SNOOZE_NEVER;
177         lastRapidSnooze = SNOOZE_NEVER;
178     }
179 
180     /**
181      * Test if this policy has a cycle defined, after which usage should reset.
182      */
hasCycle()183     public boolean hasCycle() {
184         return cycleRule.cycleIterator().hasNext();
185     }
186 
187     @Override
188     @UnsupportedAppUsage
compareTo(NetworkPolicy another)189     public int compareTo(NetworkPolicy another) {
190         if (another == null || another.limitBytes == LIMIT_DISABLED) {
191             // other value is missing or disabled; we win
192             return -1;
193         }
194         if (limitBytes == LIMIT_DISABLED || another.limitBytes < limitBytes) {
195             // we're disabled or other limit is smaller; they win
196             return 1;
197         }
198         return 0;
199     }
200 
201     @Override
hashCode()202     public int hashCode() {
203         return Objects.hash(template, cycleRule, warningBytes, limitBytes,
204                 lastWarningSnooze, lastLimitSnooze, lastRapidSnooze, metered, inferred);
205     }
206 
207     @Override
equals(Object obj)208     public boolean equals(Object obj) {
209         if (obj instanceof NetworkPolicy) {
210             final NetworkPolicy other = (NetworkPolicy) obj;
211             return warningBytes == other.warningBytes
212                     && limitBytes == other.limitBytes
213                     && lastWarningSnooze == other.lastWarningSnooze
214                     && lastLimitSnooze == other.lastLimitSnooze
215                     && lastRapidSnooze == other.lastRapidSnooze
216                     && metered == other.metered
217                     && inferred == other.inferred
218                     && Objects.equals(template, other.template)
219                     && Objects.equals(cycleRule, other.cycleRule);
220         }
221         return false;
222     }
223 
224     @Override
toString()225     public String toString() {
226         return new StringBuilder("NetworkPolicy{")
227                 .append("template=").append(template)
228                 .append(" cycleRule=").append(cycleRule)
229                 .append(" warningBytes=").append(warningBytes)
230                 .append(" limitBytes=").append(limitBytes)
231                 .append(" lastWarningSnooze=").append(lastWarningSnooze)
232                 .append(" lastLimitSnooze=").append(lastLimitSnooze)
233                 .append(" lastRapidSnooze=").append(lastRapidSnooze)
234                 .append(" metered=").append(metered)
235                 .append(" inferred=").append(inferred)
236                 .append("}").toString();
237     }
238 
239     @UnsupportedAppUsage
240     public static final @android.annotation.NonNull Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
241         @Override
242         public NetworkPolicy createFromParcel(Parcel in) {
243             return new NetworkPolicy(in);
244         }
245 
246         @Override
247         public NetworkPolicy[] newArray(int size) {
248             return new NetworkPolicy[size];
249         }
250     };
251 
getBytesForBackup()252     public byte[] getBytesForBackup() throws IOException {
253         ByteArrayOutputStream baos = new ByteArrayOutputStream();
254         DataOutputStream out = new DataOutputStream(baos);
255 
256         out.writeInt(VERSION_RAPID);
257         out.write(template.getBytesForBackup());
258         cycleRule.writeToStream(out);
259         out.writeLong(warningBytes);
260         out.writeLong(limitBytes);
261         out.writeLong(lastWarningSnooze);
262         out.writeLong(lastLimitSnooze);
263         out.writeLong(lastRapidSnooze);
264         out.writeInt(metered ? 1 : 0);
265         out.writeInt(inferred ? 1 : 0);
266         return baos.toByteArray();
267     }
268 
getNetworkPolicyFromBackup(DataInputStream in)269     public static NetworkPolicy getNetworkPolicyFromBackup(DataInputStream in) throws IOException,
270             BackupUtils.BadVersionException {
271         final int version = in.readInt();
272         if (version < VERSION_INIT || version > VERSION_RAPID) {
273             throw new BackupUtils.BadVersionException("Unknown backup version: " + version);
274         }
275 
276         final NetworkTemplate template = NetworkTemplate.getNetworkTemplateFromBackup(in);
277         final RecurrenceRule cycleRule;
278         if (version >= VERSION_RULE) {
279             cycleRule = new RecurrenceRule(in);
280         } else {
281             final int cycleDay = in.readInt();
282             final String cycleTimezone = BackupUtils.readString(in);
283             cycleRule = buildRule(cycleDay, ZoneId.of(cycleTimezone));
284         }
285         final long warningBytes = in.readLong();
286         final long limitBytes = in.readLong();
287         final long lastWarningSnooze = in.readLong();
288         final long lastLimitSnooze = in.readLong();
289         final long lastRapidSnooze;
290         if (version >= VERSION_RAPID) {
291             lastRapidSnooze = in.readLong();
292         } else {
293             lastRapidSnooze = SNOOZE_NEVER;
294         }
295         final boolean metered = in.readInt() == 1;
296         final boolean inferred = in.readInt() == 1;
297         return new NetworkPolicy(template, cycleRule, warningBytes, limitBytes, lastWarningSnooze,
298                 lastLimitSnooze, lastRapidSnooze, metered, inferred);
299     }
300 }
301