blob: e8057fbd41508cbe358628c317adb27ca6396f45 [file] [log] [blame]
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001/*
2 * Copyright (C) 2017 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
17package com.android.server.job.controllers;
18
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070019import android.content.Context;
Makoto Onuki9be01402017-11-10 13:22:26 -080020import android.os.SystemClock;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070021import android.os.UserHandle;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070022import android.util.Slog;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080023import android.util.proto.ProtoOutputStream;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070024
Makoto Onukie4918212018-02-06 11:30:15 -080025import com.android.internal.util.Preconditions;
26import com.android.server.AppStateTracker;
27import com.android.server.AppStateTracker.Listener;
28import com.android.server.LocalServices;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070029import com.android.server.job.JobSchedulerService;
30import com.android.server.job.JobStore;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080031import com.android.server.job.StateControllerProto;
32import com.android.server.job.StateControllerProto.BackgroundJobsController.TrackedJob;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070033
34import java.io.PrintWriter;
35
36public final class BackgroundJobsController extends StateController {
37
38 private static final String LOG_TAG = "BackgroundJobsController";
39 private static final boolean DEBUG = JobSchedulerService.DEBUG;
40
41 // Singleton factory
42 private static final Object sCreationLock = new Object();
43 private static volatile BackgroundJobsController sController;
44
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070045 private final JobSchedulerService mJobSchedulerService;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070046
Makoto Onukie4918212018-02-06 11:30:15 -080047 private final AppStateTracker mAppStateTracker;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070048
49 public static BackgroundJobsController get(JobSchedulerService service) {
50 synchronized (sCreationLock) {
51 if (sController == null) {
52 sController = new BackgroundJobsController(service, service.getContext(),
53 service.getLock());
54 }
55 return sController;
56 }
57 }
58
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070059 private BackgroundJobsController(JobSchedulerService service, Context context, Object lock) {
60 super(service, context, lock);
61 mJobSchedulerService = service;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070062
Makoto Onukie4918212018-02-06 11:30:15 -080063 mAppStateTracker = Preconditions.checkNotNull(
64 LocalServices.getService(AppStateTracker.class));
65 mAppStateTracker.addListener(mForceAppStandbyListener);
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070066 }
67
68 @Override
69 public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
Makoto Onuki9be01402017-11-10 13:22:26 -080070 updateSingleJobRestrictionLocked(jobStatus);
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070071 }
72
73 @Override
74 public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
75 boolean forUpdate) {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070076 }
77
78 @Override
79 public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
Suprabh Shuklaa78acfd2017-10-13 19:29:36 -070080 pw.println("BackgroundJobsController");
Makoto Onuki9be01402017-11-10 13:22:26 -080081
Makoto Onukie4918212018-02-06 11:30:15 -080082 mAppStateTracker.dump(pw, "");
Makoto Onuki9be01402017-11-10 13:22:26 -080083
84 pw.println("Job state:");
85 mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
86 if (!jobStatus.shouldDump(filterUid)) {
87 return;
88 }
89 final int uid = jobStatus.getSourceUid();
Kweku Adams85f2fbc2017-12-18 12:04:12 -080090 final String sourcePkg = jobStatus.getSourcePackageName();
Makoto Onuki9be01402017-11-10 13:22:26 -080091 pw.print(" #");
92 jobStatus.printUniqueId(pw);
93 pw.print(" from ");
94 UserHandle.formatUid(pw, uid);
Makoto Onukie4918212018-02-06 11:30:15 -080095 pw.print(mAppStateTracker.isUidActive(uid) ? " active" : " idle");
96 if (mAppStateTracker.isUidPowerSaveWhitelisted(uid) ||
97 mAppStateTracker.isUidTempPowerSaveWhitelisted(uid)) {
Makoto Onuki9be01402017-11-10 13:22:26 -080098 pw.print(", whitelisted");
99 }
100 pw.print(": ");
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800101 pw.print(sourcePkg);
Makoto Onuki9be01402017-11-10 13:22:26 -0800102
Makoto Onuki2206af32017-11-21 16:25:35 -0800103 pw.print(" [RUN_ANY_IN_BACKGROUND ");
Makoto Onukie4918212018-02-06 11:30:15 -0800104 pw.print(mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, sourcePkg)
Makoto Onuki2206af32017-11-21 16:25:35 -0800105 ? "allowed]" : "disallowed]");
Makoto Onuki9be01402017-11-10 13:22:26 -0800106
107 if ((jobStatus.satisfiedConstraints
108 & JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
109 pw.println(" RUNNABLE");
110 } else {
111 pw.println(" WAITING");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700112 }
113 });
114 }
115
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800116 @Override
117 public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
118 final long token = proto.start(fieldId);
119 final long mToken = proto.start(StateControllerProto.BACKGROUND);
120
Makoto Onukie4918212018-02-06 11:30:15 -0800121 mAppStateTracker.dumpProto(proto,
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800122 StateControllerProto.BackgroundJobsController.FORCE_APP_STANDBY_TRACKER);
123
124 mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
125 if (!jobStatus.shouldDump(filterUid)) {
126 return;
127 }
128 final long jsToken =
129 proto.start(StateControllerProto.BackgroundJobsController.TRACKED_JOBS);
130
131 jobStatus.writeToShortProto(proto,
132 TrackedJob.INFO);
133 final int sourceUid = jobStatus.getSourceUid();
134 proto.write(TrackedJob.SOURCE_UID, sourceUid);
135 final String sourcePkg = jobStatus.getSourcePackageName();
136 proto.write(TrackedJob.SOURCE_PACKAGE_NAME, sourcePkg);
137
138 proto.write(TrackedJob.IS_IN_FOREGROUND,
Makoto Onukie4918212018-02-06 11:30:15 -0800139 mAppStateTracker.isUidActive(sourceUid));
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800140 proto.write(TrackedJob.IS_WHITELISTED,
Makoto Onukie4918212018-02-06 11:30:15 -0800141 mAppStateTracker.isUidPowerSaveWhitelisted(sourceUid) ||
142 mAppStateTracker.isUidTempPowerSaveWhitelisted(sourceUid));
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800143
144 proto.write(
145 TrackedJob.CAN_RUN_ANY_IN_BACKGROUND,
Makoto Onukie4918212018-02-06 11:30:15 -0800146 mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800147 sourceUid, sourcePkg));
148
149 proto.write(
150 TrackedJob.ARE_CONSTRAINTS_SATISFIED,
151 (jobStatus.satisfiedConstraints &
152 JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0);
153
154 proto.end(jsToken);
155 });
156
157 proto.end(mToken);
158 proto.end(token);
159 }
160
Makoto Onuki9be01402017-11-10 13:22:26 -0800161 private void updateAllJobRestrictionsLocked() {
162 updateJobRestrictionsLocked(/*filterUid=*/ -1);
163 }
164
165 private void updateJobRestrictionsForUidLocked(int uid) {
166
167 // TODO Use forEachJobForSourceUid() once we have it.
168
169 updateJobRestrictionsLocked(/*filterUid=*/ uid);
170 }
171
172 private void updateJobRestrictionsLocked(int filterUid) {
173 final UpdateJobFunctor updateTrackedJobs =
174 new UpdateJobFunctor(filterUid);
175
176 final long start = DEBUG ? SystemClock.elapsedRealtimeNanos() : 0;
177
178 mJobSchedulerService.getJobStore().forEachJob(updateTrackedJobs);
179
180 final long time = DEBUG ? (SystemClock.elapsedRealtimeNanos() - start) : 0;
181 if (DEBUG) {
182 Slog.d(LOG_TAG, String.format(
183 "Job status updated: %d/%d checked/total jobs, %d us",
184 updateTrackedJobs.mCheckedCount,
185 updateTrackedJobs.mTotalCount,
186 (time / 1000)
187 ));
188 }
189
190 if (updateTrackedJobs.mChanged) {
191 mStateChangedListener.onControllerStateChanged();
192 }
193 }
194
Makoto Onuki9be01402017-11-10 13:22:26 -0800195 boolean updateSingleJobRestrictionLocked(JobStatus jobStatus) {
196
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700197 final int uid = jobStatus.getSourceUid();
Makoto Onuki9be01402017-11-10 13:22:26 -0800198 final String packageName = jobStatus.getSourcePackageName();
199
Makoto Onukie4918212018-02-06 11:30:15 -0800200 final boolean canRun = !mAppStateTracker.areJobsRestricted(uid, packageName,
Makoto Onuki15407842018-01-19 14:23:11 -0800201 (jobStatus.getInternalFlags() & JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION)
202 != 0);
Makoto Onuki9be01402017-11-10 13:22:26 -0800203
204 return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700205 }
206
Makoto Onuki9be01402017-11-10 13:22:26 -0800207 private final class UpdateJobFunctor implements JobStore.JobStatusFunctor {
208 private final int mFilterUid;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700209
Makoto Onuki9be01402017-11-10 13:22:26 -0800210 boolean mChanged = false;
211 int mTotalCount = 0;
212 int mCheckedCount = 0;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700213
Makoto Onuki9be01402017-11-10 13:22:26 -0800214 UpdateJobFunctor(int filterUid) {
215 mFilterUid = filterUid;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700216 }
217
218 @Override
219 public void process(JobStatus jobStatus) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800220 mTotalCount++;
221 if ((mFilterUid > 0) && (mFilterUid != jobStatus.getSourceUid())) {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700222 return;
223 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800224 mCheckedCount++;
225 if (updateSingleJobRestrictionLocked(jobStatus)) {
226 mChanged = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700227 }
228 }
229 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800230
231 private final Listener mForceAppStandbyListener = new Listener() {
232 @Override
Makoto Onuki2206af32017-11-21 16:25:35 -0800233 public void updateAllJobs() {
Christopher Tate998fb4e2018-01-17 14:40:38 -0800234 synchronized (mLock) {
235 updateAllJobRestrictionsLocked();
236 }
Makoto Onuki2206af32017-11-21 16:25:35 -0800237 }
238
239 @Override
240 public void updateJobsForUid(int uid) {
Christopher Tate998fb4e2018-01-17 14:40:38 -0800241 synchronized (mLock) {
242 updateJobRestrictionsForUidLocked(uid);
243 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800244 }
245
246 @Override
Makoto Onuki2206af32017-11-21 16:25:35 -0800247 public void updateJobsForUidPackage(int uid, String packageName) {
Christopher Tate998fb4e2018-01-17 14:40:38 -0800248 synchronized (mLock) {
249 updateJobRestrictionsForUidLocked(uid);
250 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800251 }
252 };
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700253}