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 java.io.FileDescriptor;
20 import java.io.PrintWriter;
21 
22 /**
23  * This class represents the list of SAR inputs that will be used to select the proper
24  * power profile.
25  * This includes:
26  *  - SAR sensor status
27  *  - Is there an ongoing voice call
28  *  - Is SoftAP active
29  * It also contains info about state of the other Wifi modes
30  *  - Client mode (Sta)
31  *  - ScanOnly mode
32  * It also keeps history for the reporting of SAR states/scenario to avoid unnecessary reporting
33  *  - keeps track of the last reported states
34  *  - keeps track of the last reported SAR scenario
35  *  - keeps track of if all wifi modes were disabled (no reporting should happen then)
36  */
37 public class SarInfo {
38     /**
39      * This value is used as an initial value for the last reported scenario
40      * It is intended to be different than all valid SAR scenario values (including the
41      * reset value).
42      * Using this to initialize the lastReportedScenario results in that the first scenario
43      * (including reset) would be reported.
44      */
45     public static final int INITIAL_SAR_SCENARIO = -2;
46 
47     /**
48      * This value is used for the reset scenario (no TX Power backoff)
49      * Valid scenario values only include scenarios with Tx Power backoff,
50      * so we need this one to represent the "No backoff" case.
51      */
52     public static final int RESET_SAR_SCENARIO = -1;
53 
54     private static final String SAR_SENSOR_FREE_SPACE_STR = "SAR_SENSOR_FREE_SPACE";
55     private static final String SAR_SENSOR_NEAR_BODY_STR  = "SAR_SENSOR_NEAR_BODY";
56     private static final String SAR_SENSOR_NEAR_HAND_STR  = "SAR_SENSOR_NEAR_HAND";
57     private static final String SAR_SENSOR_NEAR_HEAD_STR  = "SAR_SENSOR_NEAR_HEAD";
58 
59     public static final int SAR_SENSOR_FREE_SPACE = 1;
60     public static final int SAR_SENSOR_NEAR_HAND  = 2;
61     public static final int SAR_SENSOR_NEAR_HEAD  = 3;
62     public static final int SAR_SENSOR_NEAR_BODY  = 4;
63 
64     /* For Logging */
65     private static final String TAG = "WifiSarInfo";
66 
67     /* SAR support configs */
68     public boolean sarVoiceCallSupported;
69     public boolean sarSapSupported;
70     public boolean sarSensorSupported;
71 
72     public int sensorState = SAR_SENSOR_FREE_SPACE;
73     public boolean isWifiClientEnabled = false;
74     public boolean isWifiSapEnabled = false;
75     public boolean isWifiScanOnlyEnabled = false;
76     public boolean isVoiceCall = false;
77     public boolean isEarPieceActive = false;
78     public int attemptedSarScenario = RESET_SAR_SCENARIO;
79 
80     private boolean mAllWifiDisabled = true;
81 
82     /* Variables representing the last successfully reported values to hal */
83     private int mLastReportedSensorState = SAR_SENSOR_FREE_SPACE;
84     private boolean mLastReportedIsWifiSapEnabled = false;
85     private boolean mLastReportedIsVoiceCall = false;
86     private boolean mLastReportedIsEarPieceActive = false;
87     private int mLastReportedScenario = INITIAL_SAR_SCENARIO;
88     private long mLastReportedScenarioTs = 0;
89 
90     /**
91      * shouldReport()
92      * This method returns false in the following cases:
93      * 1. If all Wifi modes are disabled.
94      * 2. Values contributing to the SAR scenario selection have not changed
95      *    since last successful reporting.
96      *
97      * Special cases to allow for devices that require setting the SAR scenario value
98      * when the chip comes up (initial startup, or during operation)
99      * 1. This method would report true even with unchanged values from last reporting,
100      *    if any wifi mode is just enabled after all wifi modes were disabled.
101      * 2. This method would report true the first time it is called with any wifi mode enabled.
102      */
shouldReport()103     public boolean shouldReport() {
104         /* Check if all Wifi modes are disabled */
105         if (!isWifiClientEnabled && !isWifiSapEnabled && !isWifiScanOnlyEnabled) {
106             mAllWifiDisabled = true;
107             return false;
108         }
109 
110         /* Check if Wifi was all disabled before this call */
111         if (mAllWifiDisabled) {
112             return true;
113         }
114 
115         /* Check if some change happened since last successful reporting */
116         if ((sensorState != mLastReportedSensorState)
117                 || (isWifiSapEnabled != mLastReportedIsWifiSapEnabled)
118                 || (isVoiceCall != mLastReportedIsVoiceCall)
119                 || (isEarPieceActive != mLastReportedIsEarPieceActive)) {
120             return true;
121         } else {
122             return false;
123         }
124     }
125 
126     /**
127      * reportingSuccessful()
128      * This method is called when reporting SAR scenario is fully successful
129      * This results in caching the last reported inputs for future comparison.
130      */
reportingSuccessful()131     public void reportingSuccessful() {
132         mLastReportedSensorState = sensorState;
133         mLastReportedIsWifiSapEnabled = isWifiSapEnabled;
134         mLastReportedIsVoiceCall = isVoiceCall;
135         mLastReportedIsEarPieceActive = isEarPieceActive;
136         mLastReportedScenario = attemptedSarScenario;
137         mLastReportedScenarioTs = System.currentTimeMillis();
138 
139         mAllWifiDisabled = false;
140     }
141 
142     /**
143      *  resetSarScenarioNeeded()
144      *  Returns true if a call towards HAL to reset SAR scenario would be necessary.
145      *  Returns false if the last call to HAL was already a reset, and hence
146      *  another call to reset the SAR scenario would be redundant.
147      */
resetSarScenarioNeeded()148     public boolean resetSarScenarioNeeded() {
149         return setSarScenarioNeeded(RESET_SAR_SCENARIO);
150     }
151 
152     /**
153      * setSarScenarioNeeded()
154      * Returns true if a call towards HAL to set SAR scenario to that value would be
155      * necessary. This happens in the following cases:
156      *   1. All Wifi modes were disabled, hence we need to init the SAR scenario value.
157      *   2. The new scenario is different from the last reported one.
158      *
159      * Returns false if the last call to HAL was to set the scenario to that value, hence,
160      * another call to set the SAR scenario to the same value would be redundant.
161      */
setSarScenarioNeeded(int scenario)162     public boolean setSarScenarioNeeded(int scenario) {
163         attemptedSarScenario = scenario;
164 
165         if (mAllWifiDisabled || (mLastReportedScenario != scenario)) {
166             return true;
167         }
168         return false;
169     }
170 
171     /**
172      * dump()
173      * Dumps the state of SarInfo
174      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)175     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
176         pw.println("Dump of SarInfo");
177         pw.println("Current values:");
178         pw.println("    Sensor state is: " + sensorStateToString(sensorState));
179         pw.println("    Voice Call state is: " + isVoiceCall);
180         pw.println("    Wifi Client state is: " + isWifiClientEnabled);
181         pw.println("    Wifi Soft AP state is: " + isWifiSapEnabled);
182         pw.println("    Wifi ScanOnly state is: " + isWifiScanOnlyEnabled);
183         pw.println("    Earpiece state is : " + isEarPieceActive);
184         pw.println("Last reported values:");
185         pw.println("    Sensor state is: " + sensorStateToString(mLastReportedSensorState));
186         pw.println("    Soft AP state is: " + mLastReportedIsWifiSapEnabled);
187         pw.println("    Voice Call state is: " + mLastReportedIsVoiceCall);
188         pw.println("    Earpiece state is: " + mLastReportedIsEarPieceActive);
189         pw.println("Last reported scenario: " + mLastReportedScenario);
190         pw.println("Reported " +  (System.currentTimeMillis() - mLastReportedScenarioTs) / 1000
191                 + " seconds ago");
192     }
193 
194     /**
195      * Convert SAR sensor state to string
196      */
sensorStateToString(int sensorState)197     public static String sensorStateToString(int sensorState) {
198         switch(sensorState) {
199             case SAR_SENSOR_FREE_SPACE:
200                 return SAR_SENSOR_FREE_SPACE_STR;
201             case SAR_SENSOR_NEAR_BODY:
202                 return SAR_SENSOR_NEAR_BODY_STR;
203             case SAR_SENSOR_NEAR_HAND:
204                 return SAR_SENSOR_NEAR_HAND_STR;
205             case SAR_SENSOR_NEAR_HEAD:
206                 return SAR_SENSOR_NEAR_HEAD_STR;
207             default:
208                 return "Invalid SAR sensor state";
209         }
210     }
211 }
212