Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 692640f4 authored by Robert Greenwalt's avatar Robert Greenwalt
Browse files

Support requesting restricted default

Carrier app will need to use the default cell network when the carrier
has restricted that (reprovisioning when out of bytes).  Add support
for bringing up internet with restricted capability, sidesteping
user/carrier enablement.

bug:28567303
Change-Id: I83fc29fa6707a7014ae1bc2e914cfa120f07c983
parent aa13a63e
Loading
Loading
Loading
Loading
+50 −22
Original line number Diff line number Diff line
@@ -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;

@@ -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) {
@@ -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() {
@@ -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);
+55 −0
Original line number Diff line number Diff line
@@ -825,6 +825,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);
@@ -894,6 +944,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) {
@@ -1516,6 +1570,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);
+10 −6
Original line number Diff line number Diff line
@@ -952,14 +952,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) {
@@ -1337,7 +1337,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)))
@@ -1574,10 +1574,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();

+10 −6
Original line number Diff line number Diff line
@@ -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;

@@ -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));
    }