Index: net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java |
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java |
index 60eaf031d0fa7226d36d67cb1dcae3f6325dc234..a3fa198a4fd9e904b922c0c4416ab4d4512b504b 100644 |
--- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java |
+++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java |
@@ -36,6 +36,8 @@ import org.chromium.net.ConnectionType.ConnectionTypeEnum; |
import java.io.IOException; |
import java.util.Arrays; |
+import javax.annotation.concurrent.GuardedBy; |
+ |
/** |
* Used by the NetworkChangeNotifier to listens to platform changes in connectivity. |
* Note that use of this class requires that the app have the platform |
@@ -46,11 +48,16 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver { |
private final boolean mConnected; |
private final int mType; |
private final int mSubtype; |
+ // WIFI SSID of the connection. Always non-null (i.e. instead of null it'll be an empty |
+ // string) to facilitate .equals(). |
+ private final String mWifiSsid; |
- public NetworkState(boolean connected, int type, int subtype) { |
+ public NetworkState(boolean connected, int type, int subtype, String wifiSsid) { |
mConnected = connected; |
mType = type; |
mSubtype = subtype; |
+ assert mType == ConnectivityManager.TYPE_WIFI || wifiSsid == null; |
+ mWifiSsid = wifiSsid == null ? "" : wifiSsid; |
} |
public boolean isConnected() { |
@@ -64,6 +71,11 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver { |
public int getNetworkSubType() { |
return mSubtype; |
} |
+ |
+ // WiFi SSID, always non-null to facilitate .equals() |
+ public String getWifiSsid() { |
+ return mWifiSsid; |
+ } |
} |
/** Queries the ConnectivityManager for information about the current connection. */ |
@@ -85,12 +97,23 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver { |
* Returns connection type and status information about the current |
* default network. |
*/ |
- NetworkState getNetworkState() { |
+ NetworkState getNetworkState(WifiManagerDelegate wifiManagerDelegate) { |
final NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); |
if (networkInfo == null || !networkInfo.isConnected()) { |
- return new NetworkState(false, -1, -1); |
+ return new NetworkState(false, -1, -1, null); |
+ } |
+ // If Wifi, then fetch SSID also |
+ if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { |
+ // Since Android 4.2 the SSID can be retrieved from NetworkInfo.getExtraInfo(). |
+ if (networkInfo.getExtraInfo() != null && !"".equals(networkInfo.getExtraInfo())) { |
+ return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype(), |
+ networkInfo.getExtraInfo()); |
+ } |
+ // Fetch WiFi SSID directly from WifiManagerDelegate if not in NetworkInfo. |
+ return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype(), |
+ wifiManagerDelegate.getWifiSsid()); |
} |
- return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype()); |
+ return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype(), null); |
} |
// Fetches NetworkInfo and records UMA for NullPointerExceptions. |
@@ -238,35 +261,64 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver { |
/** Queries the WifiManager for SSID of the current Wifi connection. */ |
static class WifiManagerDelegate { |
private final Context mContext; |
- private final WifiManager mWifiManager; |
- private final boolean mHasWifiPermission; |
+ // Lock all members below. |
+ private final Object mLock = new Object(); |
+ // Has mHasWifiPermission been calculated. |
+ @GuardedBy("mLock") |
+ private boolean mHasWifiPermissionComputed; |
+ // Only valid when mHasWifiPermissionComputed is set. |
+ @GuardedBy("mLock") |
+ private boolean mHasWifiPermission; |
+ // Only valid when mHasWifiPermission is set. |
+ @GuardedBy("mLock") |
+ private WifiManager mWifiManager; |
WifiManagerDelegate(Context context) { |
mContext = context; |
- // TODO(jkarlin): If the embedder doesn't have ACCESS_WIFI_STATE permission then inform |
- // native code and fail if native NetworkChangeNotifierAndroid::GetMaxBandwidth() is |
- // called. |
- mHasWifiPermission = mContext.getPackageManager().checkPermission( |
- permission.ACCESS_WIFI_STATE, mContext.getPackageName()) |
- == PackageManager.PERMISSION_GRANTED; |
- mWifiManager = mHasWifiPermission |
- ? (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE) : null; |
} |
// For testing. |
WifiManagerDelegate() { |
// All the methods below should be overridden. |
mContext = null; |
- mWifiManager = null; |
- mHasWifiPermission = false; |
} |
- String getWifiSSID() { |
+ // Lazily determine if app has ACCESS_WIFI_STATE permission. |
+ @GuardedBy("mLock") |
+ private boolean hasPermissionLocked() { |
+ if (mHasWifiPermissionComputed) { |
+ return mHasWifiPermission; |
+ } |
+ mHasWifiPermission = mContext.getPackageManager().checkPermission( |
+ permission.ACCESS_WIFI_STATE, mContext.getPackageName()) |
+ == PackageManager.PERMISSION_GRANTED; |
+ mWifiManager = mHasWifiPermission |
+ ? (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE) |
+ : null; |
+ mHasWifiPermissionComputed = true; |
+ return mHasWifiPermission; |
+ } |
+ |
+ String getWifiSsid() { |
+ // Synchronized because this method can be called on multiple threads (e.g. UI thread |
+ // from a private caller, and another thread calling a public API like |
+ // getCurrentNetworkState) and is otherwise racy. |
+ synchronized (mLock) { |
+ // If app has permission it's faster to query WifiManager directly. |
+ if (hasPermissionLocked()) { |
+ WifiInfo wifiInfo = getWifiInfoLocked(); |
+ if (wifiInfo != null) { |
+ return wifiInfo.getSSID(); |
+ } |
+ return ""; |
+ } |
+ } |
return AndroidNetworkLibrary.getWifiSSID(mContext); |
} |
// Fetches WifiInfo and records UMA for NullPointerExceptions. |
- private WifiInfo getWifiInfo() { |
+ @GuardedBy("mLock") |
+ private WifiInfo getWifiInfoLocked() { |
try { |
WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); |
RecordHistogram.recordBooleanHistogram("NCN.getWifiInfo1stSuccess", true); |
@@ -571,7 +623,7 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver { |
} |
final NetworkState networkState = getCurrentNetworkState(); |
mConnectionType = convertToConnectionType(networkState); |
- mWifiSSID = getCurrentWifiSSID(networkState); |
+ mWifiSSID = networkState.getWifiSsid(); |
mMaxBandwidthMbps = getCurrentMaxBandwidthInMbps(networkState); |
mMaxBandwidthConnectionType = mConnectionType; |
mIntentFilter = new NetworkConnectivityIntentFilter(); |
@@ -654,7 +706,7 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver { |
} |
public NetworkState getCurrentNetworkState() { |
- return mConnectivityManagerDelegate.getNetworkState(); |
+ return mConnectivityManagerDelegate.getNetworkState(mWifiManagerDelegate); |
} |
/** |
@@ -849,11 +901,6 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver { |
convertToConnectionSubtype(networkState)); |
} |
- private String getCurrentWifiSSID(NetworkState networkState) { |
- if (convertToConnectionType(networkState) != ConnectionType.CONNECTION_WIFI) return ""; |
- return mWifiManagerDelegate.getWifiSSID(); |
- } |
- |
// BroadcastReceiver |
@Override |
public void onReceive(Context context, Intent intent) { |
@@ -867,7 +914,7 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver { |
private void connectionTypeChanged(NetworkState networkState) { |
@ConnectionTypeEnum |
int newConnectionType = convertToConnectionType(networkState); |
- String newWifiSSID = getCurrentWifiSSID(networkState); |
+ String newWifiSSID = networkState.getWifiSsid(); |
if (newConnectionType == mConnectionType && newWifiSSID.equals(mWifiSSID)) return; |
mConnectionType = newConnectionType; |