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