diff options
Diffstat (limited to 'wifi')
17 files changed, 826 insertions, 881 deletions
diff --git a/wifi/java/android/net/wifi/BatchedScanResult.java b/wifi/java/android/net/wifi/BatchedScanResult.java index eb4e027..7598b92 100644 --- a/wifi/java/android/net/wifi/BatchedScanResult.java +++ b/wifi/java/android/net/wifi/BatchedScanResult.java @@ -20,7 +20,6 @@ import android.os.Parcelable; import android.os.Parcel; import java.util.ArrayList; -import java.util.Collection; import java.util.List; /** diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 149bda6..4a6b1ff 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -111,8 +111,6 @@ interface IWifiManager String getConfigFile(); - void captivePortalCheckComplete(); - void enableTdls(String remoteIPAddress, boolean enable); void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable); diff --git a/wifi/java/android/net/wifi/WifiApConfigStore.java b/wifi/java/android/net/wifi/WifiApConfigStore.java index 0531ca3..e675ad4 100644 --- a/wifi/java/android/net/wifi/WifiApConfigStore.java +++ b/wifi/java/android/net/wifi/WifiApConfigStore.java @@ -36,7 +36,6 @@ import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.net.InetAddress; import java.util.UUID; /** diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java index a6ae215..e45c2e7 100644 --- a/wifi/java/android/net/wifi/WifiConfigStore.java +++ b/wifi/java/android/net/wifi/WifiConfigStore.java @@ -30,12 +30,15 @@ import android.net.wifi.WifiConfiguration.ProxySettings; import android.net.wifi.WifiConfiguration.Status; import android.net.wifi.NetworkUpdateResult; import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; + import android.os.Environment; import android.os.FileObserver; -import android.os.Message; import android.os.Handler; import android.os.HandlerThread; +import android.os.Process; import android.os.UserHandle; +import android.security.Credentials; +import android.security.KeyChain; import android.security.KeyStore; import android.text.TextUtils; import android.util.LocalLog; @@ -56,15 +59,14 @@ import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.PublicKey; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; /** * This class provides the API to manage configured @@ -155,6 +157,61 @@ class WifiConfigStore { private static final String EXCLUSION_LIST_KEY = "exclusionList"; private static final String EOS = "eos"; + + /* Enterprise configuration keys */ + /** + * In old configurations, the "private_key" field was used. However, newer + * configurations use the key_id field with the engine_id set to "keystore". + * If this field is found in the configuration, the migration code is + * triggered. + */ + public static final String OLD_PRIVATE_KEY_NAME = "private_key"; + + /** + * String representing the keystore OpenSSL ENGINE's ID. + */ + public static final String ENGINE_ID_KEYSTORE = "keystore"; + + /** + * String representing the keystore URI used for wpa_supplicant. + */ + public static final String KEYSTORE_URI = "keystore://"; + + /** + * String to set the engine value to when it should be enabled. + */ + public static final String ENGINE_ENABLE = "1"; + + /** + * String to set the engine value to when it should be disabled. + */ + public static final String ENGINE_DISABLE = "0"; + + public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE; + public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + Credentials.USER_CERTIFICATE; + public static final String EAP_KEY = "eap"; + public static final String PHASE2_KEY = "phase2"; + public static final String IDENTITY_KEY = "identity"; + public static final String ANON_IDENTITY_KEY = "anonymous_identity"; + public static final String PASSWORD_KEY = "password"; + public static final String CLIENT_CERT_KEY = "client_cert"; + public static final String CA_CERT_KEY = "ca_cert"; + public static final String SUBJECT_MATCH_KEY = "subject_match"; + public static final String ENGINE_KEY = "engine"; + public static final String ENGINE_ID_KEY = "engine_id"; + public static final String PRIVATE_KEY_ID_KEY = "key_id"; + public static final String OPP_KEY_CACHING = "proactive_key_caching"; + + /** This represents an empty value of an enterprise field. + * NULL is used at wpa_supplicant to indicate an empty value + */ + static final String EMPTY_VALUE = "NULL"; + + /** Internal use only */ + private static final String[] ENTERPRISE_CONFIG_SUPPLICANT_KEYS = new String[] { EAP_KEY, + PHASE2_KEY, IDENTITY_KEY, ANON_IDENTITY_KEY, PASSWORD_KEY, CLIENT_CERT_KEY, + CA_CERT_KEY, SUBJECT_MATCH_KEY, ENGINE_KEY, ENGINE_ID_KEY, PRIVATE_KEY_ID_KEY }; + private final LocalLog mLocalLog; private final WpaConfigFileObserver mFileObserver; @@ -390,7 +447,7 @@ class WifiConfigStore { if (config != null) { // Remove any associated keys if (config.enterpriseConfig != null) { - config.enterpriseConfig.removeKeys(mKeyStore); + removeKeys(config.enterpriseConfig); } mConfiguredNetworks.remove(netId); mNetworkIds.remove(configKey(config)); @@ -754,7 +811,7 @@ class WifiConfigStore { if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { - if (config.enterpriseConfig.needsSoftwareBackedKeyStore()) { + if (needsSoftwareBackedKeyStore(config.enterpriseConfig)) { return true; } } @@ -1239,7 +1296,7 @@ class WifiConfigStore { WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig; - if (enterpriseConfig.needsKeyStore()) { + if (needsKeyStore(enterpriseConfig)) { /** * Keyguard settings may eventually be controlled by device policy. * We check here if keystore is unlocked before installing @@ -1259,7 +1316,7 @@ class WifiConfigStore { WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); String keyId = config.getKeyIdForCredentials(currentConfig); - if (!enterpriseConfig.installKeys(mKeyStore, keyId)) { + if (!installKeys(enterpriseConfig, keyId)) { loge(config.SSID + ": failed to install keys"); break setVariables; } @@ -1276,7 +1333,7 @@ class WifiConfigStore { netId, key, value)) { - enterpriseConfig.removeKeys(mKeyStore); + removeKeys(enterpriseConfig); loge(config.SSID + ": failed to set " + key + ": " + value); break setVariables; @@ -1589,21 +1646,21 @@ class WifiConfigStore { config.enterpriseConfig = new WifiEnterpriseConfig(); } HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields(); - for (String key : WifiEnterpriseConfig.getSupplicantKeys()) { + for (String key : ENTERPRISE_CONFIG_SUPPLICANT_KEYS) { value = mWifiNative.getNetworkVariable(netId, key); if (!TextUtils.isEmpty(value)) { enterpriseFields.put(key, removeDoubleQuotes(value)); } else { - enterpriseFields.put(key, WifiEnterpriseConfig.EMPTY_VALUE); + enterpriseFields.put(key, EMPTY_VALUE); } } - if (config.enterpriseConfig.migrateOldEapTlsNative(mWifiNative, netId)) { + if (migrateOldEapTlsNative(config.enterpriseConfig, netId)) { saveConfig(); } - config.enterpriseConfig.migrateCerts(mKeyStore); - config.enterpriseConfig.initializeSoftwareKeystoreFlag(mKeyStore); + migrateCerts(config.enterpriseConfig); + // initializeSoftwareKeystoreFlag(config.enterpriseConfig, mKeyStore); } private String removeDoubleQuotes(String string) { @@ -1725,4 +1782,241 @@ class WifiConfigStore { } } + // Certificate and privake key management for EnterpriseConfig + boolean needsKeyStore(WifiEnterpriseConfig config) { + // Has no keys to be installed + if (config.getClientCertificate() == null && config.getCaCertificate() == null) + return false; + return true; + } + + static boolean isHardwareBackedKey(PrivateKey key) { + return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); + } + + static boolean hasHardwareBackedKey(Certificate certificate) { + return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); + } + + boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) { + String client = config.getClientCertificateAlias(); + if (!TextUtils.isEmpty(client)) { + // a valid client certificate is configured + + // BUGBUG: keyStore.get() never returns certBytes; because it is not + // taking WIFI_UID as a parameter. It always looks for certificate + // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that + // all certificates need software keystore until we get the get() API + // fixed. + + return true; + } + + /* + try { + + if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials + .USER_CERTIFICATE + client); + + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + if (factory == null) { + Slog.e(TAG, "Error getting certificate factory"); + return; + } + + byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); + if (certBytes != null) { + Certificate cert = (X509Certificate) factory.generateCertificate( + new ByteArrayInputStream(certBytes)); + + if (cert != null) { + mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); + + if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials + .USER_CERTIFICATE + client); + if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : + "does not need" ) + " software key store"); + } else { + Slog.d(TAG, "could not generate certificate"); + } + } else { + Slog.e(TAG, "Could not load client certificate " + Credentials + .USER_CERTIFICATE + client); + mNeedsSoftwareKeystore = true; + } + + } catch(CertificateException e) { + Slog.e(TAG, "Could not read certificates"); + mCaCert = null; + mClientCertificate = null; + } + */ + + return false; + } + + boolean installKeys(WifiEnterpriseConfig config, String name) { + boolean ret = true; + String privKeyName = Credentials.USER_PRIVATE_KEY + name; + String userCertName = Credentials.USER_CERTIFICATE + name; + String caCertName = Credentials.CA_CERTIFICATE + name; + if (config.getClientCertificate() != null) { + byte[] privKeyData = config.getClientPrivateKey().getEncoded(); + if (isHardwareBackedKey(config.getClientPrivateKey())) { + // Hardware backed key store is secure enough to store keys un-encrypted, this + // removes the need for user to punch a PIN to get access to these keys + if (DBG) Log.d(TAG, "importing keys " + name + " in hardware backed store"); + ret = mKeyStore.importKey(privKeyName, privKeyData, android.os.Process.WIFI_UID, + KeyStore.FLAG_NONE); + } else { + // Software backed key store is NOT secure enough to store keys un-encrypted. + // Save keys encrypted so they are protected with user's PIN. User will + // have to unlock phone before being able to use these keys and connect to + // networks. + if (DBG) Log.d(TAG, "importing keys " + name + " in software backed store"); + ret = mKeyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, + KeyStore.FLAG_ENCRYPTED); + } + if (ret == false) { + return ret; + } + + ret = putCertInKeyStore(userCertName, config.getClientCertificate()); + if (ret == false) { + // Remove private key installed + mKeyStore.delKey(privKeyName, Process.WIFI_UID); + return ret; + } + } + + if (config.getCaCertificate() != null) { + ret = putCertInKeyStore(caCertName, config.getCaCertificate()); + if (ret == false) { + if (config.getClientCertificate() != null) { + // Remove client key+cert + mKeyStore.delKey(privKeyName, Process.WIFI_UID); + mKeyStore.delete(userCertName, Process.WIFI_UID); + } + return ret; + } + } + + // Set alias names + if (config.getClientCertificate() != null) { + config.setClientCertificateAlias(name); + config.resetClientKeyEntry(); + } + + if (config.getCaCertificate() != null) { + config.setCaCertificateAlias(name); + config.resetCaCertificate(); + } + + return ret; + } + + private boolean putCertInKeyStore(String name, Certificate cert) { + try { + byte[] certData = Credentials.convertToPem(cert); + if (DBG) Log.d(TAG, "putting certificate " + name + " in keystore"); + return mKeyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); + + } catch (IOException e1) { + return false; + } catch (CertificateException e2) { + return false; + } + } + + void removeKeys(WifiEnterpriseConfig config) { + String client = config.getClientCertificateAlias(); + // a valid client certificate is configured + if (!TextUtils.isEmpty(client)) { + if (DBG) Log.d(TAG, "removing client private key and user cert"); + mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); + mKeyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); + } + + String ca = config.getCaCertificateAlias(); + // a valid ca certificate is configured + if (!TextUtils.isEmpty(ca)) { + if (DBG) Log.d(TAG, "removing CA cert"); + mKeyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); + } + } + + + /** Migrates the old style TLS config to the new config style. This should only be used + * when restoring an old wpa_supplicant.conf or upgrading from a previous + * platform version. + * @return true if the config was updated + * @hide + */ + boolean migrateOldEapTlsNative(WifiEnterpriseConfig config, int netId) { + String oldPrivateKey = mWifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME); + /* + * If the old configuration value is not present, then there is nothing + * to do. + */ + if (TextUtils.isEmpty(oldPrivateKey)) { + return false; + } else { + // Also ignore it if it's empty quotes. + oldPrivateKey = removeDoubleQuotes(oldPrivateKey); + if (TextUtils.isEmpty(oldPrivateKey)) { + return false; + } + } + + config.setFieldValue(ENGINE_KEY, ENGINE_ENABLE); + config.setFieldValue(ENGINE_ID_KEY, ENGINE_ID_KEYSTORE); + + /* + * The old key started with the keystore:// URI prefix, but we don't + * need that anymore. Trim it off if it exists. + */ + final String keyName; + if (oldPrivateKey.startsWith(KEYSTORE_URI)) { + keyName = new String(oldPrivateKey.substring(KEYSTORE_URI.length())); + } else { + keyName = oldPrivateKey; + } + config.setFieldValue(PRIVATE_KEY_ID_KEY, keyName); + + mWifiNative.setNetworkVariable(netId, ENGINE_KEY, config.getFieldValue(ENGINE_KEY, "")); + + mWifiNative.setNetworkVariable(netId, ENGINE_ID_KEY, + config.getFieldValue(ENGINE_ID_KEY, "")); + + mWifiNative.setNetworkVariable(netId, PRIVATE_KEY_ID_KEY, + config.getFieldValue(PRIVATE_KEY_ID_KEY, "")); + + // Remove old private_key string so we don't run this again. + mWifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE); + + return true; + } + + /** Migrate certs from global pool to wifi UID if not already done */ + void migrateCerts(WifiEnterpriseConfig config) { + String client = config.getClientCertificateAlias(); + // a valid client certificate is configured + if (!TextUtils.isEmpty(client)) { + if (!mKeyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) { + mKeyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1, + Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); + mKeyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1, + Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); + } + } + + String ca = config.getCaCertificateAlias(); + // a valid ca certificate is configured + if (!TextUtils.isEmpty(ca)) { + if (!mKeyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) { + mKeyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1, + Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); + } + } + } } diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index c7ebecb..452d84b 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -17,19 +17,13 @@ package android.net.wifi; import android.os.Parcel; import android.os.Parcelable; -import android.os.Process; import android.security.Credentials; -import android.security.KeyChain; -import android.security.KeyStore; import android.text.TextUtils; -import android.util.Slog; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; -import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; @@ -44,62 +38,11 @@ import java.util.Map; * and any associated credentials. */ public class WifiEnterpriseConfig implements Parcelable { - private static final String TAG = "WifiEnterpriseConfig"; - private static final boolean DBG = false; - /** - * In old configurations, the "private_key" field was used. However, newer - * configurations use the key_id field with the engine_id set to "keystore". - * If this field is found in the configuration, the migration code is - * triggered. - */ - private static final String OLD_PRIVATE_KEY_NAME = "private_key"; - - /** - * String representing the keystore OpenSSL ENGINE's ID. - */ - private static final String ENGINE_ID_KEYSTORE = "keystore"; - - /** - * String representing the keystore URI used for wpa_supplicant. - */ - private static final String KEYSTORE_URI = "keystore://"; - - /** - * String to set the engine value to when it should be enabled. - */ - private static final String ENGINE_ENABLE = "1"; - - /** - * String to set the engine value to when it should be disabled. - */ - private static final String ENGINE_DISABLE = "0"; - - private static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE; - private static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + Credentials.USER_CERTIFICATE; - - private static final String EAP_KEY = "eap"; - private static final String PHASE2_KEY = "phase2"; - private static final String IDENTITY_KEY = "identity"; - private static final String ANON_IDENTITY_KEY = "anonymous_identity"; - private static final String PASSWORD_KEY = "password"; - private static final String CLIENT_CERT_KEY = "client_cert"; - private static final String CA_CERT_KEY = "ca_cert"; - private static final String SUBJECT_MATCH_KEY = "subject_match"; - private static final String ENGINE_KEY = "engine"; - private static final String ENGINE_ID_KEY = "engine_id"; - private static final String PRIVATE_KEY_ID_KEY = "key_id"; - private static final String OPP_KEY_CACHING = "proactive_key_caching"; private HashMap<String, String> mFields = new HashMap<String, String>(); private X509Certificate mCaCert; private PrivateKey mClientPrivateKey; private X509Certificate mClientCertificate; - private boolean mNeedsSoftwareKeystore = false; - - /** This represents an empty value of an enterprise field. - * NULL is used at wpa_supplicant to indicate an empty value - */ - static final String EMPTY_VALUE = "NULL"; public WifiEnterpriseConfig() { // Do not set defaults so that the enterprise fields that are not changed @@ -246,7 +189,8 @@ public class WifiEnterpriseConfig implements Parcelable { public static final int GTC = 4; private static final String PREFIX = "auth="; /** @hide */ - public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP", "MSCHAPV2", "GTC" }; + public static final String[] strings = {WifiConfigStore.EMPTY_VALUE, "PAP", "MSCHAP", + "MSCHAPV2", "GTC" }; /** Prevent initialization */ private Phase2() {} @@ -257,13 +201,6 @@ public class WifiEnterpriseConfig implements Parcelable { return mFields; } - /** Internal use only */ - static String[] getSupplicantKeys() { - return new String[] { EAP_KEY, PHASE2_KEY, IDENTITY_KEY, ANON_IDENTITY_KEY, PASSWORD_KEY, - CLIENT_CERT_KEY, CA_CERT_KEY, SUBJECT_MATCH_KEY, ENGINE_KEY, ENGINE_ID_KEY, - PRIVATE_KEY_ID_KEY }; - } - /** * Set the EAP authentication method. * @param eapMethod is one {@link Eap#PEAP}, {@link Eap#TLS}, {@link Eap#TTLS} or @@ -277,8 +214,8 @@ public class WifiEnterpriseConfig implements Parcelable { case Eap.PWD: case Eap.TLS: case Eap.TTLS: - mFields.put(EAP_KEY, Eap.strings[eapMethod]); - mFields.put(OPP_KEY_CACHING, "1"); + mFields.put(WifiConfigStore.EAP_KEY, Eap.strings[eapMethod]); + mFields.put(WifiConfigStore.OPP_KEY_CACHING, "1"); break; default: throw new IllegalArgumentException("Unknown EAP method"); @@ -290,7 +227,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @return eap method configured */ public int getEapMethod() { - String eapMethod = mFields.get(EAP_KEY); + String eapMethod = mFields.get(WifiConfigStore.EAP_KEY); return getStringIndex(Eap.strings, eapMethod, Eap.NONE); } @@ -306,14 +243,14 @@ public class WifiEnterpriseConfig implements Parcelable { public void setPhase2Method(int phase2Method) { switch (phase2Method) { case Phase2.NONE: - mFields.put(PHASE2_KEY, EMPTY_VALUE); + mFields.put(WifiConfigStore.PHASE2_KEY, WifiConfigStore.EMPTY_VALUE); break; /** Valid methods */ case Phase2.PAP: case Phase2.MSCHAP: case Phase2.MSCHAPV2: case Phase2.GTC: - mFields.put(PHASE2_KEY, convertToQuotedString( + mFields.put(WifiConfigStore.PHASE2_KEY, convertToQuotedString( Phase2.PREFIX + Phase2.strings[phase2Method])); break; default: @@ -326,7 +263,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @return a phase 2 method defined at {@link Phase2} * */ public int getPhase2Method() { - String phase2Method = removeDoubleQuotes(mFields.get(PHASE2_KEY)); + String phase2Method = removeDoubleQuotes(mFields.get(WifiConfigStore.PHASE2_KEY)); // Remove auth= prefix if (phase2Method.startsWith(Phase2.PREFIX)) { phase2Method = phase2Method.substring(Phase2.PREFIX.length()); @@ -339,7 +276,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @param identity */ public void setIdentity(String identity) { - setFieldValue(IDENTITY_KEY, identity, ""); + setFieldValue(WifiConfigStore.IDENTITY_KEY, identity, ""); } /** @@ -347,7 +284,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @return the identity */ public String getIdentity() { - return getFieldValue(IDENTITY_KEY, ""); + return getFieldValue(WifiConfigStore.IDENTITY_KEY, ""); } /** @@ -356,14 +293,14 @@ public class WifiEnterpriseConfig implements Parcelable { * @param anonymousIdentity the anonymous identity */ public void setAnonymousIdentity(String anonymousIdentity) { - setFieldValue(ANON_IDENTITY_KEY, anonymousIdentity, ""); + setFieldValue(WifiConfigStore.ANON_IDENTITY_KEY, anonymousIdentity, ""); } /** Get the anonymous identity * @return anonymous identity */ public String getAnonymousIdentity() { - return getFieldValue(ANON_IDENTITY_KEY, ""); + return getFieldValue(WifiConfigStore.ANON_IDENTITY_KEY, ""); } /** @@ -371,7 +308,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @param password the password */ public void setPassword(String password) { - setFieldValue(PASSWORD_KEY, password, ""); + setFieldValue(WifiConfigStore.PASSWORD_KEY, password, ""); } /** @@ -381,7 +318,7 @@ public class WifiEnterpriseConfig implements Parcelable { * framework, returns "*". */ public String getPassword() { - return getFieldValue(PASSWORD_KEY, ""); + return getFieldValue(WifiConfigStore.PASSWORD_KEY, ""); } /** @@ -394,7 +331,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @hide */ public void setCaCertificateAlias(String alias) { - setFieldValue(CA_CERT_KEY, alias, CA_CERT_PREFIX); + setFieldValue(WifiConfigStore.CA_CERT_KEY, alias, WifiConfigStore.CA_CERT_PREFIX); } /** @@ -403,7 +340,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @hide */ public String getCaCertificateAlias() { - return getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); + return getFieldValue(WifiConfigStore.CA_CERT_KEY, WifiConfigStore.CA_CERT_PREFIX); } /** @@ -431,7 +368,6 @@ public class WifiEnterpriseConfig implements Parcelable { /** * Get CA certificate - * * @return X.509 CA certificate */ public X509Certificate getCaCertificate() { @@ -439,6 +375,13 @@ public class WifiEnterpriseConfig implements Parcelable { } /** + * @hide + */ + public void resetCaCertificate() { + mCaCert = null; + } + + /** * Set Client certificate alias. * * <p> See the {@link android.security.KeyChain} for details on installing or choosing @@ -448,15 +391,16 @@ public class WifiEnterpriseConfig implements Parcelable { * @hide */ public void setClientCertificateAlias(String alias) { - setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX); - setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY); + setFieldValue(WifiConfigStore.CLIENT_CERT_KEY, alias, WifiConfigStore.CLIENT_CERT_PREFIX); + setFieldValue(WifiConfigStore.PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY); // Also, set engine parameters if (TextUtils.isEmpty(alias)) { - mFields.put(ENGINE_KEY, ENGINE_DISABLE); - mFields.put(ENGINE_ID_KEY, EMPTY_VALUE); + mFields.put(WifiConfigStore.ENGINE_KEY, WifiConfigStore.ENGINE_DISABLE); + mFields.put(WifiConfigStore.ENGINE_ID_KEY, WifiConfigStore.EMPTY_VALUE); } else { - mFields.put(ENGINE_KEY, ENGINE_ENABLE); - mFields.put(ENGINE_ID_KEY, convertToQuotedString(ENGINE_ID_KEYSTORE)); + mFields.put(WifiConfigStore.ENGINE_KEY, WifiConfigStore.ENGINE_ENABLE); + mFields.put(WifiConfigStore.ENGINE_ID_KEY, + convertToQuotedString(WifiConfigStore.ENGINE_ID_KEYSTORE)); } } @@ -466,7 +410,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @hide */ public String getClientCertificateAlias() { - return getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); + return getFieldValue(WifiConfigStore.CLIENT_CERT_KEY, WifiConfigStore.CLIENT_CERT_PREFIX); } /** @@ -507,116 +451,19 @@ public class WifiEnterpriseConfig implements Parcelable { return mClientCertificate; } - boolean needsKeyStore() { - // Has no keys to be installed - if (mClientCertificate == null && mCaCert == null) return false; - return true; - } - - static boolean isHardwareBackedKey(PrivateKey key) { - return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); - } - - static boolean hasHardwareBackedKey(Certificate certificate) { - return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); - } - - boolean needsSoftwareBackedKeyStore() { - return mNeedsSoftwareKeystore; - } - - boolean installKeys(android.security.KeyStore keyStore, String name) { - boolean ret = true; - String privKeyName = Credentials.USER_PRIVATE_KEY + name; - String userCertName = Credentials.USER_CERTIFICATE + name; - String caCertName = Credentials.CA_CERTIFICATE + name; - if (mClientCertificate != null) { - byte[] privKeyData = mClientPrivateKey.getEncoded(); - if (isHardwareBackedKey(mClientPrivateKey)) { - // Hardware backed key store is secure enough to store keys un-encrypted, this - // removes the need for user to punch a PIN to get access to these keys - if (DBG) Slog.d(TAG, "importing keys " + name + " in hardware backed " + - "store"); - ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, - KeyStore.FLAG_NONE); - } else { - // Software backed key store is NOT secure enough to store keys un-encrypted. - // Save keys encrypted so they are protected with user's PIN. User will - // have to unlock phone before being able to use these keys and connect to - // networks. - if (DBG) Slog.d(TAG, "importing keys " + name + " in software backed store"); - ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, - KeyStore.FLAG_ENCRYPTED); - mNeedsSoftwareKeystore = true; - } - if (ret == false) { - return ret; - } - - ret = putCertInKeyStore(keyStore, userCertName, mClientCertificate); - if (ret == false) { - // Remove private key installed - keyStore.delKey(privKeyName, Process.WIFI_UID); - return ret; - } - } - - if (mCaCert != null) { - ret = putCertInKeyStore(keyStore, caCertName, mCaCert); - if (ret == false) { - if (mClientCertificate != null) { - // Remove client key+cert - keyStore.delKey(privKeyName, Process.WIFI_UID); - keyStore.delete(userCertName, Process.WIFI_UID); - } - return ret; - } - } - - // Set alias names - if (mClientCertificate != null) { - setClientCertificateAlias(name); - mClientPrivateKey = null; - mClientCertificate = null; - } - - if (mCaCert != null) { - setCaCertificateAlias(name); - mCaCert = null; - } - - return ret; - } - - private boolean putCertInKeyStore(android.security.KeyStore keyStore, String name, - Certificate cert) { - try { - byte[] certData = Credentials.convertToPem(cert); - if (DBG) Slog.d(TAG, "putting certificate " + name + " in keystore"); - return keyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); - - } catch (IOException e1) { - return false; - } catch (CertificateException e2) { - return false; - } + /** + * @hide + */ + public void resetClientKeyEntry() { + mClientPrivateKey = null; + mClientCertificate = null; } - void removeKeys(KeyStore keyStore) { - String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); - // a valid client certificate is configured - if (!TextUtils.isEmpty(client)) { - if (DBG) Slog.d(TAG, "removing client private key and user cert"); - keyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); - keyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); - } - - String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); - // a valid ca certificate is configured - if (!TextUtils.isEmpty(ca)) { - if (DBG) Slog.d(TAG, "removing CA cert"); - keyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); - } + /** + * @hide + */ + public PrivateKey getClientPrivateKey() { + return mClientPrivateKey; } /** @@ -625,7 +472,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @param subjectMatch substring to be matched */ public void setSubjectMatch(String subjectMatch) { - setFieldValue(SUBJECT_MATCH_KEY, subjectMatch, ""); + setFieldValue(WifiConfigStore.SUBJECT_MATCH_KEY, subjectMatch, ""); } /** @@ -633,147 +480,24 @@ public class WifiEnterpriseConfig implements Parcelable { * @return the subject match string */ public String getSubjectMatch() { - return getFieldValue(SUBJECT_MATCH_KEY, ""); + return getFieldValue(WifiConfigStore.SUBJECT_MATCH_KEY, ""); } /** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */ String getKeyId(WifiEnterpriseConfig current) { - String eap = mFields.get(EAP_KEY); - String phase2 = mFields.get(PHASE2_KEY); + String eap = mFields.get(WifiConfigStore.EAP_KEY); + String phase2 = mFields.get(WifiConfigStore.PHASE2_KEY); // If either eap or phase2 are not initialized, use current config details if (TextUtils.isEmpty((eap))) { - eap = current.mFields.get(EAP_KEY); + eap = current.mFields.get(WifiConfigStore.EAP_KEY); } if (TextUtils.isEmpty(phase2)) { - phase2 = current.mFields.get(PHASE2_KEY); + phase2 = current.mFields.get(WifiConfigStore.PHASE2_KEY); } return eap + "_" + phase2; } - /** Migrates the old style TLS config to the new config style. This should only be used - * when restoring an old wpa_supplicant.conf or upgrading from a previous - * platform version. - * @return true if the config was updated - * @hide - */ - boolean migrateOldEapTlsNative(WifiNative wifiNative, int netId) { - String oldPrivateKey = wifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME); - /* - * If the old configuration value is not present, then there is nothing - * to do. - */ - if (TextUtils.isEmpty(oldPrivateKey)) { - return false; - } else { - // Also ignore it if it's empty quotes. - oldPrivateKey = removeDoubleQuotes(oldPrivateKey); - if (TextUtils.isEmpty(oldPrivateKey)) { - return false; - } - } - - mFields.put(ENGINE_KEY, ENGINE_ENABLE); - mFields.put(ENGINE_ID_KEY, convertToQuotedString(ENGINE_ID_KEYSTORE)); - - /* - * The old key started with the keystore:// URI prefix, but we don't - * need that anymore. Trim it off if it exists. - */ - final String keyName; - if (oldPrivateKey.startsWith(KEYSTORE_URI)) { - keyName = new String(oldPrivateKey.substring(KEYSTORE_URI.length())); - } else { - keyName = oldPrivateKey; - } - mFields.put(PRIVATE_KEY_ID_KEY, convertToQuotedString(keyName)); - - wifiNative.setNetworkVariable(netId, ENGINE_KEY, mFields.get(ENGINE_KEY)); - wifiNative.setNetworkVariable(netId, ENGINE_ID_KEY, mFields.get(ENGINE_ID_KEY)); - wifiNative.setNetworkVariable(netId, PRIVATE_KEY_ID_KEY, mFields.get(PRIVATE_KEY_ID_KEY)); - // Remove old private_key string so we don't run this again. - wifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE); - return true; - } - - /** Migrate certs from global pool to wifi UID if not already done */ - void migrateCerts(android.security.KeyStore keyStore) { - String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); - // a valid client certificate is configured - if (!TextUtils.isEmpty(client)) { - if (!keyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) { - keyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1, - Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); - keyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1, - Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); - } - } - - String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); - // a valid ca certificate is configured - if (!TextUtils.isEmpty(ca)) { - if (!keyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) { - keyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1, - Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); - } - } - } - - void initializeSoftwareKeystoreFlag(android.security.KeyStore keyStore) { - String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); - if (!TextUtils.isEmpty(client)) { - // a valid client certificate is configured - - // BUGBUG: keyStore.get() never returns certBytes; because it is not - // taking WIFI_UID as a parameter. It always looks for certificate - // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that - // all certificates need software keystore until we get the get() API - // fixed. - - mNeedsSoftwareKeystore = true; - - /* - try { - - if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials - .USER_CERTIFICATE + client); - - CertificateFactory factory = CertificateFactory.getInstance("X.509"); - if (factory == null) { - Slog.e(TAG, "Error getting certificate factory"); - return; - } - - byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); - if (certBytes != null) { - Certificate cert = (X509Certificate) factory.generateCertificate( - new ByteArrayInputStream(certBytes)); - - if (cert != null) { - mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); - - if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials - .USER_CERTIFICATE + client); - if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : - "does not need" ) + " software key store"); - } else { - Slog.d(TAG, "could not generate certificate"); - } - } else { - Slog.e(TAG, "Could not load client certificate " + Credentials - .USER_CERTIFICATE + client); - mNeedsSoftwareKeystore = true; - } - - } catch(CertificateException e) { - Slog.e(TAG, "Could not read certificates"); - mCaCert = null; - mClientCertificate = null; - } - */ - } - } - private String removeDoubleQuotes(String string) { if (TextUtils.isEmpty(string)) return ""; int length = string.length(); @@ -806,11 +530,12 @@ public class WifiEnterpriseConfig implements Parcelable { * @param key into the hash * @param prefix is the prefix that the value may have * @return value + * @hide */ - private String getFieldValue(String key, String prefix) { + String getFieldValue(String key, String prefix) { String value = mFields.get(key); // Uninitialized or known to be empty after reading from supplicant - if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return ""; + if (TextUtils.isEmpty(value) || WifiConfigStore.EMPTY_VALUE.equals(value)) return ""; value = removeDoubleQuotes(value); if (value.startsWith(prefix)) { @@ -827,12 +552,27 @@ public class WifiEnterpriseConfig implements Parcelable { */ private void setFieldValue(String key, String value, String prefix) { if (TextUtils.isEmpty(value)) { - mFields.put(key, EMPTY_VALUE); + mFields.put(key, WifiConfigStore.EMPTY_VALUE); } else { mFields.put(key, convertToQuotedString(prefix + value)); } } + + /** Set a value with an optional prefix at key + * @param key into the hash + * @param value to be set + * @param prefix an optional value to be prefixed to actual value + * @hide + */ + public void setFieldValue(String key, String value) { + if (TextUtils.isEmpty(value)) { + mFields.put(key, WifiConfigStore.EMPTY_VALUE); + } else { + mFields.put(key, convertToQuotedString(value)); + } + } + @Override public String toString() { StringBuffer sb = new StringBuffer(); diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index 5d130c6..dea0c6c 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -62,7 +62,6 @@ public class WifiInfo implements Parcelable { private String mBSSID; private WifiSsid mWifiSsid; private int mNetworkId; - private boolean mHiddenSSID; /** Received Signal Strength Indicator */ private int mRssi; @@ -86,7 +85,6 @@ public class WifiInfo implements Parcelable { mSupplicantState = SupplicantState.UNINITIALIZED; mRssi = -9999; mLinkSpeed = -1; - mHiddenSSID = false; } /** @@ -99,7 +97,6 @@ public class WifiInfo implements Parcelable { mBSSID = source.mBSSID; mWifiSsid = source.mWifiSsid; mNetworkId = source.mNetworkId; - mHiddenSSID = source.mHiddenSSID; mRssi = source.mRssi; mLinkSpeed = source.mLinkSpeed; mIpAddress = source.mIpAddress; @@ -110,8 +107,6 @@ public class WifiInfo implements Parcelable { void setSSID(WifiSsid wifiSsid) { mWifiSsid = wifiSsid; - // network is considered not hidden by default - mHiddenSSID = false; } /** @@ -244,12 +239,7 @@ public class WifiInfo implements Parcelable { * SSID-specific probe request must be used for scans. */ public boolean getHiddenSSID() { - return mHiddenSSID; - } - - /** {@hide} */ - public void setHiddenSSID(boolean hiddenSSID) { - mHiddenSSID = hiddenSSID; + return mWifiSsid.isHidden(); } /** diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 3b47e63..ae1fbf7 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -35,7 +35,6 @@ import android.util.SparseArray; import java.net.InetAddress; import java.util.concurrent.CountDownLatch; -import com.android.internal.R; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; @@ -2163,13 +2162,6 @@ public class WifiManager { } } - /** @hide */ - public void captivePortalCheckComplete() { - try { - mService.captivePortalCheckComplete(); - } catch (RemoteException e) {} - } - protected void finalize() throws Throwable { try { synchronized (sThreadRefLock) { diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java index 6817777..a18954c 100644 --- a/wifi/java/android/net/wifi/WifiMonitor.java +++ b/wifi/java/android/net/wifi/WifiMonitor.java @@ -20,24 +20,19 @@ import android.net.NetworkInfo; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pGroup; -import android.net.wifi.p2p.WifiP2pService; -import android.net.wifi.p2p.WifiP2pService.P2pStatus; import android.net.wifi.p2p.WifiP2pProvDiscEvent; +import android.net.wifi.p2p.WifiP2pService.P2pStatus; import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; -import android.net.wifi.StateChangeResult; import android.os.Message; import android.util.Log; - import com.android.internal.util.Protocol; import com.android.internal.util.StateMachine; import java.util.HashMap; -import java.util.Iterator; import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Listens for events from the wpa_supplicant server, and passes them on @@ -337,10 +332,6 @@ public class WifiMonitor { /* Indicates assoc reject event */ public static final int ASSOCIATION_REJECTION_EVENT = BASE + 43; - /** - * This indicates the supplicant connection for the monitor is closed - */ - private static final String MONITOR_SOCKET_CLOSED_STR = "connection closed"; /** * This indicates a read error on the monitor socket conenction @@ -354,56 +345,57 @@ public class WifiMonitor { private final String mInterfaceName; private final WifiNative mWifiNative; - private final StateMachine mWifiStateMachine; + private final StateMachine mStateMachine; private boolean mMonitoring; + // This is a global counter, since it's not monitor specific. However, the existing + // implementation forwards all "global" control events like CTRL-EVENT-TERMINATING + // to the p2p0 monitor. Is that expected ? It seems a bit surprising. + // + // TODO: If the p2p0 monitor isn't registered, the behaviour is even more surprising. + // The event will be dispatched to all monitors, and each of them will end up incrementing + // it in their dispatchXXX method. If we have 5 registered monitors (say), 2 consecutive + // recv errors will cause us to disconnect from the supplicant (instead of the intended 10). + // + // This variable is always accessed and modified under a WifiMonitorSingleton lock. + private static int sRecvErrors; + public WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative) { if (DBG) Log.d(TAG, "Creating WifiMonitor"); mWifiNative = wifiNative; mInterfaceName = wifiNative.mInterfaceName; - mWifiStateMachine = wifiStateMachine; + mStateMachine = wifiStateMachine; mMonitoring = false; - WifiMonitorSingleton.getMonitor().registerInterfaceMonitor(mInterfaceName, this); + WifiMonitorSingleton.sInstance.registerInterfaceMonitor(mInterfaceName, this); } public void startMonitoring() { - WifiMonitorSingleton.getMonitor().startMonitoring(mInterfaceName); + WifiMonitorSingleton.sInstance.startMonitoring(mInterfaceName); } public void stopMonitoring() { - WifiMonitorSingleton.getMonitor().stopMonitoring(mInterfaceName); + WifiMonitorSingleton.sInstance.stopMonitoring(mInterfaceName); } public void stopSupplicant() { - WifiMonitorSingleton.getMonitor().stopSupplicant(); + WifiMonitorSingleton.sInstance.stopSupplicant(); } public void killSupplicant(boolean p2pSupported) { - WifiMonitorSingleton.getMonitor().killSupplicant(p2pSupported); + WifiMonitorSingleton.sInstance.killSupplicant(p2pSupported); } private static class WifiMonitorSingleton { - private static Object sSingletonLock = new Object(); - private static WifiMonitorSingleton sWifiMonitorSingleton = null; - private HashMap<String, WifiMonitor> mIfaceMap = new HashMap<String, WifiMonitor>(); + private static final WifiMonitorSingleton sInstance = new WifiMonitorSingleton(); + + private final HashMap<String, WifiMonitor> mIfaceMap = new HashMap<String, WifiMonitor>(); private boolean mConnected = false; private WifiNative mWifiNative; private WifiMonitorSingleton() { } - static WifiMonitorSingleton getMonitor() { - if (DBG) Log.d(TAG, "WifiMonitorSingleton gotten"); - synchronized (sSingletonLock) { - if (sWifiMonitorSingleton == null) { - if (DBG) Log.d(TAG, "WifiMonitorSingleton created"); - sWifiMonitorSingleton = new WifiMonitorSingleton(); - } - } - return sWifiMonitorSingleton; - } - public synchronized void startMonitoring(String iface) { WifiMonitor m = mIfaceMap.get(iface); if (m == null) { @@ -415,14 +407,14 @@ public class WifiMonitor { if (mConnected) { m.mMonitoring = true; - m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT); + m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT); } else { if (DBG) Log.d(TAG, "connecting to supplicant"); int connectTries = 0; while (true) { if (mWifiNative.connectToSupplicant()) { m.mMonitoring = true; - m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT); + m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT); new MonitorThread(mWifiNative, this).start(); mConnected = true; break; @@ -434,7 +426,7 @@ public class WifiMonitor { } } else { mIfaceMap.remove(iface); - m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); + m.mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); Log.e(TAG, "startMonitoring(" + iface + ") failed!"); break; } @@ -444,13 +436,13 @@ public class WifiMonitor { public synchronized void stopMonitoring(String iface) { WifiMonitor m = mIfaceMap.get(iface); - if (DBG) Log.d(TAG, "stopMonitoring(" + iface + ") = " + m.mWifiStateMachine); + if (DBG) Log.d(TAG, "stopMonitoring(" + iface + ") = " + m.mStateMachine); m.mMonitoring = false; - m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); + m.mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); } public synchronized void registerInterfaceMonitor(String iface, WifiMonitor m) { - if (DBG) Log.d(TAG, "registerInterface(" + iface + "+" + m.mWifiStateMachine + ")"); + if (DBG) Log.d(TAG, "registerInterface(" + iface + "+" + m.mStateMachine + ")"); mIfaceMap.put(iface, m); if (mWifiNative == null) { mWifiNative = m.mWifiNative; @@ -462,7 +454,7 @@ public class WifiMonitor { // objects will remain in the mIfaceMap; and won't ever get deleted WifiMonitor m = mIfaceMap.remove(iface); - if (DBG) Log.d(TAG, "unregisterInterface(" + iface + "+" + m.mWifiStateMachine + ")"); + if (DBG) Log.d(TAG, "unregisterInterface(" + iface + "+" + m.mStateMachine + ")"); } public synchronized void stopSupplicant() { @@ -470,26 +462,74 @@ public class WifiMonitor { } public synchronized void killSupplicant(boolean p2pSupported) { - mWifiNative.killSupplicant(p2pSupported); + WifiNative.killSupplicant(p2pSupported); mConnected = false; - Iterator<Map.Entry<String, WifiMonitor>> it = mIfaceMap.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry<String, WifiMonitor> e = it.next(); - WifiMonitor m = e.getValue(); + for (WifiMonitor m : mIfaceMap.values()) { m.mMonitoring = false; } } - private synchronized WifiMonitor getMonitor(String iface) { - return mIfaceMap.get(iface); + private synchronized boolean dispatchEvent(String eventStr) { + String iface; + if (eventStr.startsWith("IFNAME=")) { + int space = eventStr.indexOf(' '); + if (space != -1) { + iface = eventStr.substring(7, space); + if (!mIfaceMap.containsKey(iface) && iface.startsWith("p2p-")) { + // p2p interfaces are created dynamically, but we have + // only one P2p state machine monitoring all of them; look + // for it explicitly, and send messages there .. + iface = "p2p0"; + } + eventStr = eventStr.substring(space + 1); + } else { + // No point dispatching this event to any interface, the dispatched + // event string will begin with "IFNAME=" which dispatchEvent can't really + // do anything about. + Log.e(TAG, "Dropping malformed event (unparsable iface): " + eventStr); + return false; + } + } else { + // events without prefix belong to p2p0 monitor + iface = "p2p0"; + } + + if (DBG) Log.d(TAG, "Dispatching event to interface: " + iface); + + WifiMonitor m = mIfaceMap.get(iface); + if (m != null) { + if (m.mMonitoring) { + if (m.dispatchEvent(eventStr)) { + mConnected = false; + return true; + } + + return false; + } else { + if (DBG) Log.d(TAG, "Dropping event because (" + iface + ") is stopped"); + return false; + } + } else { + if (DBG) Log.d(TAG, "Sending to all monitors because there's no matching iface"); + boolean done = false; + for (WifiMonitor monitor : mIfaceMap.values()) { + if (monitor.mMonitoring && monitor.dispatchEvent(eventStr)) { + done = true; + } + } + + if (done) { + mConnected = false; + } + + return done; + } } } private static class MonitorThread extends Thread { private final WifiNative mWifiNative; private final WifiMonitorSingleton mWifiMonitorSingleton; - private int mRecvErrors = 0; - private StateMachine mStateMachine = null; public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) { super("WifiMonitor"); @@ -507,445 +547,390 @@ public class WifiMonitor { Log.d(TAG, "Event [" + eventStr + "]"); } - String iface = "p2p0"; - WifiMonitor m = null; - mStateMachine = null; - - if (eventStr.startsWith("IFNAME=")) { - int space = eventStr.indexOf(' '); - if (space != -1) { - iface = eventStr.substring(7,space); - m = mWifiMonitorSingleton.getMonitor(iface); - if (m == null && iface.startsWith("p2p-")) { - // p2p interfaces are created dynamically, but we have - // only one P2p state machine monitoring all of them; look - // for it explicitly, and send messages there .. - m = mWifiMonitorSingleton.getMonitor("p2p0"); - } - eventStr = eventStr.substring(space + 1); - } - } else { - // events without prefix belong to p2p0 monitor - m = mWifiMonitorSingleton.getMonitor("p2p0"); - } - - if (m != null) { - if (m.mMonitoring) { - mStateMachine = m.mWifiStateMachine; - } else { - if (DBG) Log.d(TAG, "Dropping event because monitor (" + iface + - ") is stopped"); - continue; - } - } - - if (mStateMachine != null) { - if (dispatchEvent(eventStr)) { - break; - } - } else { - if (DBG) Log.d(TAG, "Sending to all monitors because there's no interface id"); - boolean done = false; - Iterator<Map.Entry<String, WifiMonitor>> it = - mWifiMonitorSingleton.mIfaceMap.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry<String, WifiMonitor> e = it.next(); - m = e.getValue(); - mStateMachine = m.mWifiStateMachine; - if (dispatchEvent(eventStr)) { - done = true; - } - } - - if (done) { - // After this thread terminates, we'll no longer - // be connected to the supplicant - if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events"); - mWifiMonitorSingleton.mConnected = false; - break; - } + if (mWifiMonitorSingleton.dispatchEvent(eventStr)) { + if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events"); + break; } } } + } - /* @return true if the event was supplicant disconnection */ - private boolean dispatchEvent(String eventStr) { - - if (!eventStr.startsWith(EVENT_PREFIX_STR)) { - if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) && - 0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) { - mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); - } else if (eventStr.startsWith(WPS_SUCCESS_STR)) { - mStateMachine.sendMessage(WPS_SUCCESS_EVENT); - } else if (eventStr.startsWith(WPS_FAIL_STR)) { - handleWpsFailEvent(eventStr); - } else if (eventStr.startsWith(WPS_OVERLAP_STR)) { - mStateMachine.sendMessage(WPS_OVERLAP_EVENT); - } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) { - mStateMachine.sendMessage(WPS_TIMEOUT_EVENT); - } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) { - handleP2pEvents(eventStr); - } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) { - handleHostApEvents(eventStr); - } - else { - if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr); - } - return false; + /* @return true if the event was supplicant disconnection */ + private boolean dispatchEvent(String eventStr) { + + if (!eventStr.startsWith(EVENT_PREFIX_STR)) { + if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) && + 0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) { + mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); + } else if (eventStr.startsWith(WPS_SUCCESS_STR)) { + mStateMachine.sendMessage(WPS_SUCCESS_EVENT); + } else if (eventStr.startsWith(WPS_FAIL_STR)) { + handleWpsFailEvent(eventStr); + } else if (eventStr.startsWith(WPS_OVERLAP_STR)) { + mStateMachine.sendMessage(WPS_OVERLAP_EVENT); + } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) { + mStateMachine.sendMessage(WPS_TIMEOUT_EVENT); + } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) { + handleP2pEvents(eventStr); + } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) { + handleHostApEvents(eventStr); + } + else { + if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr); } + return false; + } - String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR); - int nameEnd = eventName.indexOf(' '); - if (nameEnd != -1) - eventName = eventName.substring(0, nameEnd); - if (eventName.length() == 0) { - if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name"); - return false; + String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR); + int nameEnd = eventName.indexOf(' '); + if (nameEnd != -1) + eventName = eventName.substring(0, nameEnd); + if (eventName.length() == 0) { + if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name"); + return false; + } + /* + * Map event name into event enum + */ + int event; + if (eventName.equals(CONNECTED_STR)) + event = CONNECTED; + else if (eventName.equals(DISCONNECTED_STR)) + event = DISCONNECTED; + else if (eventName.equals(STATE_CHANGE_STR)) + event = STATE_CHANGE; + else if (eventName.equals(SCAN_RESULTS_STR)) + event = SCAN_RESULTS; + else if (eventName.equals(LINK_SPEED_STR)) + event = LINK_SPEED; + else if (eventName.equals(TERMINATING_STR)) + event = TERMINATING; + else if (eventName.equals(DRIVER_STATE_STR)) + event = DRIVER_STATE; + else if (eventName.equals(EAP_FAILURE_STR)) + event = EAP_FAILURE; + else if (eventName.equals(ASSOC_REJECT_STR)) + event = ASSOC_REJECT; + else + event = UNKNOWN; + + String eventData = eventStr; + if (event == DRIVER_STATE || event == LINK_SPEED) + eventData = eventData.split(" ")[1]; + else if (event == STATE_CHANGE || event == EAP_FAILURE) { + int ind = eventStr.indexOf(" "); + if (ind != -1) { + eventData = eventStr.substring(ind + 1); } - /* - * Map event name into event enum - */ - int event; - if (eventName.equals(CONNECTED_STR)) - event = CONNECTED; - else if (eventName.equals(DISCONNECTED_STR)) - event = DISCONNECTED; - else if (eventName.equals(STATE_CHANGE_STR)) - event = STATE_CHANGE; - else if (eventName.equals(SCAN_RESULTS_STR)) - event = SCAN_RESULTS; - else if (eventName.equals(LINK_SPEED_STR)) - event = LINK_SPEED; - else if (eventName.equals(TERMINATING_STR)) - event = TERMINATING; - else if (eventName.equals(DRIVER_STATE_STR)) - event = DRIVER_STATE; - else if (eventName.equals(EAP_FAILURE_STR)) - event = EAP_FAILURE; - else if (eventName.equals(ASSOC_REJECT_STR)) - event = ASSOC_REJECT; - else - event = UNKNOWN; - - String eventData = eventStr; - if (event == DRIVER_STATE || event == LINK_SPEED) - eventData = eventData.split(" ")[1]; - else if (event == STATE_CHANGE || event == EAP_FAILURE) { - int ind = eventStr.indexOf(" "); - if (ind != -1) { - eventData = eventStr.substring(ind + 1); - } - } else { - int ind = eventStr.indexOf(" - "); - if (ind != -1) { - eventData = eventStr.substring(ind + 3); - } + } else { + int ind = eventStr.indexOf(" - "); + if (ind != -1) { + eventData = eventStr.substring(ind + 3); } + } - if (event == STATE_CHANGE) { - handleSupplicantStateChange(eventData); - } else if (event == DRIVER_STATE) { - handleDriverEvent(eventData); - } else if (event == TERMINATING) { - /** - * Close the supplicant connection if we see - * too many recv errors - */ - if (eventData.startsWith(WPA_RECV_ERROR_STR)) { - if (++mRecvErrors > MAX_RECV_ERRORS) { - if (DBG) { - Log.d(TAG, "too many recv errors, closing connection"); - } - } else { - return false; + if (event == STATE_CHANGE) { + handleSupplicantStateChange(eventData); + } else if (event == DRIVER_STATE) { + handleDriverEvent(eventData); + } else if (event == TERMINATING) { + /** + * Close the supplicant connection if we see + * too many recv errors + */ + if (eventData.startsWith(WPA_RECV_ERROR_STR)) { + if (++sRecvErrors > MAX_RECV_ERRORS) { + if (DBG) { + Log.d(TAG, "too many recv errors, closing connection"); } + } else { + return false; } - - // notify and exit - mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); - return true; - } else if (event == EAP_FAILURE) { - if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) { - mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); - } - } else if (event == ASSOC_REJECT) { - mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT); - } else { - handleEvent(event, eventData); } - mRecvErrors = 0; - return false; - } - private void handleDriverEvent(String state) { - if (state == null) { - return; - } - if (state.equals("HANGED")) { - mStateMachine.sendMessage(DRIVER_HUNG_EVENT); + // notify and exit + mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); + return true; + } else if (event == EAP_FAILURE) { + if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) { + mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); } + } else if (event == ASSOC_REJECT) { + mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT); + } else { + handleEvent(event, eventData); } + sRecvErrors = 0; + return false; + } - /** - * Handle all supplicant events except STATE-CHANGE - * @param event the event type - * @param remainder the rest of the string following the - * event name and " — " - */ - void handleEvent(int event, String remainder) { - switch (event) { - case DISCONNECTED: - handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder); - break; - - case CONNECTED: - handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder); - break; - - case SCAN_RESULTS: - mStateMachine.sendMessage(SCAN_RESULTS_EVENT); - break; + private void handleDriverEvent(String state) { + if (state == null) { + return; + } + if (state.equals("HANGED")) { + mStateMachine.sendMessage(DRIVER_HUNG_EVENT); + } + } - case UNKNOWN: - break; - } + /** + * Handle all supplicant events except STATE-CHANGE + * @param event the event type + * @param remainder the rest of the string following the + * event name and " — " + */ + void handleEvent(int event, String remainder) { + switch (event) { + case DISCONNECTED: + handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder); + break; + + case CONNECTED: + handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder); + break; + + case SCAN_RESULTS: + mStateMachine.sendMessage(SCAN_RESULTS_EVENT); + break; + + case UNKNOWN: + break; } + } - private void handleWpsFailEvent(String dataString) { - final Pattern p = Pattern.compile(WPS_FAIL_PATTERN); - Matcher match = p.matcher(dataString); - if (match.find()) { - String cfgErr = match.group(1); - String reason = match.group(2); - - if (reason != null) { - switch(Integer.parseInt(reason)) { - case REASON_TKIP_ONLY_PROHIBITED: - mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, - WifiManager.WPS_TKIP_ONLY_PROHIBITED, 0)); - return; - case REASON_WEP_PROHIBITED: - mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, - WifiManager.WPS_WEP_PROHIBITED, 0)); - return; - } + private void handleWpsFailEvent(String dataString) { + final Pattern p = Pattern.compile(WPS_FAIL_PATTERN); + Matcher match = p.matcher(dataString); + if (match.find()) { + String cfgErr = match.group(1); + String reason = match.group(2); + + if (reason != null) { + switch(Integer.parseInt(reason)) { + case REASON_TKIP_ONLY_PROHIBITED: + mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, + WifiManager.WPS_TKIP_ONLY_PROHIBITED, 0)); + return; + case REASON_WEP_PROHIBITED: + mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, + WifiManager.WPS_WEP_PROHIBITED, 0)); + return; } - if (cfgErr != null) { - switch(Integer.parseInt(cfgErr)) { - case CONFIG_AUTH_FAILURE: - mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, - WifiManager.WPS_AUTH_FAILURE, 0)); - return; - case CONFIG_MULTIPLE_PBC_DETECTED: - mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, - WifiManager.WPS_OVERLAP_ERROR, 0)); - return; - } + } + if (cfgErr != null) { + switch(Integer.parseInt(cfgErr)) { + case CONFIG_AUTH_FAILURE: + mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, + WifiManager.WPS_AUTH_FAILURE, 0)); + return; + case CONFIG_MULTIPLE_PBC_DETECTED: + mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, + WifiManager.WPS_OVERLAP_ERROR, 0)); + return; } } - //For all other errors, return a generic internal error - mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, - WifiManager.ERROR, 0)); } + //For all other errors, return a generic internal error + mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, + WifiManager.ERROR, 0)); + } - /* <event> status=<err> and the special case of <event> reason=FREQ_CONFLICT */ - private P2pStatus p2pError(String dataString) { - P2pStatus err = P2pStatus.UNKNOWN; - String[] tokens = dataString.split(" "); - if (tokens.length < 2) return err; - String[] nameValue = tokens[1].split("="); - if (nameValue.length != 2) return err; - - /* Handle the special case of reason=FREQ+CONFLICT */ - if (nameValue[1].equals("FREQ_CONFLICT")) { - return P2pStatus.NO_COMMON_CHANNEL; - } - try { - err = P2pStatus.valueOf(Integer.parseInt(nameValue[1])); - } catch (NumberFormatException e) { - e.printStackTrace(); - } - return err; + /* <event> status=<err> and the special case of <event> reason=FREQ_CONFLICT */ + private P2pStatus p2pError(String dataString) { + P2pStatus err = P2pStatus.UNKNOWN; + String[] tokens = dataString.split(" "); + if (tokens.length < 2) return err; + String[] nameValue = tokens[1].split("="); + if (nameValue.length != 2) return err; + + /* Handle the special case of reason=FREQ+CONFLICT */ + if (nameValue[1].equals("FREQ_CONFLICT")) { + return P2pStatus.NO_COMMON_CHANNEL; } + try { + err = P2pStatus.valueOf(Integer.parseInt(nameValue[1])); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + return err; + } - /** - * Handle p2p events - */ - private void handleP2pEvents(String dataString) { - if (dataString.startsWith(P2P_DEVICE_FOUND_STR)) { - mStateMachine.sendMessage(P2P_DEVICE_FOUND_EVENT, new WifiP2pDevice(dataString)); - } else if (dataString.startsWith(P2P_DEVICE_LOST_STR)) { - mStateMachine.sendMessage(P2P_DEVICE_LOST_EVENT, new WifiP2pDevice(dataString)); - } else if (dataString.startsWith(P2P_FIND_STOPPED_STR)) { - mStateMachine.sendMessage(P2P_FIND_STOPPED_EVENT); - } else if (dataString.startsWith(P2P_GO_NEG_REQUEST_STR)) { - mStateMachine.sendMessage(P2P_GO_NEGOTIATION_REQUEST_EVENT, - new WifiP2pConfig(dataString)); - } else if (dataString.startsWith(P2P_GO_NEG_SUCCESS_STR)) { - mStateMachine.sendMessage(P2P_GO_NEGOTIATION_SUCCESS_EVENT); - } else if (dataString.startsWith(P2P_GO_NEG_FAILURE_STR)) { - mStateMachine.sendMessage(P2P_GO_NEGOTIATION_FAILURE_EVENT, p2pError(dataString)); - } else if (dataString.startsWith(P2P_GROUP_FORMATION_SUCCESS_STR)) { - mStateMachine.sendMessage(P2P_GROUP_FORMATION_SUCCESS_EVENT); - } else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) { - mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT, p2pError(dataString)); - } else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) { - mStateMachine.sendMessage(P2P_GROUP_STARTED_EVENT, new WifiP2pGroup(dataString)); - } else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) { - mStateMachine.sendMessage(P2P_GROUP_REMOVED_EVENT, new WifiP2pGroup(dataString)); - } else if (dataString.startsWith(P2P_INVITATION_RECEIVED_STR)) { - mStateMachine.sendMessage(P2P_INVITATION_RECEIVED_EVENT, - new WifiP2pGroup(dataString)); - } else if (dataString.startsWith(P2P_INVITATION_RESULT_STR)) { - mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, p2pError(dataString)); - } else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) { - mStateMachine.sendMessage(P2P_PROV_DISC_PBC_REQ_EVENT, - new WifiP2pProvDiscEvent(dataString)); - } else if (dataString.startsWith(P2P_PROV_DISC_PBC_RSP_STR)) { - mStateMachine.sendMessage(P2P_PROV_DISC_PBC_RSP_EVENT, - new WifiP2pProvDiscEvent(dataString)); - } else if (dataString.startsWith(P2P_PROV_DISC_ENTER_PIN_STR)) { - mStateMachine.sendMessage(P2P_PROV_DISC_ENTER_PIN_EVENT, - new WifiP2pProvDiscEvent(dataString)); - } else if (dataString.startsWith(P2P_PROV_DISC_SHOW_PIN_STR)) { - mStateMachine.sendMessage(P2P_PROV_DISC_SHOW_PIN_EVENT, - new WifiP2pProvDiscEvent(dataString)); - } else if (dataString.startsWith(P2P_PROV_DISC_FAILURE_STR)) { - mStateMachine.sendMessage(P2P_PROV_DISC_FAILURE_EVENT); - } else if (dataString.startsWith(P2P_SERV_DISC_RESP_STR)) { - List<WifiP2pServiceResponse> list = WifiP2pServiceResponse.newInstance(dataString); - if (list != null) { - mStateMachine.sendMessage(P2P_SERV_DISC_RESP_EVENT, list); - } else { - Log.e(TAG, "Null service resp " + dataString); - } + /** + * Handle p2p events + */ + private void handleP2pEvents(String dataString) { + if (dataString.startsWith(P2P_DEVICE_FOUND_STR)) { + mStateMachine.sendMessage(P2P_DEVICE_FOUND_EVENT, new WifiP2pDevice(dataString)); + } else if (dataString.startsWith(P2P_DEVICE_LOST_STR)) { + mStateMachine.sendMessage(P2P_DEVICE_LOST_EVENT, new WifiP2pDevice(dataString)); + } else if (dataString.startsWith(P2P_FIND_STOPPED_STR)) { + mStateMachine.sendMessage(P2P_FIND_STOPPED_EVENT); + } else if (dataString.startsWith(P2P_GO_NEG_REQUEST_STR)) { + mStateMachine.sendMessage(P2P_GO_NEGOTIATION_REQUEST_EVENT, + new WifiP2pConfig(dataString)); + } else if (dataString.startsWith(P2P_GO_NEG_SUCCESS_STR)) { + mStateMachine.sendMessage(P2P_GO_NEGOTIATION_SUCCESS_EVENT); + } else if (dataString.startsWith(P2P_GO_NEG_FAILURE_STR)) { + mStateMachine.sendMessage(P2P_GO_NEGOTIATION_FAILURE_EVENT, p2pError(dataString)); + } else if (dataString.startsWith(P2P_GROUP_FORMATION_SUCCESS_STR)) { + mStateMachine.sendMessage(P2P_GROUP_FORMATION_SUCCESS_EVENT); + } else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) { + mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT, p2pError(dataString)); + } else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) { + mStateMachine.sendMessage(P2P_GROUP_STARTED_EVENT, new WifiP2pGroup(dataString)); + } else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) { + mStateMachine.sendMessage(P2P_GROUP_REMOVED_EVENT, new WifiP2pGroup(dataString)); + } else if (dataString.startsWith(P2P_INVITATION_RECEIVED_STR)) { + mStateMachine.sendMessage(P2P_INVITATION_RECEIVED_EVENT, + new WifiP2pGroup(dataString)); + } else if (dataString.startsWith(P2P_INVITATION_RESULT_STR)) { + mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, p2pError(dataString)); + } else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) { + mStateMachine.sendMessage(P2P_PROV_DISC_PBC_REQ_EVENT, + new WifiP2pProvDiscEvent(dataString)); + } else if (dataString.startsWith(P2P_PROV_DISC_PBC_RSP_STR)) { + mStateMachine.sendMessage(P2P_PROV_DISC_PBC_RSP_EVENT, + new WifiP2pProvDiscEvent(dataString)); + } else if (dataString.startsWith(P2P_PROV_DISC_ENTER_PIN_STR)) { + mStateMachine.sendMessage(P2P_PROV_DISC_ENTER_PIN_EVENT, + new WifiP2pProvDiscEvent(dataString)); + } else if (dataString.startsWith(P2P_PROV_DISC_SHOW_PIN_STR)) { + mStateMachine.sendMessage(P2P_PROV_DISC_SHOW_PIN_EVENT, + new WifiP2pProvDiscEvent(dataString)); + } else if (dataString.startsWith(P2P_PROV_DISC_FAILURE_STR)) { + mStateMachine.sendMessage(P2P_PROV_DISC_FAILURE_EVENT); + } else if (dataString.startsWith(P2P_SERV_DISC_RESP_STR)) { + List<WifiP2pServiceResponse> list = WifiP2pServiceResponse.newInstance(dataString); + if (list != null) { + mStateMachine.sendMessage(P2P_SERV_DISC_RESP_EVENT, list); + } else { + Log.e(TAG, "Null service resp " + dataString); } } + } - /** - * Handle hostap events - */ - private void handleHostApEvents(String dataString) { - String[] tokens = dataString.split(" "); - /* AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */ - if (tokens[0].equals(AP_STA_CONNECTED_STR)) { - mStateMachine.sendMessage(AP_STA_CONNECTED_EVENT, new WifiP2pDevice(dataString)); + /** + * Handle hostap events + */ + private void handleHostApEvents(String dataString) { + String[] tokens = dataString.split(" "); + /* AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */ + if (tokens[0].equals(AP_STA_CONNECTED_STR)) { + mStateMachine.sendMessage(AP_STA_CONNECTED_EVENT, new WifiP2pDevice(dataString)); /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */ - } else if (tokens[0].equals(AP_STA_DISCONNECTED_STR)) { - mStateMachine.sendMessage(AP_STA_DISCONNECTED_EVENT, new WifiP2pDevice(dataString)); - } + } else if (tokens[0].equals(AP_STA_DISCONNECTED_STR)) { + mStateMachine.sendMessage(AP_STA_DISCONNECTED_EVENT, new WifiP2pDevice(dataString)); } + } - /** - * Handle the supplicant STATE-CHANGE event - * @param dataString New supplicant state string in the format: - * id=network-id state=new-state - */ - private void handleSupplicantStateChange(String dataString) { - WifiSsid wifiSsid = null; - int index = dataString.lastIndexOf("SSID="); - if (index != -1) { - wifiSsid = WifiSsid.createFromAsciiEncoded( - dataString.substring(index + 5)); + /** + * Handle the supplicant STATE-CHANGE event + * @param dataString New supplicant state string in the format: + * id=network-id state=new-state + */ + private void handleSupplicantStateChange(String dataString) { + WifiSsid wifiSsid = null; + int index = dataString.lastIndexOf("SSID="); + if (index != -1) { + wifiSsid = WifiSsid.createFromAsciiEncoded( + dataString.substring(index + 5)); + } + String[] dataTokens = dataString.split(" "); + + String BSSID = null; + int networkId = -1; + int newState = -1; + for (String token : dataTokens) { + String[] nameValue = token.split("="); + if (nameValue.length != 2) { + continue; } - String[] dataTokens = dataString.split(" "); - - String BSSID = null; - int networkId = -1; - int newState = -1; - for (String token : dataTokens) { - String[] nameValue = token.split("="); - if (nameValue.length != 2) { - continue; - } - - if (nameValue[0].equals("BSSID")) { - BSSID = nameValue[1]; - continue; - } - - int value; - try { - value = Integer.parseInt(nameValue[1]); - } catch (NumberFormatException e) { - continue; - } - if (nameValue[0].equals("id")) { - networkId = value; - } else if (nameValue[0].equals("state")) { - newState = value; - } + if (nameValue[0].equals("BSSID")) { + BSSID = nameValue[1]; + continue; } - if (newState == -1) return; - - SupplicantState newSupplicantState = SupplicantState.INVALID; - for (SupplicantState state : SupplicantState.values()) { - if (state.ordinal() == newState) { - newSupplicantState = state; - break; - } + int value; + try { + value = Integer.parseInt(nameValue[1]); + } catch (NumberFormatException e) { + continue; } - if (newSupplicantState == SupplicantState.INVALID) { - Log.w(TAG, "Invalid supplicant state: " + newState); + + if (nameValue[0].equals("id")) { + networkId = value; + } else if (nameValue[0].equals("state")) { + newState = value; } - notifySupplicantStateChange(networkId, wifiSsid, BSSID, newSupplicantState); } - private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) { - String BSSID = null; - int networkId = -1; - if (newState == NetworkInfo.DetailedState.CONNECTED) { - Matcher match = mConnectedEventPattern.matcher(data); - if (!match.find()) { - if (DBG) Log.d(TAG, "Could not find BSSID in CONNECTED event string"); - } else { - BSSID = match.group(1); - try { - networkId = Integer.parseInt(match.group(2)); - } catch (NumberFormatException e) { - networkId = -1; - } - } - notifyNetworkStateChange(newState, BSSID, networkId); + if (newState == -1) return; + + SupplicantState newSupplicantState = SupplicantState.INVALID; + for (SupplicantState state : SupplicantState.values()) { + if (state.ordinal() == newState) { + newSupplicantState = state; + break; } } + if (newSupplicantState == SupplicantState.INVALID) { + Log.w(TAG, "Invalid supplicant state: " + newState); + } + notifySupplicantStateChange(networkId, wifiSsid, BSSID, newSupplicantState); + } - /** - * Send the state machine a notification that the state of Wifi connectivity - * has changed. - * @param networkId the configured network on which the state change occurred - * @param newState the new network state - * @param BSSID when the new state is {@link DetailedState#CONNECTED - * NetworkInfo.DetailedState.CONNECTED}, - * this is the MAC address of the access point. Otherwise, it - * is {@code null}. - */ - void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) { - if (newState == NetworkInfo.DetailedState.CONNECTED) { - Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT, - netId, 0, BSSID); - mStateMachine.sendMessage(m); + private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) { + String BSSID = null; + int networkId = -1; + if (newState == NetworkInfo.DetailedState.CONNECTED) { + Matcher match = mConnectedEventPattern.matcher(data); + if (!match.find()) { + if (DBG) Log.d(TAG, "Could not find BSSID in CONNECTED event string"); } else { - Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT, - netId, 0, BSSID); - mStateMachine.sendMessage(m); + BSSID = match.group(1); + try { + networkId = Integer.parseInt(match.group(2)); + } catch (NumberFormatException e) { + networkId = -1; + } } + notifyNetworkStateChange(newState, BSSID, networkId); } + } - /** - * Send the state machine a notification that the state of the supplicant - * has changed. - * @param networkId the configured network on which the state change occurred - * @param wifiSsid network name - * @param BSSID network address - * @param newState the new {@code SupplicantState} - */ - void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID, - SupplicantState newState) { - mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, - new StateChangeResult(networkId, wifiSsid, BSSID, newState))); + /** + * Send the state machine a notification that the state of Wifi connectivity + * has changed. + * @param newState the new network state + * @param BSSID when the new state is {@link NetworkInfo.DetailedState#CONNECTED}, + * this is the MAC address of the access point. Otherwise, it + * is {@code null}. + * @param netId the configured network on which the state change occurred + */ + void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) { + if (newState == NetworkInfo.DetailedState.CONNECTED) { + Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT, + netId, 0, BSSID); + mStateMachine.sendMessage(m); + } else { + Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT, + netId, 0, BSSID); + mStateMachine.sendMessage(m); } } + + /** + * Send the state machine a notification that the state of the supplicant + * has changed. + * @param networkId the configured network on which the state change occurred + * @param wifiSsid network name + * @param BSSID network address + * @param newState the new {@code SupplicantState} + */ + void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID, + SupplicantState newState) { + mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, + new StateChangeResult(networkId, wifiSsid, BSSID, newState))); + } } diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java index a35a34b..f8ba95d 100644 --- a/wifi/java/android/net/wifi/WifiSsid.java +++ b/wifi/java/android/net/wifi/WifiSsid.java @@ -16,9 +16,8 @@ package android.net.wifi; -import android.os.Parcelable; import android.os.Parcel; -import android.util.Log; +import android.os.Parcelable; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; @@ -42,7 +41,7 @@ import java.util.Locale; public class WifiSsid implements Parcelable { private static final String TAG = "WifiSsid"; - public ByteArrayOutputStream octets = new ByteArrayOutputStream(32); + public final ByteArrayOutputStream octets = new ByteArrayOutputStream(32); private static final int HEX_RADIX = 16; public static final String NONE = "<unknown ssid>"; @@ -58,7 +57,6 @@ public class WifiSsid implements Parcelable { public static WifiSsid createFromHex(String hexStr) { WifiSsid a = new WifiSsid(); - int length = 0; if (hexStr == null) return a; if (hexStr.startsWith("0x") || hexStr.startsWith("0X")) { @@ -191,8 +189,13 @@ public class WifiSsid implements Parcelable { } /** @hide */ + public boolean isHidden() { + return isArrayAllZeroes(octets.toByteArray()); + } + + /** @hide */ public byte[] getOctets() { - return octets.toByteArray(); + return octets.toByteArray(); } /** @hide */ diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 69d3efe..149f08d 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -56,14 +56,12 @@ import android.net.wifi.WpsResult.Status; import android.net.wifi.p2p.WifiP2pManager; import android.net.wifi.p2p.WifiP2pService; import android.os.BatteryStats; -import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.INetworkManagementService; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; -import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -71,7 +69,6 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; -import android.util.Log; import android.util.LruCache; import android.text.TextUtils; @@ -87,7 +84,6 @@ import com.android.server.net.BaseNetworkObserver; import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; -import java.net.Inet6Address; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -306,8 +302,6 @@ public class WifiStateMachine extends StateMachine { static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; /* A delayed message sent to start driver when it fail to come up */ static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; - /* Ready to switch to network as default */ - static final int CMD_CAPTIVE_CHECK_COMPLETE = BASE + 20; /* Start the soft access point */ static final int CMD_START_AP = BASE + 21; @@ -544,8 +538,6 @@ public class WifiStateMachine extends StateMachine { private State mObtainingIpState = new ObtainingIpState(); /* Waiting for link quality verification to be complete */ private State mVerifyingLinkState = new VerifyingLinkState(); - /* Waiting for captive portal check to be complete */ - private State mCaptivePortalCheckState = new CaptivePortalCheckState(); /* Connected with IP addr */ private State mConnectedState = new ConnectedState(); /* disconnect issued, waiting for network disconnect confirmation */ @@ -791,7 +783,6 @@ public class WifiStateMachine extends StateMachine { addState(mL2ConnectedState, mConnectModeState); addState(mObtainingIpState, mL2ConnectedState); addState(mVerifyingLinkState, mL2ConnectedState); - addState(mCaptivePortalCheckState, mL2ConnectedState); addState(mConnectedState, mL2ConnectedState); addState(mDisconnectingState, mConnectModeState); addState(mDisconnectedState, mConnectModeState); @@ -1346,10 +1337,6 @@ public class WifiStateMachine extends StateMachine { } } - public void captivePortalCheckComplete() { - sendMessage(CMD_CAPTIVE_CHECK_COMPLETE); - } - /** * TODO: doc */ @@ -2529,7 +2516,6 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_DRIVER: case CMD_DELAYED_STOP_DRIVER: case CMD_DRIVER_START_TIMED_OUT: - case CMD_CAPTIVE_CHECK_COMPLETE: case CMD_START_AP: case CMD_START_AP_SUCCESS: case CMD_START_AP_FAILURE: @@ -3809,29 +3795,17 @@ public class WifiStateMachine extends StateMachine { break; case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); - transitionTo(mCaptivePortalCheckState); - break; - default: - if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); - return NOT_HANDLED; - } - return HANDLED; - } - } + // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve + // existing behaviour. The captive portal check really happens after we + // transition into DetailedState.CONNECTED. + setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); + mWifiConfigStore.updateStatus(mLastNetworkId, + DetailedState.CAPTIVE_PORTAL_CHECK); + sendNetworkStateChangeBroadcast(mLastBssid); - class CaptivePortalCheckState extends State { - @Override - public void enter() { - log(getName() + " enter"); - setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); - mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CAPTIVE_PORTAL_CHECK); - sendNetworkStateChangeBroadcast(mLastBssid); - } - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case CMD_CAPTIVE_CHECK_COMPLETE: - log(getName() + " CMD_CAPTIVE_CHECK_COMPLETE"); + // NOTE: This might look like an odd place to enable IPV6 but this is in + // response to transitioning into GOOD_LINK_DETECTED. Similarly, we disable + // ipv6 when we transition into POOR_LINK_DETECTED in mConnectedState. try { mNwService.enableIpv6(mInterfaceName); } catch (RemoteException re) { @@ -3839,12 +3813,16 @@ public class WifiStateMachine extends StateMachine { } catch (IllegalStateException e) { loge("Failed to enable IPv6: " + e); } + + log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); setNetworkDetailedState(DetailedState.CONNECTED); mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); sendNetworkStateChangeBroadcast(mLastBssid); transitionTo(mConnectedState); + break; default: + if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); return NOT_HANDLED; } return HANDLED; @@ -3876,6 +3854,7 @@ public class WifiStateMachine extends StateMachine { } return HANDLED; } + @Override public void exit() { /* Request a CS wakelock during transition to mobile */ diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 615c893..7ded171 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -115,14 +115,6 @@ public class WifiStateTracker extends BaseNetworkStateTracker { return true; } - /** - * Captive check is complete, switch to network - */ - @Override - public void captivePortalCheckComplete() { - mWifiManager.captivePortalCheckComplete(); - } - @Override public void captivePortalCheckCompleted(boolean isCaptivePortal) { // not implemented diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java index 6278c89..c2823e8 100644 --- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java +++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java @@ -29,11 +29,8 @@ import android.net.wifi.RssiPacketCountInfo; import android.os.Message; import android.os.SystemClock; import android.provider.Settings; -import android.provider.Settings.Secure; -import android.util.Log; import android.util.LruCache; -import com.android.internal.R; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import com.android.internal.util.State; diff --git a/wifi/java/android/net/wifi/WpsInfo.java b/wifi/java/android/net/wifi/WpsInfo.java index b80df21..2ad4ad0 100644 --- a/wifi/java/android/net/wifi/WpsInfo.java +++ b/wifi/java/android/net/wifi/WpsInfo.java @@ -19,8 +19,6 @@ package android.net.wifi; import android.os.Parcelable; import android.os.Parcel; -import java.util.BitSet; - /** * A class representing Wi-Fi Protected Setup * diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java index 0900351..fbcf09b 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java @@ -20,7 +20,6 @@ import android.os.Parcelable; import android.os.Parcel; import android.net.wifi.p2p.WifiP2pDevice; import android.text.TextUtils; -import android.util.Log; import java.util.ArrayList; import java.util.Collection; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index 4988b92..3ed2406 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -19,8 +19,6 @@ package android.net.wifi.p2p; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; -import android.net.ConnectivityManager; -import android.net.IConnectivityManager; import android.net.wifi.WpsInfo; import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo; import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceResponse; @@ -29,16 +27,12 @@ import android.net.wifi.p2p.nsd.WifiP2pServiceRequest; import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo; import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse; -import android.os.Binder; import android.os.Bundle; -import android.os.IBinder; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.WorkSource; import android.text.TextUtils; import android.util.Log; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java b/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java index b3f34b4..98683cb 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java @@ -16,10 +16,6 @@ package android.net.wifi.p2p; -import android.os.Parcelable; -import android.os.Parcel; -import android.util.Log; - /** * A class representing a Wi-Fi p2p provisional discovery request/response * See {@link #WifiP2pProvDiscEvent} for supported types diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java index 8b07208..7803f7d 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java @@ -18,27 +18,20 @@ package android.net.wifi.p2p; import android.app.AlertDialog; import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; -import android.net.IConnectivityManager; import android.net.ConnectivityManager; import android.net.DhcpResults; import android.net.DhcpStateMachine; import android.net.InterfaceConfiguration; import android.net.LinkAddress; -import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkUtils; -import android.net.wifi.WifiManager; import android.net.wifi.WifiMonitor; import android.net.wifi.WifiNative; import android.net.wifi.WifiStateMachine; @@ -51,13 +44,10 @@ import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.INetworkManagementService; -import android.os.Handler; -import android.os.HandlerThread; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; @@ -72,7 +62,6 @@ import android.widget.EditText; import android.widget.TextView; import com.android.internal.R; -import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import com.android.internal.util.State; @@ -1092,6 +1081,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { @Override public void exit() { + sendP2pDiscoveryChangedBroadcast(false); sendP2pStateChangedBroadcast(false); mNetworkInfo.setIsAvailable(false); |