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 com.android.server.net; 18 19 import android.net.NetworkIdentity; 20 import android.service.NetworkIdentitySetProto; 21 import android.util.proto.ProtoOutputStream; 22 23 import java.io.DataInputStream; 24 import java.io.DataOutputStream; 25 import java.io.IOException; 26 import java.util.HashSet; 27 28 import static android.net.ConnectivityManager.TYPE_MOBILE; 29 30 /** 31 * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} 32 * active on that interface. 33 * 34 * @hide 35 */ 36 public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements 37 Comparable<NetworkIdentitySet> { 38 private static final int VERSION_INIT = 1; 39 private static final int VERSION_ADD_ROAMING = 2; 40 private static final int VERSION_ADD_NETWORK_ID = 3; 41 private static final int VERSION_ADD_METERED = 4; 42 private static final int VERSION_ADD_DEFAULT_NETWORK = 5; 43 NetworkIdentitySet()44 public NetworkIdentitySet() { 45 } 46 NetworkIdentitySet(DataInputStream in)47 public NetworkIdentitySet(DataInputStream in) throws IOException { 48 final int version = in.readInt(); 49 final int size = in.readInt(); 50 for (int i = 0; i < size; i++) { 51 if (version <= VERSION_INIT) { 52 final int ignored = in.readInt(); 53 } 54 final int type = in.readInt(); 55 final int subType = in.readInt(); 56 final String subscriberId = readOptionalString(in); 57 final String networkId; 58 if (version >= VERSION_ADD_NETWORK_ID) { 59 networkId = readOptionalString(in); 60 } else { 61 networkId = null; 62 } 63 final boolean roaming; 64 if (version >= VERSION_ADD_ROAMING) { 65 roaming = in.readBoolean(); 66 } else { 67 roaming = false; 68 } 69 70 final boolean metered; 71 if (version >= VERSION_ADD_METERED) { 72 metered = in.readBoolean(); 73 } else { 74 // If this is the old data and the type is mobile, treat it as metered. (Note that 75 // if this is a mobile network, TYPE_MOBILE is the only possible type that could be 76 // used.) 77 metered = (type == TYPE_MOBILE); 78 } 79 80 final boolean defaultNetwork; 81 if (version >= VERSION_ADD_DEFAULT_NETWORK) { 82 defaultNetwork = in.readBoolean(); 83 } else { 84 defaultNetwork = true; 85 } 86 87 add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered, 88 defaultNetwork)); 89 } 90 } 91 writeToStream(DataOutputStream out)92 public void writeToStream(DataOutputStream out) throws IOException { 93 out.writeInt(VERSION_ADD_DEFAULT_NETWORK); 94 out.writeInt(size()); 95 for (NetworkIdentity ident : this) { 96 out.writeInt(ident.getType()); 97 out.writeInt(ident.getSubType()); 98 writeOptionalString(out, ident.getSubscriberId()); 99 writeOptionalString(out, ident.getNetworkId()); 100 out.writeBoolean(ident.getRoaming()); 101 out.writeBoolean(ident.getMetered()); 102 out.writeBoolean(ident.getDefaultNetwork()); 103 } 104 } 105 106 /** @return whether any {@link NetworkIdentity} in this set is considered metered. */ isAnyMemberMetered()107 public boolean isAnyMemberMetered() { 108 if (isEmpty()) { 109 return false; 110 } 111 for (NetworkIdentity ident : this) { 112 if (ident.getMetered()) { 113 return true; 114 } 115 } 116 return false; 117 } 118 119 /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */ isAnyMemberRoaming()120 public boolean isAnyMemberRoaming() { 121 if (isEmpty()) { 122 return false; 123 } 124 for (NetworkIdentity ident : this) { 125 if (ident.getRoaming()) { 126 return true; 127 } 128 } 129 return false; 130 } 131 132 /** @return whether any {@link NetworkIdentity} in this set is considered on the default 133 network. */ areAllMembersOnDefaultNetwork()134 public boolean areAllMembersOnDefaultNetwork() { 135 if (isEmpty()) { 136 return true; 137 } 138 for (NetworkIdentity ident : this) { 139 if (!ident.getDefaultNetwork()) { 140 return false; 141 } 142 } 143 return true; 144 } 145 writeOptionalString(DataOutputStream out, String value)146 private static void writeOptionalString(DataOutputStream out, String value) throws IOException { 147 if (value != null) { 148 out.writeByte(1); 149 out.writeUTF(value); 150 } else { 151 out.writeByte(0); 152 } 153 } 154 readOptionalString(DataInputStream in)155 private static String readOptionalString(DataInputStream in) throws IOException { 156 if (in.readByte() != 0) { 157 return in.readUTF(); 158 } else { 159 return null; 160 } 161 } 162 163 @Override compareTo(NetworkIdentitySet another)164 public int compareTo(NetworkIdentitySet another) { 165 if (isEmpty()) return -1; 166 if (another.isEmpty()) return 1; 167 168 final NetworkIdentity ident = iterator().next(); 169 final NetworkIdentity anotherIdent = another.iterator().next(); 170 return ident.compareTo(anotherIdent); 171 } 172 writeToProto(ProtoOutputStream proto, long tag)173 public void writeToProto(ProtoOutputStream proto, long tag) { 174 final long start = proto.start(tag); 175 176 for (NetworkIdentity ident : this) { 177 ident.writeToProto(proto, NetworkIdentitySetProto.IDENTITIES); 178 } 179 180 proto.end(start); 181 } 182 } 183