1 /*
2  * Copyright (C) 2017 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.wifi.aware;
18 
19 import android.net.NetworkSpecifier;
20 import android.net.wifi.util.HexEncoding;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.util.Log;
24 
25 import java.security.MessageDigest;
26 import java.security.NoSuchAlgorithmException;
27 import java.util.Arrays;
28 import java.util.HashSet;
29 import java.util.Set;
30 import java.util.StringJoiner;
31 
32 /**
33  * A network specifier object used to represent the capabilities of an network agent. A collection
34  * of multiple WifiAwareNetworkSpecifier objects whose matching critiera (satisfiedBy) is an OR:
35  * a match on any of the network specifiers in the collection is a match.
36  *
37  * This class is not intended for use in network requests.
38  *
39  * @hide
40  */
41 public class WifiAwareAgentNetworkSpecifier extends NetworkSpecifier implements Parcelable {
42     private static final String TAG = "WifiAwareAgentNs";
43 
44     private static final boolean VDBG = false; // STOPSHIP if true
45 
46     private Set<ByteArrayWrapper> mNetworkSpecifiers = new HashSet<>();
47     private MessageDigest mDigester;
48 
WifiAwareAgentNetworkSpecifier()49     public WifiAwareAgentNetworkSpecifier() {
50         initialize();
51     }
52 
WifiAwareAgentNetworkSpecifier(WifiAwareNetworkSpecifier ns)53     public WifiAwareAgentNetworkSpecifier(WifiAwareNetworkSpecifier ns) {
54         initialize();
55         mNetworkSpecifiers.add(convert(ns));
56     }
57 
WifiAwareAgentNetworkSpecifier(WifiAwareNetworkSpecifier[] nss)58     public WifiAwareAgentNetworkSpecifier(WifiAwareNetworkSpecifier[] nss) {
59         initialize();
60         for (WifiAwareNetworkSpecifier ns : nss) {
61             mNetworkSpecifiers.add(convert(ns));
62         }
63     }
64 
isEmpty()65     public boolean isEmpty() {
66         return mNetworkSpecifiers.isEmpty();
67     }
68 
69     @Override
describeContents()70     public int describeContents() {
71         return 0;
72     }
73 
74     @Override
writeToParcel(Parcel dest, int flags)75     public void writeToParcel(Parcel dest, int flags) {
76         dest.writeArray(mNetworkSpecifiers.toArray());
77     }
78 
79     public static final @android.annotation.NonNull Creator<WifiAwareAgentNetworkSpecifier> CREATOR =
80             new Creator<WifiAwareAgentNetworkSpecifier>() {
81                 @Override
82                 public WifiAwareAgentNetworkSpecifier createFromParcel(Parcel in) {
83                     WifiAwareAgentNetworkSpecifier agentNs = new WifiAwareAgentNetworkSpecifier();
84                     Object[] objs = in.readArray(null);
85                     for (Object obj : objs) {
86                         agentNs.mNetworkSpecifiers.add((ByteArrayWrapper) obj);
87                     }
88                     return agentNs;
89                 }
90 
91                 @Override
92                 public WifiAwareAgentNetworkSpecifier[] newArray(int size) {
93                     return new WifiAwareAgentNetworkSpecifier[size];
94                 }
95             };
96 
97     @Override
hashCode()98     public int hashCode() {
99         return mNetworkSpecifiers.hashCode();
100     }
101 
102     @Override
equals(Object obj)103     public boolean equals(Object obj) {
104         if (obj == this) {
105             return true;
106         }
107         if (!(obj instanceof WifiAwareAgentNetworkSpecifier)) {
108             return false;
109         }
110         return mNetworkSpecifiers.equals(((WifiAwareAgentNetworkSpecifier) obj).mNetworkSpecifiers);
111     }
112 
113     @Override
toString()114     public String toString() {
115         StringJoiner sj = new StringJoiner(",");
116         for (ByteArrayWrapper baw: mNetworkSpecifiers) {
117             sj.add(baw.toString());
118         }
119         return sj.toString();
120     }
121 
122     @Override
canBeSatisfiedBy(NetworkSpecifier other)123     public boolean canBeSatisfiedBy(NetworkSpecifier other) {
124         if (!(other instanceof WifiAwareAgentNetworkSpecifier)) {
125             return false;
126         }
127         WifiAwareAgentNetworkSpecifier otherNs = (WifiAwareAgentNetworkSpecifier) other;
128 
129         // called as old.satifiedBy(new): satisfied if old contained in new
130         for (ByteArrayWrapper baw: mNetworkSpecifiers) {
131             if (!otherNs.mNetworkSpecifiers.contains(baw)) {
132                 return false;
133             }
134         }
135 
136         return true;
137     }
138 
satisfiesAwareNetworkSpecifier(WifiAwareNetworkSpecifier ns)139     public boolean satisfiesAwareNetworkSpecifier(WifiAwareNetworkSpecifier ns) {
140         if (VDBG) Log.v(TAG, "satisfiesAwareNetworkSpecifier: ns=" + ns);
141         ByteArrayWrapper nsBytes = convert(ns);
142         return mNetworkSpecifiers.contains(nsBytes);
143     }
144 
145     @Override
redact()146     public NetworkSpecifier redact() {
147         return null;
148     }
149 
initialize()150     private void initialize() {
151         try {
152             mDigester = MessageDigest.getInstance("SHA-256");
153         } catch (NoSuchAlgorithmException e) {
154             Log.e(TAG, "Can not instantiate a SHA-256 digester!? Will match nothing.");
155             return;
156         }
157     }
158 
convert(WifiAwareNetworkSpecifier ns)159     private ByteArrayWrapper convert(WifiAwareNetworkSpecifier ns) {
160         if (mDigester == null) {
161             return null;
162         }
163 
164         Parcel parcel = Parcel.obtain();
165         ns.writeToParcel(parcel, 0);
166         byte[] bytes = parcel.marshall();
167 
168         mDigester.reset();
169         mDigester.update(bytes);
170         return new ByteArrayWrapper(mDigester.digest());
171     }
172 
173     private static class ByteArrayWrapper implements Parcelable {
174         private byte[] mData;
175 
ByteArrayWrapper(byte[] data)176         ByteArrayWrapper(byte[] data) {
177             mData = data;
178         }
179 
180         @Override
hashCode()181         public int hashCode() {
182             return Arrays.hashCode(mData);
183         }
184 
185         @Override
equals(Object obj)186         public boolean equals(Object obj) {
187             if (obj == this) {
188                 return true;
189             }
190             if (!(obj instanceof ByteArrayWrapper)) {
191                 return false;
192             }
193             return Arrays.equals(((ByteArrayWrapper) obj).mData, mData);
194         }
195 
196         @Override
describeContents()197         public int describeContents() {
198             return 0;
199         }
200 
201         @Override
writeToParcel(Parcel dest, int flags)202         public void writeToParcel(Parcel dest, int flags) {
203             dest.writeByteArray(mData);
204         }
205 
206         public static final @android.annotation.NonNull Creator<ByteArrayWrapper> CREATOR =
207                 new Creator<ByteArrayWrapper>() {
208                     @Override
209                     public ByteArrayWrapper createFromParcel(Parcel in) {
210                         return new ByteArrayWrapper(in.createByteArray());
211                     }
212 
213                     @Override
214                     public ByteArrayWrapper[] newArray(int size) {
215                         return new ByteArrayWrapper[size];
216                     }
217                 };
218 
219         @Override
toString()220         public String toString() {
221             return new String(HexEncoding.encode(mData));
222         }
223     }
224 }
225