16de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams/* 26de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * Copyright (C) 2014 The Android Open Source Project 36de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * 46de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * Licensed under the Apache License, Version 2.0 (the "License"); 56de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * you may not use this file except in compliance with the License. 66de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * You may obtain a copy of the License at 76de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * 86de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * http://www.apache.org/licenses/LICENSE-2.0 96de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * 106de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * Unless required by applicable law or agreed to in writing, software 116de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * distributed under the License is distributed on an "AS IS" BASIS, 126de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * See the License for the specific language governing permissions and 146de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams * limitations under the License 156de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams */ 166de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams 177060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tatepackage com.android.server.job.controllers; 186de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams 191b6519bd87a59a10e9928e5772a17976692611daJeff Sharkeyimport android.app.job.JobInfo; 206de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williamsimport android.content.BroadcastReceiver; 216de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williamsimport android.content.Context; 226de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williamsimport android.content.Intent; 236de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williamsimport android.content.IntentFilter; 246de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williamsimport android.net.ConnectivityManager; 25f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkeyimport android.net.INetworkPolicyListener; 266de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williamsimport android.net.NetworkInfo; 27f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkeyimport android.net.NetworkPolicyManager; 286de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williamsimport android.os.UserHandle; 299b9244b6941110ea2d940d9fc8eed0cdff96a016Matthew Williamsimport android.util.Slog; 306de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams 31f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkeyimport com.android.internal.annotations.GuardedBy; 327060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport com.android.server.job.JobSchedulerService; 337060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport com.android.server.job.StateChangedListener; 346de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams 35effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williamsimport java.io.PrintWriter; 36f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkeyimport java.util.ArrayList; 376de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams 386de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams/** 399b9244b6941110ea2d940d9fc8eed0cdff96a016Matthew Williams * Handles changes in connectivity. 40f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey * <p> 41f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey * Each app can have a different default networks or different connectivity 42f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey * status due to user-requested network policies, so we need to check 43f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey * constraints on a per-UID basis. 446de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams */ 45effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williamspublic class ConnectivityController extends StateController implements 46effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams ConnectivityManager.OnNetworkActiveListener { 477060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private static final String TAG = "JobScheduler.Conn"; 486de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams 49f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey private final ConnectivityManager mConnManager; 50f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey private final NetworkPolicyManager mNetPolicyManager; 51f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 52f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey @GuardedBy("mLock") 53f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey private final ArrayList<JobStatus> mTrackedJobs = new ArrayList<JobStatus>(); 54f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 559b9244b6941110ea2d940d9fc8eed0cdff96a016Matthew Williams /** Singleton. */ 569b9244b6941110ea2d940d9fc8eed0cdff96a016Matthew Williams private static ConnectivityController mSingleton; 57effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams private static Object sCreationLock = new Object(); 58691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams 597060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate public static ConnectivityController get(JobSchedulerService jms) { 60effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams synchronized (sCreationLock) { 61effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams if (mSingleton == null) { 6233d31c5b70c7d056e799e34bb6eccbe6939714eaDianne Hackborn mSingleton = new ConnectivityController(jms, jms.getContext(), jms.getLock()); 63effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams } 64effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams return mSingleton; 659b9244b6941110ea2d940d9fc8eed0cdff96a016Matthew Williams } 669b9244b6941110ea2d940d9fc8eed0cdff96a016Matthew Williams } 679b9244b6941110ea2d940d9fc8eed0cdff96a016Matthew Williams 6833d31c5b70c7d056e799e34bb6eccbe6939714eaDianne Hackborn private ConnectivityController(StateChangedListener stateChangedListener, Context context, 6933d31c5b70c7d056e799e34bb6eccbe6939714eaDianne Hackborn Object lock) { 7033d31c5b70c7d056e799e34bb6eccbe6939714eaDianne Hackborn super(stateChangedListener, context, lock); 71f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 72f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey mConnManager = mContext.getSystemService(ConnectivityManager.class); 73f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); 74f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 75f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); 766de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams mContext.registerReceiverAsUser( 77f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey mConnectivityReceiver, UserHandle.SYSTEM, intentFilter, null, null); 78f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 79f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey mNetPolicyManager.registerListener(mNetPolicyListener); 806de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams } 816de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams 826de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams @Override 83b0001f6fb1383d9824c2733896b0b348e7f77240Dianne Hackborn public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { 84f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint() 85f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey || jobStatus.hasNotRoamingConstraint()) { 86f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey updateConstraintsSatisfied(jobStatus); 87b0001f6fb1383d9824c2733896b0b348e7f77240Dianne Hackborn mTrackedJobs.add(jobStatus); 886de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams } 896de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams } 906de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams 916de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams @Override 92f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, 93f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey boolean forUpdate) { 94f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint() 95f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey || jobStatus.hasNotRoamingConstraint()) { 96b0001f6fb1383d9824c2733896b0b348e7f77240Dianne Hackborn mTrackedJobs.remove(jobStatus); 97effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams } 986de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams } 996de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams 100f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey private boolean updateConstraintsSatisfied(JobStatus jobStatus) { 1011b6519bd87a59a10e9928e5772a17976692611daJeff Sharkey final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; 1021b6519bd87a59a10e9928e5772a17976692611daJeff Sharkey final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobStatus.getSourceUid(), 1031b6519bd87a59a10e9928e5772a17976692611daJeff Sharkey ignoreBlocked); 104f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey final boolean connected = (info != null) && info.isConnected(); 105f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey final boolean unmetered = connected && !info.isMetered(); 106f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey final boolean notRoaming = connected && !info.isRoaming(); 107f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 108f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey boolean changed = false; 109f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey changed |= jobStatus.setConnectivityConstraintSatisfied(connected); 110f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey changed |= jobStatus.setUnmeteredConstraintSatisfied(unmetered); 111f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey changed |= jobStatus.setNotRoamingConstraintSatisfied(notRoaming); 112f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey return changed; 113f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey } 114f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 1156de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams /** 116f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey * Update all jobs tracked by this controller. 117f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey * 118f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey * @param uid only update jobs belonging to this UID, or {@code -1} to 119f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey * update all tracked jobs. 1206de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams */ 121f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey private void updateTrackedJobs(int uid) { 12233d31c5b70c7d056e799e34bb6eccbe6939714eaDianne Hackborn synchronized (mLock) { 123effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams boolean changed = false; 124f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey for (int i = 0; i < mTrackedJobs.size(); i++) { 125f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey final JobStatus js = mTrackedJobs.get(i); 126f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey if (uid == -1 || uid == js.getSourceUid()) { 127f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey changed |= updateConstraintsSatisfied(js); 128effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams } 129effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams } 130effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams if (changed) { 131effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams mStateChangedListener.onControllerStateChanged(); 1326de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams } 1336de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams } 134effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams } 135effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams 136effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams /** 1377060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * We know the network has just come up. We want to run any jobs that are ready. 138effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams */ 139f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey @Override 140effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams public synchronized void onNetworkActive() { 14133d31c5b70c7d056e799e34bb6eccbe6939714eaDianne Hackborn synchronized (mLock) { 142f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey for (int i = 0; i < mTrackedJobs.size(); i++) { 143f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey final JobStatus js = mTrackedJobs.get(i); 1447060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate if (js.isReady()) { 145effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams if (DEBUG) { 1467060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Slog.d(TAG, "Running " + js + " due to network activity."); 147effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams } 1487060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate mStateChangedListener.onRunJobNow(js); 149effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams } 150effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams } 1519b9244b6941110ea2d940d9fc8eed0cdff96a016Matthew Williams } 1526de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams } 1536de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams 154f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() { 1556de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams @Override 1566de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams public void onReceive(Context context, Intent intent) { 157f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey updateTrackedJobs(-1); 158f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey } 159f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey }; 160f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 161f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey private INetworkPolicyListener mNetPolicyListener = new INetworkPolicyListener.Stub() { 162f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey @Override 163f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey public void onUidRulesChanged(int uid, int uidRules) { 164f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey updateTrackedJobs(uid); 165f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey } 166f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 167f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey @Override 168f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey public void onMeteredIfacesChanged(String[] meteredIfaces) { 169f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey updateTrackedJobs(-1); 170f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey } 171f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 172f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey @Override 173f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey public void onRestrictBackgroundChanged(boolean restrictBackground) { 174f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey updateTrackedJobs(-1); 175f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey } 176f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey 177f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey @Override 178f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) { 179f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey updateTrackedJobs(uid); 1806de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams } 18199d5d3d7759883119665d928d110edb14df44eccFelipe Leme 18299d5d3d7759883119665d928d110edb14df44eccFelipe Leme @Override 18399d5d3d7759883119665d928d110edb14df44eccFelipe Leme public void onRestrictBackgroundBlacklistChanged(int uid, boolean blacklisted) { 18499d5d3d7759883119665d928d110edb14df44eccFelipe Leme updateTrackedJobs(uid); 18599d5d3d7759883119665d928d110edb14df44eccFelipe Leme } 1866de79e2b17fa0796ea4d39fd9555b563c484248dMatthew Williams }; 187effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams 188effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams @Override 189ef3aa6ee53c5e4f1c50dd5a9b5821c54e449d4b3Dianne Hackborn public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { 190e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn pw.println("Connectivity."); 191e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn pw.print("Tracking "); 192e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn pw.print(mTrackedJobs.size()); 193e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn pw.println(":"); 194f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey for (int i = 0; i < mTrackedJobs.size(); i++) { 195f07c7b9fd0a640bff4bf7690373613da217fe69bJeff Sharkey final JobStatus js = mTrackedJobs.get(i); 196ef3aa6ee53c5e4f1c50dd5a9b5821c54e449d4b3Dianne Hackborn if (js.shouldDump(filterUid)) { 197e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn pw.print(" #"); 198e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn js.printUniqueId(pw); 199e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn pw.print(" from "); 200e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn UserHandle.formatUid(pw, js.getSourceUid()); 201e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn pw.print(": C="); pw.print(js.hasConnectivityConstraint()); 202e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn pw.print(": UM="); pw.print(js.hasUnmeteredConstraint()); 203e9a988caca733d2f292991a52a0047685a69812fDianne Hackborn pw.print(": NR="); pw.println(js.hasNotRoamingConstraint()); 204ef3aa6ee53c5e4f1c50dd5a9b5821c54e449d4b3Dianne Hackborn } 205effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams } 206effacfa75bd9c2ebc889a7bc4f002c07f82f4c31Matthew Williams } 2076078b50b017fbcf8d6cbf9f83226ed5667d5729eRobert Greenwalt} 208