• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.annotation.NonNull;
20 import android.app.ActivityManager;
21 import android.content.Context;
22 import android.net.wifi.IWifiLowLatencyLockListener;
23 import android.net.wifi.WifiManager;
24 import android.os.BatteryStatsManager;
25 import android.os.Binder;
26 import android.os.Handler;
27 import android.os.IBinder;
28 import android.os.RemoteCallbackList;
29 import android.os.RemoteException;
30 import android.os.WorkSource;
31 import android.os.WorkSource.WorkChain;
32 import android.util.Log;
33 import android.util.Pair;
34 import android.util.SparseArray;
35 
36 import com.android.internal.annotations.VisibleForTesting;
37 import com.android.modules.utils.build.SdkLevel;
38 import com.android.server.wifi.proto.WifiStatsLog;
39 import com.android.server.wifi.util.WifiPermissionsUtil;
40 import com.android.server.wifi.util.WorkSourceUtil;
41 import com.android.wifi.resources.R;
42 
43 import java.io.PrintWriter;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.BitSet;
47 import java.util.List;
48 import java.util.NoSuchElementException;
49 import java.util.concurrent.Executor;
50 
51 /**
52  * WifiLockManager maintains the list of wake locks held by different applications.
53  */
54 public class WifiLockManager {
55     private static final String TAG = "WifiLockManager";
56 
57     private static final int LOW_LATENCY_SUPPORT_UNDEFINED = -1;
58     private static final int LOW_LATENCY_NOT_SUPPORTED     =  0;
59     private static final int LOW_LATENCY_SUPPORTED         =  1;
60 
61     private static final int IGNORE_SCREEN_STATE_MASK = 0x01;
62     private static final int IGNORE_WIFI_STATE_MASK   = 0x02;
63     @VisibleForTesting
64     public static final long DELAY_LOCK_RELEASE_MS = 1000;
65 
66     private int mLatencyModeSupport = LOW_LATENCY_SUPPORT_UNDEFINED;
67 
68     private boolean mVerboseLoggingEnabled = false;
69 
70     private final Clock mClock;
71     private final Context mContext;
72     private final BatteryStatsManager mBatteryStats;
73     private final FrameworkFacade mFrameworkFacade;
74     private final ActiveModeWarden mActiveModeWarden;
75     private final ActivityManager mActivityManager;
76     private final Handler mHandler;
77     private final WifiMetrics mWifiMetrics;
78 
79     private final List<WifiLock> mWifiLocks = new ArrayList<>();
80     // map UIDs to their corresponding records (for low-latency locks)
81     private final SparseArray<UidRec> mLowLatencyUidWatchList = new SparseArray<>();
82     /** the current op mode of the primary ClientModeManager */
83     private int mCurrentOpMode = WifiManager.WIFI_MODE_NO_LOCKS_HELD;
84     private boolean mScreenOn = false;
85     /** whether Wifi is connected on the primary ClientModeManager */
86     private boolean mWifiConnected = false;
87 
88     // For shell command support
89     private boolean mForceHiPerfMode = false;
90     private boolean mForceLowLatencyMode = false;
91 
92     // some wifi lock statistics
93     private int mFullHighPerfLocksAcquired;
94     private int mFullHighPerfLocksReleased;
95     private int mFullLowLatencyLocksAcquired;
96     private int mFullLowLatencyLocksReleased;
97     private long mCurrentSessionStartTimeMs;
98     private final DeviceConfigFacade mDeviceConfigFacade;
99     private final WifiPermissionsUtil mWifiPermissionsUtil;
100     private final RemoteCallbackList<IWifiLowLatencyLockListener>
101             mWifiLowLatencyLockListeners = new RemoteCallbackList<>();
102     private boolean mIsLowLatencyActivated = false;
103     private WorkSource mLowLatencyBlamedWorkSource = new WorkSource();
104     private WorkSource mHighPerfBlamedWorkSource = new WorkSource();
105     private enum BlameReason {
106         WIFI_CONNECTION_STATE_CHANGED,
107         SCREEN_STATE_CHANGED,
108     };
109     private final Object mLock = new Object();
110 
WifiLockManager( Context context, BatteryStatsManager batteryStats, ActiveModeWarden activeModeWarden, FrameworkFacade frameworkFacade, Handler handler, Clock clock, WifiMetrics wifiMetrics, DeviceConfigFacade deviceConfigFacade, WifiPermissionsUtil wifiPermissionsUtil, WifiDeviceStateChangeManager wifiDeviceStateChangeManager)111     WifiLockManager(
112             Context context,
113             BatteryStatsManager batteryStats,
114             ActiveModeWarden activeModeWarden,
115             FrameworkFacade frameworkFacade,
116             Handler handler,
117             Clock clock,
118             WifiMetrics wifiMetrics,
119             DeviceConfigFacade deviceConfigFacade,
120             WifiPermissionsUtil wifiPermissionsUtil,
121             WifiDeviceStateChangeManager wifiDeviceStateChangeManager) {
122         mContext = context;
123         mBatteryStats = batteryStats;
124         mActiveModeWarden = activeModeWarden;
125         mFrameworkFacade = frameworkFacade;
126         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
127         mHandler = handler;
128         mClock = clock;
129         mWifiMetrics = wifiMetrics;
130         mDeviceConfigFacade = deviceConfigFacade;
131         mWifiPermissionsUtil = wifiPermissionsUtil;
132 
133         wifiDeviceStateChangeManager.registerStateChangeCallback(
134                 new WifiDeviceStateChangeManager.StateChangeCallback() {
135                     @Override
136                     public void onScreenStateChanged(boolean screenOn) {
137                         handleScreenStateChanged(screenOn);
138                     }
139                 });
140 
141         // Register for UID fg/bg transitions
142         registerUidImportanceTransitions();
143     }
144 
canDisableChipPowerSave()145     private boolean canDisableChipPowerSave() {
146         return mContext.getResources().getBoolean(
147                 R.bool.config_wifiLowLatencyLockDisableChipPowerSave);
148     }
149 
150     // Check for conditions to activate high-perf lock
canActivateHighPerfLock(int ignoreMask)151     private boolean canActivateHighPerfLock(int ignoreMask) {
152         boolean check = true;
153 
154         // Only condition is when Wifi is connected
155         if ((ignoreMask & IGNORE_WIFI_STATE_MASK) == 0) {
156             check = check && mWifiConnected;
157         }
158 
159         return check;
160     }
161 
canActivateHighPerfLock()162     private boolean canActivateHighPerfLock() {
163         return canActivateHighPerfLock(0);
164     }
165 
166     // Check for conditions to activate low-latency lock
canActivateLowLatencyLock(int ignoreMask, UidRec uidRec)167     private boolean canActivateLowLatencyLock(int ignoreMask, UidRec uidRec) {
168         boolean check = true;
169 
170         if ((ignoreMask & IGNORE_WIFI_STATE_MASK) == 0) {
171             check = check && mWifiConnected;
172         }
173         if ((ignoreMask & IGNORE_SCREEN_STATE_MASK) == 0) {
174             check = check && mScreenOn;
175         }
176         if (uidRec != null) {
177             check = check && uidRec.mIsFg;
178         }
179 
180         return check;
181     }
182 
canActivateLowLatencyLock(int ignoreMask)183     private boolean canActivateLowLatencyLock(int ignoreMask) {
184         return canActivateLowLatencyLock(ignoreMask, null);
185     }
186 
canActivateLowLatencyLock()187     private boolean canActivateLowLatencyLock() {
188         return canActivateLowLatencyLock(0, null);
189     }
190 
onAppForeground(final int uid, final int importance)191     private void onAppForeground(final int uid, final int importance) {
192         mHandler.post(() -> {
193             UidRec uidRec = mLowLatencyUidWatchList.get(uid);
194             if (uidRec == null) {
195                 // Not a uid in the watch list
196                 return;
197             }
198 
199             boolean newModeIsFg = isAppForeground(uid, importance);
200             if (uidRec.mIsFg == newModeIsFg) {
201                 return; // already at correct state
202             }
203 
204             uidRec.mIsFg = newModeIsFg;
205             updateOpMode();
206 
207             // If conditions for lock activation are met,
208             // then UID either share the blame, or removed from sharing
209             // whether to start or stop the blame based on UID fg/bg state
210             if (canActivateLowLatencyLock(
211                     uidRec.mIsScreenOnExempted ? IGNORE_SCREEN_STATE_MASK : 0)) {
212                 setBlameLowLatencyUid(uid, uidRec.mIsFg);
213                 notifyLowLatencyActiveUsersChanged();
214             }
215         });
216     }
217 
218     // Detect UIDs going,
219     //          - Foreground <-> Background
220     //          - Foreground service <-> Background
registerUidImportanceTransitions()221     private void registerUidImportanceTransitions() {
222         mActivityManager.addOnUidImportanceListener(new ActivityManager.OnUidImportanceListener() {
223             @Override
224             public void onUidImportance(final int uid, final int importance) {
225                 onAppForeground(uid, importance);
226             }
227         }, ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND);
228         mActivityManager.addOnUidImportanceListener(new ActivityManager.OnUidImportanceListener() {
229             @Override
230             public void onUidImportance(final int uid, final int importance) {
231                 onAppForeground(uid, importance);
232             }
233         }, ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
234     }
235 
236     /**
237      * Method allowing a calling app to acquire a Wifi WakeLock in the supplied mode.
238      *
239      * This method checks that the lock mode is a valid WifiLock mode.
240      * @param lockMode int representation of the Wifi WakeLock type.
241      * @param tag String passed to WifiManager.WifiLock
242      * @param binder IBinder for the calling app
243      * @param ws WorkSource of the calling app
244      *
245      * @return true if the lock was successfully acquired, false if the lockMode was invalid.
246      */
acquireWifiLock(int lockMode, String tag, IBinder binder, WorkSource ws)247     public boolean acquireWifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
248         // Make a copy of the WorkSource before adding it to the WakeLock
249         // This is to make sure worksource value can not be changed by caller
250         // after function returns.
251         WorkSource newWorkSource = new WorkSource(ws);
252         // High perf lock is deprecated from Android U onwards. Acquisition of  High perf lock
253         // will be treated as a call to Low Latency Lock.
254         if (mDeviceConfigFacade.isHighPerfLockDeprecated() && SdkLevel.isAtLeastU()
255                 && lockMode == WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
256             lockMode = WifiManager.WIFI_MODE_FULL_LOW_LATENCY;
257         }
258         return addLock(new WifiLock(lockMode, tag, binder, newWorkSource));
259     }
260 
261     /**
262      * Method used by applications to release a WiFi Wake lock.
263      *
264      * @param binder IBinder for the calling app.
265      * @return true if the lock was released, false if the caller did not hold any locks
266      */
releaseWifiLock(IBinder binder)267     public boolean releaseWifiLock(IBinder binder) {
268         return releaseLock(binder);
269     }
270 
271     /**
272      * Method used to get the strongest lock type currently held by the WifiLockManager.
273      *
274      * If no locks are held, WifiManager.WIFI_MODE_NO_LOCKS_HELD is returned.
275      *
276      * @return int representing the currently held (highest power consumption) lock.
277      */
278     @VisibleForTesting
getStrongestLockMode()279     synchronized int getStrongestLockMode() {
280         // If Wifi Client is not connected, then all locks are not effective
281         if (!mWifiConnected) {
282             return WifiManager.WIFI_MODE_NO_LOCKS_HELD;
283         }
284 
285         // Check if mode is forced to hi-perf
286         if (mForceHiPerfMode) {
287             return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
288         }
289 
290         // Check if mode is forced to low-latency
291         if (mForceLowLatencyMode) {
292             return WifiManager.WIFI_MODE_FULL_LOW_LATENCY;
293         }
294 
295         if (mScreenOn && countFgLowLatencyUids(false) > 0) {
296             return WifiManager.WIFI_MODE_FULL_LOW_LATENCY;
297         }
298 
299         if (!mScreenOn && countFgLowLatencyUids(true) > 0) {
300             return WifiManager.WIFI_MODE_FULL_LOW_LATENCY;
301         }
302 
303         if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
304             return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
305         }
306 
307         return WifiManager.WIFI_MODE_NO_LOCKS_HELD;
308     }
309 
310     /**
311      * Method to create a WorkSource containing all active WifiLock WorkSources.
312      */
createMergedWorkSource()313     public synchronized WorkSource createMergedWorkSource() {
314         WorkSource mergedWS = new WorkSource();
315         for (WifiLock lock : mWifiLocks) {
316             mergedWS.add(lock.getWorkSource());
317         }
318         return mergedWS;
319     }
320 
321     /**
322      * Method used to update WifiLocks with a new WorkSouce.
323      *
324      * @param binder IBinder for the calling application.
325      * @param ws WorkSource to add to the existing WifiLock(s).
326      */
updateWifiLockWorkSource(IBinder binder, WorkSource ws)327     public synchronized void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
328 
329         // Now check if there is an active lock
330         WifiLock wl = findLockByBinder(binder);
331         if (wl == null) {
332             throw new IllegalArgumentException("Wifi lock not active");
333         }
334 
335         // Make a copy of the WorkSource before adding it to the WakeLock
336         // This is to make sure worksource value can not be changed by caller
337         // after function returns.
338         WorkSource newWorkSource = new WorkSource(ws);
339 
340         if (mVerboseLoggingEnabled) {
341             Log.d(TAG, "updateWifiLockWakeSource: " + wl + ", newWorkSource=" + newWorkSource);
342         }
343 
344         // Note:
345         // Log the acquire before the release to avoid "holes" in the collected data due to
346         // an acquire event immediately after a release in the case where newWorkSource and
347         // wl.mWorkSource share one or more attribution UIDs. Both batteryStats and statsd
348         // can correctly match "nested" acquire / release pairs.
349         switch(wl.mMode) {
350             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
351                 // Shift blame to new worksource if needed
352                 if (canActivateHighPerfLock()) {
353                     setBlameHiPerfWs(newWorkSource, true);
354                     setBlameHiPerfWs(wl.mWorkSource, false);
355                 }
356                 break;
357             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
358                 addWsToLlWatchList(newWorkSource);
359                 removeWsFromLlWatchList(wl.mWorkSource);
360                 updateOpMode();
361                 break;
362             default:
363                 // Do nothing
364                 break;
365         }
366 
367         wl.mWorkSource = newWorkSource;
368     }
369 
370     /**
371      * Method Used for shell command support
372      *
373      * @param isEnabled True to force hi-perf mode, false to leave it up to acquired wifiLocks.
374      * @return True for success, false for failure (failure turns forcing mode off)
375      */
forceHiPerfMode(boolean isEnabled)376     public boolean forceHiPerfMode(boolean isEnabled) {
377         mForceHiPerfMode = isEnabled;
378         mForceLowLatencyMode = false;
379         if (!updateOpMode()) {
380             Log.e(TAG, "Failed to force hi-perf mode, returning to normal mode");
381             mForceHiPerfMode = false;
382             return false;
383         }
384         return true;
385     }
386 
387     /**
388      * Method Used for shell command support
389      *
390      * @param isEnabled True to force low-latency mode, false to leave it up to acquired wifiLocks.
391      * @return True for success, false for failure (failure turns forcing mode off)
392      */
forceLowLatencyMode(boolean isEnabled)393     public boolean forceLowLatencyMode(boolean isEnabled) {
394         mForceLowLatencyMode = isEnabled;
395         mForceHiPerfMode = false;
396         if (!updateOpMode()) {
397             Log.e(TAG, "Failed to force low-latency mode, returning to normal mode");
398             mForceLowLatencyMode = false;
399             return false;
400         }
401         return true;
402     }
403 
404     /**
405      * Handler for screen state (on/off) changes
406      */
handleScreenStateChanged(boolean screenOn)407     private void handleScreenStateChanged(boolean screenOn) {
408         if (mVerboseLoggingEnabled) {
409             Log.d(TAG, "handleScreenStateChanged: screenOn = " + screenOn);
410         }
411 
412         mScreenOn = screenOn;
413 
414         if (canActivateLowLatencyLock(IGNORE_SCREEN_STATE_MASK)) {
415             // Update the running mode
416             updateOpMode();
417             // Adjust blaming for UIDs in foreground
418             setBlameLowLatencyWatchList(BlameReason.SCREEN_STATE_CHANGED, screenOn);
419         }
420     }
421 
422     /**
423      * Handler for Wifi Client mode state changes
424      */
updateWifiClientConnected( ClientModeManager clientModeManager, boolean isConnected)425     public void updateWifiClientConnected(
426             ClientModeManager clientModeManager, boolean isConnected) {
427         boolean hasAtLeastOneConnection = isConnected
428                 || mActiveModeWarden.getClientModeManagers().stream().anyMatch(
429                         cmm -> cmm.isConnected());
430         if (mVerboseLoggingEnabled) {
431             Log.d(TAG, "updateWifiClientConnected hasAtLeastOneConnection="
432                     + hasAtLeastOneConnection);
433         }
434         if (mWifiConnected == hasAtLeastOneConnection) {
435             // No need to take action
436             return;
437         }
438         mWifiConnected = hasAtLeastOneConnection;
439 
440         // Adjust blaming for UIDs in foreground carrying low latency locks
441         if (canActivateLowLatencyLock(countFgLowLatencyUids(/*isScreenOnExempted*/ true) > 0
442                 ? IGNORE_SCREEN_STATE_MASK | IGNORE_WIFI_STATE_MASK
443                 : IGNORE_WIFI_STATE_MASK)) {
444             setBlameLowLatencyWatchList(BlameReason.WIFI_CONNECTION_STATE_CHANGED, mWifiConnected);
445         }
446 
447         // Adjust blaming for UIDs carrying high perf locks
448         // Note that blaming is adjusted only if needed,
449         // since calling this API is reference counted
450         if (canActivateHighPerfLock(IGNORE_WIFI_STATE_MASK)) {
451             setBlameHiPerfLocks(mWifiConnected);
452         }
453 
454         updateOpMode();
455     }
456 
setBlameHiPerfLocks(boolean shouldBlame)457     private synchronized void setBlameHiPerfLocks(boolean shouldBlame) {
458         for (WifiLock lock : mWifiLocks) {
459             if (lock.mMode == WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
460                 setBlameHiPerfWs(lock.getWorkSource(), shouldBlame);
461             }
462         }
463     }
464 
465     /**
466      * Validate that the lock mode is valid - i.e. one of the supported enumerations.
467      *
468      * @param lockMode The lock mode to verify.
469      * @return true for valid lock modes, false otherwise.
470      */
isValidLockMode(int lockMode)471     public static boolean isValidLockMode(int lockMode) {
472         if (lockMode != WifiManager.WIFI_MODE_FULL
473                 && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY
474                 && lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF
475                 && lockMode != WifiManager.WIFI_MODE_FULL_LOW_LATENCY) {
476             return false;
477         }
478         return true;
479     }
480 
isAnyLowLatencyAppExemptedFromForeground(int[] uids)481     private boolean isAnyLowLatencyAppExemptedFromForeground(int[] uids) {
482         if (uids == null) return false;
483         for (int uid : uids) {
484             UidRec uidRec = mLowLatencyUidWatchList.get(uid);
485             if (uidRec != null && uidRec.mIsFgExempted) {
486                 return true;
487             }
488         }
489         return false;
490     }
491 
isAppExemptedFromImportance(int uid, int importance)492     private boolean isAppExemptedFromImportance(int uid, int importance) {
493         // Exemption for applications running with CAR Mode permissions.
494         if (mWifiPermissionsUtil.checkRequestCompanionProfileAutomotiveProjectionPermission(uid)
495                 && (importance
496                 <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE)) {
497             return true;
498         }
499         // Add any exemption cases for applications regarding restricting Low latency locks to
500         // running in the foreground.
501         return false;
502     }
503 
isAppForeground(final int uid, final int importance)504     private boolean isAppForeground(final int uid, final int importance) {
505         if ((importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)) {
506             return true;
507         }
508         return isAppExemptedFromImportance(uid, importance);
509     }
510 
isAnyLowLatencyAppExemptedFromScreenOn(int[] uids)511     private boolean isAnyLowLatencyAppExemptedFromScreenOn(int[] uids) {
512         if (uids == null) return false;
513         for (int uid : uids) {
514             UidRec uidRec = mLowLatencyUidWatchList.get(uid);
515             if (uidRec != null && uidRec.mIsScreenOnExempted) {
516                 return true;
517             }
518         }
519         return false;
520     }
521 
isAppExemptedFromScreenOn(int uid)522     private boolean isAppExemptedFromScreenOn(int uid) {
523         // Exemption for applications running with CAR Mode permissions.
524         if (mWifiPermissionsUtil.checkRequestCompanionProfileAutomotiveProjectionPermission(uid)) {
525             return true;
526         }
527         // Add more exemptions here
528         return false;
529     }
530 
addUidToLlWatchList(int uid)531     private void addUidToLlWatchList(int uid) {
532         UidRec uidRec = mLowLatencyUidWatchList.get(uid);
533         if (uidRec != null) {
534             uidRec.mLockCount++;
535         } else {
536             uidRec = new UidRec(uid);
537             uidRec.mLockCount = 1;
538             mLowLatencyUidWatchList.put(uid, uidRec);
539             notifyLowLatencyOwnershipChanged();
540 
541             uidRec.mIsFg = isAppForeground(uid,
542                     mContext.getSystemService(ActivityManager.class).getUidImportance(uid));
543             // Save the current permission of foreground & 'screen on' exemption.
544             uidRec.mIsFgExempted = isAppExemptedFromImportance(uid,
545                     ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND);
546             uidRec.mIsScreenOnExempted = isAppExemptedFromScreenOn(uid);
547 
548             if (canActivateLowLatencyLock(
549                     uidRec.mIsScreenOnExempted ? IGNORE_SCREEN_STATE_MASK : 0,
550                     uidRec)) {
551                 // Share the blame for this uid
552                 setBlameLowLatencyUid(uid, true);
553                 notifyLowLatencyActiveUsersChanged();
554             }
555         }
556     }
557 
removeUidFromLlWatchList(int uid)558     private void removeUidFromLlWatchList(int uid) {
559         UidRec uidRec = mLowLatencyUidWatchList.get(uid);
560         if (uidRec == null) {
561             Log.e(TAG, "Failed to find uid in low-latency watch list");
562             return;
563         }
564 
565         if (uidRec.mLockCount > 0) {
566             uidRec.mLockCount--;
567         } else {
568             Log.e(TAG, "Error, uid record contains no locks");
569         }
570         if (uidRec.mLockCount == 0) {
571             mLowLatencyUidWatchList.remove(uid);
572             notifyLowLatencyOwnershipChanged();
573 
574             // Remove blame for this UID if it was already set
575             // Note that blame needs to be stopped only if it was started before
576             // to avoid calling the API unnecessarily, since it is reference counted
577             if (canActivateLowLatencyLock(uidRec.mIsScreenOnExempted ? IGNORE_SCREEN_STATE_MASK : 0,
578                     uidRec)) {
579                 setBlameLowLatencyUid(uid, false);
580                 notifyLowLatencyActiveUsersChanged();
581             }
582         }
583     }
584 
addWsToLlWatchList(WorkSource ws)585     private void addWsToLlWatchList(WorkSource ws) {
586         int wsSize = ws.size();
587         for (int i = 0; i < wsSize; i++) {
588             final int uid = ws.getUid(i);
589             addUidToLlWatchList(uid);
590         }
591 
592         final List<WorkChain> workChains = ws.getWorkChains();
593         if (workChains != null) {
594             for (int i = 0; i < workChains.size(); ++i) {
595                 final WorkChain workChain = workChains.get(i);
596                 final int uid = workChain.getAttributionUid();
597                 addUidToLlWatchList(uid);
598             }
599         }
600     }
601 
removeWsFromLlWatchList(WorkSource ws)602     private void removeWsFromLlWatchList(WorkSource ws) {
603         int wsSize = ws.size();
604         for (int i = 0; i < wsSize; i++) {
605             final int uid = ws.getUid(i);
606             removeUidFromLlWatchList(uid);
607         }
608 
609         final List<WorkChain> workChains = ws.getWorkChains();
610         if (workChains != null) {
611             for (int i = 0; i < workChains.size(); ++i) {
612                 final WorkChain workChain = workChains.get(i);
613                 final int uid = workChain.getAttributionUid();
614                 removeUidFromLlWatchList(uid);
615             }
616         }
617     }
618 
addLock(WifiLock lock)619     private synchronized boolean addLock(WifiLock lock) {
620         if (mVerboseLoggingEnabled) {
621             Log.d(TAG, "addLock: " + lock);
622         }
623 
624         if (findLockByBinder(lock.getBinder()) != null) {
625             if (mVerboseLoggingEnabled) {
626                 Log.d(TAG, "attempted to add a lock when already holding one");
627             }
628             return false;
629         }
630 
631         mWifiLocks.add(lock);
632 
633         switch(lock.mMode) {
634             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
635                 ++mFullHighPerfLocksAcquired;
636                 // Start blaming this worksource if conditions are met
637                 if (canActivateHighPerfLock()) {
638                     setBlameHiPerfWs(lock.mWorkSource, true);
639                 }
640                 break;
641             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
642                 addWsToLlWatchList(lock.getWorkSource());
643                 ++mFullLowLatencyLocksAcquired;
644                 break;
645             default:
646                 // Do nothing
647                 break;
648         }
649 
650         // Recalculate the operating mode
651         updateOpMode();
652         mHandler.removeCallbacksAndMessages(mLock);
653         return true;
654     }
655 
removeLock(IBinder binder)656     private synchronized WifiLock removeLock(IBinder binder) {
657         WifiLock lock = findLockByBinder(binder);
658         if (lock != null) {
659             mWifiLocks.remove(lock);
660             lock.unlinkDeathRecipient();
661         }
662         return lock;
663     }
664 
releaseLock(IBinder binder)665     private synchronized boolean releaseLock(IBinder binder) {
666         WifiLock wifiLock = removeLock(binder);
667         if (wifiLock == null) {
668             // attempting to release a lock that does not exist.
669             return false;
670         }
671 
672         if (mVerboseLoggingEnabled) {
673             Log.d(TAG, "releaseLock: " + wifiLock);
674         }
675 
676         WorkSource ws = wifiLock.getWorkSource();
677         Pair<int[], String[]> uidsAndTags = WorkSourceUtil.getUidsAndTagsForWs(ws);
678 
679         switch(wifiLock.mMode) {
680             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
681                 mWifiMetrics.addWifiLockManagerAcqSession(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
682                         uidsAndTags.first,
683                         uidsAndTags.second,
684                         mWifiPermissionsUtil.getWifiCallerType(wifiLock.getUid(),
685                                 ws.getPackageName(0)),
686                         mClock.getElapsedSinceBootMillis() - wifiLock.getAcqTimestamp(),
687                         canDisableChipPowerSave(),
688                         false,
689                         false);
690                 ++mFullHighPerfLocksReleased;
691                 // Stop blaming only if blaming was set before (conditions are met).
692                 // This is to avoid calling the api unncessarily, since this API is
693                 // reference counted in batteryStats and statsd
694                 if (canActivateHighPerfLock()) {
695                     setBlameHiPerfWs(wifiLock.mWorkSource, false);
696                 }
697                 break;
698             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
699                 mWifiMetrics.addWifiLockManagerAcqSession(WifiManager.WIFI_MODE_FULL_LOW_LATENCY,
700                         uidsAndTags.first,
701                         uidsAndTags.second,
702                         mWifiPermissionsUtil.getWifiCallerType(wifiLock.getUid(),
703                                 ws.getPackageName(0)),
704                         mClock.getElapsedSinceBootMillis() - wifiLock.getAcqTimestamp(),
705                         canDisableChipPowerSave(),
706                         isAnyLowLatencyAppExemptedFromScreenOn(uidsAndTags.first),
707                         isAnyLowLatencyAppExemptedFromForeground(uidsAndTags.first));
708                 removeWsFromLlWatchList(wifiLock.getWorkSource());
709                 ++mFullLowLatencyLocksReleased;
710                 break;
711             default:
712                 // Do nothing
713                 break;
714         }
715         // Delay 1s to release the lock to avoid stress the HAL.
716         mHandler.postDelayed(this::updateOpMode, mLock, DELAY_LOCK_RELEASE_MS);
717         return true;
718     }
719 
720     /**
721      * Reset the given ClientModeManager's power save/low latency mode to the default.
722      * The method calls needed to reset is the reverse of the method calls used to set.
723      * @return true if the operation succeeded, false otherwise
724      */
resetCurrentMode(@onNull ClientModeManager clientModeManager)725     private boolean resetCurrentMode(@NonNull ClientModeManager clientModeManager) {
726         Pair<int[], String[]> uidsAndTags = null;
727         switch (mCurrentOpMode) {
728             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
729                 if (!setPowerSave(clientModeManager, ClientMode.POWER_SAVE_CLIENT_WIFI_LOCK,
730                         true)) {
731                     Log.e(TAG, "Failed to reset the OpMode from hi-perf to Normal");
732                     return false;
733                 }
734                 uidsAndTags = WorkSourceUtil.getUidsAndTagsForWs(mHighPerfBlamedWorkSource);
735                 mWifiMetrics.addWifiLockManagerActiveSession(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
736                         uidsAndTags.first,
737                         uidsAndTags.second,
738                         mClock.getElapsedSinceBootMillis() - mCurrentSessionStartTimeMs,
739                         canDisableChipPowerSave(),
740                         false,
741                         false);
742                 mHighPerfBlamedWorkSource.clear();
743                 break;
744 
745             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
746                 if (!setLowLatencyMode(clientModeManager, false)) {
747                     Log.e(TAG, "Failed to reset the OpMode from low-latency to Normal");
748                     return false;
749                 }
750                 uidsAndTags = WorkSourceUtil.getUidsAndTagsForWs(mLowLatencyBlamedWorkSource);
751                 mWifiMetrics.addWifiLockManagerActiveSession(WifiManager.WIFI_MODE_FULL_LOW_LATENCY,
752                         uidsAndTags.first,
753                         uidsAndTags.second,
754                         mClock.getElapsedSinceBootMillis() - mCurrentSessionStartTimeMs,
755                         canDisableChipPowerSave(),
756                         isAnyLowLatencyAppExemptedFromScreenOn(uidsAndTags.first),
757                         isAnyLowLatencyAppExemptedFromForeground(uidsAndTags.first));
758                 mLowLatencyBlamedWorkSource.clear();
759                 break;
760 
761             case WifiManager.WIFI_MODE_NO_LOCKS_HELD:
762             default:
763                 // No action
764                 break;
765         }
766 
767         // reset the current mode
768         mCurrentOpMode = WifiManager.WIFI_MODE_NO_LOCKS_HELD;
769         return true;
770     }
771 
772     /**
773      * Set power save mode with an overlay check. It's a wrapper for
774      * {@link ClientModeImpl#setPowerSave(int, boolean)}.
775      */
setPowerSave(@onNull ClientModeManager clientModeManager, @ClientMode.PowerSaveClientType int client, boolean ps)776     private boolean setPowerSave(@NonNull ClientModeManager clientModeManager,
777             @ClientMode.PowerSaveClientType int client, boolean ps) {
778         // Check the overlay allows lock to control chip power save.
779         if (canDisableChipPowerSave()) {
780             return clientModeManager.setPowerSave(client, ps);
781         }
782         // Otherwise, pretend the call is a success.
783         return true;
784     }
785 
786     /**
787      * Set the new lock mode on the given ClientModeManager
788      * @return true if the operation succeeded, false otherwise
789      */
setNewMode(@onNull ClientModeManager clientModeManager, int newLockMode)790     private boolean setNewMode(@NonNull ClientModeManager clientModeManager, int newLockMode) {
791         switch (newLockMode) {
792             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
793                 if (!setPowerSave(clientModeManager, ClientMode.POWER_SAVE_CLIENT_WIFI_LOCK,
794                         false)) {
795                     Log.e(TAG, "Failed to set the OpMode to hi-perf");
796                     return false;
797                 }
798                 mCurrentSessionStartTimeMs = mClock.getElapsedSinceBootMillis();
799                 break;
800 
801             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
802                 if (!setLowLatencyMode(clientModeManager, true)) {
803                     Log.e(TAG, "Failed to set the OpMode to low-latency");
804                     return false;
805                 }
806                 mCurrentSessionStartTimeMs = mClock.getElapsedSinceBootMillis();
807                 break;
808 
809             case WifiManager.WIFI_MODE_NO_LOCKS_HELD:
810                 // No action
811                 break;
812 
813             default:
814                 // Invalid mode, don't change currentOpMode, and exit with error
815                 Log.e(TAG, "Invalid new opMode: " + newLockMode);
816                 return false;
817         }
818 
819         // Now set the mode to the new value
820         mCurrentOpMode = newLockMode;
821         return true;
822     }
823 
updateOpMode()824     private synchronized boolean updateOpMode() {
825         final int newLockMode = getStrongestLockMode();
826 
827         if (newLockMode == mCurrentOpMode) {
828             // No action is needed
829             return true;
830         }
831 
832         if (mVerboseLoggingEnabled) {
833             Log.d(TAG, "Current opMode: " + mCurrentOpMode
834                     + " New LockMode: " + newLockMode);
835         }
836 
837         ClientModeManager primaryManager = mActiveModeWarden.getPrimaryClientModeManager();
838 
839         // Otherwise, we need to change current mode, first reset it to normal
840         if (!resetCurrentMode(primaryManager)) {
841             return false;
842         }
843 
844         // Now switch to the new opMode
845         return setNewMode(primaryManager, newLockMode);
846     }
847 
848     /** Returns the cached low latency mode support value, or tries to fetch it if not yet known. */
getLowLatencyModeSupport()849     private int getLowLatencyModeSupport() {
850         if (mLatencyModeSupport != LOW_LATENCY_SUPPORT_UNDEFINED) {
851             return mLatencyModeSupport;
852         }
853 
854         BitSet supportedFeatures =
855                 mActiveModeWarden.getPrimaryClientModeManager().getSupportedFeaturesBitSet();
856         if (supportedFeatures.isEmpty()) {
857             return LOW_LATENCY_SUPPORT_UNDEFINED;
858         }
859 
860         if (supportedFeatures.get(WifiManager.WIFI_FEATURE_LOW_LATENCY)) {
861             mLatencyModeSupport = LOW_LATENCY_SUPPORTED;
862         } else {
863             mLatencyModeSupport = LOW_LATENCY_NOT_SUPPORTED;
864         }
865         return mLatencyModeSupport;
866     }
867 
setLowLatencyMode(ClientModeManager clientModeManager, boolean enabled)868     private boolean setLowLatencyMode(ClientModeManager clientModeManager, boolean enabled) {
869         int lowLatencySupport = getLowLatencyModeSupport();
870 
871         if (lowLatencySupport == LOW_LATENCY_SUPPORT_UNDEFINED) {
872             // Support undefined, no action is taken
873             return false;
874         }
875 
876         if (lowLatencySupport == LOW_LATENCY_SUPPORTED) {
877             if (!clientModeManager.setLowLatencyMode(enabled)) {
878                 Log.e(TAG, "Failed to set low latency mode");
879                 return false;
880             }
881 
882             if (!setPowerSave(clientModeManager, ClientMode.POWER_SAVE_CLIENT_WIFI_LOCK,
883                     !enabled)) {
884                 Log.e(TAG, "Failed to set power save mode");
885                 // Revert the low latency mode
886                 clientModeManager.setLowLatencyMode(!enabled);
887                 return false;
888             }
889         } else if (lowLatencySupport == LOW_LATENCY_NOT_SUPPORTED) {
890             // Only set power save mode
891             if (!setPowerSave(clientModeManager, ClientMode.POWER_SAVE_CLIENT_WIFI_LOCK,
892                     !enabled)) {
893                 Log.e(TAG, "Failed to set power save mode");
894                 return false;
895             }
896         }
897 
898         mIsLowLatencyActivated = enabled;
899         notifyLowLatencyActivated();
900         notifyLowLatencyActiveUsersChanged();
901         return true;
902     }
903 
getLowLatencyLockOwners()904     private int[] getLowLatencyLockOwners() {
905         int[] owners = new int[mLowLatencyUidWatchList.size()];
906         for (int idx = 0; idx < mLowLatencyUidWatchList.size(); idx++) {
907             owners[idx] = mLowLatencyUidWatchList.valueAt(idx).mUid;
908         }
909         return owners;
910     }
911 
getLowLatencyActiveUsers()912     private int[] getLowLatencyActiveUsers() {
913         // Return empty array if low latency mode is not activated. Otherwise, return UIDs which are
914         // in foreground or exempted.
915         if (!mIsLowLatencyActivated) return new int[0];
916         ArrayList<Integer> activeUsers = new ArrayList<>();
917         for (int idx = 0; idx < mLowLatencyUidWatchList.size(); idx++) {
918             if (mLowLatencyUidWatchList.valueAt(idx).mIsFg) {
919                 activeUsers.add(mLowLatencyUidWatchList.valueAt(idx).mUid);
920             }
921         }
922         return activeUsers.stream().mapToInt(i->i).toArray();
923     }
924 
925     /**
926      * See {@link WifiManager#addWifiLowLatencyLockListener(Executor,
927      * WifiManager.WifiLowLatencyLockListener)}
928      */
addWifiLowLatencyLockListener(@onNull IWifiLowLatencyLockListener listener)929     public boolean addWifiLowLatencyLockListener(@NonNull IWifiLowLatencyLockListener listener) {
930         if (!mWifiLowLatencyLockListeners.register(listener)) {
931             return false;
932         }
933         // Notify the new listener about the current enablement of low latency mode.
934         try {
935             listener.onActivatedStateChanged(mIsLowLatencyActivated);
936             listener.onOwnershipChanged(getLowLatencyLockOwners());
937             if (mIsLowLatencyActivated) {
938                 listener.onActiveUsersChanged(getLowLatencyActiveUsers());
939             }
940         } catch (RemoteException e) {
941             Log.e(TAG, "addWifiLowLatencyLockListener: Failure notifying listener" + e);
942         }
943         return true;
944     }
945 
946     /**
947      * See
948      * {@link WifiManager#removeWifiLowLatencyLockListener(WifiManager.WifiLowLatencyLockListener)}
949      */
removeWifiLowLatencyLockListener(@onNull IWifiLowLatencyLockListener listener)950     public boolean removeWifiLowLatencyLockListener(@NonNull IWifiLowLatencyLockListener listener) {
951         return mWifiLowLatencyLockListeners.unregister(listener);
952     }
953 
notifyLowLatencyActivated()954     private void notifyLowLatencyActivated() {
955         int numCallbacks = mWifiLowLatencyLockListeners.beginBroadcast();
956         if (mVerboseLoggingEnabled) {
957             Log.i(TAG, "Broadcasting IWifiLowLatencyLockListener#onActivatedStateChanged activated="
958                     + mIsLowLatencyActivated);
959         }
960         for (int i = 0; i < numCallbacks; i++) {
961             try {
962                 mWifiLowLatencyLockListeners.getBroadcastItem(i).onActivatedStateChanged(
963                         mIsLowLatencyActivated);
964             } catch (RemoteException e) {
965                 Log.e(TAG,
966                         "Failure broadcasting IWifiLowLatencyLockListener#onActivatedStateChanged"
967                                 + e);
968             }
969         }
970         mWifiLowLatencyLockListeners.finishBroadcast();
971         mWifiMetrics.setLowLatencyState(mIsLowLatencyActivated);
972     }
973 
notifyLowLatencyOwnershipChanged()974     private void notifyLowLatencyOwnershipChanged() {
975         int numCallbacks = mWifiLowLatencyLockListeners.beginBroadcast();
976         int[] owners = getLowLatencyLockOwners();
977         if (mVerboseLoggingEnabled) {
978             Log.i(TAG, "Broadcasting IWifiLowLatencyLockListener#onOwnershipChanged: UIDs "
979                     + Arrays.toString(owners));
980         }
981         for (int i = 0; i < numCallbacks; i++) {
982             try {
983                 mWifiLowLatencyLockListeners.getBroadcastItem(i).onOwnershipChanged(owners);
984             } catch (RemoteException e) {
985                 Log.e(TAG,
986                         "Failure broadcasting IWifiLowLatencyLockListener#onOwnershipChanged" + e);
987             }
988         }
989         mWifiLowLatencyLockListeners.finishBroadcast();
990     }
991 
notifyLowLatencyActiveUsersChanged()992     private void notifyLowLatencyActiveUsersChanged() {
993         if (!mIsLowLatencyActivated) return;
994         int numCallbacks = mWifiLowLatencyLockListeners.beginBroadcast();
995         int[] activeUsers = getLowLatencyActiveUsers();
996         if (mVerboseLoggingEnabled) {
997             Log.i(TAG, "Broadcasting IWifiLowLatencyLockListener#onActiveUsersChanged: UIDs "
998                     + Arrays.toString(activeUsers));
999         }
1000         for (int i = 0; i < numCallbacks; i++) {
1001             try {
1002                 mWifiLowLatencyLockListeners.getBroadcastItem(i).onActiveUsersChanged(activeUsers);
1003             } catch (RemoteException e) {
1004                 Log.e(TAG, "Failure broadcasting IWifiLowLatencyLockListener#onActiveUsersChanged"
1005                         + e);
1006             }
1007         }
1008         mWifiLowLatencyLockListeners.finishBroadcast();
1009     }
1010 
findLockByBinder(IBinder binder)1011     private synchronized WifiLock findLockByBinder(IBinder binder) {
1012         for (WifiLock lock : mWifiLocks) {
1013             if (lock.getBinder() == binder) {
1014                 return lock;
1015             }
1016         }
1017         return null;
1018     }
1019 
countFgLowLatencyUids(boolean isScreenOnExempted)1020     private int countFgLowLatencyUids(boolean isScreenOnExempted) {
1021         int uidCount = 0;
1022         int listSize = mLowLatencyUidWatchList.size();
1023         for (int idx = 0; idx < listSize; idx++) {
1024             UidRec uidRec = mLowLatencyUidWatchList.valueAt(idx);
1025             if (uidRec.mIsFg) {
1026                 if (isScreenOnExempted) {
1027                     if (uidRec.mIsScreenOnExempted) uidCount++;
1028                 } else {
1029                     uidCount++;
1030                 }
1031             }
1032         }
1033         return uidCount;
1034     }
1035 
setBlameHiPerfWs(WorkSource ws, boolean shouldBlame)1036     private void setBlameHiPerfWs(WorkSource ws, boolean shouldBlame) {
1037         long ident = Binder.clearCallingIdentity();
1038         Pair<int[], String[]> uidsAndTags = WorkSourceUtil.getUidsAndTagsForWs(ws);
1039         try {
1040             if (shouldBlame) {
1041                 mHighPerfBlamedWorkSource.add(ws);
1042                 mBatteryStats.reportFullWifiLockAcquiredFromSource(ws);
1043                 WifiStatsLog.write(WifiStatsLog.WIFI_LOCK_STATE_CHANGED,
1044                         uidsAndTags.first, uidsAndTags.second,
1045                         WifiStatsLog.WIFI_LOCK_STATE_CHANGED__STATE__ON,
1046                         WifiStatsLog.WIFI_LOCK_STATE_CHANGED__MODE__WIFI_MODE_FULL_HIGH_PERF);
1047             } else {
1048                 mBatteryStats.reportFullWifiLockReleasedFromSource(ws);
1049                 WifiStatsLog.write(WifiStatsLog.WIFI_LOCK_STATE_CHANGED,
1050                         uidsAndTags.first, uidsAndTags.second,
1051                         WifiStatsLog.WIFI_LOCK_STATE_CHANGED__STATE__OFF,
1052                         WifiStatsLog.WIFI_LOCK_STATE_CHANGED__MODE__WIFI_MODE_FULL_HIGH_PERF);
1053             }
1054         } finally {
1055             Binder.restoreCallingIdentity(ident);
1056         }
1057     }
1058 
setBlameLowLatencyUid(int uid, boolean shouldBlame)1059     private void setBlameLowLatencyUid(int uid, boolean shouldBlame) {
1060         long ident = Binder.clearCallingIdentity();
1061         try {
1062             if (shouldBlame) {
1063                 mLowLatencyBlamedWorkSource.add(new WorkSource(uid));
1064                 mBatteryStats.reportFullWifiLockAcquiredFromSource(new WorkSource(uid));
1065                 WifiStatsLog.write_non_chained(WifiStatsLog.WIFI_LOCK_STATE_CHANGED, uid, null,
1066                         WifiStatsLog.WIFI_LOCK_STATE_CHANGED__STATE__ON,
1067                         WifiStatsLog.WIFI_LOCK_STATE_CHANGED__MODE__WIFI_MODE_FULL_LOW_LATENCY);
1068             } else {
1069                 mBatteryStats.reportFullWifiLockReleasedFromSource(new WorkSource(uid));
1070                 WifiStatsLog.write_non_chained(WifiStatsLog.WIFI_LOCK_STATE_CHANGED, uid, null,
1071                         WifiStatsLog.WIFI_LOCK_STATE_CHANGED__STATE__OFF,
1072                         WifiStatsLog.WIFI_LOCK_STATE_CHANGED__MODE__WIFI_MODE_FULL_LOW_LATENCY);
1073             }
1074         } finally {
1075             Binder.restoreCallingIdentity(ident);
1076         }
1077     }
1078 
setBlameLowLatencyWatchList(BlameReason reason, boolean shouldBlame)1079     private void setBlameLowLatencyWatchList(BlameReason reason, boolean shouldBlame) {
1080         boolean notify = false;
1081         for (int idx = 0; idx < mLowLatencyUidWatchList.size(); idx++) {
1082             UidRec uidRec = mLowLatencyUidWatchList.valueAt(idx);
1083             // The blame state of the UIDs should not be changed if the app is exempted from
1084             // screen-on and the reason for blaming is screen state change.
1085             if (uidRec.mIsScreenOnExempted && reason == BlameReason.SCREEN_STATE_CHANGED) {
1086                 continue;
1087             }
1088             // Affect the blame for only UIDs running in foreground
1089             // UIDs running in the background are already not blamed,
1090             // and they should remain in that state.
1091             if (uidRec.mIsFg) {
1092                 setBlameLowLatencyUid(uidRec.mUid, shouldBlame);
1093                 notify = true;
1094             }
1095         }
1096         if (notify) notifyLowLatencyActiveUsersChanged();
1097     }
1098 
dump(PrintWriter pw)1099     protected synchronized void dump(PrintWriter pw) {
1100         pw.println("Locks acquired: "
1101                 + mFullHighPerfLocksAcquired + " full high perf, "
1102                 + mFullLowLatencyLocksAcquired + " full low latency");
1103         pw.println("Locks released: "
1104                 + mFullHighPerfLocksReleased + " full high perf, "
1105                 + mFullLowLatencyLocksReleased + " full low latency");
1106 
1107         pw.println();
1108         pw.println("Locks held:");
1109         for (WifiLock lock : mWifiLocks) {
1110             pw.print("    ");
1111             pw.println(lock);
1112         }
1113     }
1114 
enableVerboseLogging(boolean verboseEnabled)1115     protected void enableVerboseLogging(boolean verboseEnabled) {
1116         mVerboseLoggingEnabled = verboseEnabled;
1117     }
1118 
1119     private class WifiLock implements IBinder.DeathRecipient {
1120         String mTag;
1121         int mUid;
1122         IBinder mBinder;
1123         int mMode;
1124         WorkSource mWorkSource;
1125         long mAcqTimestamp;
1126 
WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws)1127         WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1128             mTag = tag;
1129             mBinder = binder;
1130             mUid = Binder.getCallingUid();
1131             mMode = lockMode;
1132             mWorkSource = ws;
1133             mAcqTimestamp = mClock.getElapsedSinceBootMillis();
1134             try {
1135                 mBinder.linkToDeath(this, 0);
1136             } catch (RemoteException e) {
1137                 Log.e(TAG, "mBinder.linkToDeath failed: " + e.getMessage());
1138                 binderDied();
1139             }
1140         }
1141 
getWorkSource()1142         protected WorkSource getWorkSource() {
1143             return mWorkSource;
1144         }
1145 
getUid()1146         protected int getUid() {
1147             return mUid;
1148         }
1149 
getBinder()1150         protected IBinder getBinder() {
1151             return mBinder;
1152         }
1153 
getAcqTimestamp()1154         protected long getAcqTimestamp() {
1155             return mAcqTimestamp;
1156         }
1157 
binderDied()1158         public void binderDied() {
1159             mHandler.post(() -> releaseLock(mBinder));
1160         }
1161 
unlinkDeathRecipient()1162         public void unlinkDeathRecipient() {
1163             try {
1164                 mBinder.unlinkToDeath(this, 0);
1165             } catch (NoSuchElementException e) {
1166                 Log.e(TAG, "mBinder.unlinkToDeath failed: " + e.getMessage());
1167             }
1168         }
1169 
toString()1170         public String toString() {
1171             return "WifiLock{" + this.mTag + " type=" + this.mMode + " uid=" + mUid
1172                     + " workSource=" + mWorkSource + "}";
1173         }
1174     }
1175 
1176     private class UidRec {
1177         final int mUid;
1178         // Count of locks owned or co-owned by this UID
1179         int mLockCount;
1180         // Is this UID running in foreground or in exempted state (e.g. foreground-service)
1181         boolean mIsFg;
1182         boolean mIsFgExempted = false;
1183         boolean mIsScreenOnExempted = false;
1184 
UidRec(int uid)1185         UidRec(int uid) {
1186             mUid = uid;
1187         }
1188     }
1189 }
1190