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