Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 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.content; |
| 18 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 19 | import android.annotation.Nullable; |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 20 | import android.app.job.JobParameters; |
| 21 | import android.app.job.JobService; |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 22 | import android.os.Message; |
Makoto Onuki | 7273aad | 2018-01-11 15:51:23 -0800 | [diff] [blame] | 23 | import android.os.SystemClock; |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 24 | import android.util.Log; |
| 25 | import android.util.Slog; |
| 26 | import android.util.SparseArray; |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 27 | import android.util.SparseBooleanArray; |
Makoto Onuki | 7273aad | 2018-01-11 15:51:23 -0800 | [diff] [blame] | 28 | import android.util.SparseLongArray; |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 29 | |
| 30 | import com.android.internal.annotations.GuardedBy; |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 31 | |
| 32 | public class SyncJobService extends JobService { |
| 33 | private static final String TAG = "SyncManager"; |
| 34 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 35 | private static final Object sLock = new Object(); |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 36 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 37 | @GuardedBy("sLock") |
| 38 | private static SyncJobService sInstance; |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 39 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 40 | @GuardedBy("sLock") |
| 41 | private static final SparseArray<JobParameters> sJobParamsMap = new SparseArray<>(); |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 42 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 43 | @GuardedBy("sLock") |
| 44 | private static final SparseBooleanArray sStartedSyncs = new SparseBooleanArray(); |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 45 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 46 | @GuardedBy("sLock") |
| 47 | private static final SparseLongArray sJobStartUptimes = new SparseLongArray(); |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 48 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 49 | private static final SyncLogger sLogger = SyncLogger.getInstance(); |
Makoto Onuki | 7273aad | 2018-01-11 15:51:23 -0800 | [diff] [blame] | 50 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 51 | private void updateInstance() { |
| 52 | synchronized (SyncJobService.class) { |
| 53 | sInstance = this; |
| 54 | } |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 55 | } |
| 56 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 57 | @Nullable |
| 58 | private static SyncJobService getInstance() { |
| 59 | synchronized (sLock) { |
| 60 | if (sInstance == null) { |
| 61 | Slog.wtf(TAG, "sInstance == null"); |
| 62 | } |
| 63 | return sInstance; |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 64 | } |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | public static boolean isReady() { |
| 68 | synchronized (sLock) { |
| 69 | return sInstance != null; |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 70 | } |
| 71 | } |
| 72 | |
| 73 | @Override |
| 74 | public boolean onStartJob(JobParameters params) { |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 75 | updateInstance(); |
Makoto Onuki | a9dca24 | 2017-06-21 17:06:49 -0700 | [diff] [blame] | 76 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 77 | sLogger.purgeOldLogs(); |
| 78 | |
| 79 | SyncOperation op = SyncOperation.maybeCreateFromJobExtras(params.getExtras()); |
| 80 | |
| 81 | if (op == null) { |
| 82 | Slog.wtf(TAG, "Got invalid job " + params.getJobId()); |
| 83 | return false; |
| 84 | } |
| 85 | |
| 86 | final boolean readyToSync = SyncManager.readyToSync(op.target.userId); |
| 87 | |
| 88 | sLogger.log("onStartJob() jobid=", params.getJobId(), " op=", op, |
| 89 | " readyToSync", readyToSync); |
| 90 | |
| 91 | if (!readyToSync) { |
| 92 | // If the user isn't unlocked or the device has been provisioned yet, just stop the job |
| 93 | // at this point. If it's a non-periodic sync, ask the job scheduler to reschedule it. |
| 94 | // If it's a periodic sync, then just wait until the next cycle. |
| 95 | final boolean wantsReschedule = !op.isPeriodic; |
| 96 | jobFinished(params, wantsReschedule); |
| 97 | return true; |
| 98 | } |
Makoto Onuki | a9dca24 | 2017-06-21 17:06:49 -0700 | [diff] [blame] | 99 | |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 100 | boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 101 | synchronized (sLock) { |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 102 | final int jobId = params.getJobId(); |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 103 | sJobParamsMap.put(jobId, params); |
Makoto Onuki | 7273aad | 2018-01-11 15:51:23 -0800 | [diff] [blame] | 104 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 105 | sStartedSyncs.delete(jobId); |
| 106 | sJobStartUptimes.put(jobId, SystemClock.uptimeMillis()); |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 107 | } |
| 108 | Message m = Message.obtain(); |
| 109 | m.what = SyncManager.SyncHandler.MESSAGE_START_SYNC; |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 110 | if (isLoggable) { |
| 111 | Slog.v(TAG, "Got start job message " + op.target); |
| 112 | } |
| 113 | m.obj = op; |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 114 | SyncManager.sendMessage(m); |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 115 | return true; |
| 116 | } |
| 117 | |
| 118 | @Override |
| 119 | public boolean onStopJob(JobParameters params) { |
| 120 | if (Log.isLoggable(TAG, Log.VERBOSE)) { |
| 121 | Slog.v(TAG, "onStopJob called " + params.getJobId() + ", reason: " |
| 122 | + params.getStopReason()); |
| 123 | } |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 124 | final SyncOperation op = SyncOperation.maybeCreateFromJobExtras(params.getExtras()); |
| 125 | if (op == null) { |
| 126 | Slog.wtf(TAG, "Got invalid job " + params.getJobId()); |
| 127 | return false; |
| 128 | } |
Makoto Onuki | 056a975 | 2018-05-08 15:21:56 -0700 | [diff] [blame] | 129 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 130 | final boolean readyToSync = SyncManager.readyToSync(op.target.userId); |
| 131 | |
| 132 | sLogger.log("onStopJob() ", sLogger.jobParametersToString(params), |
Makoto Onuki | 056a975 | 2018-05-08 15:21:56 -0700 | [diff] [blame] | 133 | " readyToSync=", readyToSync); |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 134 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 135 | synchronized (sLock) { |
| 136 | final int jobId = params.getJobId(); |
| 137 | sJobParamsMap.remove(jobId); |
| 138 | |
| 139 | final long startUptime = sJobStartUptimes.get(jobId); |
Makoto Onuki | 7273aad | 2018-01-11 15:51:23 -0800 | [diff] [blame] | 140 | final long nowUptime = SystemClock.uptimeMillis(); |
Makoto Onuki | d2bfec6 | 2018-01-12 13:58:01 -0800 | [diff] [blame] | 141 | final long runtime = nowUptime - startUptime; |
| 142 | |
Makoto Onuki | 056a975 | 2018-05-08 15:21:56 -0700 | [diff] [blame] | 143 | |
Makoto Onuki | 7273aad | 2018-01-11 15:51:23 -0800 | [diff] [blame] | 144 | if (startUptime == 0) { |
| 145 | wtf("Job " + jobId + " start uptime not found: " |
| 146 | + " params=" + jobParametersToString(params)); |
Makoto Onuki | d2bfec6 | 2018-01-12 13:58:01 -0800 | [diff] [blame] | 147 | } else if (runtime > 60 * 1000) { |
Makoto Onuki | 7273aad | 2018-01-11 15:51:23 -0800 | [diff] [blame] | 148 | // WTF if startSyncH() hasn't happened, *unless* onStopJob() was called too soon. |
| 149 | // (1 minute threshold.) |
Makoto Onuki | 056a975 | 2018-05-08 15:21:56 -0700 | [diff] [blame] | 150 | // Also don't wtf when it's not ready to sync. |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 151 | if (readyToSync && !sStartedSyncs.get(jobId)) { |
Makoto Onuki | 7273aad | 2018-01-11 15:51:23 -0800 | [diff] [blame] | 152 | wtf("Job " + jobId + " didn't start: " |
| 153 | + " startUptime=" + startUptime |
| 154 | + " nowUptime=" + nowUptime |
| 155 | + " params=" + jobParametersToString(params)); |
| 156 | } |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 157 | } |
| 158 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 159 | sStartedSyncs.delete(jobId); |
| 160 | sJobStartUptimes.delete(jobId); |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 161 | } |
| 162 | Message m = Message.obtain(); |
| 163 | m.what = SyncManager.SyncHandler.MESSAGE_STOP_SYNC; |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 164 | m.obj = op; |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 165 | |
| 166 | // Reschedule if this job was NOT explicitly canceled. |
| 167 | m.arg1 = params.getStopReason() != JobParameters.REASON_CANCELED ? 1 : 0; |
| 168 | // Apply backoff only if stop is called due to timeout. |
| 169 | m.arg2 = params.getStopReason() == JobParameters.REASON_TIMEOUT ? 1 : 0; |
| 170 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 171 | SyncManager.sendMessage(m); |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 172 | return false; |
| 173 | } |
| 174 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 175 | public static void callJobFinished(int jobId, boolean needsReschedule, String why) { |
| 176 | final SyncJobService instance = getInstance(); |
| 177 | if (instance != null) { |
| 178 | instance.callJobFinishedInner(jobId, needsReschedule, why); |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | public void callJobFinishedInner(int jobId, boolean needsReschedule, String why) { |
| 183 | synchronized (sLock) { |
| 184 | JobParameters params = sJobParamsMap.get(jobId); |
| 185 | sLogger.log("callJobFinished()", |
Makoto Onuki | 87d4262 | 2017-12-13 12:01:45 -0800 | [diff] [blame] | 186 | " jobid=", jobId, |
Makoto Onuki | a9dca24 | 2017-06-21 17:06:49 -0700 | [diff] [blame] | 187 | " needsReschedule=", needsReschedule, |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 188 | " ", sLogger.jobParametersToString(params), |
Makoto Onuki | a9dca24 | 2017-06-21 17:06:49 -0700 | [diff] [blame] | 189 | " why=", why); |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 190 | if (params != null) { |
| 191 | jobFinished(params, needsReschedule); |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 192 | sJobParamsMap.remove(jobId); |
Shreyas Basarge | 8c834c0 | 2016-01-07 13:53:16 +0000 | [diff] [blame] | 193 | } else { |
| 194 | Slog.e(TAG, "Job params not found for " + String.valueOf(jobId)); |
| 195 | } |
| 196 | } |
| 197 | } |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 198 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 199 | public static void markSyncStarted(int jobId) { |
| 200 | synchronized (sLock) { |
| 201 | sStartedSyncs.put(jobId, true); |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 202 | } |
| 203 | } |
| 204 | |
| 205 | public static String jobParametersToString(JobParameters params) { |
| 206 | if (params == null) { |
| 207 | return "job:null"; |
| 208 | } else { |
| 209 | return "job:#" + params.getJobId() + ":" |
Makoto Onuki | d2bfec6 | 2018-01-12 13:58:01 -0800 | [diff] [blame] | 210 | + "sr=[" + params.getStopReason() + "/" + params.getDebugStopReason() + "]:" |
Makoto Onuki | 5397be1 | 2017-12-20 16:22:34 +0900 | [diff] [blame] | 211 | + SyncOperation.maybeCreateFromJobExtras(params.getExtras()); |
| 212 | } |
| 213 | } |
Makoto Onuki | 7273aad | 2018-01-11 15:51:23 -0800 | [diff] [blame] | 214 | |
Makoto Onuki | 3ab7781 | 2018-07-09 14:29:33 -0700 | [diff] [blame] | 215 | private static void wtf(String message) { |
| 216 | sLogger.log(message); |
Makoto Onuki | 7273aad | 2018-01-11 15:51:23 -0800 | [diff] [blame] | 217 | Slog.wtf(TAG, message); |
| 218 | } |
Makoto Onuki | 118c0da | 2017-07-14 10:27:03 -0700 | [diff] [blame] | 219 | } |