/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.wifi;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothA2dp;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.NetworkInfo;
import android.net.NetworkStateTracker;
import android.net.DhcpInfo;
import android.net.NetworkUtils;
import android.net.ConnectivityManager;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
import android.os.Message;
import android.os.Parcelable;
import android.os.PowerManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.WorkSource;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
import android.util.Config;
import com.android.internal.app.IBatteryStats;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Track the state of Wifi connectivity. All event handling is done here,
* and all changes in connectivity state are initiated here.
*
* @hide
*/
public class WifiStateTracker extends NetworkStateTracker {
private static final boolean LOCAL_LOGD = Config.LOGD || false;
private static final String TAG = "WifiStateTracker";
// Event log tags (must be in sync with event-log-tags)
private static final int EVENTLOG_NETWORK_STATE_CHANGED = 50021;
private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED = 50022;
private static final int EVENTLOG_DRIVER_STATE_CHANGED = 50023;
private static final int EVENTLOG_INTERFACE_CONFIGURATION_STATE_CHANGED = 50024;
private static final int EVENTLOG_SUPPLICANT_CONNECTION_STATE_CHANGED = 50025;
// Event codes
private static final int EVENT_SUPPLICANT_CONNECTION = 1;
private static final int EVENT_SUPPLICANT_DISCONNECT = 2;
private static final int EVENT_SUPPLICANT_STATE_CHANGED = 3;
private static final int EVENT_NETWORK_STATE_CHANGED = 4;
private static final int EVENT_SCAN_RESULTS_AVAILABLE = 5;
private static final int EVENT_INTERFACE_CONFIGURATION_SUCCEEDED = 6;
private static final int EVENT_INTERFACE_CONFIGURATION_FAILED = 7;
private static final int EVENT_POLL_INTERVAL = 8;
private static final int EVENT_DHCP_START = 9;
private static final int EVENT_DHCP_RENEW = 10;
private static final int EVENT_DEFERRED_DISCONNECT = 11;
private static final int EVENT_DEFERRED_RECONNECT = 12;
/**
* The driver is started or stopped. The object will be the state: true for
* started, false for stopped.
*/
private static final int EVENT_DRIVER_STATE_CHANGED = 13;
private static final int EVENT_PASSWORD_KEY_MAY_BE_INCORRECT = 14;
private static final int EVENT_MAYBE_START_SCAN_POST_DISCONNECT = 15;
/**
* The driver state indication.
*/
private static final int DRIVER_STARTED = 0;
private static final int DRIVER_STOPPED = 1;
private static final int DRIVER_HUNG = 2;
/**
* Interval in milliseconds between polling for connection
* status items that are not sent via asynchronous events.
* An example is RSSI (signal strength).
*/
private static final int POLL_STATUS_INTERVAL_MSECS = 3000;
/**
* The max number of the WPA supplicant loop iterations before we
* decide that the loop should be terminated:
*/
private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4;
/**
* When a DISCONNECT event is received, we defer handling it to
* allow for the possibility that the DISCONNECT is about to
* be followed shortly by a CONNECT to the same network we were
* just connected to. In such a case, we don't want to report
* the network as down, nor do we want to reconfigure the network
* interface, etc. If we get a CONNECT event for another network
* within the delay window, we immediately handle the pending
* disconnect before processing the CONNECT.<p/>
* The five second delay is chosen somewhat arbitrarily, but is
* meant to cover most of the cases where a DISCONNECT/CONNECT
* happens to a network.
*/
private static final int DISCONNECT_DELAY_MSECS = 5000;
/**
* When the supplicant goes idle after we do an explicit disconnect
* following a DHCP failure, we need to kick the supplicant into
* trying to associate with access points.
*/
private static final int RECONNECT_DELAY_MSECS = 2000;
/**
* When the supplicant disconnects from an AP it sometimes forgets
* to restart scanning. Wait this delay before asking it to start
* scanning (in case it forgot). 15 sec is the standard delay between
* scans.
*/
private static final int KICKSTART_SCANNING_DELAY_MSECS = 15000;
/**
* The maximum number of times we will retry a connection to an access point
* for which we have failed in acquiring an IP address from DHCP. A value of
* N means that we will make N+1 connection attempts in all.
* <p>
* See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
* value if a Settings value is not present.
*/
private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
//Minimum dhcp lease duration for renewal
private static final int MIN_RENEWAL_TIME_SECS = 5 * 60; //5 minutes
private static final int DRIVER_POWER_MODE_AUTO = 0;
private static final int DRIVER_POWER_MODE_ACTIVE = 1;
/**
* The current WPA supplicant loop state (used to detect looping behavior):
*/
private SupplicantState mSupplicantLoopState = SupplicantState.DISCONNECTED;
/**
* The current number of WPA supplicant loop iterations:
*/
private int mNumSupplicantLoopIterations = 0;
/**
* The current number of supplicant state changes. This is used to determine
* if we've received any new info since we found out it was DISCONNECTED or
* INACTIVE. If we haven't for X ms, we then request a scan - it should have
* done that automatically, but sometimes some firmware does not.
*/
private int mNumSupplicantStateChanges = 0;
/**
* True if we received an eve