16a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvistpackage com.android.server.wifi.hotspot2;
26a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvist
3ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpandeimport com.android.server.wifi.Clock;
46a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvistimport com.android.server.wifi.anqp.ANQPElement;
577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.anqp.Constants;
66a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvist
71d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvistimport java.util.ArrayList;
86a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvistimport java.util.Collections;
91d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvistimport java.util.HashMap;
101d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvistimport java.util.List;
1177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.Map;
126a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvist
136a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvistpublic class ANQPData {
145bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist    /**
155bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist     * The regular cache time for entries with a non-zero domain id.
165bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist     */
1777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final long ANQP_QUALIFIED_CACHE_TIMEOUT = 3600000L;
185bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist    /**
195bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist     * The cache time for entries with a zero domain id. The zero domain id indicates that ANQP
205bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist     * data from the AP may change at any time, thus a relatively short cache time is given to
215bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist     * such data, but still long enough to avoid excessive querying.
225bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist     */
2382414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist    private static final long ANQP_UNQUALIFIED_CACHE_TIMEOUT = 300000L;
245bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist    /**
255bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist     * This is the hold off time for pending queries, i.e. the time during which subsequent queries
265bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist     * are squelched.
275bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist     */
285bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist    private static final long ANQP_HOLDOFF_TIME = 10000L;
2977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
3082414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist    /**
3182414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist     * Max value for the retry counter for unanswered queries. This limits the maximum time-out to
3282414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist     * ANQP_HOLDOFF_TIME * 2^MAX_RETRY. With current values this results in 640s.
3382414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist     */
3482414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist    private static final int MAX_RETRY = 6;
3582414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist
3677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final NetworkDetail mNetwork;
3777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final Map<Constants.ANQPElementType, ANQPElement> mANQPElements;
386a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvist    private final long mCtime;
3977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final long mExpiry;
4082414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist    private final int mRetry;
41ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande    private final Clock mClock;
4277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
43ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande    public ANQPData(Clock clock, NetworkDetail network,
4477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                    Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
456a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvist
46ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande        mClock = clock;
4777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mNetwork = network;
481d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        mANQPElements = anqpElements != null ? new HashMap<>(anqpElements) : null;
49ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande        mCtime = mClock.currentTimeMillis();
5082414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist        mRetry = 0;
515bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist        if (anqpElements == null) {
525bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist            mExpiry = mCtime + ANQP_HOLDOFF_TIME;
535bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist        }
545bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist        else if (network.getAnqpDomainID() == 0) {
555bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist            mExpiry = mCtime + ANQP_UNQUALIFIED_CACHE_TIMEOUT;
565bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist        }
575bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist        else {
585bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist            mExpiry = mCtime + ANQP_QUALIFIED_CACHE_TIMEOUT;
595bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist        }
606a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvist    }
616a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvist
62ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande    public ANQPData(Clock clock, NetworkDetail network, ANQPData existing) {
63ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande        mClock = clock;
6482414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist        mNetwork = network;
6582414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist        mANQPElements = null;
66ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande        mCtime = mClock.currentTimeMillis();
6782414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist        if (existing == null) {
6882414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist            mRetry = 0;
6982414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist            mExpiry = mCtime + ANQP_HOLDOFF_TIME;
7082414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist        }
7182414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist        else {
7282414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist            mRetry = Math.max(existing.getRetry() + 1, MAX_RETRY);
7382414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist            mExpiry = ANQP_HOLDOFF_TIME * (1<<mRetry);
7482414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist        }
7582414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist    }
7682414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist
771d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist    public List<Constants.ANQPElementType> disjoint(List<Constants.ANQPElementType> querySet) {
781d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        if (mANQPElements == null) {
791d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist            // Ignore the query set for pending responses, it has minimal probability to happen
801d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist            // and a new query will be reissued on the next round anyway.
811d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist            return null;
821d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        }
831d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        else {
841d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist            List<Constants.ANQPElementType> additions = new ArrayList<>();
851d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist            for (Constants.ANQPElementType element : querySet) {
861d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                if (!mANQPElements.containsKey(element)) {
871d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                    additions.add(element);
881d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                }
891d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist            }
901d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist            return additions.isEmpty() ? null : additions;
911d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        }
921d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist    }
931d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist
9477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public Map<Constants.ANQPElementType, ANQPElement> getANQPElements() {
955bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist        return Collections.unmodifiableMap(mANQPElements);
966a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvist    }
9777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
9877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public NetworkDetail getNetwork() {
9977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mNetwork;
10077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
10177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1025bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist    public boolean expired() {
103ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande        return expired(mClock.currentTimeMillis());
10477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
10577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
10677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean expired(long at) {
1075bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist        return mExpiry <= at;
10877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
10977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1101d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist    protected boolean hasData() {
1111d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        return mANQPElements != null;
1121d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist    }
1131d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist
1141d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist    protected void merge(Map<Constants.ANQPElementType, ANQPElement> data) {
1151d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        if (data != null) {
1161d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist            mANQPElements.putAll(data);
1171d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        }
1181d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist    }
1191d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist
1205bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist    protected boolean isValid(NetworkDetail nwk) {
1215bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist        return mANQPElements != null &&
1225bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist                nwk.getAnqpDomainID() == mNetwork.getAnqpDomainID() &&
123ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande                mExpiry > mClock.currentTimeMillis();
124ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    }
125ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist
12682414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist    private int getRetry() {
12782414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist        return mRetry;
12882414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist    }
12982414ead13eb2554cf412ad00a30d9e21499bf75Jan Nordqvist
1309f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist    public String toString(boolean brief) {
131a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        StringBuilder sb = new StringBuilder();
132a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        sb.append(mNetwork.toKeyString()).append(", domid ").append(mNetwork.getAnqpDomainID());
133a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        if (mANQPElements == null) {
134a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist            sb.append(", unresolved, ");
135a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        }
136a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        else {
137a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist            sb.append(", ").append(mANQPElements.size()).append(" elements, ");
138a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        }
139ae815bc71287f8a85727034c40bb07247a3d9415Vinit Deshpande        long now = mClock.currentTimeMillis();
140a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        sb.append(Utils.toHMS(now-mCtime)).append(" old, expires in ").
141a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist                append(Utils.toHMS(mExpiry-now)).append(' ');
1429f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist        if (brief) {
1439f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist            sb.append(expired(now) ? 'x' : '-');
1449f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist            sb.append(mANQPElements == null ? 'u' : '-');
1459f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist        }
1469f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist        else if (mANQPElements != null) {
1479f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist            sb.append(" data=").append(mANQPElements);
1489f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist        }
149a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        return sb.toString();
150a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist    }
1519f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist
1529f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist    @Override
1539f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist    public String toString() {
1549f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist        return toString(true);
1559f7795c694d048fdfecc4117cf5ddbd3e6ae1406Jan Nordqvist    }
1566a3903fed590e369b576bddbe1ae2d788768ddfeJan Nordqvist}
157