/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.net;

import android.os.Parcel;
import android.os.Parcelable;
import android.util.BackupUtils;
import android.util.Range;
import android.util.RecurrenceRule;

import com.android.internal.util.Preconditions;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Iterator;
import java.util.Objects;

Policy for networks matching a NetworkTemplate, including usage cycle and limits to be enforced.
@hide
/** * Policy for networks matching a {@link NetworkTemplate}, including usage cycle * and limits to be enforced. * * @hide */
public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> { private static final int VERSION_INIT = 1; private static final int VERSION_RULE = 2; private static final int VERSION_RAPID = 3; public static final int CYCLE_NONE = -1; public static final long WARNING_DISABLED = -1; public static final long LIMIT_DISABLED = -1; public static final long SNOOZE_NEVER = -1; public NetworkTemplate template; public RecurrenceRule cycleRule; public long warningBytes = WARNING_DISABLED; public long limitBytes = LIMIT_DISABLED; public long lastWarningSnooze = SNOOZE_NEVER; public long lastLimitSnooze = SNOOZE_NEVER; public long lastRapidSnooze = SNOOZE_NEVER; @Deprecated public boolean metered = true; public boolean inferred = false; private static final long DEFAULT_MTU = 1500; public static RecurrenceRule buildRule(int cycleDay, ZoneId cycleTimezone) { if (cycleDay != NetworkPolicy.CYCLE_NONE) { return RecurrenceRule.buildRecurringMonthly(cycleDay, cycleTimezone); } else { return RecurrenceRule.buildNever(); } } @Deprecated public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone, long warningBytes, long limitBytes, boolean metered) { this(template, cycleDay, cycleTimezone, warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, metered, false); } @Deprecated public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone, long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered, boolean inferred) { this(template, buildRule(cycleDay, ZoneId.of(cycleTimezone)), warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred); } @Deprecated public NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered, boolean inferred) { this(template, cycleRule, warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze, SNOOZE_NEVER, metered, inferred); } public NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze, long lastRapidSnooze, boolean metered, boolean inferred) { this.template = Preconditions.checkNotNull(template, "missing NetworkTemplate"); this.cycleRule = Preconditions.checkNotNull(cycleRule, "missing RecurrenceRule"); this.warningBytes = warningBytes; this.limitBytes = limitBytes; this.lastWarningSnooze = lastWarningSnooze; this.lastLimitSnooze = lastLimitSnooze; this.lastRapidSnooze = lastRapidSnooze; this.metered = metered; this.inferred = inferred; } private NetworkPolicy(Parcel source) { template = source.readParcelable(null); cycleRule = source.readParcelable(null); warningBytes = source.readLong(); limitBytes = source.readLong(); lastWarningSnooze = source.readLong(); lastLimitSnooze = source.readLong(); lastRapidSnooze = source.readLong(); metered = source.readInt() != 0; inferred = source.readInt() != 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(template, flags); dest.writeParcelable(cycleRule, flags); dest.writeLong(warningBytes); dest.writeLong(limitBytes); dest.writeLong(lastWarningSnooze); dest.writeLong(lastLimitSnooze); dest.writeLong(lastRapidSnooze); dest.writeInt(metered ? 1 : 0); dest.writeInt(inferred ? 1 : 0); } @Override public int describeContents() { return 0; } public Iterator<Range<ZonedDateTime>> cycleIterator() { return cycleRule.cycleIterator(); }
Test if given measurement is over warningBytes.
/** * Test if given measurement is over {@link #warningBytes}. */
public boolean isOverWarning(long totalBytes) { return warningBytes != WARNING_DISABLED && totalBytes >= warningBytes; }
Test if given measurement is near enough to limitBytes to be considered over-limit.
/** * Test if given measurement is near enough to {@link #limitBytes} to be * considered over-limit. */
public boolean isOverLimit(long totalBytes) { // over-estimate, since kernel will trigger limit once first packet // trips over limit. totalBytes += 2 * DEFAULT_MTU; return limitBytes != LIMIT_DISABLED && totalBytes >= limitBytes; }
Clear any existing snooze values, setting to SNOOZE_NEVER.
/** * Clear any existing snooze values, setting to {@link #SNOOZE_NEVER}. */
public void clearSnooze() { lastWarningSnooze = SNOOZE_NEVER; lastLimitSnooze = SNOOZE_NEVER; lastRapidSnooze = SNOOZE_NEVER; }
Test if this policy has a cycle defined, after which usage should reset.
/** * Test if this policy has a cycle defined, after which usage should reset. */
public boolean hasCycle() { return cycleRule.cycleIterator().hasNext(); } @Override public int compareTo(NetworkPolicy another) { if (another == null || another.limitBytes == LIMIT_DISABLED) { // other value is missing or disabled; we win return -1; } if (limitBytes == LIMIT_DISABLED || another.limitBytes < limitBytes) { // we're disabled or other limit is smaller; they win return 1; } return 0; } @Override public int hashCode() { return Objects.hash(template, cycleRule, warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze, lastRapidSnooze, metered, inferred); } @Override public boolean equals(Object obj) { if (obj instanceof NetworkPolicy) { final NetworkPolicy other = (NetworkPolicy) obj; return warningBytes == other.warningBytes && limitBytes == other.limitBytes && lastWarningSnooze == other.lastWarningSnooze && lastLimitSnooze == other.lastLimitSnooze && lastRapidSnooze == other.lastRapidSnooze && metered == other.metered && inferred == other.inferred && Objects.equals(template, other.template) && Objects.equals(cycleRule, other.cycleRule); } return false; } @Override public String toString() { return new StringBuilder("NetworkPolicy{") .append("template=").append(template) .append(" cycleRule=").append(cycleRule) .append(" warningBytes=").append(warningBytes) .append(" limitBytes=").append(limitBytes) .append(" lastWarningSnooze=").append(lastWarningSnooze) .append(" lastLimitSnooze=").append(lastLimitSnooze) .append(" lastRapidSnooze=").append(lastRapidSnooze) .append(" metered=").append(metered) .append(" inferred=").append(inferred) .append("}").toString(); } public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() { @Override public NetworkPolicy createFromParcel(Parcel in) { return new NetworkPolicy(in); } @Override public NetworkPolicy[] newArray(int size) { return new NetworkPolicy[size]; } }; public byte[] getBytesForBackup() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(baos); out.writeInt(VERSION_RAPID); out.write(template.getBytesForBackup()); cycleRule.writeToStream(out); out.writeLong(warningBytes); out.writeLong(limitBytes); out.writeLong(lastWarningSnooze); out.writeLong(lastLimitSnooze); out.writeLong(lastRapidSnooze); out.writeInt(metered ? 1 : 0); out.writeInt(inferred ? 1 : 0); return baos.toByteArray(); } public static NetworkPolicy getNetworkPolicyFromBackup(DataInputStream in) throws IOException, BackupUtils.BadVersionException { final int version = in.readInt(); if (version < VERSION_INIT || version > VERSION_RAPID) { throw new BackupUtils.BadVersionException("Unknown backup version: " + version); } final NetworkTemplate template = NetworkTemplate.getNetworkTemplateFromBackup(in); final RecurrenceRule cycleRule; if (version >= VERSION_RULE) { cycleRule = new RecurrenceRule(in); } else { final int cycleDay = in.readInt(); final String cycleTimezone = BackupUtils.readString(in); cycleRule = buildRule(cycleDay, ZoneId.of(cycleTimezone)); } final long warningBytes = in.readLong(); final long limitBytes = in.readLong(); final long lastWarningSnooze = in.readLong(); final long lastLimitSnooze = in.readLong(); final long lastRapidSnooze; if (version >= VERSION_RAPID) { lastRapidSnooze = in.readLong(); } else { lastRapidSnooze = SNOOZE_NEVER; } final boolean metered = in.readInt() == 1; final boolean inferred = in.readInt() == 1; return new NetworkPolicy(template, cycleRule, warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze, lastRapidSnooze, metered, inferred); } }