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 
17 package com.android.server.wifi.hotspot2;
18 
19 import com.android.internal.annotations.VisibleForTesting;
20 import com.android.server.wifi.Clock;
21 import com.android.server.wifi.hotspot2.anqp.ANQPElement;
22 import com.android.server.wifi.hotspot2.anqp.Constants;
23 
24 import java.io.PrintWriter;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 
30 /**
31  * Cache for storing ANQP data.  This is simply a data cache, all the logic related to
32  * ANQP data query will be handled elsewhere (e.g. the consumer of the cache).
33  */
34 public class AnqpCache {
35     @VisibleForTesting
36     public static final long CACHE_SWEEP_INTERVAL_MILLISECONDS = 60000L;
37 
38     private long mLastSweep;
39     private Clock mClock;
40 
41     private final Map<ANQPNetworkKey, ANQPData> mANQPCache;
42 
AnqpCache(Clock clock)43     public AnqpCache(Clock clock) {
44         mClock = clock;
45         mANQPCache = new HashMap<>();
46         mLastSweep = mClock.getElapsedSinceBootMillis();
47     }
48 
49     /**
50      * Add an ANQP entry associated with the given key.
51      *
52      * @param key The key that's associated with the entry
53      * @param anqpElements The ANQP elements from the AP
54      */
addEntry(ANQPNetworkKey key, Map<Constants.ANQPElementType, ANQPElement> anqpElements)55     public void addEntry(ANQPNetworkKey key,
56             Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
57         ANQPData data = new ANQPData(mClock, anqpElements);
58         mANQPCache.put(key, data);
59     }
60 
61     /**
62      * Add or update additional ANQP elements to an ANQP entry associated with a given key. This
63      * method is useful for Venue URL or any other ANQP element which is queried after a connection
64      * is made.
65      *
66      * @param key The key that's associated with the entry
67      * @param anqpElements The additional ANQP elements from the AP, post connection
68      */
addOrUpdateEntry(ANQPNetworkKey key, Map<Constants.ANQPElementType, ANQPElement> anqpElements)69     public void addOrUpdateEntry(ANQPNetworkKey key,
70             Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
71         if (!mANQPCache.containsKey(key)) {
72             // Create a new entry
73             addEntry(key, anqpElements);
74             return;
75         }
76         mANQPCache.get(key).update(anqpElements);
77     }
78 
79     /**
80      * Get the ANQP data associated with the given AP.
81      *
82      * @param key The key that's associated with the entry
83      * @return {@link ANQPData}
84      */
getEntry(ANQPNetworkKey key)85     public ANQPData getEntry(ANQPNetworkKey key) {
86         return mANQPCache.get(key);
87     }
88 
89     /**
90      * Go through the cache to remove any expired entries.
91      */
sweep()92     public void sweep() {
93         long now = mClock.getElapsedSinceBootMillis();
94         // Check if it is time to perform the sweep.
95         if (now < mLastSweep + CACHE_SWEEP_INTERVAL_MILLISECONDS) {
96             return;
97         }
98 
99         // Get all expired keys.
100         List<ANQPNetworkKey> expiredKeys = new ArrayList<>();
101         for (Map.Entry<ANQPNetworkKey, ANQPData> entry : mANQPCache.entrySet()) {
102             if (entry.getValue().expired(now)) {
103                 expiredKeys.add(entry.getKey());
104             }
105         }
106 
107         // Remove all expired entries.
108         for (ANQPNetworkKey key : expiredKeys) {
109             mANQPCache.remove(key);
110         }
111         mLastSweep = now;
112     }
113 
dump(PrintWriter out)114     public void dump(PrintWriter out) {
115         out.println("Last sweep " + Utils.toHMS(mClock.getElapsedSinceBootMillis() - mLastSweep)
116                 + " ago.");
117         for (Map.Entry<ANQPNetworkKey, ANQPData> entry : mANQPCache.entrySet()) {
118             out.println(entry.getKey() + ": " + entry.getValue());
119         }
120     }
121 
122     /**
123      * Flush the ANQP cache
124      */
flush()125     public void flush() {
126         mANQPCache.clear();
127         mLastSweep = mClock.getElapsedSinceBootMillis();
128     }
129 }
130