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 static android.net.NetworkStats.METERED_ALL;
20 import static android.net.NetworkStats.METERED_YES;
21 import static android.net.NetworkTemplate.MATCH_BLUETOOTH;
22 import static android.net.NetworkTemplate.MATCH_CARRIER;
23 import static android.net.NetworkTemplate.MATCH_ETHERNET;
24 import static android.net.NetworkTemplate.MATCH_MOBILE;
25 import static android.net.NetworkTemplate.MATCH_WIFI;
26 
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.compat.annotation.UnsupportedAppUsage;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 import android.util.BackupUtils;
33 import android.util.Log;
34 import android.util.Range;
35 import android.util.RecurrenceRule;
36 
37 import com.android.internal.util.Preconditions;
38 
39 import java.io.ByteArrayOutputStream;
40 import java.io.DataInputStream;
41 import java.io.DataOutputStream;
42 import java.io.IOException;
43 import java.time.ZoneId;
44 import java.time.ZonedDateTime;
45 import java.util.Iterator;
46 import java.util.Objects;
47 import java.util.Set;
48 
49 /**
50  * Policy for networks matching a {@link NetworkTemplate}, including usage cycle
51  * and limits to be enforced.
52  *
53  * @hide
54  */
55 public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
56     private static final String TAG = NetworkPolicy.class.getSimpleName();
57     private static final int VERSION_INIT = 1;
58     private static final int VERSION_RULE = 2;
59     private static final int VERSION_RAPID = 3;
60 
61     /**
62      * Initial Version of the NetworkTemplate backup serializer.
63      */
64     private static final int TEMPLATE_BACKUP_VERSION_1_INIT = 1;
65     private static final int TEMPLATE_BACKUP_VERSION_2_UNSUPPORTED = 2;
66     /**
67      * Version of the NetworkTemplate backup serializer that added carrier template support.
68      */
69     private static final int TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE = 3;
70     /**
71      * Latest Version of the NetworkTemplate Backup Serializer.
72      */
73     private static final int TEMPLATE_BACKUP_VERSION_LATEST =
74             TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE;
75 
76     public static final int CYCLE_NONE = -1;
77     public static final long WARNING_DISABLED = -1;
78     public static final long LIMIT_DISABLED = -1;
79     public static final long SNOOZE_NEVER = -1;
80 
81     @UnsupportedAppUsage
82     public NetworkTemplate template;
83     public RecurrenceRule cycleRule;
84     @UnsupportedAppUsage
85     public long warningBytes = WARNING_DISABLED;
86     @UnsupportedAppUsage
87     public long limitBytes = LIMIT_DISABLED;
88     public long lastWarningSnooze = SNOOZE_NEVER;
89     public long lastLimitSnooze = SNOOZE_NEVER;
90     public long lastRapidSnooze = SNOOZE_NEVER;
91     @UnsupportedAppUsage
92     @Deprecated public boolean metered = true;
93     @UnsupportedAppUsage
94     public boolean inferred = false;
95 
96     private static final long DEFAULT_MTU = 1500;
97 
buildRule(int cycleDay, ZoneId cycleTimezone)98     public static RecurrenceRule buildRule(int cycleDay, ZoneId cycleTimezone) {
99         if (cycleDay != NetworkPolicy.CYCLE_NONE) {
100             return RecurrenceRule.buildRecurringMonthly(cycleDay, cycleTimezone);
101         } else {
102             return RecurrenceRule.buildNever();
103         }
104     }
105 
106     @Deprecated
NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone, long warningBytes, long limitBytes, boolean metered)107     public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone,
108             long warningBytes, long limitBytes, boolean metered) {
109         this(template, cycleDay, cycleTimezone, warningBytes, limitBytes, SNOOZE_NEVER,
110                 SNOOZE_NEVER, metered, false);
111     }
112 
113     @Deprecated
114     @UnsupportedAppUsage
NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone, long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered, boolean inferred)115     public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone,
116             long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze,
117             boolean metered, boolean inferred) {
118         this(template, buildRule(cycleDay, ZoneId.of(cycleTimezone)), warningBytes,
119                 limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred);
120     }
121 
122     @Deprecated
NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered, boolean inferred)123     public NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes,
124             long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered,
125             boolean inferred) {
126         this(template, cycleRule, warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze,
127                 SNOOZE_NEVER, metered, inferred);
128     }
129 
NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze, long lastRapidSnooze, boolean metered, boolean inferred)130     public NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes,
131             long limitBytes, long lastWarningSnooze, long lastLimitSnooze, long lastRapidSnooze,
132             boolean metered, boolean inferred) {
133         this.template = Preconditions.checkNotNull(template, "missing NetworkTemplate");
134         this.cycleRule = Preconditions.checkNotNull(cycleRule, "missing RecurrenceRule");
135         this.warningBytes = warningBytes;
136         this.limitBytes = limitBytes;
137         this.lastWarningSnooze = lastWarningSnooze;
138         this.lastLimitSnooze = lastLimitSnooze;
139         this.lastRapidSnooze = lastRapidSnooze;
140         this.metered = metered;
141         this.inferred = inferred;
142     }
143 
NetworkPolicy(Parcel source)144     private NetworkPolicy(Parcel source) {
145         template = source.readParcelable(null, android.net.NetworkTemplate.class);
146         cycleRule = source.readParcelable(null, android.util.RecurrenceRule.class);
147         warningBytes = source.readLong();
148         limitBytes = source.readLong();
149         lastWarningSnooze = source.readLong();
150         lastLimitSnooze = source.readLong();
151         lastRapidSnooze = source.readLong();
152         metered = source.readInt() != 0;
153         inferred = source.readInt() != 0;
154     }
155 
156     @Override
writeToParcel(Parcel dest, int flags)157     public void writeToParcel(Parcel dest, int flags) {
158         dest.writeParcelable(template, flags);
159         dest.writeParcelable(cycleRule, flags);
160         dest.writeLong(warningBytes);
161         dest.writeLong(limitBytes);
162         dest.writeLong(lastWarningSnooze);
163         dest.writeLong(lastLimitSnooze);
164         dest.writeLong(lastRapidSnooze);
165         dest.writeInt(metered ? 1 : 0);
166         dest.writeInt(inferred ? 1 : 0);
167     }
168 
169     @Override
describeContents()170     public int describeContents() {
171         return 0;
172     }
173 
cycleIterator()174     public Iterator<Range<ZonedDateTime>> cycleIterator() {
175         return cycleRule.cycleIterator();
176     }
177 
178     /**
179      * Test if given measurement is over {@link #warningBytes}.
180      */
181     @UnsupportedAppUsage
isOverWarning(long totalBytes)182     public boolean isOverWarning(long totalBytes) {
183         return warningBytes != WARNING_DISABLED && totalBytes >= warningBytes;
184     }
185 
186     /**
187      * Test if given measurement is near enough to {@link #limitBytes} to be
188      * considered over-limit.
189      */
190     @UnsupportedAppUsage
isOverLimit(long totalBytes)191     public boolean isOverLimit(long totalBytes) {
192         // over-estimate, since kernel will trigger limit once first packet
193         // trips over limit.
194         totalBytes += 2 * DEFAULT_MTU;
195         return limitBytes != LIMIT_DISABLED && totalBytes >= limitBytes;
196     }
197 
198     /**
199      * Clear any existing snooze values, setting to {@link #SNOOZE_NEVER}.
200      */
201     @UnsupportedAppUsage
clearSnooze()202     public void clearSnooze() {
203         lastWarningSnooze = SNOOZE_NEVER;
204         lastLimitSnooze = SNOOZE_NEVER;
205         lastRapidSnooze = SNOOZE_NEVER;
206     }
207 
208     /**
209      * Test if this policy has a cycle defined, after which usage should reset.
210      */
hasCycle()211     public boolean hasCycle() {
212         return cycleRule.cycleIterator().hasNext();
213     }
214 
215     @Override
216     @UnsupportedAppUsage
compareTo(NetworkPolicy another)217     public int compareTo(NetworkPolicy another) {
218         if (another == null || another.limitBytes == LIMIT_DISABLED) {
219             // other value is missing or disabled; we win
220             return -1;
221         }
222         if (limitBytes == LIMIT_DISABLED || another.limitBytes < limitBytes) {
223             // we're disabled or other limit is smaller; they win
224             return 1;
225         }
226         return 0;
227     }
228 
229     @Override
hashCode()230     public int hashCode() {
231         return Objects.hash(template, cycleRule, warningBytes, limitBytes,
232                 lastWarningSnooze, lastLimitSnooze, lastRapidSnooze, metered, inferred);
233     }
234 
235     @Override
equals(@ullable Object obj)236     public boolean equals(@Nullable Object obj) {
237         if (obj instanceof NetworkPolicy) {
238             final NetworkPolicy other = (NetworkPolicy) obj;
239             return warningBytes == other.warningBytes
240                     && limitBytes == other.limitBytes
241                     && lastWarningSnooze == other.lastWarningSnooze
242                     && lastLimitSnooze == other.lastLimitSnooze
243                     && lastRapidSnooze == other.lastRapidSnooze
244                     && metered == other.metered
245                     && inferred == other.inferred
246                     && Objects.equals(template, other.template)
247                     && Objects.equals(cycleRule, other.cycleRule);
248         }
249         return false;
250     }
251 
252     @Override
toString()253     public String toString() {
254         return new StringBuilder("NetworkPolicy{")
255                 .append("template=").append(template)
256                 .append(" cycleRule=").append(cycleRule)
257                 .append(" warningBytes=").append(warningBytes)
258                 .append(" limitBytes=").append(limitBytes)
259                 .append(" lastWarningSnooze=").append(lastWarningSnooze)
260                 .append(" lastLimitSnooze=").append(lastLimitSnooze)
261                 .append(" lastRapidSnooze=").append(lastRapidSnooze)
262                 .append(" metered=").append(metered)
263                 .append(" inferred=").append(inferred)
264                 .append("}").toString();
265     }
266 
267     @UnsupportedAppUsage
268     public static final @android.annotation.NonNull Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
269         @Override
270         public NetworkPolicy createFromParcel(Parcel in) {
271             return new NetworkPolicy(in);
272         }
273 
274         @Override
275         public NetworkPolicy[] newArray(int size) {
276             return new NetworkPolicy[size];
277         }
278     };
279 
getBytesForBackup()280     public byte[] getBytesForBackup() throws IOException {
281         ByteArrayOutputStream baos = new ByteArrayOutputStream();
282         DataOutputStream out = new DataOutputStream(baos);
283 
284         out.writeInt(VERSION_RAPID);
285         out.write(getNetworkTemplateBytesForBackup());
286         cycleRule.writeToStream(out);
287         out.writeLong(warningBytes);
288         out.writeLong(limitBytes);
289         out.writeLong(lastWarningSnooze);
290         out.writeLong(lastLimitSnooze);
291         out.writeLong(lastRapidSnooze);
292         out.writeInt(metered ? 1 : 0);
293         out.writeInt(inferred ? 1 : 0);
294         return baos.toByteArray();
295     }
296 
getNetworkPolicyFromBackup(DataInputStream in)297     public static NetworkPolicy getNetworkPolicyFromBackup(DataInputStream in) throws IOException,
298             BackupUtils.BadVersionException {
299         final int version = in.readInt();
300         if (version < VERSION_INIT || version > VERSION_RAPID) {
301             throw new BackupUtils.BadVersionException("Unknown backup version: " + version);
302         }
303 
304         final NetworkTemplate template = getNetworkTemplateFromBackup(in);
305         final RecurrenceRule cycleRule;
306         if (version >= VERSION_RULE) {
307             cycleRule = new RecurrenceRule(in);
308         } else {
309             final int cycleDay = in.readInt();
310             final String cycleTimezone = BackupUtils.readString(in);
311             cycleRule = buildRule(cycleDay, ZoneId.of(cycleTimezone));
312         }
313         final long warningBytes = in.readLong();
314         final long limitBytes = in.readLong();
315         final long lastWarningSnooze = in.readLong();
316         final long lastLimitSnooze = in.readLong();
317         final long lastRapidSnooze;
318         if (version >= VERSION_RAPID) {
319             lastRapidSnooze = in.readLong();
320         } else {
321             lastRapidSnooze = SNOOZE_NEVER;
322         }
323         final boolean metered = in.readInt() == 1;
324         final boolean inferred = in.readInt() == 1;
325         return new NetworkPolicy(template, cycleRule, warningBytes, limitBytes, lastWarningSnooze,
326                 lastLimitSnooze, lastRapidSnooze, metered, inferred);
327     }
328 
329     @NonNull
getNetworkTemplateBytesForBackup()330     private byte[] getNetworkTemplateBytesForBackup() throws IOException {
331         if (!isTemplatePersistable(this.template)) {
332             Log.wtf(TAG, "Trying to backup non-persistable template: " + this);
333         }
334 
335         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
336         final DataOutputStream out = new DataOutputStream(baos);
337 
338         out.writeInt(TEMPLATE_BACKUP_VERSION_LATEST);
339 
340         out.writeInt(template.getMatchRule());
341         final Set<String> subscriberIds = template.getSubscriberIds();
342         BackupUtils.writeString(out, subscriberIds.isEmpty()
343                 ? null : subscriberIds.iterator().next());
344         BackupUtils.writeString(out, template.getWifiNetworkKeys().isEmpty()
345                 ? null : template.getWifiNetworkKeys().iterator().next());
346         out.writeInt(template.getMeteredness());
347 
348         return baos.toByteArray();
349     }
350 
351     @NonNull
getNetworkTemplateFromBackup(DataInputStream in)352     private static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
353             throws IOException, BackupUtils.BadVersionException {
354         int version = in.readInt();
355         if (version < TEMPLATE_BACKUP_VERSION_1_INIT || version > TEMPLATE_BACKUP_VERSION_LATEST
356                 || version == TEMPLATE_BACKUP_VERSION_2_UNSUPPORTED) {
357             throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
358         }
359 
360         int matchRule = in.readInt();
361         final String subscriberId = BackupUtils.readString(in);
362         final String wifiNetworkKey = BackupUtils.readString(in);
363 
364         final int metered;
365         if (version >= TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE) {
366             metered = in.readInt();
367         } else {
368             // For backward compatibility, fill the missing filters from match rules.
369             metered = (matchRule == MATCH_MOBILE || matchRule == MATCH_CARRIER)
370                     ? METERED_YES : METERED_ALL;
371         }
372 
373         try {
374             final NetworkTemplate.Builder builder = new NetworkTemplate.Builder(matchRule)
375                     .setMeteredness(metered);
376             if (subscriberId != null) {
377                 builder.setSubscriberIds(Set.of(subscriberId));
378             }
379             if (wifiNetworkKey != null) {
380                 builder.setWifiNetworkKeys(Set.of(wifiNetworkKey));
381             }
382             return builder.build();
383         } catch (IllegalArgumentException e) {
384             throw new BackupUtils.BadVersionException(
385                     "Restored network template contains unknown match rule " + matchRule, e);
386         }
387     }
388 
389     /**
390      * Check if the template can be persisted into disk.
391      */
isTemplatePersistable(@onNull NetworkTemplate template)392     public static boolean isTemplatePersistable(@NonNull NetworkTemplate template) {
393         switch (template.getMatchRule()) {
394             case MATCH_BLUETOOTH:
395             case MATCH_ETHERNET:
396                 return true;
397             case MATCH_CARRIER:
398             case MATCH_MOBILE:
399                 return !template.getSubscriberIds().isEmpty()
400                         && template.getMeteredness() == METERED_YES;
401             case MATCH_WIFI:
402                 if (template.getWifiNetworkKeys().isEmpty()
403                         && template.getSubscriberIds().isEmpty()) {
404                     return false;
405                 }
406                 return true;
407             default:
408                 // Don't allow persistable for unknown types or legacy types such as
409                 // MATCH_MOBILE_WILDCARD, MATCH_PROXY, etc.
410                 return false;
411         }
412     }
413 }
414