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.DataInput;
24 import java.io.DataOutput;
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     private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6;
44 
NetworkIdentitySet()45     public NetworkIdentitySet() {
46     }
47 
NetworkIdentitySet(DataInput in)48     public NetworkIdentitySet(DataInput in) throws IOException {
49         final int version = in.readInt();
50         final int size = in.readInt();
51         for (int i = 0; i < size; i++) {
52             if (version <= VERSION_INIT) {
53                 final int ignored = in.readInt();
54             }
55             final int type = in.readInt();
56             final int subType = in.readInt();
57             final String subscriberId = readOptionalString(in);
58             final String networkId;
59             if (version >= VERSION_ADD_NETWORK_ID) {
60                 networkId = readOptionalString(in);
61             } else {
62                 networkId = null;
63             }
64             final boolean roaming;
65             if (version >= VERSION_ADD_ROAMING) {
66                 roaming = in.readBoolean();
67             } else {
68                 roaming = false;
69             }
70 
71             final boolean metered;
72             if (version >= VERSION_ADD_METERED) {
73                 metered = in.readBoolean();
74             } else {
75                 // If this is the old data and the type is mobile, treat it as metered. (Note that
76                 // if this is a mobile network, TYPE_MOBILE is the only possible type that could be
77                 // used.)
78                 metered = (type == TYPE_MOBILE);
79             }
80 
81             final boolean defaultNetwork;
82             if (version >= VERSION_ADD_DEFAULT_NETWORK) {
83                 defaultNetwork = in.readBoolean();
84             } else {
85                 defaultNetwork = true;
86             }
87 
88             final int oemNetCapabilities;
89             if (version >= VERSION_ADD_OEM_MANAGED_NETWORK) {
90                 oemNetCapabilities = in.readInt();
91             } else {
92                 oemNetCapabilities = NetworkIdentity.OEM_NONE;
93             }
94 
95             add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered,
96                     defaultNetwork, oemNetCapabilities));
97         }
98     }
99 
writeToStream(DataOutput out)100     public void writeToStream(DataOutput out) throws IOException {
101         out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK);
102         out.writeInt(size());
103         for (NetworkIdentity ident : this) {
104             out.writeInt(ident.getType());
105             out.writeInt(ident.getSubType());
106             writeOptionalString(out, ident.getSubscriberId());
107             writeOptionalString(out, ident.getNetworkId());
108             out.writeBoolean(ident.getRoaming());
109             out.writeBoolean(ident.getMetered());
110             out.writeBoolean(ident.getDefaultNetwork());
111             out.writeInt(ident.getOemManaged());
112         }
113     }
114 
115     /** @return whether any {@link NetworkIdentity} in this set is considered metered. */
isAnyMemberMetered()116     public boolean isAnyMemberMetered() {
117         if (isEmpty()) {
118             return false;
119         }
120         for (NetworkIdentity ident : this) {
121             if (ident.getMetered()) {
122                 return true;
123             }
124         }
125         return false;
126     }
127 
128     /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */
isAnyMemberRoaming()129     public boolean isAnyMemberRoaming() {
130         if (isEmpty()) {
131             return false;
132         }
133         for (NetworkIdentity ident : this) {
134             if (ident.getRoaming()) {
135                 return true;
136             }
137         }
138         return false;
139     }
140 
141     /** @return whether any {@link NetworkIdentity} in this set is considered on the default
142             network. */
areAllMembersOnDefaultNetwork()143     public boolean areAllMembersOnDefaultNetwork() {
144         if (isEmpty()) {
145             return true;
146         }
147         for (NetworkIdentity ident : this) {
148             if (!ident.getDefaultNetwork()) {
149                 return false;
150             }
151         }
152         return true;
153     }
154 
writeOptionalString(DataOutput out, String value)155     private static void writeOptionalString(DataOutput out, String value) throws IOException {
156         if (value != null) {
157             out.writeByte(1);
158             out.writeUTF(value);
159         } else {
160             out.writeByte(0);
161         }
162     }
163 
readOptionalString(DataInput in)164     private static String readOptionalString(DataInput in) throws IOException {
165         if (in.readByte() != 0) {
166             return in.readUTF();
167         } else {
168             return null;
169         }
170     }
171 
172     @Override
compareTo(NetworkIdentitySet another)173     public int compareTo(NetworkIdentitySet another) {
174         if (isEmpty()) return -1;
175         if (another.isEmpty()) return 1;
176 
177         final NetworkIdentity ident = iterator().next();
178         final NetworkIdentity anotherIdent = another.iterator().next();
179         return ident.compareTo(anotherIdent);
180     }
181 
dumpDebug(ProtoOutputStream proto, long tag)182     public void dumpDebug(ProtoOutputStream proto, long tag) {
183         final long start = proto.start(tag);
184 
185         for (NetworkIdentity ident : this) {
186             ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES);
187         }
188 
189         proto.end(start);
190     }
191 }
192