• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.util;
18 
19 import android.annotation.NonNull;
20 
21 import com.android.server.wifi.Clock;
22 
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Set;
26 
27 /**
28  * Utility class for Lock list which control by a missing counter which will trigger a timer when
29  * reach the threshold. When timer expires, object will be unlocked. Before unlocked, if object
30  * present again, will reset both counter and timer.
31  * @param <E>
32  */
33 public class MissingCounterTimerLockList<E> {
34     private final int mConsecutiveMissingCountToTriggerTimer;
35     private final Clock mClock;
36     private final Map<E, LockListEntry> mEntries;
37 
38     /**
39      * Create a new MissingCounterTimerLockList.
40      * @param consecutiveCount missing count threshold.
41      * @param clock system clock.
42      */
MissingCounterTimerLockList(int consecutiveCount, Clock clock)43     public MissingCounterTimerLockList(int consecutiveCount, Clock clock) {
44         mConsecutiveMissingCountToTriggerTimer = consecutiveCount;
45         mClock = clock;
46         mEntries = new HashMap<>();
47     }
48 
49     /**
50      * Update a set of object to check if object present or not.
51      * @param entrySet set of objects.
52      */
update(@onNull Set<E> entrySet)53     public void update(@NonNull Set<E> entrySet) {
54         if (entrySet == null) {
55             return;
56         }
57         for (Map.Entry<E, LockListEntry> mapEntry : mEntries.entrySet()) {
58             if (mapEntry.getValue().isExpired()) {
59                 continue;
60             }
61             if (entrySet.contains(mapEntry.getKey())) {
62                 mapEntry.getValue().onPresent();
63             } else {
64                 mapEntry.getValue().onAbsent();
65             }
66         }
67     }
68 
69     /**
70      * Add a object to lock with timer duration
71      * @param entry object to lock.
72      * @param duration duration of the timer.
73      * @param maxTimeoutDuration always remove this entry after this duration.
74      */
add(@onNull E entry, long duration, long maxTimeoutDuration)75     public void add(@NonNull E entry, long duration, long maxTimeoutDuration) {
76         if (entry == null) {
77             return;
78         }
79         mEntries.put(entry, new LockListEntry(duration, maxTimeoutDuration));
80     }
81 
82     /**
83      * Remove an object from the lock list.
84      * @param entry object to remove.
85      * @return true if lock list contains this element, otherwise false.
86      */
remove(@onNull E entry)87     public boolean remove(@NonNull E entry) {
88         return mEntries.remove(entry) != null;
89     }
90 
91     /**
92      * Check if an object is in lock list and still locked.
93      * @param entry object to check.
94      * @return true if the object is in the list and locking, otherwise false.
95      */
isLocked(@onNull E entry)96     public boolean isLocked(@NonNull E entry) {
97         if (entry == null) {
98             return false;
99         }
100         LockListEntry blockTimer = mEntries.get(entry);
101         return blockTimer != null && !blockTimer.isExpired();
102     }
103 
104     /**
105      * Return the size of the lock list
106      */
size()107     public int size() {
108         return mEntries.size();
109     }
110 
111     /**
112      * Clear the whole lock list.
113      */
clear()114     public void clear() {
115         mEntries.clear();
116     }
117 
118     class LockListEntry {
119         private final long mExpiryMs;
120         private long mTimeFirstAddedMs;
121         private long mMaxDisableDurationMs;
122         private long mStartTimeStamp;
123         private int mCount;
124 
LockListEntry(long expiryMs, long maxDisableDurationMs)125         LockListEntry(long expiryMs, long maxDisableDurationMs) {
126             mCount = mConsecutiveMissingCountToTriggerTimer;
127             mExpiryMs = expiryMs;
128             mStartTimeStamp = mClock.getWallClockMillis();
129             mTimeFirstAddedMs = mStartTimeStamp;
130             mMaxDisableDurationMs = maxDisableDurationMs;
131         }
132 
onPresent()133         void onPresent() {
134             if (isExpired()) {
135                 return;
136             }
137             mCount = mConsecutiveMissingCountToTriggerTimer;
138             mStartTimeStamp = mClock.getWallClockMillis();
139         }
140 
onAbsent()141         void onAbsent() {
142             if (mCount == 0) {
143                 // Timer already triggered
144                 return;
145             }
146             mCount--;
147             if (mCount > 0) {
148                 // Don't need to trigger timer
149                 return;
150             }
151             mStartTimeStamp = mClock.getWallClockMillis();
152         }
153 
isExpired()154         boolean isExpired() {
155             long curTimeMs = mClock.getWallClockMillis();
156             boolean maxDisableDurationPassed = mTimeFirstAddedMs + mMaxDisableDurationMs
157                     < curTimeMs;
158             boolean absentForLongEnough = mCount == 0 && mStartTimeStamp + mExpiryMs
159                     < curTimeMs;
160             return maxDisableDurationPassed || absentForLongEnough;
161         }
162     }
163 }
164