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.ConnectivityManager.TYPE_MOBILE;
20 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
21 
22 import android.annotation.NonNull;
23 import android.service.NetworkIdentitySetProto;
24 import android.util.proto.ProtoOutputStream;
25 
26 import java.io.DataInput;
27 import java.io.DataOutput;
28 import java.io.IOException;
29 import java.util.HashSet;
30 import java.util.Objects;
31 import java.util.Set;
32 
33 /**
34  * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity}
35  * active on that interface.
36  *
37  * @hide
38  */
39 public class NetworkIdentitySet extends HashSet<NetworkIdentity> {
40     private static final int VERSION_INIT = 1;
41     private static final int VERSION_ADD_ROAMING = 2;
42     private static final int VERSION_ADD_NETWORK_ID = 3;
43     private static final int VERSION_ADD_METERED = 4;
44     private static final int VERSION_ADD_DEFAULT_NETWORK = 5;
45     private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6;
46     private static final int VERSION_ADD_SUB_ID = 7;
47 
48     /**
49      * Construct a {@link NetworkIdentitySet} object.
50      */
NetworkIdentitySet()51     public NetworkIdentitySet() {
52         super();
53     }
54 
55     /** @hide */
NetworkIdentitySet(@onNull Set<NetworkIdentity> ident)56     public NetworkIdentitySet(@NonNull Set<NetworkIdentity> ident) {
57         super(ident);
58     }
59 
60     /** @hide */
NetworkIdentitySet(DataInput in)61     public NetworkIdentitySet(DataInput in) throws IOException {
62         final int version = in.readInt();
63         final int size = in.readInt();
64         for (int i = 0; i < size; i++) {
65             if (version <= VERSION_INIT) {
66                 final int ignored = in.readInt();
67             }
68             final int type = in.readInt();
69             final int ratType = in.readInt();
70             final String subscriberId = readOptionalString(in);
71             final String networkId;
72             if (version >= VERSION_ADD_NETWORK_ID) {
73                 networkId = readOptionalString(in);
74             } else {
75                 networkId = null;
76             }
77             final boolean roaming;
78             if (version >= VERSION_ADD_ROAMING) {
79                 roaming = in.readBoolean();
80             } else {
81                 roaming = false;
82             }
83 
84             final boolean metered;
85             if (version >= VERSION_ADD_METERED) {
86                 metered = in.readBoolean();
87             } else {
88                 // If this is the old data and the type is mobile, treat it as metered. (Note that
89                 // if this is a mobile network, TYPE_MOBILE is the only possible type that could be
90                 // used.)
91                 metered = (type == TYPE_MOBILE);
92             }
93 
94             final boolean defaultNetwork;
95             if (version >= VERSION_ADD_DEFAULT_NETWORK) {
96                 defaultNetwork = in.readBoolean();
97             } else {
98                 defaultNetwork = true;
99             }
100 
101             final int oemNetCapabilities;
102             if (version >= VERSION_ADD_OEM_MANAGED_NETWORK) {
103                 oemNetCapabilities = in.readInt();
104             } else {
105                 oemNetCapabilities = NetworkIdentity.OEM_NONE;
106             }
107 
108             final int subId;
109             if (version >= VERSION_ADD_SUB_ID) {
110                 subId = in.readInt();
111             } else {
112                 subId = INVALID_SUBSCRIPTION_ID;
113             }
114 
115             add(new NetworkIdentity(type, ratType, subscriberId, networkId, roaming, metered,
116                     defaultNetwork, oemNetCapabilities, subId));
117         }
118     }
119 
120     /**
121      * Method to serialize this object into a {@code DataOutput}.
122      * @hide
123      */
writeToStream(DataOutput out)124     public void writeToStream(DataOutput out) throws IOException {
125         out.writeInt(VERSION_ADD_SUB_ID);
126         out.writeInt(size());
127         for (NetworkIdentity ident : this) {
128             out.writeInt(ident.getType());
129             out.writeInt(ident.getRatType());
130             writeOptionalString(out, ident.getSubscriberId());
131             writeOptionalString(out, ident.getWifiNetworkKey());
132             out.writeBoolean(ident.isRoaming());
133             out.writeBoolean(ident.isMetered());
134             out.writeBoolean(ident.isDefaultNetwork());
135             out.writeInt(ident.getOemManaged());
136             out.writeInt(ident.getSubId());
137         }
138     }
139 
140     /**
141      * @return whether any {@link NetworkIdentity} in this set is considered metered.
142      * @hide
143      */
isAnyMemberMetered()144     public boolean isAnyMemberMetered() {
145         if (isEmpty()) {
146             return false;
147         }
148         for (NetworkIdentity ident : this) {
149             if (ident.isMetered()) {
150                 return true;
151             }
152         }
153         return false;
154     }
155 
156     /**
157      * @return whether any {@link NetworkIdentity} in this set is considered roaming.
158      * @hide
159      */
isAnyMemberRoaming()160     public boolean isAnyMemberRoaming() {
161         if (isEmpty()) {
162             return false;
163         }
164         for (NetworkIdentity ident : this) {
165             if (ident.isRoaming()) {
166                 return true;
167             }
168         }
169         return false;
170     }
171 
172     /**
173      * @return whether any {@link NetworkIdentity} in this set is considered on the default
174      *         network.
175      * @hide
176      */
areAllMembersOnDefaultNetwork()177     public boolean areAllMembersOnDefaultNetwork() {
178         if (isEmpty()) {
179             return true;
180         }
181         for (NetworkIdentity ident : this) {
182             if (!ident.isDefaultNetwork()) {
183                 return false;
184             }
185         }
186         return true;
187     }
188 
writeOptionalString(DataOutput out, String value)189     private static void writeOptionalString(DataOutput out, String value) throws IOException {
190         if (value != null) {
191             out.writeByte(1);
192             out.writeUTF(value);
193         } else {
194             out.writeByte(0);
195         }
196     }
197 
readOptionalString(DataInput in)198     private static String readOptionalString(DataInput in) throws IOException {
199         if (in.readByte() != 0) {
200             return in.readUTF();
201         } else {
202             return null;
203         }
204     }
205 
compare(@onNull NetworkIdentitySet left, @NonNull NetworkIdentitySet right)206     public static int compare(@NonNull NetworkIdentitySet left, @NonNull NetworkIdentitySet right) {
207         Objects.requireNonNull(left);
208         Objects.requireNonNull(right);
209         if (left.isEmpty() && right.isEmpty()) return 0;
210         if (left.isEmpty()) return -1;
211         if (right.isEmpty()) return 1;
212 
213         final NetworkIdentity leftIdent = left.iterator().next();
214         final NetworkIdentity rightIdent = right.iterator().next();
215         return NetworkIdentity.compare(leftIdent, rightIdent);
216     }
217 
218     /**
219      * Method to dump this object into proto debug file.
220      * @hide
221      */
dumpDebug(ProtoOutputStream proto, long tag)222     public void dumpDebug(ProtoOutputStream proto, long tag) {
223         final long start = proto.start(tag);
224 
225         for (NetworkIdentity ident : this) {
226             ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES);
227         }
228 
229         proto.end(start);
230     }
231 }
232