summaryrefslogtreecommitdiffstats
path: root/service/java/com/android/server/wifi/WifiController.java
diff options
context:
space:
mode:
Diffstat (limited to 'service/java/com/android/server/wifi/WifiController.java')
-rw-r--r--service/java/com/android/server/wifi/WifiController.java195
1 files changed, 164 insertions, 31 deletions
diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java
index 9a8967b..a22f985 100644
--- a/service/java/com/android/server/wifi/WifiController.java
+++ b/service/java/com/android/server/wifi/WifiController.java
@@ -36,8 +36,12 @@ import android.os.Message;
import android.os.SystemClock;
import android.os.WorkSource;
import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.Slog;
+import android.widget.Toast;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
@@ -57,21 +61,13 @@ class WifiController extends StateMachine {
private long mIdleMillis;
private int mSleepPolicy;
private boolean mFirstUserSignOnSeen = false;
+ private int mDefaultWifiIdleMs;
private AlarmManager mAlarmManager;
private PendingIntent mIdleIntent;
private static final int IDLE_REQUEST = 0;
/**
- * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a
- * Settings.Global value is not present. This timeout value is chosen as
- * the approximate point at which the battery drain caused by Wi-Fi
- * being enabled but not active exceeds the battery drain caused by
- * re-establishing a connection to the mobile data network.
- */
- private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
-
- /**
* See {@link Settings.Global#WIFI_REENABLE_DELAY_MS}. This is the default value if a
* Settings.Global value is not present. This is the minimum time after wifi is disabled
* we'll act on an enable. Enable requests received before this delay will be deferred.
@@ -102,19 +98,20 @@ class WifiController extends StateMachine {
private static final int BASE = Protocol.BASE_WIFI_CONTROLLER;
- static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1;
- static final int CMD_SCREEN_ON = BASE + 2;
- static final int CMD_SCREEN_OFF = BASE + 3;
- static final int CMD_BATTERY_CHANGED = BASE + 4;
- static final int CMD_DEVICE_IDLE = BASE + 5;
- static final int CMD_LOCKS_CHANGED = BASE + 6;
- static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7;
- static final int CMD_WIFI_TOGGLED = BASE + 8;
- static final int CMD_AIRPLANE_TOGGLED = BASE + 9;
- static final int CMD_SET_AP = BASE + 10;
- static final int CMD_DEFERRED_TOGGLE = BASE + 11;
- static final int CMD_USER_PRESENT = BASE + 12;
- static final int CMD_AP_START_FAILURE = BASE + 13;
+ static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1;
+ static final int CMD_SCREEN_ON = BASE + 2;
+ static final int CMD_SCREEN_OFF = BASE + 3;
+ static final int CMD_BATTERY_CHANGED = BASE + 4;
+ static final int CMD_DEVICE_IDLE = BASE + 5;
+ static final int CMD_LOCKS_CHANGED = BASE + 6;
+ static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7;
+ static final int CMD_WIFI_TOGGLED = BASE + 8;
+ static final int CMD_AIRPLANE_TOGGLED = BASE + 9;
+ static final int CMD_SET_AP = BASE + 10;
+ static final int CMD_DEFERRED_TOGGLE = BASE + 11;
+ static final int CMD_USER_PRESENT = BASE + 12;
+ static final int CMD_AP_START_FAILURE = BASE + 13;
+ static final int CMD_EMERGENCY_CALL_STATE_CHANGED = BASE + 14;
private static final int WIFI_DISABLED = 0;
private static final int WIFI_ENABLED = 1;
@@ -125,6 +122,7 @@ class WifiController extends StateMachine {
private StaDisabledWithScanState mStaDisabledWithScanState = new StaDisabledWithScanState();
private ApEnabledState mApEnabledState = new ApEnabledState();
private DeviceActiveState mDeviceActiveState = new DeviceActiveState();
+ private DeviceActiveHighPerfState mDeviceActiveHighPerfState = new DeviceActiveHighPerfState();
private DeviceInactiveState mDeviceInactiveState = new DeviceInactiveState();
private ScanOnlyLockHeldState mScanOnlyLockHeldState = new ScanOnlyLockHeldState();
private FullLockHeldState mFullLockHeldState = new FullLockHeldState();
@@ -138,6 +136,8 @@ class WifiController extends StateMachine {
mWifiStateMachine = service.mWifiStateMachine;
mSettingsStore = service.mSettingsStore;
mLocks = service.mLocks;
+ mDefaultWifiIdleMs = context.getResources().getInteger(com.android.internal.
+ R.integer.def_wifi_idle_ms);
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
@@ -147,6 +147,7 @@ class WifiController extends StateMachine {
addState(mApStaDisabledState, mDefaultState);
addState(mStaEnabledState, mDefaultState);
addState(mDeviceActiveState, mStaEnabledState);
+ addState(mDeviceActiveHighPerfState, mDeviceActiveState);
addState(mDeviceInactiveState, mStaEnabledState);
addState(mScanOnlyLockHeldState, mDeviceInactiveState);
addState(mFullLockHeldState, mDeviceInactiveState);
@@ -221,7 +222,7 @@ class WifiController extends StateMachine {
private void readWifiIdleTime() {
mIdleMillis = Settings.Global.getLong(mContext.getContentResolver(),
- Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
+ Settings.Global.WIFI_IDLE_MS, mDefaultWifiIdleMs);
}
private void readWifiSleepPolicy() {
@@ -384,6 +385,7 @@ class WifiController extends StateMachine {
case CMD_WIFI_TOGGLED:
case CMD_AIRPLANE_TOGGLED:
case CMD_EMERGENCY_MODE_CHANGED:
+ case CMD_EMERGENCY_CALL_STATE_CHANGED:
case CMD_AP_START_FAILURE:
break;
case CMD_USER_PRESENT:
@@ -429,7 +431,7 @@ class WifiController extends StateMachine {
break;
}
if (mDeviceIdle == false) {
- transitionTo(mDeviceActiveState);
+ checkLocksAndTransitionWhenDeviceActive();
} else {
checkLocksAndTransitionWhenDeviceIdle();
}
@@ -511,6 +513,7 @@ class WifiController extends StateMachine {
transitionTo(mApStaDisabledState);
}
break;
+ case CMD_EMERGENCY_CALL_STATE_CHANGED:
case CMD_EMERGENCY_MODE_CHANGED:
if (msg.arg1 == 1) {
transitionTo(mEcmState);
@@ -564,7 +567,7 @@ class WifiController extends StateMachine {
break;
}
if (mDeviceIdle == false) {
- transitionTo(mDeviceActiveState);
+ checkLocksAndTransitionWhenDeviceActive();
} else {
checkLocksAndTransitionWhenDeviceIdle();
}
@@ -623,6 +626,74 @@ class WifiController extends StateMachine {
}
class ApEnabledState extends State {
+
+ private SubscriptionManager.OnSubscriptionsChangedListener mSubListener;
+
+ @Override
+ public void enter() {
+ mSubListener = new SubscriptionManager.OnSubscriptionsChangedListener() {
+ boolean firstChange = true;
+ SubscriptionInfo lastSub;
+ String lastSubscriberId;
+
+ @Override
+ public void onSubscriptionsChanged() {
+ TelephonyManager tm = (TelephonyManager)
+ mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ final SubscriptionInfo currentSub = SubscriptionManager.from(mContext)
+ .getDefaultDataSubscriptionInfo();
+
+ if (currentSub == null) {
+ // don't disable when we're not sure yet.
+ return;
+ }
+
+ String currentSubscriberId =
+ tm.getSubscriberId(currentSub.getSubscriptionId());
+
+ if (currentSubscriberId == null) {
+ // don't disable when we're not sure yet.
+ return;
+ }
+
+ if (firstChange) {
+ lastSub = currentSub;
+ lastSubscriberId = currentSubscriberId;
+ // we always get a state change on registration.
+ firstChange = false;
+ return;
+ }
+
+ // SubscriptionInfo#getSubscriptionId() returns a
+ // framework handle and is not an IMSI. Don't use it to
+ // determine if the sub changed.
+ //
+ // TelephonyManager#getSubscriberId() returns the IMSI,
+ // so use that instead
+ if (currentSubscriberId.equals(lastSubscriberId)) {
+ // don't disable if it's the same subscription
+ return;
+ }
+
+ lastSub = currentSub;
+ lastSubscriberId = currentSubscriberId;
+
+ Toast.makeText(mContext,
+ com.android.internal.R.string.subscription_change_disabled_wifi_ap,
+ Toast.LENGTH_SHORT).show();
+ log("disabling Wifi AP due to Subscriber Id (IMSI) change");
+ WifiController.this.obtainMessage(CMD_SET_AP, 0, 0, null).sendToTarget();
+ }
+ };
+ SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener(mSubListener);
+ }
+
+ @Override
+ public void exit() {
+ SubscriptionManager.from(mContext).removeOnSubscriptionsChangedListener(mSubListener);
+ mSubListener = null;
+ }
+
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
@@ -650,6 +721,7 @@ class WifiController extends StateMachine {
}
}
break;
+ case CMD_EMERGENCY_CALL_STATE_CHANGED:
case CMD_EMERGENCY_MODE_CHANGED:
if (msg.arg1 == 1) {
mWifiStateMachine.setHostApRunning(null, false);
@@ -670,18 +742,58 @@ class WifiController extends StateMachine {
}
class EcmState extends State {
+ // we can enter EcmState either because an emergency call started or because
+ // emergency callback mode started. This count keeps track of how many such
+ // events happened; so we can exit after all are undone
+
+ private int mEcmEntryCount;
@Override
public void enter() {
mWifiStateMachine.setSupplicantRunning(false);
mWifiStateMachine.clearANQPCache();
+ mEcmEntryCount = 1;
}
@Override
public boolean processMessage(Message msg) {
- if (msg.what == CMD_EMERGENCY_MODE_CHANGED && msg.arg1 == 0) {
+ if (msg.what == CMD_EMERGENCY_CALL_STATE_CHANGED) {
+ if (msg.arg1 == 1) {
+ // nothing to do - just says emergency call started
+ mEcmEntryCount++;
+ } else if (msg.arg1 == 0) {
+ // emergency call ended
+ decrementCountAndReturnToAppropriateState();
+ }
+ return HANDLED;
+ } else if (msg.what == CMD_EMERGENCY_MODE_CHANGED) {
+
+ if (msg.arg1 == 1) {
+ // Transitioned into emergency callback mode
+ mEcmEntryCount++;
+ } else if (msg.arg1 == 0) {
+ // out of emergency callback mode
+ decrementCountAndReturnToAppropriateState();
+ }
+ return HANDLED;
+ } else {
+ return NOT_HANDLED;
+ }
+ }
+
+ private void decrementCountAndReturnToAppropriateState() {
+ boolean exitEcm = false;
+
+ if (mEcmEntryCount == 0) {
+ loge("mEcmEntryCount is 0; exiting Ecm");
+ exitEcm = true;
+ } else if (--mEcmEntryCount == 0) {
+ exitEcm = true;
+ }
+
+ if (exitEcm) {
if (mSettingsStore.isWifiToggleEnabled()) {
if (mDeviceIdle == false) {
- transitionTo(mDeviceActiveState);
+ checkLocksAndTransitionWhenDeviceActive();
} else {
checkLocksAndTransitionWhenDeviceIdle();
}
@@ -690,9 +802,6 @@ class WifiController extends StateMachine {
} else {
transitionTo(mApStaDisabledState);
}
- return HANDLED;
- } else {
- return NOT_HANDLED;
}
}
}
@@ -711,6 +820,9 @@ class WifiController extends StateMachine {
if (msg.what == CMD_DEVICE_IDLE) {
checkLocksAndTransitionWhenDeviceIdle();
// We let default state handle the rest of work
+ } else if (msg.what == CMD_LOCKS_CHANGED) {
+ checkLocksAndTransitionWhenDeviceActive();
+ return HANDLED;
} else if (msg.what == CMD_USER_PRESENT) {
// TLS networks can't connect until user unlocks keystore. KeyStore
// unlocks when the user punches PIN after the reboot. So use this
@@ -725,6 +837,16 @@ class WifiController extends StateMachine {
}
}
+ /* Parent: DeviceActiveState. Device is active, and an app is holding a high perf lock. */
+ class DeviceActiveHighPerfState extends State {
+ @Override
+ public void enter() {
+ mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mWifiStateMachine.setDriverStart(true);
+ mWifiStateMachine.setHighPerfModeEnabled(true);
+ }
+ }
+
/* Parent: StaEnabledState */
class DeviceInactiveState extends State {
@Override
@@ -735,7 +857,7 @@ class WifiController extends StateMachine {
updateBatteryWorkSource();
return HANDLED;
case CMD_SCREEN_ON:
- transitionTo(mDeviceActiveState);
+ checkLocksAndTransitionWhenDeviceActive();
// More work in default state
return NOT_HANDLED;
default:
@@ -781,6 +903,17 @@ class WifiController extends StateMachine {
}
}
+ private void checkLocksAndTransitionWhenDeviceActive() {
+ if (mLocks.hasLocks() && mLocks.getStrongestLockMode() == WIFI_MODE_FULL_HIGH_PERF) {
+ // It is possible for the screen to be off while the device is
+ // is active (mIdleMillis), so we need the high-perf mode
+ // otherwise powersaving mode will be turned on.
+ transitionTo(mDeviceActiveHighPerfState);
+ } else {
+ transitionTo(mDeviceActiveState);
+ }
+ }
+
private void checkLocksAndTransitionWhenDeviceIdle() {
if (mLocks.hasLocks()) {
switch (mLocks.getStrongestLockMode()) {