Loading src/java/com/android/internal/telephony/dataconnection/ApnContext.java +5 −9 Original line number Diff line number Diff line Loading @@ -460,11 +460,7 @@ public class ApnContext { } } /** * @param excludeDun True if excluding requests that have DUN capability * @return True if the attached network requests contain restricted capability. */ public boolean hasRestrictedRequests(boolean excludeDun) { public boolean hasNoRestrictedRequests(boolean excludeDun) { synchronized (mRefCountLock) { for (NetworkRequest nr : mNetworkRequests) { if (excludeDun && Loading @@ -472,13 +468,13 @@ public class ApnContext { NetworkCapabilities.NET_CAPABILITY_DUN)) { continue; } if (!nr.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) { return true; if (nr.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) { return false; } } } return false; return true; } private final SparseIntArray mRetriesLeftPerErrorCode = new SparseIntArray(); Loading src/java/com/android/internal/telephony/dataconnection/DataConnection.java +51 −134 Original line number Diff line number Diff line Loading @@ -123,14 +123,17 @@ public class DataConnection extends StateMachine { ApnContext mApnContext; int mProfileId; int mRilRat; final boolean mUnmeteredUseOnly; Message mOnCompletedMsg; final int mConnectionGeneration; ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) { boolean unmeteredUseOnly, Message onCompletedMsg, int connectionGeneration) { mApnContext = apnContext; mProfileId = profileId; mRilRat = rilRadioTechnology; mUnmeteredUseOnly = unmeteredUseOnly; mOnCompletedMsg = onCompletedMsg; mConnectionGeneration = connectionGeneration; } Loading @@ -140,6 +143,7 @@ public class DataConnection extends StateMachine { return "{mTag=" + mTag + " mApnContext=" + mApnContext + " mProfileId=" + mProfileId + " mRat=" + mRilRat + " mUnmeteredUseOnly=" + mUnmeteredUseOnly + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; } } Loading Loading @@ -218,9 +222,8 @@ public class DataConnection extends StateMachine { static final int EVENT_KEEPALIVE_STOP_REQUEST = BASE + 22; static final int EVENT_LINK_CAPACITY_CHANGED = BASE + 23; static final int EVENT_RESET = BASE + 24; static final int EVENT_REEVALUATE_RESTRICTED_STATE = BASE + 25; private static final int CMD_TO_STRING_COUNT = EVENT_REEVALUATE_RESTRICTED_STATE - BASE + 1; private static final int CMD_TO_STRING_COUNT = EVENT_RESET - BASE + 1; private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; static { Loading Loading @@ -252,8 +255,6 @@ public class DataConnection extends StateMachine { sCmdToString[EVENT_KEEPALIVE_STOP_REQUEST - BASE] = "EVENT_KEEPALIVE_STOP_REQUEST"; sCmdToString[EVENT_LINK_CAPACITY_CHANGED - BASE] = "EVENT_LINK_CAPACITY_CHANGED"; sCmdToString[EVENT_RESET - BASE] = "EVENT_RESET"; sCmdToString[EVENT_REEVALUATE_RESTRICTED_STATE - BASE] = "EVENT_REEVALUATE_RESTRICTED_STATE"; } // Convert cmd to string or null if unknown static String cmdToString(int cmd) { Loading Loading @@ -884,19 +885,14 @@ public class DataConnection extends StateMachine { mLinkProperties.setTcpBufferSizes(sizes); } /** * Indicates if this data connection was established for unmetered use only. Note that this * flag should be populated when data becomes active. And if it is set to true, it can be set to * false later when we are reevaluating the data connection. But if it is set to false, it * can never become true later because setting it to true will cause this data connection * losing some immutable network capabilities, which can cause issues in connectivity service. */ private boolean mUnmeteredUseOnly = false; /** * 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 * experiment 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 Loading @@ -904,78 +900,38 @@ public class DataConnection extends StateMachine { * 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. * * Note that the data connection cannot go from unrestricted to restricted because the * connectivity service does not support dynamically closing TCP connections at this point. */ private boolean mRestrictedNetworkOverride = false; /** * Check if this data connection should be restricted. We should call this when data connection * becomes active, or when we want to re-evaluate the conditions to decide if we need to * unstrict the data connection. * * @return True if this data connection needs to be restricted. */ private boolean shouldRestrictNetwork() { // first, check if there is any network request that containing restricted capability // (i.e. Do not have NET_CAPABILITY_NOT_RESTRICTED in the request) boolean isAnyRestrictedRequest = 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()) { if (apnContext.hasRestrictedRequests(true /* exclude DUN */)) { isAnyRestrictedRequest = true; break; noRestrictedRequests &= apnContext.hasNoRestrictedRequests(true /* exclude DUN */); } if (noRestrictedRequests) { return; } // If all of the network requests are non-restricted, then we don't need to restrict // the network. if (!isAnyRestrictedRequest) { return false; } // If the network is unmetered, then we don't need to restrict the network because users // won't be charged anyway. // Do we need a restricted network to satisfy the request? // Is this network metered? If not, then don't add restricted if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { return false; } // If the data is disabled, then we need to restrict the network so only privileged apps can // use the restricted network while data is disabled. if (!mDct.isDataEnabled()) { return true; return; } // If the device is roaming, and the user does not turn on data roaming, then we need to // restrict the network so only privileged apps can use it. if (!mDct.getDataRoamingEnabled() && mPhone.getServiceState().getDataRoaming()) { return true; } // Otherwise we should not restrict the network so anyone who requests can use it. return false; } /** * @return True if this data connection should only be used for unmetered purposes. */ private boolean isUnmeteredUseOnly() { // The data connection can only be unmetered used only if all requests' reasons are // unmetered. for (ApnContext apnContext : mApnContexts.keySet()) { DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); boolean isDataAllowed = mDct.isDataAllowed(apnContext, dataConnectionReasons); if (!isDataAllowed || !dataConnectionReasons.contains( DataConnectionReasons.DataAllowedReasonType.UNMETERED_APN)) { return false; } } return true; // Is data disabled? mRestrictedNetworkOverride = !mDct.isDataEnabled(); } NetworkCapabilities getNetworkCapabilities() { Loading @@ -986,7 +942,8 @@ public class DataConnection extends StateMachine { final String[] types = ApnSetting.getApnTypesStringFromBitmask( mApnSetting.getApnTypeBitmask()).split(","); for (String type : types) { if (!mRestrictedNetworkOverride && mUnmeteredUseOnly if (!mRestrictedNetworkOverride && (mConnectionParams != null && mConnectionParams.mUnmeteredUseOnly) && ApnSettingUtils.isMeteredApnType(type, mPhone)) { log("Dropped the metered " + type + " for the unmetered data call."); continue; Loading Loading @@ -1046,7 +1003,8 @@ public class DataConnection extends StateMachine { // Mark NOT_METERED in the following cases, // 1. All APNs in APN settings are unmetered. // 2. The non-restricted data and is intended for unmetered use only. if ((mUnmeteredUseOnly && !mRestrictedNetworkOverride) if (((mConnectionParams != null && mConnectionParams.mUnmeteredUseOnly) && !mRestrictedNetworkOverride) || !ApnSettingUtils.isMetered(mApnSetting, mPhone)) { result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } else { Loading @@ -1055,7 +1013,6 @@ public class DataConnection extends StateMachine { result.maybeMarkCapabilitiesRestricted(); } if (mRestrictedNetworkOverride) { result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); // don't use dun on restriction-overriden networks. Loading Loading @@ -1313,11 +1270,17 @@ public class DataConnection extends StateMachine { break; case EVENT_DISCONNECT: if (DBG) { log("DcDefaultState deferring msg.what=EVENT_DISCONNECT RefCount=" + mApnContexts.size()); } deferMessage(msg); break; case EVENT_DISCONNECT_ALL: case EVENT_REEVALUATE_RESTRICTED_STATE: if (DBG) { log("DcDefaultState deferring msg.what=" + getWhatToString(msg.what) + " RefCount=" + mApnContexts.size()); log("DcDefaultState deferring msg.what=EVENT_DISCONNECT_ALL RefCount=" + mApnContexts.size()); } deferMessage(msg); break; Loading Loading @@ -1494,10 +1457,8 @@ public class DataConnection extends StateMachine { switch (msg.what) { case EVENT_RESET: case EVENT_REEVALUATE_RESTRICTED_STATE: if (DBG) { log("DcInactiveState: msg.what=" + getWhatToString(msg.what) + ", ignore we're already done"); log("DcInactiveState: msg.what=EVENT_RESET, ignore we're already reset"); } retVal = HANDLED; break; Loading Loading @@ -1698,13 +1659,8 @@ public class DataConnection extends StateMachine { } misc.subscriberId = mPhone.getSubscriberId(); mRestrictedNetworkOverride = shouldRestrictNetwork(); mUnmeteredUseOnly = isUnmeteredUseOnly(); if (DBG) { log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly); } setNetworkRestriction(); if (DBG) log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride); mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(), "DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties, 50, misc); Loading Loading @@ -1968,37 +1924,6 @@ public class DataConnection extends StateMachine { retVal = HANDLED; break; } case EVENT_REEVALUATE_RESTRICTED_STATE: { // If the network was restricted, and now it does not need to be restricted // anymore, we should add the NET_CAPABILITY_NOT_RESTRICTED capability. if (mRestrictedNetworkOverride && !shouldRestrictNetwork()) { if (DBG) { log("Data connection becomes not-restricted. dc=" + this); } // Note we only do this when network becomes non-restricted. When a // non-restricted becomes restricted (e.g. users disable data, or turn off // data roaming), DCT will explicitly tear down the networks (because // connectivity service does not support force-close TCP connections today). // Also note that NET_CAPABILITY_NOT_RESTRICTED is an immutable capability // (see {@link NetworkCapabilities}) once we add it to the network, we can't // remove it through the entire life cycle of the connection. mRestrictedNetworkOverride = false; mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities()); } // If the data does need to be unmetered use only (e.g. users turn on data, or // device is not roaming anymore assuming data roaming is off), then we can // dynamically add those metered APN type capabilities back. (But not the // other way around because most of the APN-type capabilities are immutable // capabilities.) if (mUnmeteredUseOnly && !isUnmeteredUseOnly()) { mUnmeteredUseOnly = false; mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities()); } retVal = HANDLED; break; } default: if (VDBG) { log("DcActiveState not handled msg.what=" + getWhatToString(msg.what)); Loading Loading @@ -2334,6 +2259,7 @@ public class DataConnection extends StateMachine { * @param apnContext is the Access Point Name to bring up a connection to * @param profileId for the connection * @param rilRadioTechnology Radio technology for the data connection * @param unmeteredUseOnly Indicates the data connection can only used for unmetered purposes * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. * With AsyncResult.userObj set to the original msg.obj, * AsyncResult.result = FailCause and AsyncResult.exception = Exception(). Loading @@ -2341,13 +2267,15 @@ public class DataConnection extends StateMachine { * ignored if obsolete. */ public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) { boolean unmeteredUseOnly, Message onCompletedMsg, int connectionGeneration) { if (DBG) { log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg); log("bringUp: apnContext=" + apnContext + "unmeteredUseOnly=" + unmeteredUseOnly + " onCompletedMsg=" + onCompletedMsg); } sendMessage(DataConnection.EVENT_CONNECT, new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg, connectionGeneration)); new ConnectionParams(apnContext, profileId, rilRadioTechnology, unmeteredUseOnly, onCompletedMsg, connectionGeneration)); } /** Loading Loading @@ -2396,15 +2324,6 @@ public class DataConnection extends StateMachine { if (DBG) log("reset"); } /** * Re-evaluate the restricted state. If the restricted data connection does not need to be * restricted anymore, we need to dynamically change the network's capability. */ void reevaluateRestrictedState() { sendMessage(EVENT_REEVALUATE_RESTRICTED_STATE); if (DBG) log("reevaluate restricted state"); } /** * @return The parameters used for initiating a data connection. */ Loading Loading @@ -2638,8 +2557,6 @@ public class DataConnection extends StateMachine { pw.println("mLastFailCause=" + mLastFailCause); pw.println("mUserData=" + mUserData); pw.println("mSubscriptionOverride=" + Integer.toHexString(mSubscriptionOverride)); pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); pw.println("mInstanceNumber=" + mInstanceNumber); pw.println("mAc=" + mAc); pw.println("Network capabilities changed history:"); Loading src/java/com/android/internal/telephony/dataconnection/DcTracker.java +46 −22 Original line number Diff line number Diff line Loading @@ -818,16 +818,47 @@ public class DcTracker extends Handler { * * For example, handle reverting restricted networks back to unrestricted. If we're changing * user data to enabled and this makes data truly enabled (not disabled by other factors) we * need to reevaluate and possibly add NET_CAPABILITY_NOT_RESTRICTED capability to the data * connection. This allows non-privilege apps to use the network. * need to tear down any metered apn type that was enabled anyway by a privileged request. * This allows us to reconnect to it in an unrestricted way. * * Or when we brought up a unmetered data connection while data is off, we only limit this * data connection for unmetered use only. When data is turned back on, we need to tear that * down so a full capable data connection can be re-established. */ private void reevaluateDataConnections() { for (DataConnection dataConnection : mDataConnections.values()) { dataConnection.reevaluateRestrictedState(); if (mDataEnabledSettings.isDataEnabled()) { for (ApnContext apnContext : mApnContexts.values()) { if (apnContext.isConnectedOrConnecting()) { final DataConnection dataConnection = apnContext.getDataConnection(); if (dataConnection != null) { final NetworkCapabilities netCaps = dataConnection.getNetworkCapabilities(); if (netCaps != null && !netCaps.hasCapability(NetworkCapabilities .NET_CAPABILITY_NOT_RESTRICTED) && !netCaps.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) { if (DBG) { log("Tearing down restricted metered net:" + apnContext); } // Tearing down the restricted metered data call when // conditions change. This will allow reestablishing a new unrestricted // data connection. apnContext.setReason(Phone.REASON_DATA_ENABLED); cleanUpConnection(true, apnContext); } else if (ApnSettingUtils.isMetered(apnContext.getApnSetting(), mPhone) && (netCaps != null && netCaps.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED))) { if (DBG) { log("Tearing down unmetered net:" + apnContext); } // The APN settings is metered, but the data was still marked as // unmetered data, must be the unmetered data connection brought up when // data is off. We need to tear that down when data is enabled again. // This will allow reestablishing a new full capability data connection. apnContext.setReason(Phone.REASON_DATA_ENABLED); cleanUpConnection(true, apnContext); } } } } } } Loading Loading @@ -1213,8 +1244,7 @@ public class DcTracker extends Handler { * provided. * @return True if data connection is allowed, otherwise false. */ public boolean isDataAllowed(ApnContext apnContext, DataConnectionReasons dataConnectionReasons) { boolean isDataAllowed(ApnContext apnContext, DataConnectionReasons dataConnectionReasons) { // Step 1: Get all environment conditions. // Step 2: Special handling for emergency APN. // Step 3. Build disallowed reasons. Loading Loading @@ -1337,11 +1367,11 @@ public class DcTracker extends Handler { reasons.add(DataAllowedReasonType.UNMETERED_APN); } // If the request is restricted and there are only soft disallowed reasons (e.g. data // disabled, data roaming disabled) existing, we should allow the data. // If the request is restricted and there are only disallowed reasons due to data // disabled, we should allow the data. if (apnContext != null && apnContext.hasRestrictedRequests(true) && !reasons.allowed()) { && !apnContext.hasNoRestrictedRequests(true) && reasons.contains(DataDisallowedReasonType.DATA_DISABLED)) { reasons.add(DataAllowedReasonType.RESTRICTED_REQUEST); } Loading Loading @@ -1461,7 +1491,8 @@ public class DcTracker extends Handler { } } boolean retValue = setupData(apnContext, radioTech); boolean retValue = setupData(apnContext, radioTech, dataConnectionReasons.contains( DataAllowedReasonType.UNMETERED_APN)); notifyOffApnsOfAvailability(apnContext.getReason()); if (DBG) log("trySetupData: X retValue=" + retValue); Loading Loading @@ -1870,9 +1901,11 @@ public class DcTracker extends Handler { * * @param apnContext APN context * @param radioTech RAT of the data connection * @param unmeteredUseOnly True if this data connection should be only used for unmetered * purposes only. * @return True if successful, otherwise false. */ private boolean setupData(ApnContext apnContext, int radioTech) { private boolean setupData(ApnContext apnContext, int radioTech, boolean unmeteredUseOnly) { if (DBG) log("setupData: apnContext=" + apnContext); apnContext.requestLog("setupData"); ApnSetting apnSetting; Loading Loading @@ -1962,7 +1995,7 @@ public class DcTracker extends Handler { Message msg = obtainMessage(); msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE; msg.obj = new Pair<ApnContext, Integer>(apnContext, generation); dataConnection.bringUp(apnContext, profileId, radioTech, msg, generation); dataConnection.bringUp(apnContext, profileId, radioTech, unmeteredUseOnly, msg, generation); if (DBG) log("setupData: initing!"); return true; Loading Loading @@ -2615,8 +2648,6 @@ public class DcTracker extends Handler { private void onDataRoamingOff() { if (DBG) log("onDataRoamingOff"); reevaluateDataConnections(); if (!getDataRoamingEnabled()) { // TODO: Remove this once all old vendor RILs are gone. We don't need to set initial apn // attach and send the data profile again as the modem should have both roaming and Loading Loading @@ -2652,13 +2683,6 @@ public class DcTracker extends Handler { checkDataRoamingStatus(settingChanged); if (getDataRoamingEnabled()) { // If the restricted data was brought up when data roaming is disabled, and now users // enable data roaming, we need to re-evaluate the conditions and possibly change the // network's capability. if (settingChanged) { reevaluateDataConnections(); } if (DBG) log("onDataRoamingOnOrSettingsChanged: setup data on roaming"); setupDataOnConnectableApns(Phone.REASON_ROAMING_ON); Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +5 −4 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
src/java/com/android/internal/telephony/dataconnection/ApnContext.java +5 −9 Original line number Diff line number Diff line Loading @@ -460,11 +460,7 @@ public class ApnContext { } } /** * @param excludeDun True if excluding requests that have DUN capability * @return True if the attached network requests contain restricted capability. */ public boolean hasRestrictedRequests(boolean excludeDun) { public boolean hasNoRestrictedRequests(boolean excludeDun) { synchronized (mRefCountLock) { for (NetworkRequest nr : mNetworkRequests) { if (excludeDun && Loading @@ -472,13 +468,13 @@ public class ApnContext { NetworkCapabilities.NET_CAPABILITY_DUN)) { continue; } if (!nr.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) { return true; if (nr.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) { return false; } } } return false; return true; } private final SparseIntArray mRetriesLeftPerErrorCode = new SparseIntArray(); Loading
src/java/com/android/internal/telephony/dataconnection/DataConnection.java +51 −134 Original line number Diff line number Diff line Loading @@ -123,14 +123,17 @@ public class DataConnection extends StateMachine { ApnContext mApnContext; int mProfileId; int mRilRat; final boolean mUnmeteredUseOnly; Message mOnCompletedMsg; final int mConnectionGeneration; ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) { boolean unmeteredUseOnly, Message onCompletedMsg, int connectionGeneration) { mApnContext = apnContext; mProfileId = profileId; mRilRat = rilRadioTechnology; mUnmeteredUseOnly = unmeteredUseOnly; mOnCompletedMsg = onCompletedMsg; mConnectionGeneration = connectionGeneration; } Loading @@ -140,6 +143,7 @@ public class DataConnection extends StateMachine { return "{mTag=" + mTag + " mApnContext=" + mApnContext + " mProfileId=" + mProfileId + " mRat=" + mRilRat + " mUnmeteredUseOnly=" + mUnmeteredUseOnly + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; } } Loading Loading @@ -218,9 +222,8 @@ public class DataConnection extends StateMachine { static final int EVENT_KEEPALIVE_STOP_REQUEST = BASE + 22; static final int EVENT_LINK_CAPACITY_CHANGED = BASE + 23; static final int EVENT_RESET = BASE + 24; static final int EVENT_REEVALUATE_RESTRICTED_STATE = BASE + 25; private static final int CMD_TO_STRING_COUNT = EVENT_REEVALUATE_RESTRICTED_STATE - BASE + 1; private static final int CMD_TO_STRING_COUNT = EVENT_RESET - BASE + 1; private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; static { Loading Loading @@ -252,8 +255,6 @@ public class DataConnection extends StateMachine { sCmdToString[EVENT_KEEPALIVE_STOP_REQUEST - BASE] = "EVENT_KEEPALIVE_STOP_REQUEST"; sCmdToString[EVENT_LINK_CAPACITY_CHANGED - BASE] = "EVENT_LINK_CAPACITY_CHANGED"; sCmdToString[EVENT_RESET - BASE] = "EVENT_RESET"; sCmdToString[EVENT_REEVALUATE_RESTRICTED_STATE - BASE] = "EVENT_REEVALUATE_RESTRICTED_STATE"; } // Convert cmd to string or null if unknown static String cmdToString(int cmd) { Loading Loading @@ -884,19 +885,14 @@ public class DataConnection extends StateMachine { mLinkProperties.setTcpBufferSizes(sizes); } /** * Indicates if this data connection was established for unmetered use only. Note that this * flag should be populated when data becomes active. And if it is set to true, it can be set to * false later when we are reevaluating the data connection. But if it is set to false, it * can never become true later because setting it to true will cause this data connection * losing some immutable network capabilities, which can cause issues in connectivity service. */ private boolean mUnmeteredUseOnly = false; /** * 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 * experiment 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 Loading @@ -904,78 +900,38 @@ public class DataConnection extends StateMachine { * 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. * * Note that the data connection cannot go from unrestricted to restricted because the * connectivity service does not support dynamically closing TCP connections at this point. */ private boolean mRestrictedNetworkOverride = false; /** * Check if this data connection should be restricted. We should call this when data connection * becomes active, or when we want to re-evaluate the conditions to decide if we need to * unstrict the data connection. * * @return True if this data connection needs to be restricted. */ private boolean shouldRestrictNetwork() { // first, check if there is any network request that containing restricted capability // (i.e. Do not have NET_CAPABILITY_NOT_RESTRICTED in the request) boolean isAnyRestrictedRequest = 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()) { if (apnContext.hasRestrictedRequests(true /* exclude DUN */)) { isAnyRestrictedRequest = true; break; noRestrictedRequests &= apnContext.hasNoRestrictedRequests(true /* exclude DUN */); } if (noRestrictedRequests) { return; } // If all of the network requests are non-restricted, then we don't need to restrict // the network. if (!isAnyRestrictedRequest) { return false; } // If the network is unmetered, then we don't need to restrict the network because users // won't be charged anyway. // Do we need a restricted network to satisfy the request? // Is this network metered? If not, then don't add restricted if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { return false; } // If the data is disabled, then we need to restrict the network so only privileged apps can // use the restricted network while data is disabled. if (!mDct.isDataEnabled()) { return true; return; } // If the device is roaming, and the user does not turn on data roaming, then we need to // restrict the network so only privileged apps can use it. if (!mDct.getDataRoamingEnabled() && mPhone.getServiceState().getDataRoaming()) { return true; } // Otherwise we should not restrict the network so anyone who requests can use it. return false; } /** * @return True if this data connection should only be used for unmetered purposes. */ private boolean isUnmeteredUseOnly() { // The data connection can only be unmetered used only if all requests' reasons are // unmetered. for (ApnContext apnContext : mApnContexts.keySet()) { DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); boolean isDataAllowed = mDct.isDataAllowed(apnContext, dataConnectionReasons); if (!isDataAllowed || !dataConnectionReasons.contains( DataConnectionReasons.DataAllowedReasonType.UNMETERED_APN)) { return false; } } return true; // Is data disabled? mRestrictedNetworkOverride = !mDct.isDataEnabled(); } NetworkCapabilities getNetworkCapabilities() { Loading @@ -986,7 +942,8 @@ public class DataConnection extends StateMachine { final String[] types = ApnSetting.getApnTypesStringFromBitmask( mApnSetting.getApnTypeBitmask()).split(","); for (String type : types) { if (!mRestrictedNetworkOverride && mUnmeteredUseOnly if (!mRestrictedNetworkOverride && (mConnectionParams != null && mConnectionParams.mUnmeteredUseOnly) && ApnSettingUtils.isMeteredApnType(type, mPhone)) { log("Dropped the metered " + type + " for the unmetered data call."); continue; Loading Loading @@ -1046,7 +1003,8 @@ public class DataConnection extends StateMachine { // Mark NOT_METERED in the following cases, // 1. All APNs in APN settings are unmetered. // 2. The non-restricted data and is intended for unmetered use only. if ((mUnmeteredUseOnly && !mRestrictedNetworkOverride) if (((mConnectionParams != null && mConnectionParams.mUnmeteredUseOnly) && !mRestrictedNetworkOverride) || !ApnSettingUtils.isMetered(mApnSetting, mPhone)) { result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } else { Loading @@ -1055,7 +1013,6 @@ public class DataConnection extends StateMachine { result.maybeMarkCapabilitiesRestricted(); } if (mRestrictedNetworkOverride) { result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); // don't use dun on restriction-overriden networks. Loading Loading @@ -1313,11 +1270,17 @@ public class DataConnection extends StateMachine { break; case EVENT_DISCONNECT: if (DBG) { log("DcDefaultState deferring msg.what=EVENT_DISCONNECT RefCount=" + mApnContexts.size()); } deferMessage(msg); break; case EVENT_DISCONNECT_ALL: case EVENT_REEVALUATE_RESTRICTED_STATE: if (DBG) { log("DcDefaultState deferring msg.what=" + getWhatToString(msg.what) + " RefCount=" + mApnContexts.size()); log("DcDefaultState deferring msg.what=EVENT_DISCONNECT_ALL RefCount=" + mApnContexts.size()); } deferMessage(msg); break; Loading Loading @@ -1494,10 +1457,8 @@ public class DataConnection extends StateMachine { switch (msg.what) { case EVENT_RESET: case EVENT_REEVALUATE_RESTRICTED_STATE: if (DBG) { log("DcInactiveState: msg.what=" + getWhatToString(msg.what) + ", ignore we're already done"); log("DcInactiveState: msg.what=EVENT_RESET, ignore we're already reset"); } retVal = HANDLED; break; Loading Loading @@ -1698,13 +1659,8 @@ public class DataConnection extends StateMachine { } misc.subscriberId = mPhone.getSubscriberId(); mRestrictedNetworkOverride = shouldRestrictNetwork(); mUnmeteredUseOnly = isUnmeteredUseOnly(); if (DBG) { log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly); } setNetworkRestriction(); if (DBG) log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride); mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(), "DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties, 50, misc); Loading Loading @@ -1968,37 +1924,6 @@ public class DataConnection extends StateMachine { retVal = HANDLED; break; } case EVENT_REEVALUATE_RESTRICTED_STATE: { // If the network was restricted, and now it does not need to be restricted // anymore, we should add the NET_CAPABILITY_NOT_RESTRICTED capability. if (mRestrictedNetworkOverride && !shouldRestrictNetwork()) { if (DBG) { log("Data connection becomes not-restricted. dc=" + this); } // Note we only do this when network becomes non-restricted. When a // non-restricted becomes restricted (e.g. users disable data, or turn off // data roaming), DCT will explicitly tear down the networks (because // connectivity service does not support force-close TCP connections today). // Also note that NET_CAPABILITY_NOT_RESTRICTED is an immutable capability // (see {@link NetworkCapabilities}) once we add it to the network, we can't // remove it through the entire life cycle of the connection. mRestrictedNetworkOverride = false; mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities()); } // If the data does need to be unmetered use only (e.g. users turn on data, or // device is not roaming anymore assuming data roaming is off), then we can // dynamically add those metered APN type capabilities back. (But not the // other way around because most of the APN-type capabilities are immutable // capabilities.) if (mUnmeteredUseOnly && !isUnmeteredUseOnly()) { mUnmeteredUseOnly = false; mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities()); } retVal = HANDLED; break; } default: if (VDBG) { log("DcActiveState not handled msg.what=" + getWhatToString(msg.what)); Loading Loading @@ -2334,6 +2259,7 @@ public class DataConnection extends StateMachine { * @param apnContext is the Access Point Name to bring up a connection to * @param profileId for the connection * @param rilRadioTechnology Radio technology for the data connection * @param unmeteredUseOnly Indicates the data connection can only used for unmetered purposes * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. * With AsyncResult.userObj set to the original msg.obj, * AsyncResult.result = FailCause and AsyncResult.exception = Exception(). Loading @@ -2341,13 +2267,15 @@ public class DataConnection extends StateMachine { * ignored if obsolete. */ public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) { boolean unmeteredUseOnly, Message onCompletedMsg, int connectionGeneration) { if (DBG) { log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg); log("bringUp: apnContext=" + apnContext + "unmeteredUseOnly=" + unmeteredUseOnly + " onCompletedMsg=" + onCompletedMsg); } sendMessage(DataConnection.EVENT_CONNECT, new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg, connectionGeneration)); new ConnectionParams(apnContext, profileId, rilRadioTechnology, unmeteredUseOnly, onCompletedMsg, connectionGeneration)); } /** Loading Loading @@ -2396,15 +2324,6 @@ public class DataConnection extends StateMachine { if (DBG) log("reset"); } /** * Re-evaluate the restricted state. If the restricted data connection does not need to be * restricted anymore, we need to dynamically change the network's capability. */ void reevaluateRestrictedState() { sendMessage(EVENT_REEVALUATE_RESTRICTED_STATE); if (DBG) log("reevaluate restricted state"); } /** * @return The parameters used for initiating a data connection. */ Loading Loading @@ -2638,8 +2557,6 @@ public class DataConnection extends StateMachine { pw.println("mLastFailCause=" + mLastFailCause); pw.println("mUserData=" + mUserData); pw.println("mSubscriptionOverride=" + Integer.toHexString(mSubscriptionOverride)); pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); pw.println("mInstanceNumber=" + mInstanceNumber); pw.println("mAc=" + mAc); pw.println("Network capabilities changed history:"); Loading
src/java/com/android/internal/telephony/dataconnection/DcTracker.java +46 −22 Original line number Diff line number Diff line Loading @@ -818,16 +818,47 @@ public class DcTracker extends Handler { * * For example, handle reverting restricted networks back to unrestricted. If we're changing * user data to enabled and this makes data truly enabled (not disabled by other factors) we * need to reevaluate and possibly add NET_CAPABILITY_NOT_RESTRICTED capability to the data * connection. This allows non-privilege apps to use the network. * need to tear down any metered apn type that was enabled anyway by a privileged request. * This allows us to reconnect to it in an unrestricted way. * * Or when we brought up a unmetered data connection while data is off, we only limit this * data connection for unmetered use only. When data is turned back on, we need to tear that * down so a full capable data connection can be re-established. */ private void reevaluateDataConnections() { for (DataConnection dataConnection : mDataConnections.values()) { dataConnection.reevaluateRestrictedState(); if (mDataEnabledSettings.isDataEnabled()) { for (ApnContext apnContext : mApnContexts.values()) { if (apnContext.isConnectedOrConnecting()) { final DataConnection dataConnection = apnContext.getDataConnection(); if (dataConnection != null) { final NetworkCapabilities netCaps = dataConnection.getNetworkCapabilities(); if (netCaps != null && !netCaps.hasCapability(NetworkCapabilities .NET_CAPABILITY_NOT_RESTRICTED) && !netCaps.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) { if (DBG) { log("Tearing down restricted metered net:" + apnContext); } // Tearing down the restricted metered data call when // conditions change. This will allow reestablishing a new unrestricted // data connection. apnContext.setReason(Phone.REASON_DATA_ENABLED); cleanUpConnection(true, apnContext); } else if (ApnSettingUtils.isMetered(apnContext.getApnSetting(), mPhone) && (netCaps != null && netCaps.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED))) { if (DBG) { log("Tearing down unmetered net:" + apnContext); } // The APN settings is metered, but the data was still marked as // unmetered data, must be the unmetered data connection brought up when // data is off. We need to tear that down when data is enabled again. // This will allow reestablishing a new full capability data connection. apnContext.setReason(Phone.REASON_DATA_ENABLED); cleanUpConnection(true, apnContext); } } } } } } Loading Loading @@ -1213,8 +1244,7 @@ public class DcTracker extends Handler { * provided. * @return True if data connection is allowed, otherwise false. */ public boolean isDataAllowed(ApnContext apnContext, DataConnectionReasons dataConnectionReasons) { boolean isDataAllowed(ApnContext apnContext, DataConnectionReasons dataConnectionReasons) { // Step 1: Get all environment conditions. // Step 2: Special handling for emergency APN. // Step 3. Build disallowed reasons. Loading Loading @@ -1337,11 +1367,11 @@ public class DcTracker extends Handler { reasons.add(DataAllowedReasonType.UNMETERED_APN); } // If the request is restricted and there are only soft disallowed reasons (e.g. data // disabled, data roaming disabled) existing, we should allow the data. // If the request is restricted and there are only disallowed reasons due to data // disabled, we should allow the data. if (apnContext != null && apnContext.hasRestrictedRequests(true) && !reasons.allowed()) { && !apnContext.hasNoRestrictedRequests(true) && reasons.contains(DataDisallowedReasonType.DATA_DISABLED)) { reasons.add(DataAllowedReasonType.RESTRICTED_REQUEST); } Loading Loading @@ -1461,7 +1491,8 @@ public class DcTracker extends Handler { } } boolean retValue = setupData(apnContext, radioTech); boolean retValue = setupData(apnContext, radioTech, dataConnectionReasons.contains( DataAllowedReasonType.UNMETERED_APN)); notifyOffApnsOfAvailability(apnContext.getReason()); if (DBG) log("trySetupData: X retValue=" + retValue); Loading Loading @@ -1870,9 +1901,11 @@ public class DcTracker extends Handler { * * @param apnContext APN context * @param radioTech RAT of the data connection * @param unmeteredUseOnly True if this data connection should be only used for unmetered * purposes only. * @return True if successful, otherwise false. */ private boolean setupData(ApnContext apnContext, int radioTech) { private boolean setupData(ApnContext apnContext, int radioTech, boolean unmeteredUseOnly) { if (DBG) log("setupData: apnContext=" + apnContext); apnContext.requestLog("setupData"); ApnSetting apnSetting; Loading Loading @@ -1962,7 +1995,7 @@ public class DcTracker extends Handler { Message msg = obtainMessage(); msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE; msg.obj = new Pair<ApnContext, Integer>(apnContext, generation); dataConnection.bringUp(apnContext, profileId, radioTech, msg, generation); dataConnection.bringUp(apnContext, profileId, radioTech, unmeteredUseOnly, msg, generation); if (DBG) log("setupData: initing!"); return true; Loading Loading @@ -2615,8 +2648,6 @@ public class DcTracker extends Handler { private void onDataRoamingOff() { if (DBG) log("onDataRoamingOff"); reevaluateDataConnections(); if (!getDataRoamingEnabled()) { // TODO: Remove this once all old vendor RILs are gone. We don't need to set initial apn // attach and send the data profile again as the modem should have both roaming and Loading Loading @@ -2652,13 +2683,6 @@ public class DcTracker extends Handler { checkDataRoamingStatus(settingChanged); if (getDataRoamingEnabled()) { // If the restricted data was brought up when data roaming is disabled, and now users // enable data roaming, we need to re-evaluate the conditions and possibly change the // network's capability. if (settingChanged) { reevaluateDataConnections(); } if (DBG) log("onDataRoamingOnOrSettingsChanged: setup data on roaming"); setupDataOnConnectableApns(Phone.REASON_ROAMING_ON); Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +5 −4 File changed.Preview size limit exceeded, changes collapsed. Show changes