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