blob: 7120191472a6b58bb60c76ac7c8947ba25592412 [file] [log] [blame]
Matthew Williams6de79e22014-05-01 10:47:00 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
Christopher Tate7060b042014-06-09 19:50:00 -070017package com.android.server.job.controllers;
Matthew Williams6de79e22014-05-01 10:47:00 -070018
Jeff Sharkey1b6519b2016-04-28 15:33:18 -060019import android.app.job.JobInfo;
Matthew Williams6de79e22014-05-01 10:47:00 -070020import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.net.ConnectivityManager;
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060025import android.net.INetworkPolicyListener;
Matthew Williams6de79e22014-05-01 10:47:00 -070026import android.net.NetworkInfo;
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060027import android.net.NetworkPolicyManager;
Matthew Williams6de79e22014-05-01 10:47:00 -070028import android.os.UserHandle;
Matthew Williams9b9244b62014-05-14 11:06:04 -070029import android.util.Slog;
Matthew Williams6de79e22014-05-01 10:47:00 -070030
wangshujieb49420a72016-03-16 15:20:04 +080031import com.android.internal.os.BackgroundThread;
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060032import com.android.internal.annotations.GuardedBy;
Christopher Tate7060b042014-06-09 19:50:00 -070033import com.android.server.job.JobSchedulerService;
34import com.android.server.job.StateChangedListener;
Matthew Williams6de79e22014-05-01 10:47:00 -070035
Matthew Williamseffacfa2014-06-05 20:56:40 -070036import java.io.PrintWriter;
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060037import java.util.ArrayList;
Matthew Williams6de79e22014-05-01 10:47:00 -070038
39/**
Matthew Williams9b9244b62014-05-14 11:06:04 -070040 * Handles changes in connectivity.
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060041 * <p>
42 * Each app can have a different default networks or different connectivity
43 * status due to user-requested network policies, so we need to check
44 * constraints on a per-UID basis.
Matthew Williams6de79e22014-05-01 10:47:00 -070045 */
Matthew Williamseffacfa2014-06-05 20:56:40 -070046public class ConnectivityController extends StateController implements
47 ConnectivityManager.OnNetworkActiveListener {
Christopher Tate7060b042014-06-09 19:50:00 -070048 private static final String TAG = "JobScheduler.Conn";
Matthew Williams6de79e22014-05-01 10:47:00 -070049
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060050 private final ConnectivityManager mConnManager;
51 private final NetworkPolicyManager mNetPolicyManager;
52
53 @GuardedBy("mLock")
54 private final ArrayList<JobStatus> mTrackedJobs = new ArrayList<JobStatus>();
55
Matthew Williams9b9244b62014-05-14 11:06:04 -070056 /** Singleton. */
57 private static ConnectivityController mSingleton;
Matthew Williamseffacfa2014-06-05 20:56:40 -070058 private static Object sCreationLock = new Object();
Matthew Williams691e93e2014-05-12 15:33:09 -070059
Christopher Tate7060b042014-06-09 19:50:00 -070060 public static ConnectivityController get(JobSchedulerService jms) {
Matthew Williamseffacfa2014-06-05 20:56:40 -070061 synchronized (sCreationLock) {
62 if (mSingleton == null) {
Dianne Hackborn33d31c52016-02-16 10:30:33 -080063 mSingleton = new ConnectivityController(jms, jms.getContext(), jms.getLock());
Matthew Williamseffacfa2014-06-05 20:56:40 -070064 }
65 return mSingleton;
Matthew Williams9b9244b62014-05-14 11:06:04 -070066 }
Matthew Williams9b9244b62014-05-14 11:06:04 -070067 }
68
Dianne Hackborn33d31c52016-02-16 10:30:33 -080069 private ConnectivityController(StateChangedListener stateChangedListener, Context context,
70 Object lock) {
71 super(stateChangedListener, context, lock);
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060072
73 mConnManager = mContext.getSystemService(ConnectivityManager.class);
74 mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
75
76 final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
Matthew Williams6de79e22014-05-01 10:47:00 -070077 mContext.registerReceiverAsUser(
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060078 mConnectivityReceiver, UserHandle.SYSTEM, intentFilter, null, null);
79
80 mNetPolicyManager.registerListener(mNetPolicyListener);
Matthew Williams6de79e22014-05-01 10:47:00 -070081 }
82
83 @Override
Dianne Hackbornb0001f62016-02-16 10:30:33 -080084 public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060085 if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()
86 || jobStatus.hasNotRoamingConstraint()) {
87 updateConstraintsSatisfied(jobStatus);
Dianne Hackbornb0001f62016-02-16 10:30:33 -080088 mTrackedJobs.add(jobStatus);
Matthew Williamseffacfa2014-06-05 20:56:40 -070089 }
90 }
91
92 @Override
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060093 public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
94 boolean forUpdate) {
95 if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()
96 || jobStatus.hasNotRoamingConstraint()) {
Dianne Hackbornb0001f62016-02-16 10:30:33 -080097 mTrackedJobs.remove(jobStatus);
Matthew Williamseffacfa2014-06-05 20:56:40 -070098 }
Matthew Williams6de79e22014-05-01 10:47:00 -070099 }
100
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600101 private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600102 final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
103 final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobStatus.getSourceUid(),
104 ignoreBlocked);
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600105 final boolean connected = (info != null) && info.isConnected();
106 final boolean unmetered = connected && !info.isMetered();
107 final boolean notRoaming = connected && !info.isRoaming();
108
109 boolean changed = false;
110 changed |= jobStatus.setConnectivityConstraintSatisfied(connected);
111 changed |= jobStatus.setUnmeteredConstraintSatisfied(unmetered);
112 changed |= jobStatus.setNotRoamingConstraintSatisfied(notRoaming);
113 return changed;
114 }
115
Matthew Williams6de79e22014-05-01 10:47:00 -0700116 /**
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600117 * Update all jobs tracked by this controller.
118 *
119 * @param uid only update jobs belonging to this UID, or {@code -1} to
120 * update all tracked jobs.
Matthew Williams6de79e22014-05-01 10:47:00 -0700121 */
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600122 private void updateTrackedJobs(int uid) {
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800123 synchronized (mLock) {
Matthew Williamseffacfa2014-06-05 20:56:40 -0700124 boolean changed = false;
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600125 for (int i = 0; i < mTrackedJobs.size(); i++) {
126 final JobStatus js = mTrackedJobs.get(i);
127 if (uid == -1 || uid == js.getSourceUid()) {
128 changed |= updateConstraintsSatisfied(js);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700129 }
Matthew Williamseffacfa2014-06-05 20:56:40 -0700130 }
131 if (changed) {
132 mStateChangedListener.onControllerStateChanged();
Matthew Williams6de79e22014-05-01 10:47:00 -0700133 }
134 }
Matthew Williamseffacfa2014-06-05 20:56:40 -0700135 }
136
137 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700138 * We know the network has just come up. We want to run any jobs that are ready.
Matthew Williamseffacfa2014-06-05 20:56:40 -0700139 */
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600140 @Override
Matthew Williamseffacfa2014-06-05 20:56:40 -0700141 public synchronized void onNetworkActive() {
Dianne Hackborn33d31c52016-02-16 10:30:33 -0800142 synchronized (mLock) {
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600143 for (int i = 0; i < mTrackedJobs.size(); i++) {
144 final JobStatus js = mTrackedJobs.get(i);
Christopher Tate7060b042014-06-09 19:50:00 -0700145 if (js.isReady()) {
Matthew Williamseffacfa2014-06-05 20:56:40 -0700146 if (DEBUG) {
Christopher Tate7060b042014-06-09 19:50:00 -0700147 Slog.d(TAG, "Running " + js + " due to network activity.");
Matthew Williamseffacfa2014-06-05 20:56:40 -0700148 }
Christopher Tate7060b042014-06-09 19:50:00 -0700149 mStateChangedListener.onRunJobNow(js);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700150 }
151 }
Matthew Williams9b9244b62014-05-14 11:06:04 -0700152 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700153 }
154
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600155 private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
Matthew Williams6de79e22014-05-01 10:47:00 -0700156 @Override
157 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600158 updateTrackedJobs(-1);
159 }
160 };
161
162 private INetworkPolicyListener mNetPolicyListener = new INetworkPolicyListener.Stub() {
163 @Override
164 public void onUidRulesChanged(int uid, int uidRules) {
165 updateTrackedJobs(uid);
166 }
167
168 @Override
169 public void onMeteredIfacesChanged(String[] meteredIfaces) {
170 updateTrackedJobs(-1);
171 }
172
173 @Override
174 public void onRestrictBackgroundChanged(boolean restrictBackground) {
175 updateTrackedJobs(-1);
176 }
177
178 @Override
179 public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) {
180 updateTrackedJobs(uid);
Matthew Williams6de79e22014-05-01 10:47:00 -0700181 }
Felipe Leme99d5d3d2016-05-16 13:30:57 -0700182
183 @Override
184 public void onRestrictBackgroundBlacklistChanged(int uid, boolean blacklisted) {
185 updateTrackedJobs(uid);
186 }
Matthew Williams6de79e22014-05-01 10:47:00 -0700187 };
Matthew Williamseffacfa2014-06-05 20:56:40 -0700188
189 @Override
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700190 public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700191 pw.println("Connectivity.");
192 pw.print("Tracking ");
193 pw.print(mTrackedJobs.size());
194 pw.println(":");
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -0600195 for (int i = 0; i < mTrackedJobs.size(); i++) {
196 final JobStatus js = mTrackedJobs.get(i);
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700197 if (js.shouldDump(filterUid)) {
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700198 pw.print(" #");
199 js.printUniqueId(pw);
200 pw.print(" from ");
201 UserHandle.formatUid(pw, js.getSourceUid());
202 pw.print(": C="); pw.print(js.hasConnectivityConstraint());
203 pw.print(": UM="); pw.print(js.hasUnmeteredConstraint());
204 pw.print(": NR="); pw.println(js.hasNotRoamingConstraint());
Dianne Hackbornef3aa6e2016-04-29 18:18:08 -0700205 }
Matthew Williamseffacfa2014-06-05 20:56:40 -0700206 }
207 }
Robert Greenwalt6078b502014-06-11 16:05:07 -0700208}