Cache network capabilities.

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

Bug: 164460449
Bug: 166702583
Test: atest com.android.server.job.controllers.ConnectivityControllerTest
Test: atest CtsJobSchedulerTestCases
Change-Id: I501e5153d7bffd2494aec484c74b9e1b6252aeeb
(cherry picked from commit 6f9ab02900)
This commit is contained in:
Kweku Adams
2020-08-20 10:06:32 -07:00
parent 85cb19429e
commit 03c773ee52

View File

@@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
@@ -86,9 +87,12 @@ public final class ConnectivityController extends RestrictingController implemen
@GuardedBy("mLock")
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")
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_UID_RULES_CHANGES = 1;
@@ -165,9 +169,8 @@ public final class ConnectivityController extends RestrictingController implemen
public boolean isNetworkAvailable(JobStatus job) {
synchronized (mLock) {
for (int i = 0; i < mAvailableNetworks.size(); ++i) {
final Network network = mAvailableNetworks.valueAt(i);
final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(
network);
final Network network = mAvailableNetworks.keyAt(i);
final NetworkCapabilities capabilities = mAvailableNetworks.valueAt(i);
final boolean satisfied = isSatisfied(job, network, capabilities, mConstants);
if (DEBUG) {
Slog.v(TAG, "isNetworkAvailable(" + job + ") with network " + network
@@ -427,9 +430,33 @@ public final class ConnectivityController extends RestrictingController implemen
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) {
final Network network = mConnManager.getActiveNetworkForUid(jobStatus.getSourceUid());
final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
final NetworkCapabilities capabilities = getNetworkCapabilities(network);
return updateConstraintsSatisfied(jobStatus, network, capabilities);
}
@@ -470,19 +497,13 @@ public final class ConnectivityController extends RestrictingController implemen
*/
private void updateTrackedJobs(int filterUid, Network filterNetwork) {
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;
if (filterUid == -1) {
for (int i = mTrackedJobs.size() - 1; i >= 0; i--) {
changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i),
filterNetwork, networkToCapabilities);
changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i), filterNetwork);
}
} else {
changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid),
filterNetwork, networkToCapabilities);
changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid), filterNetwork);
}
if (changed) {
mStateChangedListener.onControllerStateChanged();
@@ -490,18 +511,13 @@ public final class ConnectivityController extends RestrictingController implemen
}
}
private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork,
ArrayMap<Network, NetworkCapabilities> networkToCapabilities) {
private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork) {
if (jobs == null || jobs.size() == 0) {
return false;
}
final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid());
NetworkCapabilities capabilities = networkToCapabilities.get(network);
if (capabilities == null) {
capabilities = mConnManager.getNetworkCapabilities(network);
networkToCapabilities.put(network, capabilities);
}
final NetworkCapabilities capabilities = getNetworkCapabilities(network);
final boolean networkMatch = (filterNetwork == null
|| Objects.equals(filterNetwork, network));
@@ -544,9 +560,9 @@ public final class ConnectivityController extends RestrictingController implemen
@Override
public void onAvailable(Network network) {
if (DEBUG) Slog.v(TAG, "onAvailable: " + network);
synchronized (mLock) {
mAvailableNetworks.add(network);
}
// Documentation says not to call getNetworkCapabilities here but wait for
// onCapabilitiesChanged instead. onCapabilitiesChanged should be called immediately
// after this, so no need to update mAvailableNetworks here.
}
@Override
@@ -554,6 +570,9 @@ public final class ConnectivityController extends RestrictingController implemen
if (DEBUG) {
Slog.v(TAG, "onCapabilitiesChanged: " + network);
}
synchronized (mLock) {
mAvailableNetworks.put(network, capabilities);
}
updateTrackedJobs(-1, network);
}
@@ -630,6 +649,8 @@ public final class ConnectivityController extends RestrictingController implemen
pw.println("Available networks:");
pw.increaseIndent();
for (int i = 0; i < mAvailableNetworks.size(); i++) {
pw.print(mAvailableNetworks.keyAt(i));
pw.print(": ");
pw.println(mAvailableNetworks.valueAt(i));
}
pw.decreaseIndent();
@@ -667,7 +688,7 @@ public final class ConnectivityController extends RestrictingController implemen
mRequestedWhitelistJobs.keyAt(i));
}
for (int i = 0; i < mAvailableNetworks.size(); i++) {
Network network = mAvailableNetworks.valueAt(i);
Network network = mAvailableNetworks.keyAt(i);
if (network != null) {
network.dumpDebug(proto,
StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);