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