• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.wifi;
18 
19 import android.net.wifi.AnqpInformationElement;
20 import android.net.wifi.ScanResult;
21 import android.net.wifi.WifiSsid;
22 
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 import com.android.server.wifi.hotspot2.NetworkDetail;
28 import com.android.server.wifi.hotspot2.Utils;
29 import com.android.server.wifi.hotspot2.anqp.ANQPElement;
30 import com.android.server.wifi.hotspot2.anqp.Constants;
31 import com.android.server.wifi.hotspot2.anqp.HSFriendlyNameElement;
32 import com.android.server.wifi.hotspot2.anqp.RawByteElement;
33 import com.android.server.wifi.hotspot2.anqp.VenueNameElement;
34 
35 import java.util.List;
36 import java.util.Map;
37 
38 /**
39  * Wifi scan result details.
40  */
41 public class ScanDetail {
42     private final ScanResult mScanResult;
43     private volatile NetworkDetail mNetworkDetail;
44     private long mSeen = 0;
45     private byte[] mInformationElementRawData;
46 
47     /**
48      * Main constructor used when converting from NativeScanResult
49      */
ScanDetail(@ullable NetworkDetail networkDetail, @Nullable WifiSsid wifiSsid, @Nullable String bssid, @Nullable String caps, int level, int frequency, long tsf, @Nullable ScanResult.InformationElement[] informationElements, @Nullable List<String> anqpLines, @Nullable byte[] informationElementRawData)50     public ScanDetail(@Nullable NetworkDetail networkDetail, @Nullable WifiSsid wifiSsid,
51             @Nullable String bssid, @Nullable String caps, int level, int frequency, long tsf,
52             @Nullable ScanResult.InformationElement[] informationElements,
53             @Nullable List<String> anqpLines, @Nullable byte[] informationElementRawData) {
54         mNetworkDetail = networkDetail;
55         long hessid = 0L;
56         int anqpDomainId = ScanResult.UNSPECIFIED;
57         byte[] osuProviders = null;
58         int channelWidth = ScanResult.UNSPECIFIED;
59         int centerFreq0 = ScanResult.UNSPECIFIED;
60         int centerFreq1 = ScanResult.UNSPECIFIED;
61         boolean isPasspoint = false;
62         boolean is80211McResponder = false;
63         if (networkDetail != null) {
64             hessid = networkDetail.getHESSID();
65             anqpDomainId = networkDetail.getAnqpDomainID();
66             osuProviders = networkDetail.getOsuProviders();
67             channelWidth = networkDetail.getChannelWidth();
68             centerFreq0 = networkDetail.getCenterfreq0();
69             centerFreq1 = networkDetail.getCenterfreq1();
70             isPasspoint = caps.contains("EAP")
71                     && networkDetail.isInterworking() && networkDetail.getHSRelease() != null;
72             is80211McResponder = networkDetail.is80211McResponderSupport();
73         }
74         mScanResult = new ScanResult(wifiSsid, bssid, hessid, anqpDomainId, osuProviders, caps,
75                 level, frequency, tsf);
76         mSeen = System.currentTimeMillis();
77         mScanResult.seen = mSeen;
78         mScanResult.channelWidth = channelWidth;
79         mScanResult.centerFreq0 = centerFreq0;
80         mScanResult.centerFreq1 = centerFreq1;
81         mScanResult.informationElements = informationElements;
82         mScanResult.anqpLines = anqpLines;
83         if (is80211McResponder) {
84             mScanResult.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
85         }
86         if (isPasspoint) {
87             mScanResult.setFlag(ScanResult.FLAG_PASSPOINT_NETWORK);
88         }
89         mInformationElementRawData = informationElementRawData;
90     }
91 
92     /**
93      * Creates a ScanDetail without NetworkDetail for unit testing
94      */
95     @VisibleForTesting
ScanDetail(@ullable WifiSsid wifiSsid, @Nullable String bssid, String caps, int level, int frequency, long tsf, long seen)96     public ScanDetail(@Nullable WifiSsid wifiSsid, @Nullable String bssid, String caps, int level,
97             int frequency, long tsf, long seen) {
98         this(null, wifiSsid, bssid, caps, level, frequency, tsf, null, null, null);
99         mSeen = seen;
100         mScanResult.seen = seen;
101     }
102 
103     /**
104      * Create a ScanDetail from a ScanResult
105      */
ScanDetail(@onNull ScanResult scanResult)106     public ScanDetail(@NonNull ScanResult scanResult) {
107         mScanResult = scanResult;
108         mNetworkDetail = new NetworkDetail(
109                 scanResult.BSSID,
110                 scanResult.informationElements,
111                 scanResult.anqpLines,
112                 scanResult.frequency);
113         // Only inherit |mScanResult.seen| if it was previously set. This ensures that |mSeen|
114         // will always contain a valid timestamp.
115         mSeen = (mScanResult.seen == 0) ? System.currentTimeMillis() : mScanResult.seen;
116     }
117 
118     /**
119      * Copy constructor
120      */
ScanDetail(@onNull ScanDetail scanDetail)121     public ScanDetail(@NonNull ScanDetail scanDetail) {
122         mScanResult = new ScanResult(scanDetail.mScanResult);
123         mNetworkDetail = new NetworkDetail(scanDetail.mNetworkDetail);
124         mSeen = scanDetail.mSeen;
125         mInformationElementRawData = scanDetail.mInformationElementRawData;
126     }
127 
128     /**
129      * Store ANQ element information
130      *
131      * @param anqpElements Map<Constants.ANQPElementType, ANQPElement>
132      */
propagateANQPInfo(Map<Constants.ANQPElementType, ANQPElement> anqpElements)133     public void propagateANQPInfo(Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
134         if (anqpElements.isEmpty()) {
135             return;
136         }
137         mNetworkDetail = mNetworkDetail.complete(anqpElements);
138         HSFriendlyNameElement fne = (HSFriendlyNameElement) anqpElements.get(
139                 Constants.ANQPElementType.HSFriendlyName);
140         // !!! Match with language
141         if (fne != null && !fne.getNames().isEmpty()) {
142             mScanResult.venueName = fne.getNames().get(0).getText();
143         } else {
144             VenueNameElement vne =
145                     (((VenueNameElement) anqpElements.get(
146                             Constants.ANQPElementType.ANQPVenueName)));
147             if (vne != null && !vne.getNames().isEmpty()) {
148                 mScanResult.venueName = vne.getNames().get(0).getText();
149             }
150         }
151         RawByteElement osuProviders = (RawByteElement) anqpElements
152                 .get(Constants.ANQPElementType.HSOSUProviders);
153         if (osuProviders != null) {
154             mScanResult.anqpElements = new AnqpInformationElement[1];
155             mScanResult.anqpElements[0] =
156                     new AnqpInformationElement(AnqpInformationElement.HOTSPOT20_VENDOR_ID,
157                             AnqpInformationElement.HS_OSU_PROVIDERS, osuProviders.getPayload());
158         }
159     }
160 
getScanResult()161     public ScanResult getScanResult() {
162         return mScanResult;
163     }
164 
getNetworkDetail()165     public NetworkDetail getNetworkDetail() {
166         return mNetworkDetail;
167     }
168 
getSSID()169     public String getSSID() {
170         return mNetworkDetail == null ? mScanResult.SSID : mNetworkDetail.getSSID();
171     }
172 
getBSSIDString()173     public String getBSSIDString() {
174         return  mNetworkDetail == null ? mScanResult.BSSID : mNetworkDetail.getBSSIDString();
175     }
176 
177     /**
178      *  Return the network detail key string.
179      */
toKeyString()180     public String toKeyString() {
181         NetworkDetail networkDetail = mNetworkDetail;
182         if (networkDetail != null) {
183             return networkDetail.toKeyString();
184         } else {
185             return "'" + mScanResult.BSSID + "':" + Utils.macToSimpleString(
186                     Utils.parseMac(mScanResult.BSSID));
187         }
188     }
189 
190     /**
191      * Return the time this network was last seen.
192      */
getSeen()193     public long getSeen() {
194         return mSeen;
195     }
196 
197     /**
198      * Update the time this network was last seen to the current system time.
199      */
setSeen()200     public long setSeen() {
201         mSeen = System.currentTimeMillis();
202         mScanResult.seen = mSeen;
203         return mSeen;
204     }
205 
206     /**
207      * Return the network information element raw data.
208      */
getInformationElementRawData()209     public byte[] getInformationElementRawData() {
210         return mInformationElementRawData;
211     }
212 
213     @Override
toString()214     public String toString() {
215         try {
216             return "'" + mScanResult.BSSID + "'/" + Utils.macToSimpleString(
217                     Utils.parseMac(mScanResult.BSSID));
218         } catch (IllegalArgumentException iae) {
219             return "'" + mScanResult.BSSID + "'/----";
220         }
221     }
222 }
223