Merge "Don't run jobs when connectivity is not validated" into oc-dev
am: 279997c435

Change-Id: I24860e318a09c271b03a906d18dcb2681ee3a9e7
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 94ca24c..b458d8b 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -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 @@
 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 @@
         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 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 @@
         }
     }
 
-    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 @@
      * @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 @@
         }
     }
 
-    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(":");