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