• Home
  • History
  • Annotate
  • 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.app.ActivityManager;
20 import android.content.Context;
21 import android.net.wifi.WifiManager;
22 import android.os.Binder;
23 import android.os.Handler;
24 import android.os.IBinder;
25 import android.os.RemoteException;
26 import android.os.WorkSource;
27 import android.os.WorkSource.WorkChain;
28 import android.util.Slog;
29 import android.util.SparseArray;
30 import android.util.StatsLog;
31 
32 import com.android.internal.app.IBatteryStats;
33 
34 import java.io.PrintWriter;
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 /**
39  * WifiLockManager maintains the list of wake locks held by different applications.
40  */
41 public class WifiLockManager {
42     private static final String TAG = "WifiLockManager";
43 
44     private static final int LOW_LATENCY_SUPPORT_UNDEFINED = -1;
45     private static final int LOW_LATENCY_NOT_SUPPORTED     =  0;
46     private static final int LOW_LATENCY_SUPPORTED         =  1;
47 
48     private static final int IGNORE_SCREEN_STATE_MASK = 0x01;
49     private static final int IGNORE_WIFI_STATE_MASK   = 0x02;
50 
51     private int mLatencyModeSupport = LOW_LATENCY_SUPPORT_UNDEFINED;
52 
53     private boolean mVerboseLoggingEnabled = false;
54 
55     private final Clock mClock;
56     private final Context mContext;
57     private final IBatteryStats mBatteryStats;
58     private final FrameworkFacade mFrameworkFacade;
59     private final ClientModeImpl mClientModeImpl;
60     private final ActivityManager mActivityManager;
61     private final Handler mHandler;
62     private final WifiMetrics mWifiMetrics;
63     private final WifiNative mWifiNative;
64 
65     private final List<WifiLock> mWifiLocks = new ArrayList<>();
66     // map UIDs to their corresponding records (for low-latency locks)
67     private final SparseArray<UidRec> mLowLatencyUidWatchList = new SparseArray<>();
68     private int mCurrentOpMode;
69     private boolean mScreenOn = false;
70     private boolean mWifiConnected = false;
71 
72     // For shell command support
73     private boolean mForceHiPerfMode = false;
74     private boolean mForceLowLatencyMode = false;
75 
76     // some wifi lock statistics
77     private int mFullHighPerfLocksAcquired;
78     private int mFullHighPerfLocksReleased;
79     private int mFullLowLatencyLocksAcquired;
80     private int mFullLowLatencyLocksReleased;
81     private long mCurrentSessionStartTimeMs;
82 
WifiLockManager(Context context, IBatteryStats batteryStats, ClientModeImpl clientModeImpl, FrameworkFacade frameworkFacade, Handler handler, WifiNative wifiNative, Clock clock, WifiMetrics wifiMetrics)83     WifiLockManager(Context context, IBatteryStats batteryStats,
84             ClientModeImpl clientModeImpl, FrameworkFacade frameworkFacade, Handler handler,
85             WifiNative wifiNative, Clock clock, WifiMetrics wifiMetrics) {
86         mContext = context;
87         mBatteryStats = batteryStats;
88         mClientModeImpl = clientModeImpl;
89         mFrameworkFacade = frameworkFacade;
90         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
91         mCurrentOpMode = WifiManager.WIFI_MODE_NO_LOCKS_HELD;
92         mWifiNative = wifiNative;
93         mHandler = handler;
94         mClock = clock;
95         mWifiMetrics = wifiMetrics;
96 
97         // Register for UID fg/bg transitions
98         registerUidImportanceTransitions();
99     }
100 
101     // Check for conditions to activate high-perf lock
canActivateHighPerfLock(int ignoreMask)102     private boolean canActivateHighPerfLock(int ignoreMask) {
103         boolean check = true;
104 
105         // Only condition is when Wifi is connected
106         if ((ignoreMask & IGNORE_WIFI_STATE_MASK) == 0) {
107             check = check && mWifiConnected;
108         }
109 
110         return check;
111     }
112 
canActivateHighPerfLock()113     private boolean canActivateHighPerfLock() {
114         return canActivateHighPerfLock(0);
115     }
116 
117     // Check for conditions to activate low-latency lock
canActivateLowLatencyLock(int ignoreMask, UidRec uidRec)118     private boolean canActivateLowLatencyLock(int ignoreMask, UidRec uidRec) {
119         boolean check = true;
120 
121         if ((ignoreMask & IGNORE_WIFI_STATE_MASK) == 0) {
122             check = check && mWifiConnected;
123         }
124         if ((ignoreMask & IGNORE_SCREEN_STATE_MASK) == 0) {
125             check = check && mScreenOn;
126         }
127         if (uidRec != null) {
128             check = check && uidRec.mIsFg;
129         }
130 
131         return check;
132     }
133 
canActivateLowLatencyLock(int ignoreMask)134     private boolean canActivateLowLatencyLock(int ignoreMask) {
135         return canActivateLowLatencyLock(ignoreMask, null);
136     }
137 
canActivateLowLatencyLock()138     private boolean canActivateLowLatencyLock() {
139         return canActivateLowLatencyLock(0, null);
140     }
141 
142     // Detect UIDs going foreground/background
registerUidImportanceTransitions()143     private void registerUidImportanceTransitions() {
144         mActivityManager.addOnUidImportanceListener(new ActivityManager.OnUidImportanceListener() {
145             @Override
146             public void onUidImportance(final int uid, final int importance) {
147                 mHandler.post(() -> {
148                     UidRec uidRec = mLowLatencyUidWatchList.get(uid);
149                     if (uidRec == null) {
150                         // Not a uid in the watch list
151                         return;
152                     }
153 
154                     boolean newModeIsFg = (importance
155                             == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND);
156                     if (uidRec.mIsFg == newModeIsFg) {
157                         return; // already at correct state
158                     }
159 
160                     uidRec.mIsFg = newModeIsFg;
161                     updateOpMode();
162 
163                     // If conditions for lock activation are met,
164                     // then UID either share the blame, or removed from sharing
165                     // whether to start or stop the blame based on UID fg/bg state
166                     if (canActivateLowLatencyLock()) {
167                         setBlameLowLatencyUid(uid, uidRec.mIsFg);
168                     }
169                 });
170             }
171         }, ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
172     }
173 
174     /**
175      * Method allowing a calling app to acquire a Wifi WakeLock in the supplied mode.
176      *
177      * This method checks that the lock mode is a valid WifiLock mode.
178      * @param lockMode int representation of the Wifi WakeLock type.
179      * @param tag String passed to WifiManager.WifiLock
180      * @param binder IBinder for the calling app
181      * @param ws WorkSource of the calling app
182      *
183      * @return true if the lock was successfully acquired, false if the lockMode was invalid.
184      */
acquireWifiLock(int lockMode, String tag, IBinder binder, WorkSource ws)185     public boolean acquireWifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
186         if (!isValidLockMode(lockMode)) {
187             throw new IllegalArgumentException("lockMode =" + lockMode);
188         }
189 
190         // Make a copy of the WorkSource before adding it to the WakeLock
191         // This is to make sure worksource value can not be changed by caller
192         // after function returns.
193         WorkSource newWorkSource = new WorkSource(ws);
194 
195         return addLock(new WifiLock(lockMode, tag, binder, newWorkSource));
196     }
197 
198     /**
199      * Method used by applications to release a WiFi Wake lock.
200      *
201      * @param binder IBinder for the calling app.
202      * @return true if the lock was released, false if the caller did not hold any locks
203      */
releaseWifiLock(IBinder binder)204     public boolean releaseWifiLock(IBinder binder) {
205         return releaseLock(binder);
206     }
207 
208     /**
209      * Method used to get the strongest lock type currently held by the WifiLockManager.
210      *
211      * If no locks are held, WifiManager.WIFI_MODE_NO_LOCKS_HELD is returned.
212      *
213      * @return int representing the currently held (highest power consumption) lock.
214      */
getStrongestLockMode()215     public synchronized int getStrongestLockMode() {
216         // If Wifi Client is not connected, then all locks are not effective
217         if (!mWifiConnected) {
218             return WifiManager.WIFI_MODE_NO_LOCKS_HELD;
219         }
220 
221         // Check if mode is forced to hi-perf
222         if (mForceHiPerfMode) {
223             return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
224         }
225 
226         // Check if mode is forced to low-latency
227         if (mForceLowLatencyMode) {
228             return WifiManager.WIFI_MODE_FULL_LOW_LATENCY;
229         }
230 
231         if (mScreenOn && countFgLowLatencyUids() > 0) {
232             return WifiManager.WIFI_MODE_FULL_LOW_LATENCY;
233         }
234 
235         if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
236             return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
237         }
238 
239         return WifiManager.WIFI_MODE_NO_LOCKS_HELD;
240     }
241 
242     /**
243      * Method to create a WorkSource containing all active WifiLock WorkSources.
244      */
createMergedWorkSource()245     public synchronized WorkSource createMergedWorkSource() {
246         WorkSource mergedWS = new WorkSource();
247         for (WifiLock lock : mWifiLocks) {
248             mergedWS.add(lock.getWorkSource());
249         }
250         return mergedWS;
251     }
252 
253     /**
254      * Method used to update WifiLocks with a new WorkSouce.
255      *
256      * @param binder IBinder for the calling application.
257      * @param ws WorkSource to add to the existing WifiLock(s).
258      */
updateWifiLockWorkSource(IBinder binder, WorkSource ws)259     public synchronized void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
260 
261         // Now check if there is an active lock
262         WifiLock wl = findLockByBinder(binder);
263         if (wl == null) {
264             throw new IllegalArgumentException("Wifi lock not active");
265         }
266 
267         // Make a copy of the WorkSource before adding it to the WakeLock
268         // This is to make sure worksource value can not be changed by caller
269         // after function returns.
270         WorkSource newWorkSource = new WorkSource(ws);
271 
272         if (mVerboseLoggingEnabled) {
273             Slog.d(TAG, "updateWifiLockWakeSource: " + wl + ", newWorkSource=" + newWorkSource);
274         }
275 
276         // Note:
277         // Log the acquire before the release to avoid "holes" in the collected data due to
278         // an acquire event immediately after a release in the case where newWorkSource and
279         // wl.mWorkSource share one or more attribution UIDs. Both batteryStats and statsd
280         // can correctly match "nested" acquire / release pairs.
281         switch(wl.mMode) {
282             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
283                 // Shift blame to new worksource if needed
284                 if (canActivateHighPerfLock()) {
285                     setBlameHiPerfWs(newWorkSource, true);
286                     setBlameHiPerfWs(wl.mWorkSource, false);
287                 }
288                 break;
289             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
290                 addWsToLlWatchList(newWorkSource);
291                 removeWsFromLlWatchList(wl.mWorkSource);
292                 updateOpMode();
293                 break;
294             default:
295                 // Do nothing
296                 break;
297         }
298 
299         wl.mWorkSource = newWorkSource;
300     }
301 
302     /**
303      * Method Used for shell command support
304      *
305      * @param isEnabled True to force hi-perf mode, false to leave it up to acquired wifiLocks.
306      * @return True for success, false for failure (failure turns forcing mode off)
307      */
forceHiPerfMode(boolean isEnabled)308     public boolean forceHiPerfMode(boolean isEnabled) {
309         mForceHiPerfMode = isEnabled;
310         mForceLowLatencyMode = false;
311         if (!updateOpMode()) {
312             Slog.e(TAG, "Failed to force hi-perf mode, returning to normal mode");
313             mForceHiPerfMode = false;
314             return false;
315         }
316         return true;
317     }
318 
319     /**
320      * Method Used for shell command support
321      *
322      * @param isEnabled True to force low-latency mode, false to leave it up to acquired wifiLocks.
323      * @return True for success, false for failure (failure turns forcing mode off)
324      */
forceLowLatencyMode(boolean isEnabled)325     public boolean forceLowLatencyMode(boolean isEnabled) {
326         mForceLowLatencyMode = isEnabled;
327         mForceHiPerfMode = false;
328         if (!updateOpMode()) {
329             Slog.e(TAG, "Failed to force low-latency mode, returning to normal mode");
330             mForceLowLatencyMode = false;
331             return false;
332         }
333         return true;
334     }
335 
336     /**
337      * Handler for screen state (on/off) changes
338      */
handleScreenStateChanged(boolean screenOn)339     public void handleScreenStateChanged(boolean screenOn) {
340         if (mVerboseLoggingEnabled) {
341             Slog.d(TAG, "handleScreenStateChanged: screenOn = " + screenOn);
342         }
343 
344         mScreenOn = screenOn;
345 
346         if (canActivateLowLatencyLock(IGNORE_SCREEN_STATE_MASK)) {
347             // Update the running mode
348             updateOpMode();
349             // Adjust blaming for UIDs in foreground
350             setBlameLowLatencyWatchList(screenOn);
351         }
352     }
353 
354     /**
355      * Handler for Wifi Client mode state changes
356      */
updateWifiClientConnected(boolean isConnected)357     public void updateWifiClientConnected(boolean isConnected) {
358         if (mWifiConnected == isConnected) {
359             // No need to take action
360             return;
361         }
362         mWifiConnected = isConnected;
363 
364         // Adjust blaming for UIDs in foreground carrying low latency locks
365         if (canActivateLowLatencyLock(IGNORE_WIFI_STATE_MASK)) {
366             setBlameLowLatencyWatchList(mWifiConnected);
367         }
368 
369         // Adjust blaming for UIDs carrying high perf locks
370         // Note that blaming is adjusted only if needed,
371         // since calling this API is reference counted
372         if (canActivateHighPerfLock(IGNORE_WIFI_STATE_MASK)) {
373             setBlameHiPerfLocks(mWifiConnected);
374         }
375 
376         updateOpMode();
377     }
378 
setBlameHiPerfLocks(boolean shouldBlame)379     private void setBlameHiPerfLocks(boolean shouldBlame) {
380         for (WifiLock lock : mWifiLocks) {
381             if (lock.mMode == WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
382                 setBlameHiPerfWs(lock.getWorkSource(), shouldBlame);
383             }
384         }
385     }
386 
isValidLockMode(int lockMode)387     private static boolean isValidLockMode(int lockMode) {
388         if (lockMode != WifiManager.WIFI_MODE_FULL
389                 && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY
390                 && lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF
391                 && lockMode != WifiManager.WIFI_MODE_FULL_LOW_LATENCY) {
392             return false;
393         }
394         return true;
395     }
396 
addUidToLlWatchList(int uid)397     private void addUidToLlWatchList(int uid) {
398         UidRec uidRec = mLowLatencyUidWatchList.get(uid);
399         if (uidRec != null) {
400             uidRec.mLockCount++;
401         } else {
402             uidRec = new UidRec(uid);
403             uidRec.mLockCount = 1;
404             mLowLatencyUidWatchList.put(uid, uidRec);
405 
406             // Now check if the uid is running in foreground
407             if (mFrameworkFacade.isAppForeground(uid)) {
408                 uidRec.mIsFg = true;
409             }
410 
411             if (canActivateLowLatencyLock(0, uidRec)) {
412                 // Share the blame for this uid
413                 setBlameLowLatencyUid(uid, true);
414             }
415         }
416     }
417 
removeUidFromLlWatchList(int uid)418     private void removeUidFromLlWatchList(int uid) {
419         UidRec uidRec = mLowLatencyUidWatchList.get(uid);
420         if (uidRec == null) {
421             Slog.e(TAG, "Failed to find uid in low-latency watch list");
422             return;
423         }
424 
425         if (uidRec.mLockCount > 0) {
426             uidRec.mLockCount--;
427         } else {
428             Slog.e(TAG, "Error, uid record conatains no locks");
429         }
430         if (uidRec.mLockCount == 0) {
431             mLowLatencyUidWatchList.remove(uid);
432 
433             // Remove blame for this UID if it was alerady set
434             // Note that blame needs to be stopped only if it was started before
435             // to avoid calling the API unnecessarily, since it is reference counted
436             if (canActivateLowLatencyLock(0, uidRec)) {
437                 setBlameLowLatencyUid(uid, false);
438             }
439         }
440     }
441 
addWsToLlWatchList(WorkSource ws)442     private void addWsToLlWatchList(WorkSource ws) {
443         int wsSize = ws.size();
444         for (int i = 0; i < wsSize; i++) {
445             final int uid = ws.get(i);
446             addUidToLlWatchList(uid);
447         }
448 
449         final List<WorkChain> workChains = ws.getWorkChains();
450         if (workChains != null) {
451             for (int i = 0; i < workChains.size(); ++i) {
452                 final WorkChain workChain = workChains.get(i);
453                 final int uid = workChain.getAttributionUid();
454                 addUidToLlWatchList(uid);
455             }
456         }
457     }
458 
removeWsFromLlWatchList(WorkSource ws)459     private void removeWsFromLlWatchList(WorkSource ws) {
460         int wsSize = ws.size();
461         for (int i = 0; i < wsSize; i++) {
462             final int uid = ws.get(i);
463             removeUidFromLlWatchList(uid);
464         }
465 
466         final List<WorkChain> workChains = ws.getWorkChains();
467         if (workChains != null) {
468             for (int i = 0; i < workChains.size(); ++i) {
469                 final WorkChain workChain = workChains.get(i);
470                 final int uid = workChain.getAttributionUid();
471                 removeUidFromLlWatchList(uid);
472             }
473         }
474     }
475 
addLock(WifiLock lock)476     private synchronized boolean addLock(WifiLock lock) {
477         if (mVerboseLoggingEnabled) {
478             Slog.d(TAG, "addLock: " + lock);
479         }
480 
481         if (findLockByBinder(lock.getBinder()) != null) {
482             if (mVerboseLoggingEnabled) {
483                 Slog.d(TAG, "attempted to add a lock when already holding one");
484             }
485             return false;
486         }
487 
488         mWifiLocks.add(lock);
489 
490         switch(lock.mMode) {
491             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
492                 ++mFullHighPerfLocksAcquired;
493                 // Start blaming this worksource if conditions are met
494                 if (canActivateHighPerfLock()) {
495                     setBlameHiPerfWs(lock.mWorkSource, true);
496                 }
497                 break;
498             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
499                 addWsToLlWatchList(lock.getWorkSource());
500                 ++mFullLowLatencyLocksAcquired;
501                 break;
502             default:
503                 // Do nothing
504                 break;
505         }
506 
507         // Recalculate the operating mode
508         updateOpMode();
509 
510         return true;
511     }
512 
removeLock(IBinder binder)513     private synchronized WifiLock removeLock(IBinder binder) {
514         WifiLock lock = findLockByBinder(binder);
515         if (lock != null) {
516             mWifiLocks.remove(lock);
517             lock.unlinkDeathRecipient();
518         }
519         return lock;
520     }
521 
releaseLock(IBinder binder)522     private synchronized boolean releaseLock(IBinder binder) {
523         WifiLock wifiLock = removeLock(binder);
524         if (wifiLock == null) {
525             // attempting to release a lock that does not exist.
526             return false;
527         }
528 
529         if (mVerboseLoggingEnabled) {
530             Slog.d(TAG, "releaseLock: " + wifiLock);
531         }
532 
533         switch(wifiLock.mMode) {
534             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
535                 ++mFullHighPerfLocksReleased;
536                 mWifiMetrics.addWifiLockAcqSession(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
537                         mClock.getElapsedSinceBootMillis() - wifiLock.getAcqTimestamp());
538                 // Stop blaming only if blaming was set before (conditions are met).
539                 // This is to avoid calling the api unncessarily, since this API is
540                 // reference counted in batteryStats and statsd
541                 if (canActivateHighPerfLock()) {
542                     setBlameHiPerfWs(wifiLock.mWorkSource, false);
543                 }
544                 break;
545             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
546                 removeWsFromLlWatchList(wifiLock.getWorkSource());
547                 ++mFullLowLatencyLocksReleased;
548                 mWifiMetrics.addWifiLockAcqSession(WifiManager.WIFI_MODE_FULL_LOW_LATENCY,
549                         mClock.getElapsedSinceBootMillis() - wifiLock.getAcqTimestamp());
550                 break;
551             default:
552                 // Do nothing
553                 break;
554         }
555 
556         // Recalculate the operating mode
557         updateOpMode();
558 
559         return true;
560     }
561 
updateOpMode()562     private synchronized boolean updateOpMode() {
563         final int newLockMode = getStrongestLockMode();
564 
565         if (newLockMode == mCurrentOpMode) {
566             // No action is needed
567             return true;
568         }
569 
570         if (mVerboseLoggingEnabled) {
571             Slog.d(TAG, "Current opMode: " + mCurrentOpMode + " New LockMode: " + newLockMode);
572         }
573 
574         // Otherwise, we need to change current mode, first reset it to normal
575         switch (mCurrentOpMode) {
576             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
577                 if (!mClientModeImpl.setPowerSave(true)) {
578                     Slog.e(TAG, "Failed to reset the OpMode from hi-perf to Normal");
579                     return false;
580                 }
581                 mWifiMetrics.addWifiLockActiveSession(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
582                         mClock.getElapsedSinceBootMillis() - mCurrentSessionStartTimeMs);
583                 break;
584 
585             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
586                 if (!setLowLatencyMode(false)) {
587                     Slog.e(TAG, "Failed to reset the OpMode from low-latency to Normal");
588                     return false;
589                 }
590                 mWifiMetrics.addWifiLockActiveSession(WifiManager.WIFI_MODE_FULL_LOW_LATENCY,
591                         mClock.getElapsedSinceBootMillis() - mCurrentSessionStartTimeMs);
592                 break;
593 
594             case WifiManager.WIFI_MODE_NO_LOCKS_HELD:
595             default:
596                 // No action
597                 break;
598         }
599 
600         // Set the current mode, before we attempt to set the new mode
601         mCurrentOpMode = WifiManager.WIFI_MODE_NO_LOCKS_HELD;
602 
603         // Now switch to the new opMode
604         switch (newLockMode) {
605             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
606                 if (!mClientModeImpl.setPowerSave(false)) {
607                     Slog.e(TAG, "Failed to set the OpMode to hi-perf");
608                     return false;
609                 }
610                 mCurrentSessionStartTimeMs = mClock.getElapsedSinceBootMillis();
611                 break;
612 
613             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
614                 if (!setLowLatencyMode(true)) {
615                     Slog.e(TAG, "Failed to set the OpMode to low-latency");
616                     return false;
617                 }
618                 mCurrentSessionStartTimeMs = mClock.getElapsedSinceBootMillis();
619                 break;
620 
621             case WifiManager.WIFI_MODE_NO_LOCKS_HELD:
622                 // No action
623                 break;
624 
625             default:
626                 // Invalid mode, don't change currentOpMode , and exit with error
627                 Slog.e(TAG, "Invalid new opMode: " + newLockMode);
628                 return false;
629         }
630 
631         // Now set the mode to the new value
632         mCurrentOpMode = newLockMode;
633         return true;
634     }
635 
getLowLatencyModeSupport()636     private int getLowLatencyModeSupport() {
637         if (mLatencyModeSupport == LOW_LATENCY_SUPPORT_UNDEFINED) {
638             String ifaceName = mWifiNative.getClientInterfaceName();
639             if (ifaceName == null) {
640                 return LOW_LATENCY_SUPPORT_UNDEFINED;
641             }
642 
643             long supportedFeatures = mWifiNative.getSupportedFeatureSet(ifaceName);
644             if (supportedFeatures != 0) {
645                 if ((supportedFeatures & WifiManager.WIFI_FEATURE_LOW_LATENCY) != 0) {
646                     mLatencyModeSupport = LOW_LATENCY_SUPPORTED;
647                 } else {
648                     mLatencyModeSupport = LOW_LATENCY_NOT_SUPPORTED;
649                 }
650             }
651         }
652 
653         return mLatencyModeSupport;
654     }
655 
setLowLatencyMode(boolean enabled)656     private boolean setLowLatencyMode(boolean enabled) {
657         int lowLatencySupport = getLowLatencyModeSupport();
658 
659         if (lowLatencySupport == LOW_LATENCY_SUPPORT_UNDEFINED) {
660             // Support undefined, no action is taken
661             return false;
662         }
663 
664         if (lowLatencySupport == LOW_LATENCY_SUPPORTED) {
665             if (!mClientModeImpl.setLowLatencyMode(enabled)) {
666                 Slog.e(TAG, "Failed to set low latency mode");
667                 return false;
668             }
669 
670             if (!mClientModeImpl.setPowerSave(!enabled)) {
671                 Slog.e(TAG, "Failed to set power save mode");
672                 // Revert the low latency mode
673                 mClientModeImpl.setLowLatencyMode(!enabled);
674                 return false;
675             }
676         } else if (lowLatencySupport == LOW_LATENCY_NOT_SUPPORTED) {
677             // Only set power save mode
678             if (!mClientModeImpl.setPowerSave(!enabled)) {
679                 Slog.e(TAG, "Failed to set power save mode");
680                 return false;
681             }
682         }
683 
684         return true;
685     }
686 
findLockByBinder(IBinder binder)687     private synchronized WifiLock findLockByBinder(IBinder binder) {
688         for (WifiLock lock : mWifiLocks) {
689             if (lock.getBinder() == binder) {
690                 return lock;
691             }
692         }
693         return null;
694     }
695 
countFgLowLatencyUids()696     private int countFgLowLatencyUids() {
697         int uidCount = 0;
698         int listSize = mLowLatencyUidWatchList.size();
699         for (int idx = 0; idx < listSize; idx++) {
700             UidRec uidRec = mLowLatencyUidWatchList.valueAt(idx);
701             if (uidRec.mIsFg) {
702                 uidCount++;
703             }
704         }
705         return uidCount;
706     }
707 
setBlameHiPerfWs(WorkSource ws, boolean shouldBlame)708     private void setBlameHiPerfWs(WorkSource ws, boolean shouldBlame) {
709         long ident = Binder.clearCallingIdentity();
710         try {
711             if (shouldBlame) {
712                 mBatteryStats.noteFullWifiLockAcquiredFromSource(ws);
713                 StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED, ws,
714                         StatsLog.WIFI_LOCK_STATE_CHANGED__STATE__ON,
715                         WifiManager.WIFI_MODE_FULL_HIGH_PERF);
716             } else {
717                 mBatteryStats.noteFullWifiLockReleasedFromSource(ws);
718                 StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED, ws,
719                         StatsLog.WIFI_LOCK_STATE_CHANGED__STATE__OFF,
720                         WifiManager.WIFI_MODE_FULL_HIGH_PERF);
721             }
722         } catch (RemoteException e) {
723             // nop
724         } finally {
725             Binder.restoreCallingIdentity(ident);
726         }
727     }
728 
setBlameLowLatencyUid(int uid, boolean shouldBlame)729     private void setBlameLowLatencyUid(int uid, boolean shouldBlame) {
730         long ident = Binder.clearCallingIdentity();
731         try {
732             if (shouldBlame) {
733                 mBatteryStats.noteFullWifiLockAcquired(uid);
734                 StatsLog.write_non_chained(StatsLog.WIFI_LOCK_STATE_CHANGED, uid, null,
735                         StatsLog.WIFI_LOCK_STATE_CHANGED__STATE__ON,
736                         WifiManager.WIFI_MODE_FULL_LOW_LATENCY);
737             } else {
738                 mBatteryStats.noteFullWifiLockReleased(uid);
739                 StatsLog.write_non_chained(StatsLog.WIFI_LOCK_STATE_CHANGED, uid, null,
740                         StatsLog.WIFI_LOCK_STATE_CHANGED__STATE__OFF,
741                         WifiManager.WIFI_MODE_FULL_LOW_LATENCY);
742             }
743         } catch (RemoteException e) {
744             // nop
745         } finally {
746             Binder.restoreCallingIdentity(ident);
747         }
748     }
749 
setBlameLowLatencyWatchList(boolean shouldBlame)750     private void setBlameLowLatencyWatchList(boolean shouldBlame) {
751         for (int idx = 0; idx < mLowLatencyUidWatchList.size(); idx++) {
752             UidRec uidRec = mLowLatencyUidWatchList.valueAt(idx);
753             // Affect the blame for only UIDs running in foreground
754             // UIDs running in the background are already not blamed,
755             // and they should remain in that state.
756             if (uidRec.mIsFg) {
757                 setBlameLowLatencyUid(uidRec.mUid, shouldBlame);
758             }
759         }
760     }
761 
dump(PrintWriter pw)762     protected void dump(PrintWriter pw) {
763         pw.println("Locks acquired: "
764                 + mFullHighPerfLocksAcquired + " full high perf, "
765                 + mFullLowLatencyLocksAcquired + " full low latency");
766         pw.println("Locks released: "
767                 + mFullHighPerfLocksReleased + " full high perf, "
768                 + mFullLowLatencyLocksReleased + " full low latency");
769 
770         pw.println();
771         pw.println("Locks held:");
772         for (WifiLock lock : mWifiLocks) {
773             pw.print("    ");
774             pw.println(lock);
775         }
776     }
777 
enableVerboseLogging(int verbose)778     protected void enableVerboseLogging(int verbose) {
779         if (verbose > 0) {
780             mVerboseLoggingEnabled = true;
781         } else {
782             mVerboseLoggingEnabled = false;
783         }
784     }
785 
786     private class WifiLock implements IBinder.DeathRecipient {
787         String mTag;
788         int mUid;
789         IBinder mBinder;
790         int mMode;
791         WorkSource mWorkSource;
792         long mAcqTimestamp;
793 
WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws)794         WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
795             mTag = tag;
796             mBinder = binder;
797             mUid = Binder.getCallingUid();
798             mMode = lockMode;
799             mWorkSource = ws;
800             mAcqTimestamp = mClock.getElapsedSinceBootMillis();
801             try {
802                 mBinder.linkToDeath(this, 0);
803             } catch (RemoteException e) {
804                 binderDied();
805             }
806         }
807 
getWorkSource()808         protected WorkSource getWorkSource() {
809             return mWorkSource;
810         }
811 
getUid()812         protected int getUid() {
813             return mUid;
814         }
815 
getBinder()816         protected IBinder getBinder() {
817             return mBinder;
818         }
819 
getAcqTimestamp()820         protected long getAcqTimestamp() {
821             return mAcqTimestamp;
822         }
823 
binderDied()824         public void binderDied() {
825             releaseLock(mBinder);
826         }
827 
unlinkDeathRecipient()828         public void unlinkDeathRecipient() {
829             mBinder.unlinkToDeath(this, 0);
830         }
831 
toString()832         public String toString() {
833             return "WifiLock{" + this.mTag + " type=" + this.mMode + " uid=" + mUid
834                     + " workSource=" + mWorkSource + "}";
835         }
836     }
837 
838     private class UidRec {
839         final int mUid;
840         // Count of locks owned or co-owned by this UID
841         int mLockCount;
842         // Is this UID running in foreground
843         boolean mIsFg;
844 
UidRec(int uid)845         UidRec(int uid) {
846             mUid = uid;
847         }
848     }
849 }
850