ANQPRequestManager.java revision ec28f863c5e46c0a75e8bdb92283304b875ee0f2
1/* 2 * Copyright (C) 2016 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 17package com.android.server.wifi.hotspot2; 18 19import android.util.Log; 20 21import com.android.internal.annotations.VisibleForTesting; 22import com.android.server.wifi.Clock; 23import com.android.server.wifi.hotspot2.anqp.Constants; 24 25import java.util.ArrayList; 26import java.util.Arrays; 27import java.util.HashMap; 28import java.util.List; 29import java.util.Map; 30 31/** 32 * Class for managing sending of ANQP requests. This manager will ignore ANQP requests for a 33 * period of time (hold off time) to a specified AP if the previous request to that AP goes 34 * unanswered or failed. The hold off time will increase exponentially until the max is reached. 35 */ 36public class ANQPRequestManager { 37 private static final String TAG = "ANQPRequestManager"; 38 39 private final PasspointEventHandler mPasspointHandler; 40 private final Clock mClock; 41 42 /** 43 * List of pending ANQP request associated with an AP (BSSID). 44 */ 45 private final Map<Long, ANQPNetworkKey> mPendingQueries; 46 47 /** 48 * List of hold off time information associated with APs specified by their BSSID. 49 * Used to determine when an ANQP request can be send to the corresponding AP after the 50 * previous request goes unanswered or failed. 51 */ 52 private final Map<Long, HoldOffInfo> mHoldOffInfo; 53 54 /** 55 * Minimum number of milliseconds to wait for before attempting ANQP queries to the same AP 56 * after previous request goes unanswered or failed. 57 */ 58 @VisibleForTesting 59 public static final int BASE_HOLDOFF_TIME_MILLISECONDS = 10000; 60 61 /** 62 * Max value for the hold off counter for unanswered/failed queries. This limits the maximum 63 * hold off time to: 64 * BASE_HOLDOFF_TIME_MILLISECONDS * 2^MAX_HOLDOFF_COUNT 65 * which is 640 seconds. 66 */ 67 @VisibleForTesting 68 public static final int MAX_HOLDOFF_COUNT = 6; 69 70 private static final List<Constants.ANQPElementType> R1_ANQP_BASE_SET = Arrays.asList( 71 Constants.ANQPElementType.ANQPVenueName, 72 Constants.ANQPElementType.ANQPIPAddrAvailability, 73 Constants.ANQPElementType.ANQPNAIRealm, 74 Constants.ANQPElementType.ANQP3GPPNetwork, 75 Constants.ANQPElementType.ANQPDomName); 76 77 private static final List<Constants.ANQPElementType> R2_ANQP_BASE_SET = Arrays.asList( 78 Constants.ANQPElementType.HSFriendlyName, 79 Constants.ANQPElementType.HSWANMetrics, 80 Constants.ANQPElementType.HSConnCapability); 81 82 /** 83 * Class to keep track of AP status for ANQP requests. 84 */ 85 private class HoldOffInfo { 86 /** 87 * Current hold off count. Will max out at {@link #MAX_HOLDOFF_COUNT}. 88 */ 89 public int holdOffCount; 90 /** 91 * The time stamp in milliseconds when we're allow to send ANQP request to the 92 * corresponding AP. 93 */ 94 public long holdOffExpirationTime; 95 } 96 97 public ANQPRequestManager(PasspointEventHandler handler, Clock clock) { 98 mPasspointHandler = handler; 99 mClock = clock; 100 mPendingQueries = new HashMap<>(); 101 mHoldOffInfo = new HashMap<>(); 102 } 103 104 /** 105 * Request ANQP elements from the specified AP. This will request the basic Release 1 ANQP 106 * elements {@link #R1_ANQP_BASE_SET}. Additional elements will be requested based on the 107 * information provided in the Information Element (Roaming Consortium OI count and the 108 * supported Hotspot 2.0 release version). 109 * 110 * @param bssid The BSSID of the AP 111 * @param anqpNetworkKey The unique network key associated with this request 112 * @param rcOIs Flag indicating the inclusion of roaming consortium OIs. When set to true, 113 * Roaming Consortium ANQP element will be requested 114 * @param hsReleaseR2 Flag indicating the support of Hotspot 2.0 Release 2. When set to true, 115 * the Release 2 ANQP elements {@link #R2_ANQP_BASE_SET} will be requested 116 * @return true if a request was sent successfully 117 */ 118 public boolean requestANQPElements(long bssid, ANQPNetworkKey anqpNetworkKey, boolean rcOIs, 119 boolean hsReleaseR2) { 120 // Check if we are allow to send the request now. 121 if (!canSendRequestNow(bssid)) { 122 return false; 123 } 124 125 // No need to hold off future requests for send failures. 126 if (!mPasspointHandler.requestANQP(bssid, getRequestElementIDs(rcOIs, hsReleaseR2))) { 127 return false; 128 } 129 130 // Update hold off info on when we are allowed to send the next ANQP request to 131 // the given AP. 132 updateHoldOffInfo(bssid); 133 134 mPendingQueries.put(bssid, anqpNetworkKey); 135 return true; 136 } 137 138 /** 139 * Notification of the completion of an ANQP request. 140 * 141 * @param bssid The BSSID of the AP 142 * @param success Flag indicating the result of the query 143 * @return {@link ANQPNetworkKey} associated with the completed request 144 */ 145 public ANQPNetworkKey onRequestCompleted(long bssid, boolean success) { 146 if (success) { 147 // Query succeeded. No need to hold off request to the given AP. 148 mHoldOffInfo.remove(bssid); 149 } 150 return mPendingQueries.remove(bssid); 151 } 152 153 /** 154 * Check if we are allowed to send ANQP request to the specified AP now. 155 * 156 * @param bssid The BSSID of an AP 157 * @return true if we are allowed to send the request now 158 */ 159 private boolean canSendRequestNow(long bssid) { 160 long currentTime = mClock.getElapsedSinceBootMillis(); 161 HoldOffInfo info = mHoldOffInfo.get(bssid); 162 if (info != null && info.holdOffExpirationTime > currentTime) { 163 Log.d(TAG, "Not allowed to send ANQP request to " + bssid + " for another " 164 + (info.holdOffExpirationTime - currentTime) / 1000 + " seconds"); 165 return false; 166 } 167 168 return true; 169 } 170 171 /** 172 * Update the ANQP request hold off info associated with the given AP. 173 * 174 * @param bssid The BSSID of an AP 175 */ 176 private void updateHoldOffInfo(long bssid) { 177 HoldOffInfo info = mHoldOffInfo.get(bssid); 178 if (info == null) { 179 info = new HoldOffInfo(); 180 mHoldOffInfo.put(bssid, info); 181 } 182 info.holdOffExpirationTime = mClock.getElapsedSinceBootMillis() 183 + BASE_HOLDOFF_TIME_MILLISECONDS * (1 << info.holdOffCount); 184 if (info.holdOffCount < MAX_HOLDOFF_COUNT) { 185 info.holdOffCount++; 186 } 187 } 188 189 /** 190 * Get the list of ANQP element IDs to request based on the Hotspot 2.0 release number 191 * and the ANQP OI count indicated in the Information Element. 192 * 193 * @param rcOIs Flag indicating the inclusion of roaming consortium OIs 194 * @param hsReleaseR2 Flag indicating support of Hotspot 2.0 Release 2 195 * @return List of ANQP Element ID 196 */ 197 private static List<Constants.ANQPElementType> getRequestElementIDs(boolean rcOIs, 198 boolean hsReleaseR2) { 199 List<Constants.ANQPElementType> requestList = new ArrayList<>(); 200 requestList.addAll(R1_ANQP_BASE_SET); 201 if (rcOIs) { 202 requestList.add(Constants.ANQPElementType.ANQPRoamingConsortium); 203 } 204 205 if (hsReleaseR2) { 206 requestList.addAll(R2_ANQP_BASE_SET); 207 } 208 return requestList; 209 } 210} 211