• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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;
18 
19 import android.net.wifi.QosPolicyParams;
20 import android.net.wifi.WifiManager;
21 
22 import java.io.PrintWriter;
23 import java.util.ArrayDeque;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Queue;
29 
30 /**
31  * Table containing application-added QoS policies that are being tracked by the framework.
32  */
33 public class ApplicationQosPolicyTrackingTable {
34     private Queue<Integer> mAvailableVirtualPolicyIds = new ArrayDeque<>();
35 
36     // Mapping between a policy hash and a policy object.
37     // See combinePolicyIdAndUid() for more information about the policy hash format.
38     private Map<Long, QosPolicyParams> mPolicyHashToPolicyMap = new HashMap<>();
39     private Map<Integer, List<Long>> mUidToPolicyHashesMap = new HashMap<>();
40 
ApplicationQosPolicyTrackingTable(int minVirtualPolicyId, int maxVirtualPolicyId)41     public ApplicationQosPolicyTrackingTable(int minVirtualPolicyId, int maxVirtualPolicyId) {
42         for (int i = minVirtualPolicyId; i <= maxVirtualPolicyId; i++) {
43             mAvailableVirtualPolicyIds.add(i);
44         }
45     }
46 
generateStatusList( int size, @WifiManager.QosRequestStatus int statusCode)47     private List<Integer> generateStatusList(
48             int size, @WifiManager.QosRequestStatus int statusCode) {
49         List<Integer> statusList = new ArrayList<>();
50         for (int i = 0; i < size; i++) {
51             statusList.add(statusCode);
52         }
53         return statusList;
54     }
55 
56     /**
57      * Combine the provided policyId and UID into a long with the format:
58      *
59      * | Bits 63-32 | Bits 31-0 |
60      * |------------|-----------|
61      * |  policyId  |    uid    |
62      *
63      * Long can be used as a unique hash identifying each policy in the table.
64      */
combinePolicyIdAndUid(int policyId, int uid)65     private static long combinePolicyIdAndUid(int policyId, int uid) {
66         long shiftedPolicyId = Integer.toUnsignedLong(policyId) << 32;
67         return shiftedPolicyId | Integer.toUnsignedLong(uid);
68     }
69 
getPolicyIdFromCombinedLong(long combined)70     private static int getPolicyIdFromCombinedLong(long combined) {
71         return (int) (combined >> 32);
72     }
73 
getUidFromCombinedLong(long combined)74     private static int getUidFromCombinedLong(long combined) {
75         return (int) (combined & 0xFFFFFFFF);
76     }
77 
78     /**
79      * Add a list of QoS policies to the tracking table.
80      *
81      * Each accepted policy will be assigned a virtual policy ID using
82      * {@link QosPolicyParams#setTranslatedPolicyId(int)}.
83      *
84      * @param policies List of policies to add.
85      * @param uid UID of the requesting application.
86      * @return List of status codes from {@link WifiManager.QosRequestStatus}. Status list will be
87      *         the same length as the input list, and each status code will correspond to the
88      *         policy at that index in the input list.
89      */
addPolicies(List<QosPolicyParams> policies, int uid)90     public List<Integer> addPolicies(List<QosPolicyParams> policies, int uid) {
91         if (mAvailableVirtualPolicyIds.size() < policies.size()) {
92             // Not enough space in the table.
93             return generateStatusList(
94                     policies.size(), WifiManager.QOS_REQUEST_STATUS_INSUFFICIENT_RESOURCES);
95         }
96         List<Integer> statusList = generateStatusList(
97                 policies.size(), WifiManager.QOS_REQUEST_STATUS_TRACKING);
98 
99         for (int i = 0; i < policies.size(); i++) {
100             QosPolicyParams policy = policies.get(i);
101             long policyHash = combinePolicyIdAndUid(policy.getPolicyId(), uid);
102             if (mPolicyHashToPolicyMap.containsKey(policyHash)) {
103                 // Policy is already in the table.
104                 statusList.set(i, WifiManager.QOS_REQUEST_STATUS_ALREADY_ACTIVE);
105                 continue;
106             }
107 
108             int virtualPolicyId = mAvailableVirtualPolicyIds.remove();
109             policy.setTranslatedPolicyId(virtualPolicyId);
110             mPolicyHashToPolicyMap.put(policyHash, policy);
111             if (!mUidToPolicyHashesMap.containsKey(uid)) {
112                 mUidToPolicyHashesMap.put(uid, new ArrayList<>());
113             }
114             mUidToPolicyHashesMap.get(uid).add(policyHash);
115         }
116         return statusList;
117     }
118 
119     /**
120      * Remove a list of policies from the tracking table.
121      *
122      * Method should be considered best-effort. Any policies in the batch
123      * that are not found will be silently ignored.
124      *
125      * @param policyIds List of policy IDs which should be removed.
126      * @param uid UID of the requesting application.
127      */
removePolicies(List<Integer> policyIds, int uid)128     public void removePolicies(List<Integer> policyIds, int uid) {
129         for (int policyId : policyIds) {
130             long policyHash = combinePolicyIdAndUid(policyId, uid);
131             QosPolicyParams policy = mPolicyHashToPolicyMap.get(policyHash);
132             if (policy == null) {
133                 continue;
134             }
135             int virtualPolicyId = policy.getTranslatedPolicyId();
136             mAvailableVirtualPolicyIds.add(virtualPolicyId);
137             mPolicyHashToPolicyMap.remove(policyHash);
138             mUidToPolicyHashesMap.get(uid).remove(Long.valueOf(policyHash));
139             if (mUidToPolicyHashesMap.get(uid).isEmpty()) {
140                 mUidToPolicyHashesMap.remove(uid);
141             }
142         }
143     }
144 
145     /**
146      * Given a list of policies, filter out any polices that are not tracked by the table.
147      *
148      * @param policyList List of policies to filter.
149      * @param uid UID of the requesting application.
150      * @return Filtered list of policies, containing only the policies that are in the table.
151      */
filterUntrackedPolicies( List<QosPolicyParams> policyList, int uid)152     public List<QosPolicyParams> filterUntrackedPolicies(
153             List<QosPolicyParams> policyList, int uid) {
154         List<QosPolicyParams> trackedPolicies = new ArrayList<>();
155         for (QosPolicyParams policy : policyList) {
156             long policyHash = combinePolicyIdAndUid(policy.getPolicyId(), uid);
157             if (mPolicyHashToPolicyMap.containsKey(policyHash)) {
158                 trackedPolicies.add(policy);
159             }
160         }
161         return trackedPolicies;
162     }
163 
164     /**
165      * Translate a list of physical policy IDs to virtual.
166      *
167      * Method should be considered best-effort. Any policies in the batch
168      * that are not found will be silently excluded from the returned list.
169      *
170      * @param policyIds List of policy IDs to translate.
171      * @param uid UID of the requesting application.
172      * @return List of virtual policy IDs.
173      */
translatePolicyIds(List<Integer> policyIds, int uid)174     public List<Integer> translatePolicyIds(List<Integer> policyIds, int uid) {
175         List<Integer> virtualPolicyIds = new ArrayList<>();
176         for (int policyId : policyIds) {
177             long policyHash = combinePolicyIdAndUid(policyId, uid);
178             QosPolicyParams policy = mPolicyHashToPolicyMap.get(policyHash);
179             if (policy == null) {
180                 continue;
181             }
182             virtualPolicyIds.add(policy.getTranslatedPolicyId());
183         }
184         return virtualPolicyIds;
185     }
186 
187     /**
188      * Retrieve the IDs for all policies owned by this requester.
189      *
190      * @param uid UID of the requesting application.
191      * @return List of policy IDs.
192      */
getAllPolicyIdsOwnedByUid(int uid)193     public List<Integer> getAllPolicyIdsOwnedByUid(int uid) {
194         List<Integer> policyIds = new ArrayList<>();
195         List<Long> policyHashes = mUidToPolicyHashesMap.get(uid);
196         if (policyHashes == null) return policyIds;
197         for (long policyHash : policyHashes) {
198             int policyId = getPolicyIdFromCombinedLong(policyHash);
199             policyIds.add(policyId);
200         }
201         return policyIds;
202     }
203 
204     /**
205      * Check whether this requester owns any policies in the table.
206      *
207      * @param uid UID of the requesting application.
208      * @return true if the requester owns any policies in the table, false otherwise.
209      */
tableContainsUid(int uid)210     public boolean tableContainsUid(int uid) {
211         return mUidToPolicyHashesMap.containsKey(uid);
212     }
213 
214     /**
215      * Get all policies that are tracked by this table.
216      *
217      * @return List of policies, or empty list if there are no policies in the table.
218      */
getAllPolicies()219     public List<QosPolicyParams> getAllPolicies() {
220         if (mPolicyHashToPolicyMap.isEmpty()) {
221             return new ArrayList<>();
222         }
223         return mPolicyHashToPolicyMap.values().stream().toList();
224     }
225 
226     /**
227      * Dump information about the internal state.
228      *
229      * @param pw PrintWriter to write the dump to.
230      */
dump(PrintWriter pw)231     public void dump(PrintWriter pw) {
232         pw.println("Dump of ApplicationQosPolicyTrackingTable");
233         int numAvailableVirtualPolicyIds = mAvailableVirtualPolicyIds.size();
234         int numTrackedPolicies = mPolicyHashToPolicyMap.size();
235         pw.println("Total table size: " + (numAvailableVirtualPolicyIds + numTrackedPolicies));
236         pw.println("Num available virtual policy IDs: " + numAvailableVirtualPolicyIds);
237         pw.println("Num tracked policies: " + numTrackedPolicies);
238         pw.println();
239 
240         pw.println("Available virtual policy IDs: " + mAvailableVirtualPolicyIds);
241         pw.println("Tracked policies:");
242         for (Map.Entry<Long, QosPolicyParams> entry : mPolicyHashToPolicyMap.entrySet()) {
243             long policyHash = entry.getKey();
244             pw.println("  Policy ID: " + getPolicyIdFromCombinedLong(policyHash));
245             pw.println("  Requester UID: " + getUidFromCombinedLong(policyHash));
246             pw.println(entry.getValue());
247         }
248         pw.println();
249     }
250 }
251