AnqpCache.java revision 751c5a4496b6f90656eb24caa35f584d8976063d
1package com.android.server.wifi.hotspot2; 2 3import android.util.Log; 4 5import com.android.server.wifi.anqp.ANQPElement; 6import com.android.server.wifi.anqp.Constants; 7 8import java.util.ArrayList; 9import java.util.HashMap; 10import java.util.List; 11import java.util.Map; 12 13public class AnqpCache implements AlarmHandler { 14 private static final long CACHE_RECHECK = 60000L; 15 16 private final HashMap<NetworkDetail, ANQPData> mANQPCache; 17 private final HashMap<Long, ANQPData> mHESSIDCache; 18 private final Chronograph mChronograph; 19 20 public AnqpCache(Chronograph chronograph) { 21 mANQPCache = new HashMap<>(); 22 mHESSIDCache = new HashMap<>(); 23 mChronograph = chronograph; 24 mChronograph.addAlarm(CACHE_RECHECK, this, null); 25 } 26 27 public boolean initiate(NetworkDetail network) { 28 synchronized (mANQPCache) { 29 if (!mANQPCache.containsKey(network)) { 30 mANQPCache.put(network, new ANQPData(network, null)); 31 return true; 32 } 33 else { 34 return false; 35 } 36 } 37 } 38 39 public int getRetry(NetworkDetail network) { 40 ANQPData data; 41 synchronized (mANQPCache) { 42 data = mANQPCache.get(network); 43 } 44 return data != null ? data.incrementAndGetRetry() : -1; 45 } 46 47 public void update(NetworkDetail network, 48 Map<Constants.ANQPElementType, ANQPElement> anqpElements) { 49 50 long now = System.currentTimeMillis(); 51 52 // Networks with a 0 ANQP Domain ID are still cached, but with a very short expiry, just 53 // long enough to prevent excessive re-querying. 54 synchronized (mANQPCache) { 55 ANQPData data = mANQPCache.get(network); 56 if (data == null || 57 !data.isResolved() || 58 data.getDomainID() != network.getAnqpDomainID() || 59 data.recacheable(now)) { 60 data = new ANQPData(network, anqpElements); 61 mANQPCache.put(network, data); 62 } 63 // The spec really talks about caching per ESS, where an ESS is a set of APs with the 64 // same SSID. Since we're presumably in HS2.0 land here I have taken the liberty to 65 // tighten the definition of an ESS as the set of APs all sharing an HESSID. 66 if (network.getAnqpDomainID() != 0 && network.getHESSID() != 0 ) { 67 mHESSIDCache.put(network.getHESSID(), data); 68 } 69 } 70 } 71 72 public ANQPData getEntry(NetworkDetail network) { 73 ANQPData data; 74 75 synchronized (mANQPCache) { 76 data = mANQPCache.get(network); 77 if (data == null && network.getAnqpDomainID() != 0 && network.getHESSID() != 0) { 78 data = mHESSIDCache.get(network.getHESSID()); 79 } 80 } 81 82 long now = System.currentTimeMillis(); 83 84 if (data == null || 85 !data.isResolved() || 86 data.getDomainID() != network.getAnqpDomainID() || 87 data.expired(now)) { 88 return null; 89 } 90 return data; 91 } 92 93 @Override 94 public void wake(Object token) { 95 long now = System.currentTimeMillis(); 96 synchronized (mANQPCache) { 97 List<NetworkDetail> regulars = new ArrayList<>(); 98 for (Map.Entry<NetworkDetail, ANQPData> entry : mANQPCache.entrySet()) { 99 if (entry.getValue().expired(now)) { 100 regulars.add(entry.getKey()); 101 } 102 } 103 for (NetworkDetail key : regulars) { 104 mANQPCache.remove(key); 105 Log.d("HS2J", "Retired " + key.toKeyString() + "/" + key.getAnqpDomainID()); 106 } 107 108 List<Long> hessids = new ArrayList<>(); 109 for (Map.Entry<Long, ANQPData> entry : mHESSIDCache.entrySet()) { 110 if (entry.getValue().expired(now)) { 111 hessids.add(entry.getKey()); 112 } 113 } 114 for (Long key : hessids) { 115 mANQPCache.remove(key); 116 Log.d("HS2J", "Retired HESSID " + key); 117 } 118 } 119 mChronograph.addAlarm(CACHE_RECHECK, this, null); 120 } 121} 122