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