Bug 1020412 - Proper handling of Context in GeckoNetworkManager. r=wesj
authorRichard Newman <rnewman@mozilla.com>
Wed, 18 Jun 2014 09:50:31 -0700
changeset 189553 eef1522f8eb1934bcb82899d2c1cfb7fe60b1d0d
parent 189552 802926a2f654a7c9562f829948fbdb24439ddf9f
child 189554 815c4fab188b032d2a4ddccff0b7f2a7d4a4d248
push id26989
push useremorley@mozilla.com
push dateThu, 19 Jun 2014 15:01:56 +0000
treeherdermozilla-central@ea703db56bcf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswesj
bugs1020412
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1020412 - Proper handling of Context in GeckoNetworkManager. r=wesj
mobile/android/base/GeckoNetworkManager.java
--- a/mobile/android/base/GeckoNetworkManager.java
+++ b/mobile/android/base/GeckoNetworkManager.java
@@ -18,20 +18,20 @@ import android.net.wifi.WifiManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
 /*
  * A part of the work of GeckoNetworkManager is to give an general connection
  * type based on the current connection. According to spec of NetworkInformation
  * API version 3, connection types include: bluetooth, cellular, ethernet, none,
  * wifi and other. The objective of providing such general connection is due to
- * some securtiy concerns. In short, we don't want to expose the information of
+ * some security concerns. In short, we don't want to expose the information of
  * exact network type, especially the cellular network type.
  *
- * Currnet connection is firstly obtained from Android's ConnectivityManager,
+ * Current connection is firstly obtained from Android's ConnectivityManager,
  * which is represented by the constant, and then will be mapped into the
  * connection type defined in Network Information API version 3.
  */
 
 public class GeckoNetworkManager extends BroadcastReceiver {
     private static final String LOGTAG = "GeckoNetworkManager";
 
     static private final GeckoNetworkManager sInstance = new GeckoNetworkManager();
@@ -52,97 +52,103 @@ public class GeckoNetworkManager extends
         }
     }
 
     private enum InfoType {
         MCC,
         MNC
     }
 
-    static private final ConnectionType kDefaultConnectionType = ConnectionType.NONE;
-
-    private static Context getApplicationContext() {
-        Context context = GeckoAppShell.getContext();
-        if (null == context)
-            return null;
-        return context.getApplicationContext();
-    }
     private ConnectionType mConnectionType = ConnectionType.NONE;
     private final IntentFilter mNetworkFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
 
     // Whether the manager should be listening to Network Information changes.
     private boolean mShouldBeListening = false;
 
     // Whether the manager should notify Gecko that a change in Network
     // Information happened.
     private boolean mShouldNotify = false;
 
+    // The application context used for registering receivers, so
+    // we can unregister them again later.
+    private volatile Context mApplicationContext;
+
     public static GeckoNetworkManager getInstance() {
         return sInstance;
     }
 
     @Override
     public void onReceive(Context aContext, Intent aIntent) {
         updateConnectionType();
     }
 
     public void start(final Context context) {
         // Note that this initialization clause only runs once.
+        mApplicationContext = context.getApplicationContext();
         if (mConnectionType == ConnectionType.NONE) {
             mConnectionType = getConnectionType();
         }
 
         mShouldBeListening = true;
         updateConnectionType();
 
         if (mShouldNotify) {
             startListening();
         }
     }
 
     private void startListening() {
-        if (null !=getApplicationContext())
-            getApplicationContext().registerReceiver(sInstance, mNetworkFilter);
+        final Context appContext = mApplicationContext;
+        if (appContext == null) {
+            Log.w(LOGTAG, "Not registering receiver: no context!");
+            return;
+        }
+
+        Log.v(LOGTAG, "Registering receiver.");
+        appContext.registerReceiver(this, mNetworkFilter);
     }
 
     public void stop() {
         mShouldBeListening = false;
 
         if (mShouldNotify) {
             stopListening();
         }
     }
 
     private void stopListening() {
-        if (null != getApplicationContext())
-            getApplicationContext().unregisterReceiver(sInstance);
+        if (null == mApplicationContext) {
+            return;
+        }
+
+        mApplicationContext.unregisterReceiver(this);
     }
 
     private int wifiDhcpGatewayAddress() {
         if (mConnectionType != ConnectionType.WIFI) {
             return 0;
         }
 
-        if (null == getApplicationContext()) {
+        if (null == mApplicationContext) {
             return 0;
         }
 
         try {
-            WifiManager mgr = (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+            WifiManager mgr = (WifiManager) mApplicationContext.getSystemService(Context.WIFI_SERVICE);
             DhcpInfo d = mgr.getDhcpInfo();
             if (d == null) {
                 return 0;
             }
 
             return d.gateway;
 
         } catch (Exception ex) {
             // getDhcpInfo() is not documented to require any permissions, but on some devices
-            // requires android.permission.ACCESS_WIFI_STATE. Just catching the generic exeption
-            // here and returning 0. Not logging because this could be noisy
+            // requires android.permission.ACCESS_WIFI_STATE. Just catch the generic exception
+            // here and returning 0. Not logging because this could be noisy.
             return 0;
         }
     }
 
     private void updateConnectionType() {
         ConnectionType previousConnectionType = mConnectionType;
         mConnectionType = getConnectionType();
 
@@ -177,23 +183,24 @@ public class GeckoNetworkManager extends
     public void disableNotifications() {
         mShouldNotify = false;
 
         if (mShouldBeListening) {
             stopListening();
         }
     }
 
-    private static ConnectionType getConnectionType() {
-        if (null == getApplicationContext()) {
+    private ConnectionType getConnectionType() {
+        final Context appContext = mApplicationContext;
+
+        if (null == appContext) {
             return ConnectionType.NONE;
         }
 
-        ConnectivityManager cm =
-            (ConnectivityManager)getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        ConnectivityManager cm = (ConnectivityManager) appContext.getSystemService(Context.CONNECTIVITY_SERVICE);
         if (cm == null) {
             Log.e(LOGTAG, "Connectivity service does not exist");
             return ConnectionType.NONE;
         }
 
         NetworkInfo ni = null;
         try {
             ni = cm.getActiveNetworkInfo();
@@ -214,21 +221,22 @@ public class GeckoNetworkManager extends
         case ConnectivityManager.TYPE_WIFI:
             return ConnectionType.WIFI;
         default:
             Log.w(LOGTAG, "Ignoring the current network type.");
             return ConnectionType.OTHER;
         }
     }
 
-    private static int getNetworkOperator(InfoType type) {
-        if (null == getApplicationContext())
+    private static int getNetworkOperator(InfoType type, Context context) {
+        if (null == context) {
             return -1;
+        }
 
-        TelephonyManager tel = (TelephonyManager)getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
+        TelephonyManager tel = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
         if (tel == null) {
             Log.e(LOGTAG, "Telephony service does not exist");
             return -1;
         }
 
         String networkOperator = tel.getNetworkOperator();
         if (networkOperator == null || networkOperator.length() <= 3) {
             return -1;
@@ -237,19 +245,24 @@ public class GeckoNetworkManager extends
             return Integer.parseInt(networkOperator.substring(3));
         } else if (type == InfoType.MCC) {
             return Integer.parseInt(networkOperator.substring(0, 3));
         }
 
         return -1;
     }
 
-    /* These are called from javascript c-types. Avoid letting pro-guard delete them */
+    /**
+     * These are called from JavaScript ctypes. Avoid letting ProGuard delete them.
+     *
+     * Note that these methods must only be called after GeckoAppShell has been
+     * initialized: they depend on access to the context.
+     */
     @JNITarget
     public static int getMCC() {
-        return getNetworkOperator(InfoType.MCC);
+        return getNetworkOperator(InfoType.MCC, GeckoAppShell.getContext().getApplicationContext());
     }
 
     @JNITarget
     public static int getMNC() {
-        return getNetworkOperator(InfoType.MNC);
+        return getNetworkOperator(InfoType.MNC, GeckoAppShell.getContext().getApplicationContext());
     }
 }