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