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

Commit 6f9ab029 authored by Kweku Adams's avatar Kweku Adams
Browse files

Cache network capabilities.

Cache network capabilities to reduce the number of calls
ConnectivityController makes to ConnectivityManager.

Bug: 164460449
Test: atest com.android.server.job.controllers.ConnectivityControllerTest
Test: atest CtsJobSchedulerTestCases
Change-Id: I501e5153d7bffd2494aec484c74b9e1b6252aeeb
parent e14fbaad
Loading
Loading
Loading
Loading
+46 −25
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;


import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;


import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.app.job.JobInfo;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager.NetworkCallback;
@@ -86,9 +87,12 @@ public final class ConnectivityController extends RestrictingController implemen
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private final SparseArray<ArraySet<JobStatus>> mRequestedWhitelistJobs = new SparseArray<>();
    private final SparseArray<ArraySet<JobStatus>> mRequestedWhitelistJobs = new SparseArray<>();


    /** List of currently available networks. */
    /**
     * Set of currently available networks mapped to their latest network capabilities. Cache the
     * latest capabilities to avoid unnecessary calls into ConnectivityManager.
     */
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private final ArraySet<Network> mAvailableNetworks = new ArraySet<>();
    private final ArrayMap<Network, NetworkCapabilities> mAvailableNetworks = new ArrayMap<>();


    private static final int MSG_DATA_SAVER_TOGGLED = 0;
    private static final int MSG_DATA_SAVER_TOGGLED = 0;
    private static final int MSG_UID_RULES_CHANGES = 1;
    private static final int MSG_UID_RULES_CHANGES = 1;
@@ -165,9 +169,8 @@ public final class ConnectivityController extends RestrictingController implemen
    public boolean isNetworkAvailable(JobStatus job) {
    public boolean isNetworkAvailable(JobStatus job) {
        synchronized (mLock) {
        synchronized (mLock) {
            for (int i = 0; i < mAvailableNetworks.size(); ++i) {
            for (int i = 0; i < mAvailableNetworks.size(); ++i) {
                final Network network = mAvailableNetworks.valueAt(i);
                final Network network = mAvailableNetworks.keyAt(i);
                final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(
                final NetworkCapabilities capabilities = mAvailableNetworks.valueAt(i);
                        network);
                final boolean satisfied = isSatisfied(job, network, capabilities, mConstants);
                final boolean satisfied = isSatisfied(job, network, capabilities, mConstants);
                if (DEBUG) {
                if (DEBUG) {
                    Slog.v(TAG, "isNetworkAvailable(" + job + ") with network " + network
                    Slog.v(TAG, "isNetworkAvailable(" + job + ") with network " + network
@@ -427,9 +430,33 @@ public final class ConnectivityController extends RestrictingController implemen
        return false;
        return false;
    }
    }


    @Nullable
    private NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
        if (network == null) {
            return null;
        }
        synchronized (mLock) {
            // There is technically a race here if the Network object is reused. This can happen
            // only if that Network disconnects and the auto-incrementing network ID in
            // ConnectivityService wraps. This should no longer be a concern if/when we only make
            // use of asynchronous calls.
            if (mAvailableNetworks.get(network) != null) {
                return mAvailableNetworks.get(network);
            }

            // This should almost never happen because any time a new network connects, the
            // NetworkCallback would populate mAvailableNetworks. However, it's currently necessary
            // because we also call synchronous methods such as getActiveNetworkForUid.
            // TODO(134978280): remove after switching to callback-based APIs
            final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
            mAvailableNetworks.put(network, capabilities);
            return capabilities;
        }
    }

    private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
    private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
        final Network network = mConnManager.getActiveNetworkForUid(jobStatus.getSourceUid());
        final Network network = mConnManager.getActiveNetworkForUid(jobStatus.getSourceUid());
        final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
        final NetworkCapabilities capabilities = getNetworkCapabilities(network);
        return updateConstraintsSatisfied(jobStatus, network, capabilities);
        return updateConstraintsSatisfied(jobStatus, network, capabilities);
    }
    }


@@ -470,19 +497,13 @@ public final class ConnectivityController extends RestrictingController implemen
     */
     */
    private void updateTrackedJobs(int filterUid, Network filterNetwork) {
    private void updateTrackedJobs(int filterUid, Network filterNetwork) {
        synchronized (mLock) {
        synchronized (mLock) {
            // Since this is a really hot codepath, temporarily cache any
            // answers that we get from ConnectivityManager.
            final ArrayMap<Network, NetworkCapabilities> networkToCapabilities = new ArrayMap<>();

            boolean changed = false;
            boolean changed = false;
            if (filterUid == -1) {
            if (filterUid == -1) {
                for (int i = mTrackedJobs.size() - 1; i >= 0; i--) {
                for (int i = mTrackedJobs.size() - 1; i >= 0; i--) {
                    changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i),
                    changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i), filterNetwork);
                            filterNetwork, networkToCapabilities);
                }
                }
            } else {
            } else {
                changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid),
                changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid), filterNetwork);
                        filterNetwork, networkToCapabilities);
            }
            }
            if (changed) {
            if (changed) {
                mStateChangedListener.onControllerStateChanged();
                mStateChangedListener.onControllerStateChanged();
@@ -490,18 +511,13 @@ public final class ConnectivityController extends RestrictingController implemen
        }
        }
    }
    }


    private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork,
    private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork) {
            ArrayMap<Network, NetworkCapabilities> networkToCapabilities) {
        if (jobs == null || jobs.size() == 0) {
        if (jobs == null || jobs.size() == 0) {
            return false;
            return false;
        }
        }


        final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid());
        final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid());
        NetworkCapabilities capabilities = networkToCapabilities.get(network);
        final NetworkCapabilities capabilities = getNetworkCapabilities(network);
        if (capabilities == null) {
            capabilities = mConnManager.getNetworkCapabilities(network);
            networkToCapabilities.put(network, capabilities);
        }
        final boolean networkMatch = (filterNetwork == null
        final boolean networkMatch = (filterNetwork == null
                || Objects.equals(filterNetwork, network));
                || Objects.equals(filterNetwork, network));


@@ -544,9 +560,9 @@ public final class ConnectivityController extends RestrictingController implemen
        @Override
        @Override
        public void onAvailable(Network network) {
        public void onAvailable(Network network) {
            if (DEBUG) Slog.v(TAG, "onAvailable: " + network);
            if (DEBUG) Slog.v(TAG, "onAvailable: " + network);
            synchronized (mLock) {
            // Documentation says not to call getNetworkCapabilities here but wait for
                mAvailableNetworks.add(network);
            // onCapabilitiesChanged instead.  onCapabilitiesChanged should be called immediately
            }
            // after this, so no need to update mAvailableNetworks here.
        }
        }


        @Override
        @Override
@@ -554,6 +570,9 @@ public final class ConnectivityController extends RestrictingController implemen
            if (DEBUG) {
            if (DEBUG) {
                Slog.v(TAG, "onCapabilitiesChanged: " + network);
                Slog.v(TAG, "onCapabilitiesChanged: " + network);
            }
            }
            synchronized (mLock) {
                mAvailableNetworks.put(network, capabilities);
            }
            updateTrackedJobs(-1, network);
            updateTrackedJobs(-1, network);
        }
        }


@@ -630,6 +649,8 @@ public final class ConnectivityController extends RestrictingController implemen
            pw.println("Available networks:");
            pw.println("Available networks:");
            pw.increaseIndent();
            pw.increaseIndent();
            for (int i = 0; i < mAvailableNetworks.size(); i++) {
            for (int i = 0; i < mAvailableNetworks.size(); i++) {
                pw.print(mAvailableNetworks.keyAt(i));
                pw.print(": ");
                pw.println(mAvailableNetworks.valueAt(i));
                pw.println(mAvailableNetworks.valueAt(i));
            }
            }
            pw.decreaseIndent();
            pw.decreaseIndent();
@@ -667,7 +688,7 @@ public final class ConnectivityController extends RestrictingController implemen
                    mRequestedWhitelistJobs.keyAt(i));
                    mRequestedWhitelistJobs.keyAt(i));
        }
        }
        for (int i = 0; i < mAvailableNetworks.size(); i++) {
        for (int i = 0; i < mAvailableNetworks.size(); i++) {
            Network network = mAvailableNetworks.valueAt(i);
            Network network = mAvailableNetworks.keyAt(i);
            if (network != null) {
            if (network != null) {
                network.dumpDebug(proto,
                network.dumpDebug(proto,
                        StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);
                        StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);