1 /*
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 
17 package com.android.server.job.controllers;
18 
19 import static com.android.server.job.JobSchedulerService.DEBUG;
20 
21 import android.annotation.NonNull;
22 import android.content.Context;
23 import android.provider.DeviceConfig;
24 import android.util.IndentingPrintWriter;
25 import android.util.Slog;
26 import android.util.proto.ProtoOutputStream;
27 
28 import com.android.internal.annotations.GuardedBy;
29 import com.android.internal.util.FrameworkStatsLog;
30 import com.android.server.job.JobSchedulerService;
31 import com.android.server.job.JobSchedulerService.Constants;
32 import com.android.server.job.StateChangedListener;
33 
34 import java.util.function.Predicate;
35 
36 /**
37  * Incorporates shared controller logic between the various controllers of the JobManager.
38  * These are solely responsible for tracking a list of jobs, and notifying the JM when these
39  * are ready to run, or whether they must be stopped.
40  */
41 public abstract class StateController {
42     private static final String TAG = "JobScheduler.SC";
43 
44     protected final JobSchedulerService mService;
45     protected final StateChangedListener mStateChangedListener;
46     protected final Context mContext;
47     protected final Object mLock;
48     protected final Constants mConstants;
49 
StateController(JobSchedulerService service)50     StateController(JobSchedulerService service) {
51         mService = service;
52         mStateChangedListener = service;
53         mContext = service.getTestableContext();
54         mLock = service.getLock();
55         mConstants = service.getConstants();
56     }
57 
58     /**
59      * Called to get the controller to start tracking relevant information. This is called before
60      * {@link #onSystemServicesReady()}.
61      */
startTrackingLocked()62     public void startTrackingLocked() {}
63 
64     /**
65      * Called when the system boot phase has reached
66      * {@link com.android.server.SystemService#PHASE_SYSTEM_SERVICES_READY}.
67      */
onSystemServicesReady()68     public void onSystemServicesReady() {
69     }
70 
71     /**
72      * Implement the logic here to decide whether a job should be tracked by this controller.
73      * This logic is put here so the JobManager can be completely agnostic of Controller logic.
74      * Also called when updating a task, so implementing controllers have to be aware of
75      * preexisting tasks.
76      * This will never be called before {@link #onSystemServicesReady()}.
77      */
maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob)78     public abstract void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob);
79 
80     /**
81      * Optionally implement logic here to prepare the job to be executed.
82      */
prepareForExecutionLocked(JobStatus jobStatus)83     public void prepareForExecutionLocked(JobStatus jobStatus) {
84     }
85 
86     /**
87      * Optionally implement logic here for when a job that was about to be executed failed to start.
88      */
unprepareFromExecutionLocked(JobStatus jobStatus)89     public void unprepareFromExecutionLocked(JobStatus jobStatus) {
90     }
91 
92     /**
93      * Remove task - this will happen if the task is cancelled, completed, etc.
94      */
maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob)95     public abstract void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob);
96 
97     /**
98      * Called when a new job is being created to reschedule an old failed job.
99      */
rescheduleForFailureLocked(JobStatus newJob, JobStatus failureToReschedule)100     public void rescheduleForFailureLocked(JobStatus newJob, JobStatus failureToReschedule) {
101     }
102 
103     /** Notice that updated configuration constants are about to be read. */
prepareForUpdatedConstantsLocked()104     public void prepareForUpdatedConstantsLocked() {}
105 
106     /** Process the specified constant and update internal constants if relevant. */
processConstantLocked(@onNull DeviceConfig.Properties properties, @NonNull String key)107     public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
108             @NonNull String key) {}
109 
110     /**
111      * Called when the JobScheduler.Constants are updated.
112      */
onConstantsUpdatedLocked()113     public void onConstantsUpdatedLocked() {
114     }
115 
116     /** Called when a package is uninstalled from the device (not for an update). */
onAppRemovedLocked(String packageName, int uid)117     public void onAppRemovedLocked(String packageName, int uid) {
118     }
119 
120     /** Called when a user is added to the device. */
onUserAddedLocked(int userId)121     public void onUserAddedLocked(int userId) {
122     }
123 
124     /** Called when a user is removed from the device. */
onUserRemovedLocked(int userId)125     public void onUserRemovedLocked(int userId) {
126     }
127 
128     /**
129      * Called when JobSchedulerService has determined that the job is not ready to be run. The
130      * Controller can evaluate if it can or should do something to promote this job's readiness.
131      */
evaluateStateLocked(JobStatus jobStatus)132     public void evaluateStateLocked(JobStatus jobStatus) {
133     }
134 
135     /**
136      * Called when something with the UID has changed. The controller should re-evaluate any
137      * internal state tracking dependent on this UID.
138      */
reevaluateStateLocked(int uid)139     public void reevaluateStateLocked(int uid) {
140     }
141 
142     /**
143      * Called when the battery status changes.
144      */
145     @GuardedBy("mLock")
onBatteryStateChangedLocked()146     public void onBatteryStateChangedLocked() {
147     }
148 
149     /**
150      * Called when a UID's base bias has changed. The more positive the bias, the more
151      * important the UID is.
152      */
153     @GuardedBy("mLock")
onUidBiasChangedLocked(int uid, int prevBias, int newBias)154     public void onUidBiasChangedLocked(int uid, int prevBias, int newBias) {
155     }
156 
wouldBeReadyWithConstraintLocked(JobStatus jobStatus, int constraint)157     protected boolean wouldBeReadyWithConstraintLocked(JobStatus jobStatus, int constraint) {
158         // This is very cheap to check (just a few conditions on data in JobStatus).
159         final boolean jobWouldBeReady = jobStatus.wouldBeReadyWithConstraint(constraint);
160         if (DEBUG) {
161             Slog.v(TAG, "wouldBeReadyWithConstraintLocked: " + jobStatus.toShortString()
162                     + " constraint=" + constraint
163                     + " readyWithConstraint=" + jobWouldBeReady);
164         }
165         if (!jobWouldBeReady) {
166             // If the job wouldn't be ready, nothing to do here.
167             return false;
168         }
169 
170         // This is potentially more expensive since JSS may have to query component
171         // presence.
172         return mService.areComponentsInPlaceLocked(jobStatus);
173     }
174 
logDeviceWideConstraintStateToStatsd(int constraint, boolean satisfied)175     protected void logDeviceWideConstraintStateToStatsd(int constraint, boolean satisfied) {
176         FrameworkStatsLog.write(
177                 FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED,
178                 JobStatus.getProtoConstraint(constraint),
179                 satisfied
180                         ? FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
181                         : FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
182     }
183 
dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate)184     public abstract void dumpControllerStateLocked(IndentingPrintWriter pw,
185             Predicate<JobStatus> predicate);
dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, Predicate<JobStatus> predicate)186     public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
187             Predicate<JobStatus> predicate) {}
188 
189     /** Dump any internal constants the Controller may have. */
dumpConstants(IndentingPrintWriter pw)190     public void dumpConstants(IndentingPrintWriter pw) {
191     }
192 
193     /** Dump any internal constants the Controller may have. */
dumpConstants(ProtoOutputStream proto)194     public void dumpConstants(ProtoOutputStream proto) {
195     }
196 
197     /**
198      * Standardize the output of userId-packageName combo.
199      */
packageToString(int userId, String packageName)200     static String packageToString(int userId, String packageName) {
201         return "<" + userId + ">" + packageName;
202     }
203 }
204