• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.internal.telephony;
18 
19 import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
20 import static android.hardware.radio.V1_0.DeviceStateType.CHARGING_STATE;
21 import static android.hardware.radio.V1_0.DeviceStateType.LOW_DATA_EXPECTED;
22 import static android.hardware.radio.V1_0.DeviceStateType.POWER_SAVE_MODE;
23 
24 import android.app.UiModeManager;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.hardware.display.DisplayManager;
30 import android.hardware.radio.V1_5.IndicationFilter;
31 import android.net.ConnectivityManager;
32 import android.net.Network;
33 import android.net.NetworkCapabilities;
34 import android.net.NetworkRequest;
35 import android.net.TetheringManager;
36 import android.os.BatteryManager;
37 import android.os.Handler;
38 import android.os.Message;
39 import android.os.PowerManager;
40 import android.os.Registrant;
41 import android.os.RegistrantList;
42 import android.provider.Settings;
43 import android.telephony.AccessNetworkConstants.AccessNetworkType;
44 import android.telephony.NetworkRegistrationInfo;
45 import android.util.LocalLog;
46 import android.view.Display;
47 
48 import com.android.internal.annotations.VisibleForTesting;
49 import com.android.internal.util.IndentingPrintWriter;
50 import com.android.telephony.Rlog;
51 
52 import java.io.FileDescriptor;
53 import java.io.PrintWriter;
54 import java.util.ArrayList;
55 import java.util.HashSet;
56 import java.util.Set;
57 
58 /**
59  * The device state monitor monitors the device state such as charging state, power saving sate,
60  * and then passes down the information to the radio modem for the modem to perform its own
61  * proprietary power saving strategy. Device state monitor also turns off the unsolicited
62  * response from the modem when the device does not need to receive it, for example, device's
63  * screen is off and does not have activities like tethering, remote display, etc...This effectively
64  * prevents the CPU from waking up by those unnecessary unsolicited responses such as signal
65  * strength update.
66  */
67 public class DeviceStateMonitor extends Handler {
68     protected static final boolean DBG = false;      /* STOPSHIP if true */
69     protected static final String TAG = DeviceStateMonitor.class.getSimpleName();
70 
71     static final int EVENT_RIL_CONNECTED                = 0;
72     static final int EVENT_AUTOMOTIVE_PROJECTION_STATE_CHANGED = 1;
73     @VisibleForTesting
74     static final int EVENT_SCREEN_STATE_CHANGED         = 2;
75     static final int EVENT_POWER_SAVE_MODE_CHANGED      = 3;
76     @VisibleForTesting
77     static final int EVENT_CHARGING_STATE_CHANGED       = 4;
78     static final int EVENT_TETHERING_STATE_CHANGED      = 5;
79     static final int EVENT_RADIO_AVAILABLE              = 6;
80     @VisibleForTesting
81     static final int EVENT_WIFI_CONNECTION_CHANGED      = 7;
82     static final int EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH = 8;
83     static final int EVENT_RADIO_ON                     = 9;
84     static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE   = 10;
85 
86     private static final int WIFI_UNAVAILABLE = 0;
87     private static final int WIFI_AVAILABLE = 1;
88 
89     private static final int NR_NSA_TRACKING_INDICATIONS_OFF = 0;
90     private static final int NR_NSA_TRACKING_INDICATIONS_EXTENDED = 1;
91     private static final int NR_NSA_TRACKING_INDICATIONS_ALWAYS_ON = 2;
92 
93     private final Phone mPhone;
94 
95     private final LocalLog mLocalLog = new LocalLog(64);
96 
97     private final RegistrantList mPhysicalChannelConfigRegistrants = new RegistrantList();
98 
99     private final NetworkRequest mWifiNetworkRequest =
100             new NetworkRequest.Builder()
101             .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
102             .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
103             .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
104             .build();
105 
106     private final ConnectivityManager.NetworkCallback mNetworkCallback =
107             new ConnectivityManager.NetworkCallback() {
108         Set<Network> mWifiNetworks = new HashSet<>();
109 
110         @Override
111         public void onAvailable(Network network) {
112             synchronized (mWifiNetworks) {
113                 if (mWifiNetworks.size() == 0) {
114                     // We just connected to Wifi, so send an update.
115                     obtainMessage(EVENT_WIFI_CONNECTION_CHANGED, WIFI_AVAILABLE, 0).sendToTarget();
116                     log("Wifi (default) connected", true);
117                 }
118                 mWifiNetworks.add(network);
119             }
120         }
121 
122         @Override
123         public void onLost(Network network) {
124             synchronized (mWifiNetworks) {
125                 mWifiNetworks.remove(network);
126                 if (mWifiNetworks.size() == 0) {
127                     // We just disconnected from the last connected wifi, so send an update.
128                     obtainMessage(
129                             EVENT_WIFI_CONNECTION_CHANGED, WIFI_UNAVAILABLE, 0).sendToTarget();
130                     log("Wifi (default) disconnected", true);
131                 }
132             }
133         }
134     };
135 
136     /**
137      * Flag for wifi/usb/bluetooth tethering turned on or not
138      */
139     private boolean mIsTetheringOn;
140 
141     /**
142      * Screen state provided by Display Manager. True indicates one of the screen is on, otherwise
143      * all off.
144      */
145     private boolean mIsScreenOn;
146 
147     /**
148      * Indicating the device is plugged in and is supplying sufficient power that the battery level
149      * is going up (or the battery is fully charged). See BatteryManager.isCharging() for the
150      * details
151      */
152     private boolean mIsCharging;
153 
154     /**
155      * Flag for device power save mode. See PowerManager.isPowerSaveMode() for the details.
156      * Note that it is not possible both mIsCharging and mIsPowerSaveOn are true at the same time.
157      * The system will automatically end power save mode when the device starts charging.
158      */
159     private boolean mIsPowerSaveOn;
160 
161     /**
162      * Low data expected mode. True indicates low data traffic is expected, for example, when the
163      * device is idle (e.g. screen is off and not doing tethering in the background). Note this
164      * doesn't mean no data is expected.
165      */
166     private boolean mIsLowDataExpected;
167 
168     /**
169      * Wifi is connected. True means both that cellular is likely to be asleep when the screen is
170      * on and that in most cases the device location is relatively close to the WiFi AP. This means
171      * that fewer location updates should be provided by cellular.
172      */
173     private boolean mIsWifiConnected;
174 
175     /**
176      * Automotive projection is active. True means the device is currently connected to Android
177      * Auto. This should be handled by mIsScreenOn, but the Android Auto display is private and not
178      * accessible by DeviceStateMonitor from DisplayMonitor.
179      */
180     private boolean mIsAutomotiveProjectionActive;
181 
182     /**
183      * Radio is on. False means that radio is either off or not available and it is ok to reduce
184      * commands to the radio to avoid unnecessary power consumption.
185      */
186     private boolean mIsRadioOn;
187 
188     /**
189      * True indicates we should always enable the signal strength reporting from radio.
190      */
191     private boolean mIsAlwaysSignalStrengthReportingEnabled;
192 
193     @VisibleForTesting
194     static final int CELL_INFO_INTERVAL_SHORT_MS = 2000;
195     @VisibleForTesting
196     static final int CELL_INFO_INTERVAL_LONG_MS = 10000;
197 
198     /** The minimum required wait time between cell info requests to the modem */
199     private int mCellInfoMinInterval = CELL_INFO_INTERVAL_SHORT_MS;
200 
201     /**
202      * The unsolicited response filter. See IndicationFilter defined in types.hal for the definition
203      * of each bit.
204      */
205     private int mUnsolicitedResponseFilter = IndicationFilter.ALL;
206 
207     private final DisplayManager.DisplayListener mDisplayListener =
208             new DisplayManager.DisplayListener() {
209                 @Override
210                 public void onDisplayAdded(int displayId) { }
211 
212                 @Override
213                 public void onDisplayRemoved(int displayId) { }
214 
215                 @Override
216                 public void onDisplayChanged(int displayId) {
217                     boolean screenOn = isScreenOn();
218                     Message msg = obtainMessage(EVENT_SCREEN_STATE_CHANGED);
219                     msg.arg1 = screenOn ? 1 : 0;
220                     sendMessage(msg);
221                 }
222             };
223 
224     /**
225      * Device state broadcast receiver
226      */
227     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
228         @Override
229         public void onReceive(Context context, Intent intent) {
230             log("received: " + intent, true);
231 
232             Message msg;
233             switch (intent.getAction()) {
234                 case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
235                     msg = obtainMessage(EVENT_POWER_SAVE_MODE_CHANGED);
236                     msg.arg1 = isPowerSaveModeOn() ? 1 : 0;
237                     log("Power Save mode " + ((msg.arg1 == 1) ? "on" : "off"), true);
238                     break;
239                 case BatteryManager.ACTION_CHARGING:
240                     msg = obtainMessage(EVENT_CHARGING_STATE_CHANGED);
241                     msg.arg1 = 1;   // charging
242                     break;
243                 case BatteryManager.ACTION_DISCHARGING:
244                     msg = obtainMessage(EVENT_CHARGING_STATE_CHANGED);
245                     msg.arg1 = 0;   // not charging
246                     break;
247                 case TetheringManager.ACTION_TETHER_STATE_CHANGED:
248                     ArrayList<String> activeTetherIfaces = intent.getStringArrayListExtra(
249                             TetheringManager.EXTRA_ACTIVE_TETHER);
250 
251                     boolean isTetheringOn = activeTetherIfaces != null
252                             && activeTetherIfaces.size() > 0;
253                     log("Tethering " + (isTetheringOn ? "on" : "off"), true);
254                     msg = obtainMessage(EVENT_TETHERING_STATE_CHANGED);
255                     msg.arg1 = isTetheringOn ? 1 : 0;
256                     break;
257                 default:
258                     log("Unexpected broadcast intent: " + intent, false);
259                     return;
260             }
261             sendMessage(msg);
262         }
263     };
264 
265     /**
266      * Device state monitor constructor. Note that each phone object should have its own device
267      * state monitor, meaning there will be two device monitors on the multi-sim device.
268      *
269      * @param phone Phone object
270      */
DeviceStateMonitor(Phone phone)271     public DeviceStateMonitor(Phone phone) {
272         mPhone = phone;
273         DisplayManager dm = (DisplayManager) phone.getContext().getSystemService(
274                 Context.DISPLAY_SERVICE);
275         dm.registerDisplayListener(mDisplayListener, null);
276 
277         mIsPowerSaveOn = isPowerSaveModeOn();
278         mIsCharging = isDeviceCharging();
279         mIsScreenOn = isScreenOn();
280         mIsRadioOn = isRadioOn();
281         mIsAutomotiveProjectionActive = isAutomotiveProjectionActive();
282         // Assuming tethering is always off after boot up.
283         mIsTetheringOn = false;
284         mIsLowDataExpected = false;
285 
286         log("DeviceStateMonitor mIsTetheringOn=" + mIsTetheringOn
287                 + ", mIsScreenOn=" + mIsScreenOn
288                 + ", mIsCharging=" + mIsCharging
289                 + ", mIsPowerSaveOn=" + mIsPowerSaveOn
290                 + ", mIsLowDataExpected=" + mIsLowDataExpected
291                 + ", mIsAutomotiveProjectionActive=" + mIsAutomotiveProjectionActive
292                 + ", mIsWifiConnected=" + mIsWifiConnected
293                 + ", mIsAlwaysSignalStrengthReportingEnabled="
294                 + mIsAlwaysSignalStrengthReportingEnabled
295                 + ", mIsRadioOn=" + mIsRadioOn, false);
296 
297         final IntentFilter filter = new IntentFilter();
298         filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
299         filter.addAction(BatteryManager.ACTION_CHARGING);
300         filter.addAction(BatteryManager.ACTION_DISCHARGING);
301         filter.addAction(TetheringManager.ACTION_TETHER_STATE_CHANGED);
302         mPhone.getContext().registerReceiver(mBroadcastReceiver, filter, null, mPhone);
303 
304         mPhone.mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
305         mPhone.mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
306         mPhone.mCi.registerForOn(this, EVENT_RADIO_ON, null);
307         mPhone.mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
308 
309         ConnectivityManager cm = (ConnectivityManager) phone.getContext().getSystemService(
310                 Context.CONNECTIVITY_SERVICE);
311         cm.registerNetworkCallback(mWifiNetworkRequest, mNetworkCallback);
312 
313         UiModeManager umm = (UiModeManager) phone.getContext().getSystemService(
314                 Context.UI_MODE_SERVICE);
315         umm.addOnProjectionStateChangedListener(PROJECTION_TYPE_AUTOMOTIVE,
316                 phone.getContext().getMainExecutor(),
317                 (t, pkgs) -> {
318                     Message msg = obtainMessage(EVENT_AUTOMOTIVE_PROJECTION_STATE_CHANGED);
319                     msg.arg1 = Math.min(pkgs.size(), 1);
320                     sendMessage(msg);
321                 });
322     }
323 
324     /**
325      * @return True if low data is expected
326      */
isLowDataExpected()327     private boolean isLowDataExpected() {
328         return (!mIsCharging && !mIsTetheringOn && !mIsScreenOn) || !mIsRadioOn;
329     }
330 
331     /**
332      * @return The minimum period between CellInfo requests to the modem
333      */
334     @VisibleForTesting
computeCellInfoMinInterval()335     public int computeCellInfoMinInterval() {
336         // The screen is on and we're either on cellular or charging. Screen on + Charging is
337         // a likely vehicular scenario, even if there is a nomadic AP.
338         if (mIsScreenOn && !mIsWifiConnected) {
339             // Screen on without WiFi - We are in a high power likely mobile situation.
340             return CELL_INFO_INTERVAL_SHORT_MS;
341         } else if (mIsScreenOn && mIsCharging) {
342             // Screen is on and we're charging, so we favor accuracy over power.
343             return CELL_INFO_INTERVAL_SHORT_MS;
344         } else {
345             // If the screen is off, apps should not need cellular location at rapid intervals.
346             // If the screen is on but we are on wifi and not charging then cellular location
347             // accuracy is not crucial, so favor modem power saving over high accuracy.
348             return CELL_INFO_INTERVAL_LONG_MS;
349         }
350     }
351 
352     /**
353      * @return True if signal strength update should be enabled. See details in
354      *         android.hardware.radio@1.2::IndicationFilter::SIGNAL_STRENGTH.
355      */
shouldEnableSignalStrengthReports()356     private boolean shouldEnableSignalStrengthReports() {
357         // We should enable signal strength update if one of the following condition is true.
358         // 1. Whenever the conditions for high power usage are met.
359         // 2. Any of system services is registrating to always listen to signal strength changes
360         //    and the radio is on (if radio is off no indications should be sent regardless, but
361         //    in the rare case that something registers/unregisters for always-on indications
362         //    and the radio is off, we might as well ignore it).
363         return shouldEnableHighPowerConsumptionIndications()
364                 || (mIsAlwaysSignalStrengthReportingEnabled && mIsRadioOn);
365     }
366 
367     /**
368      * @return True if full network state update should be enabled. When off, only significant
369      *         changes will trigger the network update unsolicited response. See details in
370      *         android.hardware.radio@1.2::IndicationFilter::FULL_NETWORK_STATE.
371      */
shouldEnableFullNetworkStateReports()372     private boolean shouldEnableFullNetworkStateReports() {
373         return shouldEnableNrTrackingIndications();
374     }
375 
376     /**
377      * @return True if data call dormancy changed update should be enabled. See details in
378      *         android.hardware.radio@1.2::IndicationFilter::DATA_CALL_DORMANCY_CHANGED.
379      */
shouldEnableDataCallDormancyChangedReports()380     private boolean shouldEnableDataCallDormancyChangedReports() {
381         return shouldEnableNrTrackingIndications();
382     }
383 
384     /**
385      * @return True if link capacity estimate update should be enabled. See details in
386      *         android.hardware.radio@1.2::IndicationFilter::LINK_CAPACITY_ESTIMATE.
387      */
shouldEnableLinkCapacityEstimateReports()388     private boolean shouldEnableLinkCapacityEstimateReports() {
389         return shouldEnableHighPowerConsumptionIndications();
390     }
391 
392     /**
393      * @return True if physical channel config update should be enabled. See details in
394      *         android.hardware.radio@1.2::IndicationFilter::PHYSICAL_CHANNEL_CONFIG.
395      */
shouldEnablePhysicalChannelConfigReports()396     private boolean shouldEnablePhysicalChannelConfigReports() {
397         return shouldEnableNrTrackingIndications();
398     }
399 
400     /**
401      * @return True if barring info update should be enabled. See details in
402      *         android.hardware.radio@1.5::IndicationFilter::BARRING_INFO.
403      */
shouldEnableBarringInfoReports()404     private boolean shouldEnableBarringInfoReports() {
405         return shouldEnableHighPowerConsumptionIndications();
406     }
407 
408     /**
409      * A common policy to determine if we should enable the necessary indications update,
410      * for power consumption's sake.
411      *
412      * @return True if the response update should be enabled.
413      */
shouldEnableHighPowerConsumptionIndications()414     public boolean shouldEnableHighPowerConsumptionIndications() {
415         // We should enable indications reports if radio is on and one of the following conditions
416         // is true:
417         // 1. The device is charging.
418         // 2. When the screen is on.
419         // 3. When the tethering is on.
420         // 4. When automotive projection (Android Auto) is on.
421         return (mIsCharging || mIsScreenOn || mIsTetheringOn || mIsAutomotiveProjectionActive)
422                 && mIsRadioOn;
423     }
424 
425     /**
426      * For 5G NSA devices, a policy to determine if we should enable NR tracking indications.
427      *
428      * @return True if the response update should be enabled.
429      */
shouldEnableNrTrackingIndications()430     private boolean shouldEnableNrTrackingIndications() {
431         int trackingMode = Settings.Global.getInt(mPhone.getContext().getContentResolver(),
432                 Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE, NR_NSA_TRACKING_INDICATIONS_OFF);
433         switch (trackingMode) {
434             case NR_NSA_TRACKING_INDICATIONS_ALWAYS_ON:
435                 return true;
436             case NR_NSA_TRACKING_INDICATIONS_EXTENDED:
437                 if (mPhone.getServiceState().getNrState()
438                         == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
439                     return true;
440                 }
441                 // fallthrough
442             case NR_NSA_TRACKING_INDICATIONS_OFF:
443                 return shouldEnableHighPowerConsumptionIndications();
444             default:
445                 return shouldEnableHighPowerConsumptionIndications();
446         }
447     }
448 
449     /**
450      * Set if Telephony need always report signal strength.
451      *
452      * @param isEnable
453      */
setAlwaysReportSignalStrength(boolean isEnable)454     public void setAlwaysReportSignalStrength(boolean isEnable) {
455         Message msg = obtainMessage(EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH);
456         msg.arg1 = isEnable ? 1 : 0;
457         sendMessage(msg);
458     }
459 
460     /**
461      * Message handler
462      *
463      * @param msg The message
464      */
465     @Override
handleMessage(Message msg)466     public void handleMessage(Message msg) {
467         log("handleMessage msg=" + msg, false);
468         switch (msg.what) {
469             case EVENT_RIL_CONNECTED:
470             case EVENT_RADIO_AVAILABLE:
471                 onReset();
472                 break;
473             case EVENT_RADIO_ON:
474                 onUpdateDeviceState(msg.what, /* state= */ true);
475                 break;
476             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
477                 onUpdateDeviceState(msg.what, /* state= */ false);
478                 break;
479             case EVENT_SCREEN_STATE_CHANGED:
480             case EVENT_POWER_SAVE_MODE_CHANGED:
481             case EVENT_CHARGING_STATE_CHANGED:
482             case EVENT_TETHERING_STATE_CHANGED:
483             case EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH:
484             case EVENT_AUTOMOTIVE_PROJECTION_STATE_CHANGED:
485                 onUpdateDeviceState(msg.what, msg.arg1 != 0);
486                 break;
487             case EVENT_WIFI_CONNECTION_CHANGED:
488                 onUpdateDeviceState(msg.what, msg.arg1 != WIFI_UNAVAILABLE);
489                 break;
490             default:
491                 throw new IllegalStateException("Unexpected message arrives. msg = " + msg.what);
492         }
493     }
494 
495     /**
496      * Update the device and send the information to the modem.
497      *
498      * @param eventType Device state event type
499      * @param state True if enabled/on, otherwise disabled/off.
500      */
onUpdateDeviceState(int eventType, boolean state)501     private void onUpdateDeviceState(int eventType, boolean state) {
502         final boolean shouldEnableBarringInfoReportsOld = shouldEnableBarringInfoReports();
503         final boolean wasHighPowerEnabled = shouldEnableHighPowerConsumptionIndications();
504         switch (eventType) {
505             case EVENT_SCREEN_STATE_CHANGED:
506                 if (mIsScreenOn == state) return;
507                 mIsScreenOn = state;
508                 break;
509             case EVENT_CHARGING_STATE_CHANGED:
510                 if (mIsCharging == state) return;
511                 mIsCharging = state;
512                 sendDeviceState(CHARGING_STATE, mIsCharging);
513                 break;
514             case EVENT_RADIO_ON:
515             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
516                 if (mIsRadioOn == state) return;
517                 mIsRadioOn = state;
518                 break;
519             case EVENT_TETHERING_STATE_CHANGED:
520                 if (mIsTetheringOn == state) return;
521                 mIsTetheringOn = state;
522                 break;
523             case EVENT_POWER_SAVE_MODE_CHANGED:
524                 if (mIsPowerSaveOn == state) return;
525                 mIsPowerSaveOn = state;
526                 sendDeviceState(POWER_SAVE_MODE, mIsPowerSaveOn);
527                 break;
528             case EVENT_WIFI_CONNECTION_CHANGED:
529                 if (mIsWifiConnected == state) return;
530                 mIsWifiConnected = state;
531                 break;
532             case EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH:
533                 if (mIsAlwaysSignalStrengthReportingEnabled == state) return;
534                 mIsAlwaysSignalStrengthReportingEnabled = state;
535                 break;
536             case EVENT_AUTOMOTIVE_PROJECTION_STATE_CHANGED:
537                 if (mIsAutomotiveProjectionActive == state) return;
538                 mIsAutomotiveProjectionActive = state;
539                 break;
540             default:
541                 return;
542         }
543 
544         final boolean isHighPowerEnabled = shouldEnableHighPowerConsumptionIndications();
545         if (wasHighPowerEnabled != isHighPowerEnabled) {
546             mPhone.notifyDeviceIdleStateChanged(!isHighPowerEnabled /*isIdle*/);
547         }
548 
549         final int newCellInfoMinInterval = computeCellInfoMinInterval();
550         if (mCellInfoMinInterval != newCellInfoMinInterval) {
551             mCellInfoMinInterval = newCellInfoMinInterval;
552             setCellInfoMinInterval(mCellInfoMinInterval);
553             log("CellInfo Min Interval Updated to " + newCellInfoMinInterval, true);
554         }
555 
556         if (mIsLowDataExpected != isLowDataExpected()) {
557             mIsLowDataExpected = !mIsLowDataExpected;
558             sendDeviceState(LOW_DATA_EXPECTED, mIsLowDataExpected);
559         }
560 
561         // Registration Failure is always reported.
562         int newFilter = IndicationFilter.REGISTRATION_FAILURE;
563 
564         if (shouldEnableSignalStrengthReports()) {
565             newFilter |= IndicationFilter.SIGNAL_STRENGTH;
566         }
567 
568         if (shouldEnableFullNetworkStateReports()) {
569             newFilter |= IndicationFilter.FULL_NETWORK_STATE;
570         }
571 
572         if (shouldEnableDataCallDormancyChangedReports()) {
573             newFilter |= IndicationFilter.DATA_CALL_DORMANCY_CHANGED;
574         }
575 
576         if (shouldEnableLinkCapacityEstimateReports()) {
577             newFilter |= IndicationFilter.LINK_CAPACITY_ESTIMATE;
578         }
579 
580         if (shouldEnablePhysicalChannelConfigReports()) {
581             newFilter |= IndicationFilter.PHYSICAL_CHANNEL_CONFIG;
582         }
583 
584         final boolean shouldEnableBarringInfoReports = shouldEnableBarringInfoReports();
585         if (shouldEnableBarringInfoReports) {
586             newFilter |= IndicationFilter.BARRING_INFO;
587         }
588 
589         // notify PhysicalChannelConfig registrants if state changes
590         if ((newFilter & IndicationFilter.PHYSICAL_CHANNEL_CONFIG)
591                 != (mUnsolicitedResponseFilter & IndicationFilter.PHYSICAL_CHANNEL_CONFIG)) {
592             mPhysicalChannelConfigRegistrants.notifyResult(
593                     (newFilter & IndicationFilter.PHYSICAL_CHANNEL_CONFIG) != 0);
594         }
595 
596         setUnsolResponseFilter(newFilter, false);
597 
598         // Pull barring info AFTER setting filter, the order matters
599         if (shouldEnableBarringInfoReports && !shouldEnableBarringInfoReportsOld) {
600             if (DBG) log("Manually pull barring info...", true);
601             // use a null message since we don't care of receiving response
602             mPhone.mCi.getBarringInfo(null);
603         }
604     }
605 
606     /**
607      * Called when RIL is connected during boot up or radio becomes available after modem restart.
608      *
609      * When modem crashes, if the user turns the screen off before RIL reconnects, device
610      * state and filter cannot be sent to modem. Resend the state here so that modem
611      * has the correct state (to stop signal strength reporting, etc).
612      */
onReset()613     private void onReset() {
614         log("onReset.", true);
615         sendDeviceState(CHARGING_STATE, mIsCharging);
616         sendDeviceState(LOW_DATA_EXPECTED, mIsLowDataExpected);
617         sendDeviceState(POWER_SAVE_MODE, mIsPowerSaveOn);
618         setUnsolResponseFilter(mUnsolicitedResponseFilter, true);
619         setLinkCapacityReportingCriteria();
620         setCellInfoMinInterval(mCellInfoMinInterval);
621     }
622 
623     /**
624      * Convert the device state type into string
625      *
626      * @param type Device state type
627      * @return The converted string
628      */
deviceTypeToString(int type)629     private String deviceTypeToString(int type) {
630         switch (type) {
631             case CHARGING_STATE: return "CHARGING_STATE";
632             case LOW_DATA_EXPECTED: return "LOW_DATA_EXPECTED";
633             case POWER_SAVE_MODE: return "POWER_SAVE_MODE";
634             default: return "UNKNOWN";
635         }
636     }
637 
638     /**
639      * Send the device state to the modem.
640      *
641      * @param type Device state type. See DeviceStateType defined in types.hal.
642      * @param state True if enabled/on, otherwise disabled/off
643      */
sendDeviceState(int type, boolean state)644     private void sendDeviceState(int type, boolean state) {
645         log("send type: " + deviceTypeToString(type) + ", state=" + state, true);
646         mPhone.mCi.sendDeviceState(type, state, null);
647     }
648 
649     /**
650      * Turn on/off the unsolicited response from the modem.
651      *
652      * @param newFilter See UnsolicitedResponseFilter in types.hal for the definition of each bit.
653      * @param force Always set the filter when true.
654      */
setUnsolResponseFilter(int newFilter, boolean force)655     private void setUnsolResponseFilter(int newFilter, boolean force) {
656         if (force || newFilter != mUnsolicitedResponseFilter) {
657             log("old filter: " + mUnsolicitedResponseFilter + ", new filter: " + newFilter, true);
658             mPhone.mCi.setUnsolResponseFilter(newFilter, null);
659             mUnsolicitedResponseFilter = newFilter;
660         }
661     }
662 
setLinkCapacityReportingCriteria()663     private void setLinkCapacityReportingCriteria() {
664         mPhone.setLinkCapacityReportingCriteria(LINK_CAPACITY_DOWNLINK_THRESHOLDS,
665                 LINK_CAPACITY_UPLINK_THRESHOLDS, AccessNetworkType.GERAN);
666         mPhone.setLinkCapacityReportingCriteria(LINK_CAPACITY_DOWNLINK_THRESHOLDS,
667                 LINK_CAPACITY_UPLINK_THRESHOLDS, AccessNetworkType.UTRAN);
668         mPhone.setLinkCapacityReportingCriteria(LINK_CAPACITY_DOWNLINK_THRESHOLDS,
669                 LINK_CAPACITY_UPLINK_THRESHOLDS, AccessNetworkType.EUTRAN);
670         mPhone.setLinkCapacityReportingCriteria(LINK_CAPACITY_DOWNLINK_THRESHOLDS,
671                 LINK_CAPACITY_UPLINK_THRESHOLDS, AccessNetworkType.CDMA2000);
672         if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) {
673             mPhone.setLinkCapacityReportingCriteria(LINK_CAPACITY_DOWNLINK_THRESHOLDS,
674                     LINK_CAPACITY_UPLINK_THRESHOLDS, AccessNetworkType.NGRAN);
675         }
676     }
677 
setCellInfoMinInterval(int rate)678     private void setCellInfoMinInterval(int rate) {
679         mPhone.setCellInfoMinInterval(rate);
680     }
681 
682     /**
683      * @return True if the device is currently in power save mode.
684      * See {@link android.os.BatteryManager#isPowerSaveMode BatteryManager.isPowerSaveMode()}.
685      */
isPowerSaveModeOn()686     private boolean isPowerSaveModeOn() {
687         final PowerManager pm = (PowerManager) mPhone.getContext().getSystemService(
688                 Context.POWER_SERVICE);
689         boolean retval = pm.isPowerSaveMode();
690         log("isPowerSaveModeOn=" + retval, true);
691         return retval;
692     }
693 
694     /**
695      * @return Return true if the battery is currently considered to be charging. This means that
696      * the device is plugged in and is supplying sufficient power that the battery level is
697      * going up (or the battery is fully charged).
698      * See {@link android.os.BatteryManager#isCharging BatteryManager.isCharging()}.
699      */
isDeviceCharging()700     private boolean isDeviceCharging() {
701         final BatteryManager bm = (BatteryManager) mPhone.getContext().getSystemService(
702                 Context.BATTERY_SERVICE);
703         boolean retval = bm.isCharging();
704         log("isDeviceCharging=" + retval, true);
705         return retval;
706     }
707 
708     /**
709      * @return True if one the device's screen (e.g. main screen, wifi display, HDMI display etc...)
710      * is on.
711      */
isScreenOn()712     private boolean isScreenOn() {
713         // Note that we don't listen to Intent.SCREEN_ON and Intent.SCREEN_OFF because they are no
714         // longer adequate for monitoring the screen state since they are not sent in cases where
715         // the screen is turned off transiently such as due to the proximity sensor.
716         final DisplayManager dm = (DisplayManager) mPhone.getContext().getSystemService(
717                 Context.DISPLAY_SERVICE);
718         Display[] displays = dm.getDisplays();
719 
720         if (displays != null) {
721             for (Display display : displays) {
722                 // Anything other than STATE_ON is treated as screen off, such as STATE_DOZE,
723                 // STATE_DOZE_SUSPEND, etc...
724                 if (display.getState() == Display.STATE_ON) {
725                     log("Screen on for display=" + display, true);
726                     return true;
727                 }
728             }
729             log("Screens all off", true);
730             return false;
731         }
732 
733         log("No displays found", true);
734         return false;
735     }
736 
737     /**
738      * @return True if the radio is on.
739      */
isRadioOn()740     private boolean isRadioOn() {
741         return mPhone.isRadioOn();
742     }
743 
744     /**
745      * @return True if automotive projection (Android Auto) is active.
746      */
isAutomotiveProjectionActive()747     private boolean isAutomotiveProjectionActive() {
748         final UiModeManager umm = (UiModeManager) mPhone.getContext().getSystemService(
749                 Context.UI_MODE_SERVICE);
750         if (umm == null) return false;
751         boolean isAutomotiveProjectionActive = (umm.getActiveProjectionTypes()
752                 & PROJECTION_TYPE_AUTOMOTIVE) != 0;
753         log("isAutomotiveProjectionActive=" + isAutomotiveProjectionActive, true);
754         return isAutomotiveProjectionActive;
755     }
756 
757     /**
758      * Register for PhysicalChannelConfig notifications changed. On change, msg.obj will be an
759      * AsyncResult with a boolean result. AsyncResult.result is true if notifications are enabled
760      * and false if they are disabled.
761      *
762      * @param h Handler to notify
763      * @param what msg.what when the message is delivered
764      * @param obj AsyncResult.userObj when the message is delivered
765      */
registerForPhysicalChannelConfigNotifChanged(Handler h, int what, Object obj)766     public void registerForPhysicalChannelConfigNotifChanged(Handler h, int what, Object obj) {
767         Registrant r = new Registrant(h, what, obj);
768         mPhysicalChannelConfigRegistrants.add(r);
769     }
770 
771     /**
772      * Unregister for PhysicalChannelConfig notifications changed.
773      * @param h Handler to notify
774      */
unregisterForPhysicalChannelConfigNotifChanged(Handler h)775     public void unregisterForPhysicalChannelConfigNotifChanged(Handler h) {
776         mPhysicalChannelConfigRegistrants.remove(h);
777     }
778 
779     /**
780      * @param msg Debug message
781      * @param logIntoLocalLog True if log into the local log
782      */
log(String msg, boolean logIntoLocalLog)783     private void log(String msg, boolean logIntoLocalLog) {
784         if (DBG) Rlog.d(TAG, msg);
785         if (logIntoLocalLog) {
786             mLocalLog.log(msg);
787         }
788     }
789 
790     /**
791      * Print the DeviceStateMonitor into the given stream.
792      *
793      * @param fd The raw file descriptor that the dump is being sent to.
794      * @param pw A PrintWriter to which the dump is to be set.
795      * @param args Additional arguments to the dump request.
796      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)797     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
798         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
799         ipw.increaseIndent();
800         ipw.println("mIsTetheringOn=" + mIsTetheringOn);
801         ipw.println("mIsScreenOn=" + mIsScreenOn);
802         ipw.println("mIsCharging=" + mIsCharging);
803         ipw.println("mIsPowerSaveOn=" + mIsPowerSaveOn);
804         ipw.println("mIsLowDataExpected=" + mIsLowDataExpected);
805         ipw.println("mIsAutomotiveProjectionActive=" + mIsAutomotiveProjectionActive);
806         ipw.println("mUnsolicitedResponseFilter=" + mUnsolicitedResponseFilter);
807         ipw.println("mIsWifiConnected=" + mIsWifiConnected);
808         ipw.println("mIsAlwaysSignalStrengthReportingEnabled="
809                 + mIsAlwaysSignalStrengthReportingEnabled);
810         ipw.println("mIsRadioOn=" + mIsRadioOn);
811         ipw.println("Local logs:");
812         ipw.increaseIndent();
813         mLocalLog.dump(fd, ipw, args);
814         ipw.decreaseIndent();
815         ipw.decreaseIndent();
816         ipw.flush();
817     }
818 
819     /**
820      * Downlink reporting thresholds in kbps
821      *
822      * <p>Threshold values taken from FCC Speed Guide when available
823      * (https://www.fcc.gov/reports-research/guides/broadband-speed-guide) and Android WiFi speed
824      * labels (https://support.google.com/pixelphone/answer/2819519#strength_speed).
825      *
826      */
827     private static final int[] LINK_CAPACITY_DOWNLINK_THRESHOLDS = new int[] {
828             100,    // VoIP
829             500,    // Web browsing
830             1000,   // SD video streaming
831             5000,   // HD video streaming
832             10000,  // file downloading
833             20000,  // 4K video streaming
834             50000,  // LTE-Advanced speeds
835             75000,
836             100000,
837             200000, // 5G speeds
838             500000,
839             1000000,
840             1500000,
841             2000000
842     };
843 
844     /** Uplink reporting thresholds in kbps */
845     private static final int[] LINK_CAPACITY_UPLINK_THRESHOLDS = new int[] {
846             100,    // VoIP calls
847             500,
848             1000,   // SD video calling
849             5000,   // HD video calling
850             10000,  // file uploading
851             20000,  // 4K video calling
852             50000,
853             75000,
854             100000,
855             200000,
856             500000
857     };
858 }
859