Don't run jobs when connectivity is not validated
Previously, the job scheduler would run jobs with connectivity
constraints as soon as "raw" connectivity was achieved. This could
cause problems, though, because the device might be behind a
captive portal or similar, so apps expecting to contact the internet
would still see connect() failures or other unexpected results.
We now run such jobs only when connectivity has been validated,
so jobs have a stronger expectation that their needed internet
access will be possible.
Bug 28346529
Bug 36137931
Test: manual; use tethered phone hotspot, both with and without SIM,
and verify that the 'validation' trigger is correct.
Change-Id: I79194467610ef9611d38f871d01f92044d0ee9de
This commit is contained in:
@@ -17,18 +17,18 @@
|
||||
package com.android.server.job.controllers;
|
||||
|
||||
import android.app.job.JobInfo;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.ConnectivityManager.NetworkCallback;
|
||||
import android.net.INetworkPolicyListener;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.job.JobSchedulerService;
|
||||
import com.android.server.job.StateChangedListener;
|
||||
@@ -46,9 +46,12 @@ import java.util.ArrayList;
|
||||
public class ConnectivityController extends StateController implements
|
||||
ConnectivityManager.OnNetworkActiveListener {
|
||||
private static final String TAG = "JobScheduler.Conn";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final ConnectivityManager mConnManager;
|
||||
private final NetworkPolicyManager mNetPolicyManager;
|
||||
private boolean mConnected;
|
||||
private boolean mValidated;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final ArrayList<JobStatus> mTrackedJobs = new ArrayList<JobStatus>();
|
||||
@@ -73,10 +76,9 @@ public class ConnectivityController extends StateController implements
|
||||
mConnManager = mContext.getSystemService(ConnectivityManager.class);
|
||||
mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
|
||||
|
||||
final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
mContext.registerReceiverAsUser(
|
||||
mConnectivityReceiver, UserHandle.SYSTEM, intentFilter, null, null);
|
||||
mConnected = mValidated = false;
|
||||
|
||||
mConnManager.registerDefaultNetworkCallback(mNetworkCallback);
|
||||
mNetPolicyManager.registerListener(mNetPolicyListener);
|
||||
}
|
||||
|
||||
@@ -84,7 +86,7 @@ public class ConnectivityController extends StateController implements
|
||||
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
|
||||
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()
|
||||
|| jobStatus.hasNotRoamingConstraint()) {
|
||||
updateConstraintsSatisfied(jobStatus);
|
||||
updateConstraintsSatisfied(jobStatus, null);
|
||||
mTrackedJobs.add(jobStatus);
|
||||
}
|
||||
}
|
||||
@@ -98,18 +100,43 @@ public class ConnectivityController extends StateController implements
|
||||
}
|
||||
}
|
||||
|
||||
private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
|
||||
private boolean updateConstraintsSatisfied(JobStatus jobStatus,
|
||||
NetworkCapabilities capabilities) {
|
||||
final int jobUid = jobStatus.getSourceUid();
|
||||
final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
|
||||
final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobStatus.getSourceUid(),
|
||||
ignoreBlocked);
|
||||
final boolean connected = (info != null) && info.isConnected();
|
||||
final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobUid, ignoreBlocked);
|
||||
if (capabilities == null) {
|
||||
final Network network = mConnManager.getActiveNetworkForUid(jobUid, ignoreBlocked);
|
||||
capabilities = mConnManager.getNetworkCapabilities(network);
|
||||
}
|
||||
|
||||
final boolean validated = capabilities != null
|
||||
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
|
||||
final boolean connected = info != null && info.isConnected();
|
||||
final boolean connectionUsable = connected && validated;
|
||||
final boolean unmetered = connected && !info.isMetered();
|
||||
final boolean notRoaming = connected && !info.isRoaming();
|
||||
|
||||
boolean changed = false;
|
||||
changed |= jobStatus.setConnectivityConstraintSatisfied(connected);
|
||||
changed |= jobStatus.setConnectivityConstraintSatisfied(connectionUsable);
|
||||
changed |= jobStatus.setUnmeteredConstraintSatisfied(unmetered);
|
||||
changed |= jobStatus.setNotRoamingConstraintSatisfied(notRoaming);
|
||||
|
||||
// Track system-uid connected/validated as a general reportable proxy for the
|
||||
// overall state of connectivity constraint satisfiability.
|
||||
if (jobUid == Process.SYSTEM_UID) {
|
||||
mConnected = connected;
|
||||
mValidated = validated;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "Connectivity " + (changed ? "CHANGED" : "unchanged")
|
||||
+ " for " + jobStatus + ": usable=" + connectionUsable
|
||||
+ " connected=" + connected
|
||||
+ " validated=" + validated
|
||||
+ " unmetered=" + unmetered
|
||||
+ " notRoaming=" + notRoaming);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -119,13 +146,13 @@ public class ConnectivityController extends StateController implements
|
||||
* @param uid only update jobs belonging to this UID, or {@code -1} to
|
||||
* update all tracked jobs.
|
||||
*/
|
||||
private void updateTrackedJobs(int uid) {
|
||||
private void updateTrackedJobs(int uid, NetworkCapabilities capabilities) {
|
||||
synchronized (mLock) {
|
||||
boolean changed = false;
|
||||
for (int i = 0; i < mTrackedJobs.size(); i++) {
|
||||
final JobStatus js = mTrackedJobs.get(i);
|
||||
if (uid == -1 || uid == js.getSourceUid()) {
|
||||
changed |= updateConstraintsSatisfied(js);
|
||||
changed |= updateConstraintsSatisfied(js, capabilities);
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
@@ -152,38 +179,61 @@ public class ConnectivityController extends StateController implements
|
||||
}
|
||||
}
|
||||
|
||||
private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
|
||||
private final NetworkCallback mNetworkCallback = new NetworkCallback() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
updateTrackedJobs(-1);
|
||||
public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "onCapabilitiesChanged() : " + networkCapabilities);
|
||||
}
|
||||
updateTrackedJobs(-1, networkCapabilities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLost(Network network) {
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Network lost");
|
||||
}
|
||||
updateTrackedJobs(-1, null);
|
||||
}
|
||||
};
|
||||
|
||||
private INetworkPolicyListener mNetPolicyListener = new INetworkPolicyListener.Stub() {
|
||||
private final INetworkPolicyListener mNetPolicyListener = new INetworkPolicyListener.Stub() {
|
||||
@Override
|
||||
public void onUidRulesChanged(int uid, int uidRules) {
|
||||
updateTrackedJobs(uid);
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Uid rules changed for " + uid);
|
||||
}
|
||||
updateTrackedJobs(uid, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeteredIfacesChanged(String[] meteredIfaces) {
|
||||
updateTrackedJobs(-1);
|
||||
// We track this via our NetworkCallback
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestrictBackgroundChanged(boolean restrictBackground) {
|
||||
updateTrackedJobs(-1);
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Background restriction change to " + restrictBackground);
|
||||
}
|
||||
updateTrackedJobs(-1, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUidPoliciesChanged(int uid, int uidPolicies) {
|
||||
updateTrackedJobs(uid);
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Uid policy changed for " + uid);
|
||||
}
|
||||
updateTrackedJobs(uid, null);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
|
||||
pw.println("Connectivity.");
|
||||
pw.print("Connectivity: connected=");
|
||||
pw.print(mConnected);
|
||||
pw.print(" validated=");
|
||||
pw.println(mValidated);
|
||||
pw.print("Tracking ");
|
||||
pw.print(mTrackedJobs.size());
|
||||
pw.println(":");
|
||||
|
||||
Reference in New Issue
Block a user