Skip to content
Snippets Groups Projects
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
No related branches found
No related tags found
No related merge requests found
...@@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment