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