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