Change DcTracker construction so only initialization is preformed. DO NOT MERGE.
Wink Saville [Wed, 2 Oct 2013 17:31:51 +0000 (10:31 -0700)]
In initApnContexts applyNewState and onSetDependency met could cause
calls to trySetupData which can send notifications or even try to
bring up a connection. This can cause problems as not all objects are
initialized. In particular when I tried to change ApnContext#isReady
to be false it caused a call to mPhone.notifyDataConnection but mPhone
wasn't completely initialized and an NPE occurred.

Bug: 9022095
Change-Id: Ie817db2c0c1b381b1f58e87817f4b2336c7a3159

src/java/com/android/internal/telephony/dataconnection/DcTracker.java

index 74f96e0..921fad2 100644 (file)
@@ -18,7 +18,6 @@ package com.android.internal.telephony.dataconnection;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -39,7 +38,6 @@ import android.os.Message;
 import android.os.Messenger;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Telephony;
 import android.telephony.CellLocation;
@@ -55,7 +53,6 @@ import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.DctConstants;
 import com.android.internal.telephony.EventLogTags;
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.gsm.GSMPhone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RILConstants;
@@ -141,7 +138,7 @@ public final class DcTracker extends DcTrackerBase {
         p.getContext().getContentResolver().registerContentObserver(
                 Telephony.Carriers.CONTENT_URI, true, mApnObserver);
 
-        initApnContextsAndDataConnection();
+        initApnContexts();
 
         for (ApnContext apnContext : mApnContexts.values()) {
             // Register the reconnect and restart actions.
@@ -226,14 +223,14 @@ public final class DcTracker extends DcTrackerBase {
         if(DBG) log("finalize");
     }
 
-    private ApnContext addApnContext(String type) {
-        ApnContext apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG);
-        apnContext.setDependencyMet(false);
+    private ApnContext addApnContext(String type, NetworkConfig networkConfig) {
+        ApnContext apnContext = new ApnContext(type, LOG_TAG);
+        apnContext.setDependencyMet(networkConfig.dependencyMet);
         mApnContexts.put(type, apnContext);
         return apnContext;
     }
 
-    protected void initApnContextsAndDataConnection() {
+    protected void initApnContexts() {
         boolean defaultEnabled = SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP, true);
         // Load device network attributes from resources
         String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray(
@@ -244,45 +241,36 @@ public final class DcTracker extends DcTrackerBase {
 
             switch (networkConfig.type) {
             case ConnectivityManager.TYPE_MOBILE:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT);
+                apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig);
                 apnContext.setEnabled(defaultEnabled);
                 break;
             case ConnectivityManager.TYPE_MOBILE_MMS:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS);
+                apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig);
                 break;
             case ConnectivityManager.TYPE_MOBILE_SUPL:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL);
+                apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL, networkConfig);
                 break;
             case ConnectivityManager.TYPE_MOBILE_DUN:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN);
+                apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN, networkConfig);
                 break;
             case ConnectivityManager.TYPE_MOBILE_HIPRI:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI);
-                ApnContext defaultContext = mApnContexts.get(PhoneConstants.APN_TYPE_DEFAULT);
-                if (defaultContext != null) {
-                    applyNewState(apnContext, apnContext.isEnabled(),
-                            defaultContext.getDependencyMet());
-                } else {
-                    // the default will set the hipri dep-met when it is created
-                }
+                // Hipri is configured the same as default
+                apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI, networkConfig);
+                apnContext.setEnabled(defaultEnabled);
                 continue;
             case ConnectivityManager.TYPE_MOBILE_FOTA:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA);
+                apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA, networkConfig);
                 break;
             case ConnectivityManager.TYPE_MOBILE_IMS:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS);
+                apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS, networkConfig);
                 break;
             case ConnectivityManager.TYPE_MOBILE_CBS:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS);
+                apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS, networkConfig);
                 break;
             default:
-                // skip unknown types
+                log("initApnContexts: skipping unknown type=" + networkConfig.type);
                 continue;
             }
-            if (apnContext != null) {
-                // set the prop, but also apply the newly set enabled and dependency values
-                onSetDependencyMet(apnContext.getApnType(), networkConfig.dependencyMet);
-            }
         }
     }
 
@@ -367,16 +355,6 @@ public final class DcTracker extends DcTrackerBase {
         return DctConstants.State.FAILED;
     }
 
-    // Return if apn type is a provisioning apn.
-    @Override
-    protected boolean isProvisioningApn(String apnType) {
-        ApnContext apnContext = mApnContexts.get(apnType);
-        if (apnContext != null) {
-            return apnContext.isProvisioningApn();
-        }
-        return false;
-    }
-
     // Return state of overall
     @Override
     public DctConstants.State getOverallState() {
@@ -622,7 +600,7 @@ public final class DcTracker extends DcTrackerBase {
 
         if (apnContext == null ){
             if (DBG) log("trySetupData new apn context for type:" + type);
-            apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG);
+            apnContext = new ApnContext(type, LOG_TAG);
             mApnContexts.put(type, apnContext);
         }
         apnContext.setReason(reason);
@@ -1153,6 +1131,18 @@ public final class DcTracker extends DcTrackerBase {
         if (DBG) log("onDataStateChanged(ar): X");
     }
 
+    private void notifyDefaultData(ApnContext apnContext) {
+        if (DBG) {
+            log("notifyDefaultData: type=" + apnContext.getApnType()
+                + ", reason:" + apnContext.getReason());
+        }
+        apnContext.setState(DctConstants.State.CONNECTED);
+        // setState(DctConstants.State.CONNECTED);
+        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+        startNetStatPoll();
+        startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
+    }
+
     // TODO: For multiple Active APNs not exactly sure how to do this.
     @Override
     protected void gotoIdleAndNotifyDataConnection(String reason) {
@@ -1488,35 +1478,6 @@ public final class DcTracker extends DcTrackerBase {
         notifyOffApnsOfAvailability(null);
     }
 
-    @Override
-    protected void completeConnection(ApnContext apnContext) {
-        boolean isProvApn = apnContext.isProvisioningApn();
-
-        if (DBG) log("completeConnection: successful, notify the world apnContext=" + apnContext);
-
-        if (mIsProvisioning && !TextUtils.isEmpty(mProvisioningUrl)) {
-            if (DBG) {
-                log("completeConnection: MOBILE_PROVISIONING_ACTION url="
-                        + mProvisioningUrl);
-            }
-            Intent newIntent =
-                    new Intent(Intent.ACTION_VIEW, Uri.parse(mProvisioningUrl));
-            newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
-                    Intent.FLAG_ACTIVITY_NEW_TASK);
-            try {
-                mPhone.getContext().startActivity(newIntent);
-            } catch (ActivityNotFoundException e) {
-                loge("completeConnection: startActivityAsUser failed" + e);
-            }
-        }
-        mIsProvisioning = false;
-        mProvisioningUrl = null;
-
-        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
-        startNetStatPoll();
-        startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
-    }
-
     /**
      * A SETUP (aka bringUp) has completed, possibly with an error. If
      * there is an error this method will call {@link #onDataSetupCompleteError}.
@@ -1590,52 +1551,7 @@ public final class DcTracker extends DcTrackerBase {
                 } else {
                     SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
                 }
-
-                // A connection is setup
-                apnContext.setState(DctConstants.State.CONNECTED);
-                boolean isProvApn = apnContext.isProvisioningApn();
-                if ((!isProvApn) || mIsProvisioning) {
-                    // Complete the connection normally notifying the world we're connected.
-                    // We do this if this isn't a special provisioning apn or if we've been
-                    // told its time to provision.
-                    completeConnection(apnContext);
-                } else {
-                    // This is a provisioning APN that we're reporting as connected. Later
-                    // when the user desires to upgrade this to a "default" connection,
-                    // mIsProvisioning == true, we'll go through the code path above.
-                    // mIsProvisioning becomes true when CMD_ENABLE_MOBILE_PROVISIONING
-                    // is sent to the DCT.
-                    if (DBG) {
-                        log("onDataSetupComplete: successful, BUT send connected to prov apn as"
-                                + " mIsProvisioning:" + mIsProvisioning + " == false"
-                                + " && (isProvisioningApn:" + isProvApn + " == true");
-                    }
-
-                    Intent intent = new Intent(
-                            TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN);
-                    intent.putExtra(PhoneConstants.DATA_APN_KEY, apnContext.getApnSetting().apn);
-                    intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnContext.getApnType());
-
-                    String apnType = apnContext.getApnType();
-                    LinkProperties linkProperties = getLinkProperties(apnType);
-                    if (linkProperties != null) {
-                        intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
-                        String iface = linkProperties.getInterfaceName();
-                        if (iface != null) {
-                            intent.putExtra(PhoneConstants.DATA_IFACE_NAME_KEY, iface);
-                        }
-                    }
-                    LinkCapabilities linkCapabilities = getLinkCapabilities(apnType);
-                    if (linkCapabilities != null) {
-                        intent.putExtra(PhoneConstants.DATA_LINK_CAPABILITIES_KEY, linkCapabilities);
-                    }
-
-                    mPhone.getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
-                }
-                if (DBG) {
-                    log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType()
-                        + ", reason:" + apnContext.getReason());
-                }
+                notifyDefaultData(apnContext);
             }
         } else {
             cause = (DcFailCause) (ar.result);