1 /* 2 * Copyright (C) 2018 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 static android.telephony.TelephonyManager.CALL_STATE_IDLE; 20 import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK; 21 import static android.telephony.TelephonyManager.CALL_STATE_RINGING; 22 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.hardware.Sensor; 28 import android.hardware.SensorEvent; 29 import android.hardware.SensorEventListener; 30 import android.hardware.SensorManager; 31 import android.media.AudioManager; 32 import android.media.AudioSystem; 33 import android.net.wifi.WifiManager; 34 import android.os.Handler; 35 import android.os.Looper; 36 import android.telephony.PhoneStateListener; 37 import android.telephony.TelephonyManager; 38 import android.text.TextUtils; 39 import android.util.Log; 40 41 import com.android.internal.R; 42 import com.android.server.wifi.util.WifiHandler; 43 44 import java.io.FileDescriptor; 45 import java.io.PrintWriter; 46 import java.util.List; 47 48 /** 49 * This class provides the Support for SAR to control WiFi TX power limits. 50 * It deals with the following: 51 * - Tracking the STA state through calls from the ClientModeManager. 52 * - Tracking the SAP state through calls from SoftApManager 53 * - Tracking the Scan-Only state through ScanOnlyModeManager 54 * - Tracking the state of the Cellular calls or data. 55 * - Tracking the sensor indicating proximity to user head/hand/body. 56 * - It constructs the sar info and send it towards the HAL 57 */ 58 public class SarManager { 59 // Period for checking on voice steam active (in ms) 60 private static final int CHECK_VOICE_STREAM_INTERVAL_MS = 5000; 61 /* For Logging */ 62 private static final String TAG = "WifiSarManager"; 63 private boolean mVerboseLoggingEnabled = true; 64 65 private SarInfo mSarInfo; 66 67 /* Configuration for SAR support */ 68 private boolean mSupportSarTxPowerLimit; 69 private boolean mSupportSarVoiceCall; 70 private boolean mSupportSarSoftAp; 71 private boolean mSupportSarSensor; 72 /* Sensor event definitions */ 73 private int mSarSensorEventFreeSpace; 74 private int mSarSensorEventNearBody; 75 private int mSarSensorEventNearHand; 76 private int mSarSensorEventNearHead; 77 78 // Device starts with screen on 79 private boolean mScreenOn = false; 80 private boolean mIsVoiceStreamCheckEnabled = false; 81 82 /** 83 * Other parameters passed in or created in the constructor. 84 */ 85 private final Context mContext; 86 private final TelephonyManager mTelephonyManager; 87 private final WifiPhoneStateListener mPhoneStateListener; 88 private final WifiNative mWifiNative; 89 private final SarSensorEventListener mSensorListener; 90 private final SensorManager mSensorManager; 91 private final Handler mHandler; 92 private final Looper mLooper; 93 private final WifiMetrics mWifiMetrics; 94 95 /** 96 * Create new instance of SarManager. 97 */ SarManager(Context context, TelephonyManager telephonyManager, Looper looper, WifiNative wifiNative, SensorManager sensorManager, WifiMetrics wifiMetrics)98 SarManager(Context context, 99 TelephonyManager telephonyManager, 100 Looper looper, 101 WifiNative wifiNative, 102 SensorManager sensorManager, 103 WifiMetrics wifiMetrics) { 104 mContext = context; 105 mTelephonyManager = telephonyManager; 106 mWifiNative = wifiNative; 107 mLooper = looper; 108 mHandler = new WifiHandler(TAG, looper); 109 mSensorManager = sensorManager; 110 mWifiMetrics = wifiMetrics; 111 mPhoneStateListener = new WifiPhoneStateListener(looper); 112 mSensorListener = new SarSensorEventListener(); 113 114 readSarConfigs(); 115 if (mSupportSarTxPowerLimit) { 116 mSarInfo = new SarInfo(); 117 setSarConfigsInInfo(); 118 registerListeners(); 119 } 120 } 121 122 /** 123 * Notify SarManager of screen status change 124 */ handleScreenStateChanged(boolean screenOn)125 public void handleScreenStateChanged(boolean screenOn) { 126 if (!mSupportSarVoiceCall) { 127 return; 128 } 129 130 if (mScreenOn == screenOn) { 131 return; 132 } 133 134 if (mVerboseLoggingEnabled) { 135 Log.d(TAG, "handleScreenStateChanged: screenOn = " + screenOn); 136 } 137 138 mScreenOn = screenOn; 139 140 // Only schedule a voice stream check if screen is turning on, and it is currently not 141 // scheduled 142 if (mScreenOn && !mIsVoiceStreamCheckEnabled) { 143 mHandler.post(() -> { 144 checkAudioDevice(); 145 }); 146 147 mIsVoiceStreamCheckEnabled = true; 148 } 149 } 150 isVoiceCallOnEarpiece()151 private boolean isVoiceCallOnEarpiece() { 152 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 153 154 return (audioManager.getDevicesForStream(AudioManager.STREAM_VOICE_CALL) 155 == AudioManager.DEVICE_OUT_EARPIECE); 156 } 157 isVoiceCallStreamActive()158 private boolean isVoiceCallStreamActive() { 159 return AudioSystem.isStreamActive(AudioManager.STREAM_VOICE_CALL, 0); 160 } 161 checkAudioDevice()162 private void checkAudioDevice() { 163 // First Check if audio stream is on 164 boolean voiceStreamActive = isVoiceCallStreamActive(); 165 boolean earPieceActive; 166 167 if (voiceStreamActive) { 168 // Check on the audio route 169 earPieceActive = isVoiceCallOnEarpiece(); 170 171 if (mVerboseLoggingEnabled) { 172 Log.d(TAG, "EarPiece active = " + earPieceActive); 173 } 174 } else { 175 earPieceActive = false; 176 } 177 178 // If audio route has changed, update SAR 179 if (earPieceActive != mSarInfo.isEarPieceActive) { 180 mSarInfo.isEarPieceActive = earPieceActive; 181 updateSarScenario(); 182 } 183 184 // Now should we proceed with the checks 185 if (!mScreenOn && !voiceStreamActive) { 186 // No need to continue checking 187 mIsVoiceStreamCheckEnabled = false; 188 } else { 189 // Schedule another check 190 mHandler.postDelayed(() -> { 191 checkAudioDevice(); 192 }, CHECK_VOICE_STREAM_INTERVAL_MS); 193 } 194 } 195 readSarConfigs()196 private void readSarConfigs() { 197 mSupportSarTxPowerLimit = mContext.getResources().getBoolean( 198 R.bool.config_wifi_framework_enable_sar_tx_power_limit); 199 /* In case SAR is disabled, 200 then all SAR inputs are automatically disabled as well (irrespective of the config) */ 201 if (!mSupportSarTxPowerLimit) { 202 mSupportSarVoiceCall = false; 203 mSupportSarSoftAp = false; 204 mSupportSarSensor = false; 205 return; 206 } 207 208 /* Voice calls are supported when SAR is supported */ 209 mSupportSarVoiceCall = true; 210 211 mSupportSarSoftAp = mContext.getResources().getBoolean( 212 R.bool.config_wifi_framework_enable_soft_ap_sar_tx_power_limit); 213 214 mSupportSarSensor = mContext.getResources().getBoolean( 215 R.bool.config_wifi_framework_enable_body_proximity_sar_tx_power_limit); 216 217 /* Read the sar sensor event Ids */ 218 if (mSupportSarSensor) { 219 mSarSensorEventFreeSpace = mContext.getResources().getInteger( 220 R.integer.config_wifi_framework_sar_free_space_event_id); 221 mSarSensorEventNearBody = mContext.getResources().getInteger( 222 R.integer.config_wifi_framework_sar_near_body_event_id); 223 mSarSensorEventNearHand = mContext.getResources().getInteger( 224 R.integer.config_wifi_framework_sar_near_hand_event_id); 225 mSarSensorEventNearHead = mContext.getResources().getInteger( 226 R.integer.config_wifi_framework_sar_near_head_event_id); 227 } 228 } 229 setSarConfigsInInfo()230 private void setSarConfigsInInfo() { 231 mSarInfo.sarVoiceCallSupported = mSupportSarVoiceCall; 232 mSarInfo.sarSapSupported = mSupportSarSoftAp; 233 mSarInfo.sarSensorSupported = mSupportSarSensor; 234 } 235 registerListeners()236 private void registerListeners() { 237 if (mSupportSarVoiceCall) { 238 /* Listen for Phone State changes */ 239 registerPhoneStateListener(); 240 registerVoiceStreamListener(); 241 } 242 243 /* Only listen for SAR sensor if supported */ 244 if (mSupportSarSensor) { 245 /* Register the SAR sensor listener. 246 * If this fails, we will assume worst case (near head) */ 247 if (!registerSensorListener()) { 248 Log.e(TAG, "Failed to register sensor listener, setting Sensor to NearHead"); 249 mSarInfo.sensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; 250 mWifiMetrics.incrementNumSarSensorRegistrationFailures(); 251 } 252 } 253 } 254 registerVoiceStreamListener()255 private void registerVoiceStreamListener() { 256 Log.i(TAG, "Registering for voice stream status"); 257 258 // Register for listening to transitions of change of voice stream devices 259 IntentFilter filter = new IntentFilter(); 260 filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION); 261 262 mContext.registerReceiver( 263 new BroadcastReceiver() { 264 @Override 265 public void onReceive(Context context, Intent intent) { 266 boolean voiceStreamActive = isVoiceCallStreamActive(); 267 if (!voiceStreamActive) { 268 // No need to proceed, there is no voice call ongoing 269 return; 270 } 271 272 String action = intent.getAction(); 273 int streamType = 274 intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 275 int device = intent.getIntExtra( 276 AudioManager.EXTRA_VOLUME_STREAM_DEVICES, -1); 277 int oldDevice = intent.getIntExtra( 278 AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, -1); 279 280 if (streamType == AudioManager.STREAM_VOICE_CALL) { 281 boolean earPieceActive = mSarInfo.isEarPieceActive; 282 if (device == AudioManager.DEVICE_OUT_EARPIECE) { 283 if (mVerboseLoggingEnabled) { 284 Log.d(TAG, "Switching to earpiece : HEAD ON"); 285 Log.d(TAG, "Old device = " + oldDevice); 286 } 287 earPieceActive = true; 288 } else if (oldDevice == AudioManager.DEVICE_OUT_EARPIECE) { 289 if (mVerboseLoggingEnabled) { 290 Log.d(TAG, "Switching from earpiece : HEAD OFF"); 291 Log.d(TAG, "New device = " + device); 292 } 293 earPieceActive = false; 294 } 295 296 if (earPieceActive != mSarInfo.isEarPieceActive) { 297 mSarInfo.isEarPieceActive = earPieceActive; 298 updateSarScenario(); 299 } 300 } 301 } 302 }, filter, null, mHandler); 303 } 304 305 /** 306 * Register the phone state listener. 307 */ registerPhoneStateListener()308 private void registerPhoneStateListener() { 309 Log.i(TAG, "Registering for telephony call state changes"); 310 mTelephonyManager.listen( 311 mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 312 } 313 314 /** 315 * Register the body/hand/head proximity sensor. 316 */ registerSensorListener()317 private boolean registerSensorListener() { 318 Log.i(TAG, "Registering for Sensor notification Listener"); 319 return mSensorListener.register(); 320 } 321 322 /** 323 * Update Wifi Client State 324 */ setClientWifiState(int state)325 public void setClientWifiState(int state) { 326 boolean newIsEnabled; 327 /* No action is taken if SAR is not supported */ 328 if (!mSupportSarTxPowerLimit) { 329 return; 330 } 331 332 if (state == WifiManager.WIFI_STATE_DISABLED) { 333 newIsEnabled = false; 334 } else if (state == WifiManager.WIFI_STATE_ENABLED) { 335 newIsEnabled = true; 336 } else { 337 /* No change so exiting with no action */ 338 return; 339 } 340 341 /* Report change to HAL if needed */ 342 if (mSarInfo.isWifiClientEnabled != newIsEnabled) { 343 mSarInfo.isWifiClientEnabled = newIsEnabled; 344 updateSarScenario(); 345 } 346 } 347 348 /** 349 * Update Wifi SoftAP State 350 */ setSapWifiState(int state)351 public void setSapWifiState(int state) { 352 boolean newIsEnabled; 353 /* No action is taken if SAR is not supported */ 354 if (!mSupportSarTxPowerLimit) { 355 return; 356 } 357 358 if (state == WifiManager.WIFI_AP_STATE_DISABLED) { 359 newIsEnabled = false; 360 } else if (state == WifiManager.WIFI_AP_STATE_ENABLED) { 361 newIsEnabled = true; 362 } else { 363 /* No change so exiting with no action */ 364 return; 365 } 366 367 /* Report change to HAL if needed */ 368 if (mSarInfo.isWifiSapEnabled != newIsEnabled) { 369 mSarInfo.isWifiSapEnabled = newIsEnabled; 370 updateSarScenario(); 371 } 372 } 373 374 /** 375 * Update Wifi ScanOnly State 376 */ setScanOnlyWifiState(int state)377 public void setScanOnlyWifiState(int state) { 378 boolean newIsEnabled; 379 /* No action is taken if SAR is not supported */ 380 if (!mSupportSarTxPowerLimit) { 381 return; 382 } 383 384 if (state == WifiManager.WIFI_STATE_DISABLED) { 385 newIsEnabled = false; 386 } else if (state == WifiManager.WIFI_STATE_ENABLED) { 387 newIsEnabled = true; 388 } else { 389 /* No change so exiting with no action */ 390 return; 391 } 392 393 /* Report change to HAL if needed */ 394 if (mSarInfo.isWifiScanOnlyEnabled != newIsEnabled) { 395 mSarInfo.isWifiScanOnlyEnabled = newIsEnabled; 396 updateSarScenario(); 397 } 398 } 399 400 /** 401 * Report Cell state event 402 */ onCellStateChangeEvent(int state)403 private void onCellStateChangeEvent(int state) { 404 boolean newIsVoiceCall; 405 switch (state) { 406 case CALL_STATE_OFFHOOK: 407 case CALL_STATE_RINGING: 408 newIsVoiceCall = true; 409 break; 410 411 case CALL_STATE_IDLE: 412 newIsVoiceCall = false; 413 break; 414 415 default: 416 Log.e(TAG, "Invalid Cell State: " + state); 417 return; 418 } 419 420 /* Report change to HAL if needed */ 421 if (mSarInfo.isVoiceCall != newIsVoiceCall) { 422 mSarInfo.isVoiceCall = newIsVoiceCall; 423 424 if (mVerboseLoggingEnabled) { 425 Log.d(TAG, "Voice Call = " + newIsVoiceCall); 426 } 427 updateSarScenario(); 428 } 429 } 430 431 /** 432 * Report an event from the SAR sensor 433 */ onSarSensorEvent(int sarSensorEvent)434 private void onSarSensorEvent(int sarSensorEvent) { 435 int newSensorState; 436 if (sarSensorEvent == mSarSensorEventFreeSpace) { 437 newSensorState = SarInfo.SAR_SENSOR_FREE_SPACE; 438 } else if (sarSensorEvent == mSarSensorEventNearBody) { 439 newSensorState = SarInfo.SAR_SENSOR_NEAR_BODY; 440 } else if (sarSensorEvent == mSarSensorEventNearHand) { 441 newSensorState = SarInfo.SAR_SENSOR_NEAR_HAND; 442 } else if (sarSensorEvent == mSarSensorEventNearHead) { 443 newSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; 444 } else { 445 Log.e(TAG, "Invalid SAR sensor event id: " + sarSensorEvent); 446 return; 447 } 448 449 /* Report change to HAL if needed */ 450 if (mSarInfo.sensorState != newSensorState) { 451 Log.d(TAG, "Setting Sensor state to " + SarInfo.sensorStateToString(newSensorState)); 452 mSarInfo.sensorState = newSensorState; 453 updateSarScenario(); 454 } 455 } 456 457 /** 458 * Enable/disable verbose logging. 459 */ enableVerboseLogging(int verbose)460 public void enableVerboseLogging(int verbose) { 461 if (verbose > 0) { 462 mVerboseLoggingEnabled = true; 463 } else { 464 mVerboseLoggingEnabled = false; 465 } 466 } 467 468 /** 469 * dump() 470 * Dumps SarManager state (as well as its SarInfo member variable state) 471 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)472 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 473 pw.println("Dump of SarManager"); 474 pw.println("isSarSupported: " + mSupportSarTxPowerLimit); 475 pw.println("isSarVoiceCallSupported: " + mSupportSarVoiceCall); 476 pw.println("isSarSoftApSupported: " + mSupportSarSoftAp); 477 pw.println("isSarSensorSupported: " + mSupportSarSensor); 478 pw.println(""); 479 if (mSarInfo != null) { 480 mSarInfo.dump(fd, pw, args); 481 } 482 } 483 484 /** 485 * Listen for phone call state events to set/reset TX power limits for SAR requirements. 486 */ 487 private class WifiPhoneStateListener extends PhoneStateListener { WifiPhoneStateListener(Looper looper)488 WifiPhoneStateListener(Looper looper) { 489 super(looper); 490 } 491 492 /** 493 * onCallStateChanged() 494 * This callback is called when a SAR sensor event is received 495 * Note that this runs in the WifiCoreHandlerThread 496 * since the corresponding Looper was passed to the WifiPhoneStateListener constructor. 497 */ 498 @Override onCallStateChanged(int state, String incomingNumber)499 public void onCallStateChanged(int state, String incomingNumber) { 500 Log.d(TAG, "Received Phone State Change: " + state); 501 502 /* In case of an unsolicited event */ 503 if (!mSupportSarTxPowerLimit || !mSupportSarVoiceCall) { 504 return; 505 } 506 onCellStateChangeEvent(state); 507 } 508 } 509 510 private class SarSensorEventListener implements SensorEventListener { 511 512 private Sensor mSensor; 513 514 /** 515 * Register the SAR listener to get SAR sensor events 516 */ register()517 private boolean register() { 518 /* Get the sensor type from configuration */ 519 String sensorType = mContext.getResources().getString( 520 R.string.config_wifi_sar_sensor_type); 521 if (TextUtils.isEmpty(sensorType)) { 522 Log.e(TAG, "Empty SAR sensor type"); 523 return false; 524 } 525 526 /* Get the sensor object */ 527 Sensor sensor = null; 528 List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); 529 for (Sensor s : sensorList) { 530 if (sensorType.equals(s.getStringType())) { 531 sensor = s; 532 break; 533 } 534 } 535 if (sensor == null) { 536 Log.e(TAG, "Failed to Find the SAR Sensor"); 537 return false; 538 } 539 540 /* Now register the listener */ 541 if (!mSensorManager.registerListener(this, sensor, 542 SensorManager.SENSOR_DELAY_NORMAL)) { 543 Log.e(TAG, "Failed to register SAR Sensor Listener"); 544 return false; 545 } 546 547 return true; 548 } 549 550 /** 551 * onSensorChanged() 552 * This callback is called when a SAR sensor event is received 553 * Note that this runs in the WifiCoreHandlerThread 554 * since, the corresponding Looper was passed to the SensorManager instance. 555 */ 556 @Override onSensorChanged(SensorEvent event)557 public void onSensorChanged(SensorEvent event) { 558 onSarSensorEvent((int) event.values[0]); 559 } 560 561 @Override onAccuracyChanged(Sensor sensor, int accuracy)562 public void onAccuracyChanged(Sensor sensor, int accuracy) { 563 } 564 } 565 566 /** 567 * updateSarScenario() 568 * Update HAL with the new SAR scenario if needed. 569 */ updateSarScenario()570 private void updateSarScenario() { 571 if (!mSarInfo.shouldReport()) { 572 return; 573 } 574 575 /* Report info to HAL*/ 576 if (mWifiNative.selectTxPowerScenario(mSarInfo)) { 577 mSarInfo.reportingSuccessful(); 578 } else { 579 Log.e(TAG, "Failed in WifiNative.selectTxPowerScenario()"); 580 } 581 582 return; 583 } 584 } 585