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