Loading src/java/com/android/internal/telephony/dataconnection/ApnContext.java +50 −22 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; Loading Loading @@ -388,8 +389,9 @@ public class ApnContext { } } private final ArrayList<LocalLog> mLocalLogs = new ArrayList<LocalLog>(); private final ArrayDeque<LocalLog> mHistoryLogs = new ArrayDeque<LocalLog>(); private final ArrayList<LocalLog> mLocalLogs = new ArrayList<>(); private final ArrayList<NetworkRequest> mNetworkRequests = new ArrayList<>(); private final ArrayDeque<LocalLog> mHistoryLogs = new ArrayDeque<>(); private final static int MAX_HISTORY_LOG_COUNT = 4; public void requestLog(String str) { Loading @@ -400,41 +402,59 @@ public class ApnContext { } } public void incRefCount(LocalLog log) { public void requestNetwork(NetworkRequest networkRequest, LocalLog log) { synchronized (mRefCountLock) { if (mLocalLogs.contains(log)) { log.log("ApnContext.incRefCount has duplicate add - " + mRefCount); if (mLocalLogs.contains(log) || mNetworkRequests.contains(networkRequest)) { log.log("ApnContext.requestNetwork has duplicate add - " + mNetworkRequests.size()); } else { mLocalLogs.add(log); log.log("ApnContext.incRefCount - " + mRefCount); } if (mRefCount++ == 0) { mNetworkRequests.add(networkRequest); if (mNetworkRequests.size() == 1) { mDcTracker.setEnabled(apnIdForApnName(mApnType), true); } } } } public void decRefCount(LocalLog log) { public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) { synchronized (mRefCountLock) { if (mLocalLogs.remove(log)) { log.log("ApnContext.decRefCount - " + mRefCount); mHistoryLogs.addFirst(log); while (mHistoryLogs.size() > MAX_HISTORY_LOG_COUNT) { mHistoryLogs.removeLast(); } if (mLocalLogs.contains(log) == false) { log.log("ApnContext.releaseNetwork can't find this log"); } else { log.log("ApnContext.decRefCount didn't find log - " + mRefCount); mLocalLogs.remove(log); } if (mRefCount-- == 1) { if (mNetworkRequests.contains(networkRequest) == false) { log.log("ApnContext.releaseNetwork can't find this request (" + networkRequest + ")"); } else { mNetworkRequests.remove(networkRequest); log.log("ApnContext.releaseNetwork left with " + mNetworkRequests.size() + " requests."); if (mNetworkRequests.size() == 0) { mDcTracker.setEnabled(apnIdForApnName(mApnType), false); } if (mRefCount < 0) { log.log("ApnContext.decRefCount went to " + mRefCount); mRefCount = 0; } } } public List<NetworkRequest> getNetworkRequests() { synchronized (mRefCountLock) { return new ArrayList<NetworkRequest>(mNetworkRequests); } } public boolean hasNoRestrictedRequests() { synchronized (mRefCountLock) { for (NetworkRequest nr : mNetworkRequests) { if (nr.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) { return false; } } } return true; } private final SparseIntArray mRetriesLeftPerErrorCode = new SparseIntArray(); public void resetErrorCodeRetries() { Loading Loading @@ -677,6 +697,14 @@ public class ApnContext { final IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); synchronized (mRefCountLock) { pw.println(toString()); if (mNetworkRequests.size() > 0) { pw.println("NetworkRequests:"); pw.increaseIndent(); for (NetworkRequest nr : mNetworkRequests) { pw.println(nr); } pw.decreaseIndent(); } pw.increaseIndent(); for (LocalLog l : mLocalLogs) { l.dump(fd, pw, args); Loading src/java/com/android/internal/telephony/dataconnection/DataConnection.java +55 −0 Original line number Diff line number Diff line Loading @@ -826,6 +826,56 @@ public class DataConnection extends StateMachine { mLinkProperties.setTcpBufferSizes(sizes); } /** * Indicates if when this connection was established we had a restricted/privileged * NetworkRequest and needed it to overcome data-enabled limitations. * * This gets set once per connection setup and is based on conditions at that time. * We could theoretically have dynamic capabilities but now is not a good time to * experiement with that. * * This flag overrides the APN-based restriction capability, restricting the network * based on both having a NetworkRequest with restricted AND needing a restricted * bit to overcome user-disabled status. This allows us to handle the common case * of having both restricted requests and unrestricted requests for the same apn: * if conditions require a restricted network to overcome user-disabled then it must * be restricted, otherwise it is unrestricted (or restricted based on APN type). * * Because we're not supporting dynamic capabilities, if conditions change and we go from * data-enabled to not or vice-versa we will need to tear down networks to deal with it * at connection setup time with the new state. * * This supports a privileged app bringing up a network without general apps having access * to it when the network is otherwise unavailable (hipri). The first use case is * pre-paid SIM reprovisioning over internet, where the carrier insists on no traffic * other than from the privileged carrier-app. */ private boolean mRestrictedNetworkOverride = false; // Should be called once when the call goes active to examine the state of things and // declare the restriction override for the life of the connection private void setNetworkRestriction() { mRestrictedNetworkOverride = false; // first, if we have no restricted requests, this override can stay FALSE: boolean noRestrictedRequests = true; for (ApnContext apnContext : mApnContexts.keySet()) { noRestrictedRequests &= apnContext.hasNoRestrictedRequests(); } if (noRestrictedRequests) { return; } // Do we need a restricted network to satisfy the request? // Is this network metered? If not, then don't add restricted if (!mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())) { return; } // Is user data disabled? mRestrictedNetworkOverride = (mDct.isDataEnabled(true) == false); } private NetworkCapabilities makeNetworkCapabilities() { NetworkCapabilities result = new NetworkCapabilities(); result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); Loading Loading @@ -895,6 +945,10 @@ public class DataConnection extends StateMachine { result.maybeMarkCapabilitiesRestricted(); } if (mRestrictedNetworkOverride) { result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } int up = 14; int down = 14; switch (mRilRat) { Loading Loading @@ -1522,6 +1576,7 @@ public class DataConnection extends StateMachine { misc.subscriberId = mPhone.getSubscriberId(); if (createNetworkAgent) { setNetworkRestriction(); mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(), "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties, 50, misc); Loading src/java/com/android/internal/telephony/dataconnection/DcTracker.java +10 −6 Original line number Diff line number Diff line Loading @@ -927,14 +927,14 @@ public class DcTracker extends Handler { final int apnId = ApnContext.apnIdForNetworkRequest(networkRequest); final ApnContext apnContext = mApnContextsById.get(apnId); log.log("DcTracker.requestNetwork for " + networkRequest + " found " + apnContext); if (apnContext != null) apnContext.incRefCount(log); if (apnContext != null) apnContext.requestNetwork(networkRequest, log); } public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) { final int apnId = ApnContext.apnIdForNetworkRequest(networkRequest); final ApnContext apnContext = mApnContextsById.get(apnId); log.log("DcTracker.releaseNetwork for " + networkRequest + " found " + apnContext); if (apnContext != null) apnContext.decRefCount(log); if (apnContext != null) apnContext.releaseNetwork(networkRequest, log); } public boolean isApnSupported(String name) { Loading Loading @@ -1274,7 +1274,7 @@ public class DcTracker extends Handler { return false; } private boolean isDataEnabled(boolean checkUserDataEnabled) { boolean isDataEnabled(boolean checkUserDataEnabled) { synchronized (mDataEnabledLock) { if (!(mInternalDataEnabled && (!checkUserDataEnabled || mUserDataEnabled) && (!checkUserDataEnabled || sPolicyDataEnabled) Loading Loading @@ -1512,10 +1512,14 @@ public class DcTracker extends Handler { boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY); final ServiceStateTracker sst = mPhone.getServiceStateTracker(); // set to false if apn type is non-metered. // set to false if apn type is non-metered or if we have a restricted (priveleged) // request for the network. // TODO - may want restricted requests to only apply to carrier-limited data access // rather than applying to user limited as well. boolean checkUserDataEnabled = (ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(), mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())); ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(), mPhone.getSubId(), mPhone.getServiceState().getDataRoaming()) && apnContext.hasNoRestrictedRequests(); DataAllowFailReason failureReason = new DataAllowFailReason(); Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java +10 −6 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ package com.android.internal.telephony.dataconnection; import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkRequest; import android.test.suitebuilder.annotation.SmallTest; import android.util.LocalLog; Loading Loading @@ -136,16 +138,18 @@ public class ApnContextTest extends TelephonyTest { @Test @SmallTest public void testRefCount() throws Exception { public void testNetworkRequest() throws Exception { LocalLog log = new LocalLog(3); mApnContext.incRefCount(log); NetworkCapabilities nc = new NetworkCapabilities(); NetworkRequest nr = new NetworkRequest(nc, 0, 0); mApnContext.requestNetwork(nr, log); verify(mDcTracker, times(1)).setEnabled(eq(DctConstants.APN_DEFAULT_ID), eq(true)); mApnContext.incRefCount(log); mApnContext.requestNetwork(nr, log); verify(mDcTracker, times(1)).setEnabled(eq(DctConstants.APN_DEFAULT_ID), eq(true)); mApnContext.decRefCount(log); verify(mDcTracker, never()).setEnabled(eq(DctConstants.APN_DEFAULT_ID), eq(false)); mApnContext.decRefCount(log); mApnContext.releaseNetwork(nr, log); verify(mDcTracker, times(1)).setEnabled(eq(DctConstants.APN_DEFAULT_ID), eq(false)); mApnContext.releaseNetwork(nr, log); verify(mDcTracker, times(1)).setEnabled(eq(DctConstants.APN_DEFAULT_ID), eq(false)); } Loading Loading
src/java/com/android/internal/telephony/dataconnection/ApnContext.java +50 −22 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; Loading Loading @@ -388,8 +389,9 @@ public class ApnContext { } } private final ArrayList<LocalLog> mLocalLogs = new ArrayList<LocalLog>(); private final ArrayDeque<LocalLog> mHistoryLogs = new ArrayDeque<LocalLog>(); private final ArrayList<LocalLog> mLocalLogs = new ArrayList<>(); private final ArrayList<NetworkRequest> mNetworkRequests = new ArrayList<>(); private final ArrayDeque<LocalLog> mHistoryLogs = new ArrayDeque<>(); private final static int MAX_HISTORY_LOG_COUNT = 4; public void requestLog(String str) { Loading @@ -400,41 +402,59 @@ public class ApnContext { } } public void incRefCount(LocalLog log) { public void requestNetwork(NetworkRequest networkRequest, LocalLog log) { synchronized (mRefCountLock) { if (mLocalLogs.contains(log)) { log.log("ApnContext.incRefCount has duplicate add - " + mRefCount); if (mLocalLogs.contains(log) || mNetworkRequests.contains(networkRequest)) { log.log("ApnContext.requestNetwork has duplicate add - " + mNetworkRequests.size()); } else { mLocalLogs.add(log); log.log("ApnContext.incRefCount - " + mRefCount); } if (mRefCount++ == 0) { mNetworkRequests.add(networkRequest); if (mNetworkRequests.size() == 1) { mDcTracker.setEnabled(apnIdForApnName(mApnType), true); } } } } public void decRefCount(LocalLog log) { public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) { synchronized (mRefCountLock) { if (mLocalLogs.remove(log)) { log.log("ApnContext.decRefCount - " + mRefCount); mHistoryLogs.addFirst(log); while (mHistoryLogs.size() > MAX_HISTORY_LOG_COUNT) { mHistoryLogs.removeLast(); } if (mLocalLogs.contains(log) == false) { log.log("ApnContext.releaseNetwork can't find this log"); } else { log.log("ApnContext.decRefCount didn't find log - " + mRefCount); mLocalLogs.remove(log); } if (mRefCount-- == 1) { if (mNetworkRequests.contains(networkRequest) == false) { log.log("ApnContext.releaseNetwork can't find this request (" + networkRequest + ")"); } else { mNetworkRequests.remove(networkRequest); log.log("ApnContext.releaseNetwork left with " + mNetworkRequests.size() + " requests."); if (mNetworkRequests.size() == 0) { mDcTracker.setEnabled(apnIdForApnName(mApnType), false); } if (mRefCount < 0) { log.log("ApnContext.decRefCount went to " + mRefCount); mRefCount = 0; } } } public List<NetworkRequest> getNetworkRequests() { synchronized (mRefCountLock) { return new ArrayList<NetworkRequest>(mNetworkRequests); } } public boolean hasNoRestrictedRequests() { synchronized (mRefCountLock) { for (NetworkRequest nr : mNetworkRequests) { if (nr.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) { return false; } } } return true; } private final SparseIntArray mRetriesLeftPerErrorCode = new SparseIntArray(); public void resetErrorCodeRetries() { Loading Loading @@ -677,6 +697,14 @@ public class ApnContext { final IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); synchronized (mRefCountLock) { pw.println(toString()); if (mNetworkRequests.size() > 0) { pw.println("NetworkRequests:"); pw.increaseIndent(); for (NetworkRequest nr : mNetworkRequests) { pw.println(nr); } pw.decreaseIndent(); } pw.increaseIndent(); for (LocalLog l : mLocalLogs) { l.dump(fd, pw, args); Loading
src/java/com/android/internal/telephony/dataconnection/DataConnection.java +55 −0 Original line number Diff line number Diff line Loading @@ -826,6 +826,56 @@ public class DataConnection extends StateMachine { mLinkProperties.setTcpBufferSizes(sizes); } /** * Indicates if when this connection was established we had a restricted/privileged * NetworkRequest and needed it to overcome data-enabled limitations. * * This gets set once per connection setup and is based on conditions at that time. * We could theoretically have dynamic capabilities but now is not a good time to * experiement with that. * * This flag overrides the APN-based restriction capability, restricting the network * based on both having a NetworkRequest with restricted AND needing a restricted * bit to overcome user-disabled status. This allows us to handle the common case * of having both restricted requests and unrestricted requests for the same apn: * if conditions require a restricted network to overcome user-disabled then it must * be restricted, otherwise it is unrestricted (or restricted based on APN type). * * Because we're not supporting dynamic capabilities, if conditions change and we go from * data-enabled to not or vice-versa we will need to tear down networks to deal with it * at connection setup time with the new state. * * This supports a privileged app bringing up a network without general apps having access * to it when the network is otherwise unavailable (hipri). The first use case is * pre-paid SIM reprovisioning over internet, where the carrier insists on no traffic * other than from the privileged carrier-app. */ private boolean mRestrictedNetworkOverride = false; // Should be called once when the call goes active to examine the state of things and // declare the restriction override for the life of the connection private void setNetworkRestriction() { mRestrictedNetworkOverride = false; // first, if we have no restricted requests, this override can stay FALSE: boolean noRestrictedRequests = true; for (ApnContext apnContext : mApnContexts.keySet()) { noRestrictedRequests &= apnContext.hasNoRestrictedRequests(); } if (noRestrictedRequests) { return; } // Do we need a restricted network to satisfy the request? // Is this network metered? If not, then don't add restricted if (!mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())) { return; } // Is user data disabled? mRestrictedNetworkOverride = (mDct.isDataEnabled(true) == false); } private NetworkCapabilities makeNetworkCapabilities() { NetworkCapabilities result = new NetworkCapabilities(); result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); Loading Loading @@ -895,6 +945,10 @@ public class DataConnection extends StateMachine { result.maybeMarkCapabilitiesRestricted(); } if (mRestrictedNetworkOverride) { result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } int up = 14; int down = 14; switch (mRilRat) { Loading Loading @@ -1522,6 +1576,7 @@ public class DataConnection extends StateMachine { misc.subscriberId = mPhone.getSubscriberId(); if (createNetworkAgent) { setNetworkRestriction(); mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(), "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties, 50, misc); Loading
src/java/com/android/internal/telephony/dataconnection/DcTracker.java +10 −6 Original line number Diff line number Diff line Loading @@ -927,14 +927,14 @@ public class DcTracker extends Handler { final int apnId = ApnContext.apnIdForNetworkRequest(networkRequest); final ApnContext apnContext = mApnContextsById.get(apnId); log.log("DcTracker.requestNetwork for " + networkRequest + " found " + apnContext); if (apnContext != null) apnContext.incRefCount(log); if (apnContext != null) apnContext.requestNetwork(networkRequest, log); } public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) { final int apnId = ApnContext.apnIdForNetworkRequest(networkRequest); final ApnContext apnContext = mApnContextsById.get(apnId); log.log("DcTracker.releaseNetwork for " + networkRequest + " found " + apnContext); if (apnContext != null) apnContext.decRefCount(log); if (apnContext != null) apnContext.releaseNetwork(networkRequest, log); } public boolean isApnSupported(String name) { Loading Loading @@ -1274,7 +1274,7 @@ public class DcTracker extends Handler { return false; } private boolean isDataEnabled(boolean checkUserDataEnabled) { boolean isDataEnabled(boolean checkUserDataEnabled) { synchronized (mDataEnabledLock) { if (!(mInternalDataEnabled && (!checkUserDataEnabled || mUserDataEnabled) && (!checkUserDataEnabled || sPolicyDataEnabled) Loading Loading @@ -1512,10 +1512,14 @@ public class DcTracker extends Handler { boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY); final ServiceStateTracker sst = mPhone.getServiceStateTracker(); // set to false if apn type is non-metered. // set to false if apn type is non-metered or if we have a restricted (priveleged) // request for the network. // TODO - may want restricted requests to only apply to carrier-limited data access // rather than applying to user limited as well. boolean checkUserDataEnabled = (ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(), mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())); ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(), mPhone.getSubId(), mPhone.getServiceState().getDataRoaming()) && apnContext.hasNoRestrictedRequests(); DataAllowFailReason failureReason = new DataAllowFailReason(); Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java +10 −6 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ package com.android.internal.telephony.dataconnection; import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkRequest; import android.test.suitebuilder.annotation.SmallTest; import android.util.LocalLog; Loading Loading @@ -136,16 +138,18 @@ public class ApnContextTest extends TelephonyTest { @Test @SmallTest public void testRefCount() throws Exception { public void testNetworkRequest() throws Exception { LocalLog log = new LocalLog(3); mApnContext.incRefCount(log); NetworkCapabilities nc = new NetworkCapabilities(); NetworkRequest nr = new NetworkRequest(nc, 0, 0); mApnContext.requestNetwork(nr, log); verify(mDcTracker, times(1)).setEnabled(eq(DctConstants.APN_DEFAULT_ID), eq(true)); mApnContext.incRefCount(log); mApnContext.requestNetwork(nr, log); verify(mDcTracker, times(1)).setEnabled(eq(DctConstants.APN_DEFAULT_ID), eq(true)); mApnContext.decRefCount(log); verify(mDcTracker, never()).setEnabled(eq(DctConstants.APN_DEFAULT_ID), eq(false)); mApnContext.decRefCount(log); mApnContext.releaseNetwork(nr, log); verify(mDcTracker, times(1)).setEnabled(eq(DctConstants.APN_DEFAULT_ID), eq(false)); mApnContext.releaseNetwork(nr, log); verify(mDcTracker, times(1)).setEnabled(eq(DctConstants.APN_DEFAULT_ID), eq(false)); } Loading