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