WorkTimer.java revision dd3c04c8aa64eb9c8d3da1bbac6024e613d39143
1accafea75309628ec2456574bcaff8c97411187bJan Clarin/* 2accafea75309628ec2456574bcaff8c97411187bJan Clarin * Copyright 2018 The Android Open Source Project 3accafea75309628ec2456574bcaff8c97411187bJan Clarin * 4accafea75309628ec2456574bcaff8c97411187bJan Clarin * Licensed under the Apache License, Version 2.0 (the "License"); 5accafea75309628ec2456574bcaff8c97411187bJan Clarin * you may not use this file except in compliance with the License. 6accafea75309628ec2456574bcaff8c97411187bJan Clarin * You may obtain a copy of the License at 7accafea75309628ec2456574bcaff8c97411187bJan Clarin * 8accafea75309628ec2456574bcaff8c97411187bJan Clarin * http://www.apache.org/licenses/LICENSE-2.0 9accafea75309628ec2456574bcaff8c97411187bJan Clarin * 10accafea75309628ec2456574bcaff8c97411187bJan Clarin * Unless required by applicable law or agreed to in writing, software 11accafea75309628ec2456574bcaff8c97411187bJan Clarin * distributed under the License is distributed on an "AS IS" BASIS, 12accafea75309628ec2456574bcaff8c97411187bJan Clarin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13accafea75309628ec2456574bcaff8c97411187bJan Clarin * See the License for the specific language governing permissions and 14accafea75309628ec2456574bcaff8c97411187bJan Clarin * limitations under the License. 15accafea75309628ec2456574bcaff8c97411187bJan Clarin */ 16accafea75309628ec2456574bcaff8c97411187bJan Clarin 17accafea75309628ec2456574bcaff8c97411187bJan Clarinpackage android.arch.background.workmanager.impl.background.systemalarm; 18accafea75309628ec2456574bcaff8c97411187bJan Clarin 19accafea75309628ec2456574bcaff8c97411187bJan Clarinimport android.arch.background.workmanager.BaseWork; 20accafea75309628ec2456574bcaff8c97411187bJan Clarinimport android.arch.background.workmanager.impl.logger.Logger; 21accafea75309628ec2456574bcaff8c97411187bJan Clarinimport android.support.annotation.NonNull; 22accafea75309628ec2456574bcaff8c97411187bJan Clarinimport android.support.annotation.RestrictTo; 23dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumarimport android.support.annotation.VisibleForTesting; 24accafea75309628ec2456574bcaff8c97411187bJan Clarin 25dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumarimport java.util.HashMap; 26accafea75309628ec2456574bcaff8c97411187bJan Clarinimport java.util.Map; 27accafea75309628ec2456574bcaff8c97411187bJan Clarinimport java.util.concurrent.Executors; 28accafea75309628ec2456574bcaff8c97411187bJan Clarinimport java.util.concurrent.ScheduledExecutorService; 29accafea75309628ec2456574bcaff8c97411187bJan Clarinimport java.util.concurrent.TimeUnit; 30accafea75309628ec2456574bcaff8c97411187bJan Clarin 31accafea75309628ec2456574bcaff8c97411187bJan Clarin/** 32dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * Manages timers to enforce a time limit for processing {@link BaseWork}. 33dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * Notifies a {@link TimeLimitExceededListener} when the time limit 34dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * is exceeded. 35accafea75309628ec2456574bcaff8c97411187bJan Clarin * 36accafea75309628ec2456574bcaff8c97411187bJan Clarin * @hide 37accafea75309628ec2456574bcaff8c97411187bJan Clarin */ 38accafea75309628ec2456574bcaff8c97411187bJan Clarin@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 39dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumarclass WorkTimer { 40dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 41accafea75309628ec2456574bcaff8c97411187bJan Clarin private static final String TAG = "WorkTimer"; 42accafea75309628ec2456574bcaff8c97411187bJan Clarin 43dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final ScheduledExecutorService mExecutorService; 44dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final Map<String, WorkTimerRunnable> mTimerMap; 45dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final Map<String, TimeLimitExceededListener> mListeners; 46dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final Object mLock; 47dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 48dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar WorkTimer() { 49dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mTimerMap = new HashMap<>(); 50dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mListeners = new HashMap<>(); 51dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mLock = new Object(); 52dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mExecutorService = Executors.newSingleThreadScheduledExecutor(); 53dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 54accafea75309628ec2456574bcaff8c97411187bJan Clarin 55dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @SuppressWarnings("FutureReturnValueIgnored") 56dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar void startTimer(@NonNull final String workSpecId, 57dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar long processingTimeMillis, 58dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @NonNull TimeLimitExceededListener listener) { 59accafea75309628ec2456574bcaff8c97411187bJan Clarin 60dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar synchronized (mLock) { 61dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar Logger.debug(TAG, "Starting timer for %s", workSpecId); 62dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // clear existing timer's first 63dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar stopTimer(workSpecId); 64dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar WorkTimerRunnable runnable = new WorkTimerRunnable(this, workSpecId); 65dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mTimerMap.put(workSpecId, runnable); 66dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mListeners.put(workSpecId, listener); 67dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mExecutorService.schedule(runnable, processingTimeMillis, TimeUnit.MILLISECONDS); 68dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 69accafea75309628ec2456574bcaff8c97411187bJan Clarin } 70accafea75309628ec2456574bcaff8c97411187bJan Clarin 71dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar void stopTimer(@NonNull final String workSpecId) { 72dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar synchronized (mLock) { 73dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar if (mTimerMap.containsKey(workSpecId)) { 74dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar Logger.debug(TAG, "Stopping timer for %s", workSpecId); 75dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mTimerMap.remove(workSpecId); 76dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mListeners.remove(workSpecId); 77accafea75309628ec2456574bcaff8c97411187bJan Clarin } 78dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 79dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 80accafea75309628ec2456574bcaff8c97411187bJan Clarin 81dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @VisibleForTesting 82dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar synchronized Map<String, WorkTimerRunnable> getTimerMap() { 83dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar return mTimerMap; 84accafea75309628ec2456574bcaff8c97411187bJan Clarin } 85accafea75309628ec2456574bcaff8c97411187bJan Clarin 86dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @VisibleForTesting 87dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar synchronized Map<String, TimeLimitExceededListener> getListeners() { 88dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar return mListeners; 89dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 90dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 91dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar /** 92dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * The actual runnable scheduled on the scheduled executor. 93dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar */ 94dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar static class WorkTimerRunnable implements Runnable { 95dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar static final String TAG = "WrkTimerRunnable"; 96dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 97dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final WorkTimer mWorkTimer; 98dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final String mWorkSpecId; 99dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 100dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar WorkTimerRunnable(@NonNull WorkTimer workTimer, @NonNull String workSpecId) { 101dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mWorkTimer = workTimer; 102dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mWorkSpecId = workSpecId; 103dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 104dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 105dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @Override 106dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar public void run() { 107dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar synchronized (mWorkTimer.mLock) { 108dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar if (mWorkTimer.mTimerMap.containsKey(mWorkSpecId)) { 109dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mWorkTimer.mTimerMap.remove(mWorkSpecId); 110dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // notify time limit exceeded. 111dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar TimeLimitExceededListener listener = mWorkTimer.mListeners.remove(mWorkSpecId); 112dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar if (listener != null) { 113dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar listener.onTimeLimitExceeded(mWorkSpecId); 114dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 115dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } else { 116dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar Logger.debug(TAG, "Timer with %s is already marked as complete.", mWorkSpecId); 117dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 118dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 119accafea75309628ec2456574bcaff8c97411187bJan Clarin } 120accafea75309628ec2456574bcaff8c97411187bJan Clarin } 121accafea75309628ec2456574bcaff8c97411187bJan Clarin 122accafea75309628ec2456574bcaff8c97411187bJan Clarin interface TimeLimitExceededListener { 123accafea75309628ec2456574bcaff8c97411187bJan Clarin void onTimeLimitExceeded(@NonNull String workSpecId); 124accafea75309628ec2456574bcaff8c97411187bJan Clarin } 125accafea75309628ec2456574bcaff8c97411187bJan Clarin} 126