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