Merge "Add ability to override subscriber capabilities."
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 58b8e62..80d483b 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -16,6 +16,9 @@
package com.android.internal.telephony.dataconnection;
+import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
+import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
+
import android.app.PendingIntent;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -173,6 +176,7 @@
private DcFailCause mLastFailCause;
private static final String NULL_IP = "0.0.0.0";
private Object mUserData;
+ private int mSubscriptionOverride;
private int mRilRat = Integer.MAX_VALUE;
private int mDataRegState = Integer.MAX_VALUE;
private NetworkInfo mNetworkInfo;
@@ -203,9 +207,10 @@
static final int EVENT_BW_REFRESH_RESPONSE = BASE + 14;
static final int EVENT_DATA_CONNECTION_VOICE_CALL_STARTED = BASE + 15;
static final int EVENT_DATA_CONNECTION_VOICE_CALL_ENDED = BASE + 16;
+ static final int EVENT_DATA_CONNECTION_OVERRIDE_CHANGED = BASE + 17;
private static final int CMD_TO_STRING_COUNT =
- EVENT_DATA_CONNECTION_VOICE_CALL_ENDED - BASE + 1;
+ EVENT_DATA_CONNECTION_OVERRIDE_CHANGED - BASE + 1;
private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
static {
@@ -229,6 +234,8 @@
"EVENT_DATA_CONNECTION_VOICE_CALL_STARTED";
sCmdToString[EVENT_DATA_CONNECTION_VOICE_CALL_ENDED - BASE] =
"EVENT_DATA_CONNECTION_VOICE_CALL_ENDED";
+ sCmdToString[EVENT_DATA_CONNECTION_OVERRIDE_CHANGED - BASE] =
+ "EVENT_DATA_CONNECTION_OVERRIDE_CHANGED";
}
// Convert cmd to string or null if unknown
static String cmdToString(int cmd) {
@@ -511,6 +518,12 @@
mPhone.mCi.setupDataCall(cp.mRilRat, dp, isModemRoaming, allowRoaming, msg);
}
+ public void onSubscriptionOverride(int overrideMask, int overrideValue) {
+ mSubscriptionOverride = (mSubscriptionOverride & ~overrideMask)
+ | (overrideValue & overrideMask);
+ sendMessage(obtainMessage(EVENT_DATA_CONNECTION_OVERRIDE_CHANGED));
+ }
+
/**
* TearDown the data connection when the deactivation is complete a Message with
* msg.what == EVENT_DEACTIVATE_DONE and msg.obj == AsyncResult with AsyncResult.obj
@@ -1006,14 +1019,19 @@
result.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(mPhone.getSubId())));
- if (!mPhone.getServiceState().getDataRoaming()) {
- result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
- } else {
- result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
- }
+ result.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING,
+ !mPhone.getServiceState().getDataRoaming());
result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
+ // Override values set above when requested by policy
+ if ((mSubscriptionOverride & OVERRIDE_UNMETERED) != 0) {
+ result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ }
+ if ((mSubscriptionOverride & OVERRIDE_CONGESTED) != 0) {
+ result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
+ }
+
return result;
}
@@ -1343,6 +1361,7 @@
break;
case EVENT_DATA_CONNECTION_ROAM_ON:
case EVENT_DATA_CONNECTION_ROAM_OFF:
+ case EVENT_DATA_CONNECTION_OVERRIDE_CHANGED:
updateNetworkInfo();
if (mNetworkAgent != null) {
mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities());
@@ -1791,7 +1810,8 @@
break;
}
case EVENT_DATA_CONNECTION_ROAM_ON:
- case EVENT_DATA_CONNECTION_ROAM_OFF: {
+ case EVENT_DATA_CONNECTION_ROAM_OFF:
+ case EVENT_DATA_CONNECTION_OVERRIDE_CHANGED: {
updateNetworkInfo();
if (mNetworkAgent != null) {
mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities());
@@ -2237,6 +2257,7 @@
pw.println("mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime));
pw.println("mLastFailCause=" + mLastFailCause);
pw.println("mUserData=" + mUserData);
+ pw.println("mSubscriptionOverride=" + Integer.toHexString(mSubscriptionOverride));
pw.println("mInstanceNumber=" + mInstanceNumber);
pw.println("mAc=" + mAc);
pw.println("Network capabilities changed history:");
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index c21713f..b4ceff6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -17,8 +17,10 @@
package com.android.internal.telephony.dataconnection;
import android.content.Context;
+import android.net.INetworkPolicyListener;
import android.net.LinkAddress;
import android.net.LinkProperties.CompareResult;
+import android.net.NetworkPolicyManager;
import android.net.NetworkUtils;
import android.os.AsyncResult;
import android.os.Build;
@@ -55,9 +57,10 @@
private DcTesterDeactivateAll mDcTesterDeactivateAll;
// package as its used by Testing code
- ArrayList<DataConnection> mDcListAll = new ArrayList<DataConnection>();
- private HashMap<Integer, DataConnection> mDcListActiveByCid =
- new HashMap<Integer, DataConnection>();
+ // @GuardedBy("mDcListAll")
+ final ArrayList<DataConnection> mDcListAll = new ArrayList<>();
+ // @GuardedBy("mDcListAll")
+ private final HashMap<Integer, DataConnection> mDcListActiveByCid = new HashMap<>();
/**
* Constants for the data connection activity:
@@ -72,7 +75,9 @@
private DccDefaultState mDccDefaultState = new DccDefaultState();
- TelephonyManager mTelephonyManager;
+ final TelephonyManager mTelephonyManager;
+ final NetworkPolicyManager mNetworkPolicyManager;
+
private PhoneStateListener mPhoneStateListener;
//mExecutingCarrierChange tracks whether the phone is currently executing
@@ -105,8 +110,12 @@
}
};
- mTelephonyManager = (TelephonyManager) phone.getContext().getSystemService(Context.TELEPHONY_SERVICE);
- if(mTelephonyManager != null) {
+ mTelephonyManager = (TelephonyManager) phone.getContext()
+ .getSystemService(Context.TELEPHONY_SERVICE);
+ mNetworkPolicyManager = (NetworkPolicyManager) phone.getContext()
+ .getSystemService(Context.NETWORK_POLICY_SERVICE);
+
+ if (mTelephonyManager != null) {
mTelephonyManager.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
}
@@ -125,29 +134,39 @@
}
void addDc(DataConnection dc) {
- mDcListAll.add(dc);
+ synchronized (mDcListAll) {
+ mDcListAll.add(dc);
+ }
}
void removeDc(DataConnection dc) {
- mDcListActiveByCid.remove(dc.mCid);
- mDcListAll.remove(dc);
+ synchronized (mDcListAll) {
+ mDcListActiveByCid.remove(dc.mCid);
+ mDcListAll.remove(dc);
+ }
}
public void addActiveDcByCid(DataConnection dc) {
if (DBG && dc.mCid < 0) {
log("addActiveDcByCid dc.mCid < 0 dc=" + dc);
}
- mDcListActiveByCid.put(dc.mCid, dc);
+ synchronized (mDcListAll) {
+ mDcListActiveByCid.put(dc.mCid, dc);
+ }
}
public DataConnection getActiveDcByCid(int cid) {
- return mDcListActiveByCid.get(cid);
+ synchronized (mDcListAll) {
+ return mDcListActiveByCid.get(cid);
+ }
}
void removeActiveDcByCid(DataConnection dc) {
- DataConnection removedDc = mDcListActiveByCid.remove(dc.mCid);
- if (DBG && removedDc == null) {
- log("removeActiveDcByCid removedDc=null dc=" + dc);
+ synchronized (mDcListAll) {
+ DataConnection removedDc = mDcListActiveByCid.remove(dc.mCid);
+ if (DBG && removedDc == null) {
+ log("removeActiveDcByCid removedDc=null dc=" + dc);
+ }
}
}
@@ -155,6 +174,21 @@
return mExecutingCarrierChange;
}
+ private final INetworkPolicyListener mListener = new NetworkPolicyManager.Listener() {
+ @Override
+ public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) {
+ if (mPhone == null || mPhone.getSubId() != subId) return;
+
+ final HashMap<Integer, DataConnection> dcListActiveByCid;
+ synchronized (mDcListAll) {
+ dcListActiveByCid = new HashMap<>(mDcListActiveByCid);
+ }
+ for (DataConnection dc : dcListActiveByCid.values()) {
+ dc.onSubscriptionOverride(overrideMask, overrideValue);
+ }
+ }
+ };
+
private class DccDefaultState extends State {
@Override
public void enter() {
@@ -166,6 +200,9 @@
mDcTesterDeactivateAll =
new DcTesterDeactivateAll(mPhone, DcController.this, getHandler());
}
+ if (mNetworkPolicyManager != null) {
+ mNetworkPolicyManager.registerListener(mListener);
+ }
}
@Override
@@ -177,6 +214,9 @@
if (mDcTesterDeactivateAll != null) {
mDcTesterDeactivateAll.dispose();
}
+ if (mNetworkPolicyManager != null) {
+ mNetworkPolicyManager.unregisterListener(mListener);
+ }
}
@Override
@@ -214,12 +254,19 @@
* @param dcsList as sent by RIL_UNSOL_DATA_CALL_LIST_CHANGED
*/
private void onDataStateChanged(ArrayList<DataCallResponse> dcsList) {
+ final ArrayList<DataConnection> dcListAll;
+ final HashMap<Integer, DataConnection> dcListActiveByCid;
+ synchronized (mDcListAll) {
+ dcListAll = new ArrayList<>(mDcListAll);
+ dcListActiveByCid = new HashMap<>(mDcListActiveByCid);
+ }
+
if (DBG) {
lr("onDataStateChanged: dcsList=" + dcsList
- + " mDcListActiveByCid=" + mDcListActiveByCid);
+ + " dcListActiveByCid=" + dcListActiveByCid);
}
if (VDBG) {
- log("onDataStateChanged: mDcListAll=" + mDcListAll);
+ log("onDataStateChanged: mDcListAll=" + dcListAll);
}
// Create hashmap of cid to DataCallResponse
@@ -232,7 +279,7 @@
// Add a DC that is active but not in the
// dcsList to the list of DC's to retry
ArrayList<DataConnection> dcsToRetry = new ArrayList<DataConnection>();
- for (DataConnection dc : mDcListActiveByCid.values()) {
+ for (DataConnection dc : dcListActiveByCid.values()) {
if (dataCallResponseListByCid.get(dc.mCid) == null) {
if (DBG) log("onDataStateChanged: add to retry dc=" + dc);
dcsToRetry.add(dc);
@@ -249,7 +296,7 @@
for (DataCallResponse newState : dcsList) {
- DataConnection dc = mDcListActiveByCid.get(newState.getCallId());
+ DataConnection dc = dcListActiveByCid.get(newState.getCallId());
if (dc == null) {
// UNSOL_DATA_CALL_LIST_CHANGED arrived before SETUP_DATA_CALL completed.
loge("onDataStateChanged: no associated DC yet, ignore");
@@ -437,14 +484,18 @@
@Override
public String toString() {
- return "mDcListAll=" + mDcListAll + " mDcListActiveByCid=" + mDcListActiveByCid;
+ synchronized (mDcListAll) {
+ return "mDcListAll=" + mDcListAll + " mDcListActiveByCid=" + mDcListActiveByCid;
+ }
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
super.dump(fd, pw, args);
pw.println(" mPhone=" + mPhone);
- pw.println(" mDcListAll=" + mDcListAll);
- pw.println(" mDcListActiveByCid=" + mDcListActiveByCid);
+ synchronized (mDcListAll) {
+ pw.println(" mDcListAll=" + mDcListAll);
+ pw.println(" mDcListActiveByCid=" + mDcListActiveByCid);
+ }
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
index 3decf92..98b3deb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -16,6 +16,11 @@
package com.android.internal.telephony.dataconnection;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
+import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
+
import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS;
@@ -26,8 +31,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -362,6 +367,48 @@
.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
}
+ @Test
+ public void testOverrideUnmetered() throws Exception {
+ mContextFixture.getCarrierConfigBundle().putStringArray(
+ CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[] { "default" });
+ testConnectEvent();
+
+ assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+
+ mDc.onSubscriptionOverride(OVERRIDE_UNMETERED, OVERRIDE_UNMETERED);
+
+ assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+
+ mDc.onSubscriptionOverride(OVERRIDE_UNMETERED, 0);
+
+ assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+ }
+
+ @Test
+ public void testOverrideCongested() throws Exception {
+ mContextFixture.getCarrierConfigBundle().putStringArray(
+ CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[] { "default" });
+ testConnectEvent();
+
+ assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+
+ mDc.onSubscriptionOverride(OVERRIDE_CONGESTED, OVERRIDE_CONGESTED);
+
+ assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+
+ mDc.onSubscriptionOverride(OVERRIDE_CONGESTED, 0);
+
+ assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+ }
+
@SmallTest
public void testIsIpAddress() throws Exception {
// IPv4