ANQPData.java revision 1d5cd3938f9191184cd9aea3059a3b62bf3a0372
1package com.android.server.wifi.hotspot2;
2
3import com.android.server.wifi.anqp.ANQPElement;
4import com.android.server.wifi.anqp.Constants;
5
6import java.util.ArrayList;
7import java.util.Collections;
8import java.util.HashMap;
9import java.util.List;
10import java.util.Map;
11
12public class ANQPData {
13    /**
14     * The regular cache time for entries with a non-zero domain id.
15     */
16    private static final long ANQP_QUALIFIED_CACHE_TIMEOUT = 3600000L;
17    /**
18     * The cache time for entries with a zero domain id. The zero domain id indicates that ANQP
19     * data from the AP may change at any time, thus a relatively short cache time is given to
20     * such data, but still long enough to avoid excessive querying.
21     */
22    private static final long ANQP_UNQUALIFIED_CACHE_TIMEOUT = 300000L;
23    /**
24     * This is the hold off time for pending queries, i.e. the time during which subsequent queries
25     * are squelched.
26     */
27    private static final long ANQP_HOLDOFF_TIME = 10000L;
28
29    /**
30     * Max value for the retry counter for unanswered queries. This limits the maximum time-out to
31     * ANQP_HOLDOFF_TIME * 2^MAX_RETRY. With current values this results in 640s.
32     */
33    private static final int MAX_RETRY = 6;
34
35    private final NetworkDetail mNetwork;
36    private final Map<Constants.ANQPElementType, ANQPElement> mANQPElements;
37    private final long mCtime;
38    private final long mExpiry;
39    private final int mRetry;
40
41    public ANQPData(NetworkDetail network,
42                    Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
43
44        mNetwork = network;
45        mANQPElements = anqpElements != null ? new HashMap<>(anqpElements) : null;
46        mCtime = System.currentTimeMillis();
47        mRetry = 0;
48        if (anqpElements == null) {
49            mExpiry = mCtime + ANQP_HOLDOFF_TIME;
50        }
51        else if (network.getAnqpDomainID() == 0) {
52            mExpiry = mCtime + ANQP_UNQUALIFIED_CACHE_TIMEOUT;
53        }
54        else {
55            mExpiry = mCtime + ANQP_QUALIFIED_CACHE_TIMEOUT;
56        }
57    }
58
59    public ANQPData(NetworkDetail network, ANQPData existing) {
60        mNetwork = network;
61        mANQPElements = null;
62        mCtime = System.currentTimeMillis();
63        if (existing == null) {
64            mRetry = 0;
65            mExpiry = mCtime + ANQP_HOLDOFF_TIME;
66        }
67        else {
68            mRetry = Math.max(existing.getRetry() + 1, MAX_RETRY);
69            mExpiry = ANQP_HOLDOFF_TIME * (1<<mRetry);
70        }
71    }
72
73    public List<Constants.ANQPElementType> disjoint(List<Constants.ANQPElementType> querySet) {
74        if (mANQPElements == null) {
75            // Ignore the query set for pending responses, it has minimal probability to happen
76            // and a new query will be reissued on the next round anyway.
77            return null;
78        }
79        else {
80            List<Constants.ANQPElementType> additions = new ArrayList<>();
81            for (Constants.ANQPElementType element : querySet) {
82                if (!mANQPElements.containsKey(element)) {
83                    additions.add(element);
84                }
85            }
86            return additions.isEmpty() ? null : additions;
87        }
88    }
89
90    public Map<Constants.ANQPElementType, ANQPElement> getANQPElements() {
91        return Collections.unmodifiableMap(mANQPElements);
92    }
93
94    public NetworkDetail getNetwork() {
95        return mNetwork;
96    }
97
98    public boolean expired() {
99        return expired(System.currentTimeMillis());
100    }
101
102    public boolean expired(long at) {
103        return mExpiry <= at;
104    }
105
106    protected boolean hasData() {
107        return mANQPElements != null;
108    }
109
110    protected void merge(Map<Constants.ANQPElementType, ANQPElement> data) {
111        if (data != null) {
112            mANQPElements.putAll(data);
113        }
114    }
115
116    protected boolean isValid(NetworkDetail nwk) {
117        return mANQPElements != null &&
118                nwk.getAnqpDomainID() == mNetwork.getAnqpDomainID() &&
119                mExpiry > System.currentTimeMillis();
120    }
121
122    private int getRetry() {
123        return mRetry;
124    }
125
126    public String toString(boolean brief) {
127        StringBuilder sb = new StringBuilder();
128        sb.append(mNetwork.toKeyString()).append(", domid ").append(mNetwork.getAnqpDomainID());
129        if (mANQPElements == null) {
130            sb.append(", unresolved, ");
131        }
132        else {
133            sb.append(", ").append(mANQPElements.size()).append(" elements, ");
134        }
135        long now = System.currentTimeMillis();
136        sb.append(Utils.toHMS(now-mCtime)).append(" old, expires in ").
137                append(Utils.toHMS(mExpiry-now)).append(' ');
138        if (brief) {
139            sb.append(expired(now) ? 'x' : '-');
140            sb.append(mANQPElements == null ? 'u' : '-');
141        }
142        else if (mANQPElements != null) {
143            sb.append(" data=").append(mANQPElements);
144        }
145        return sb.toString();
146    }
147
148    @Override
149    public String toString() {
150        return toString(true);
151    }
152}
153