1dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar/* 2dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * Copyright 2018 The Android Open Source Project 3dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * 4dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * Licensed under the Apache License, Version 2.0 (the "License"); 5dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * you may not use this file except in compliance with the License. 6dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * You may obtain a copy of the License at 7dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * 8dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * http://www.apache.org/licenses/LICENSE-2.0 9dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * 10dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * Unless required by applicable law or agreed to in writing, software 11dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * distributed under the License is distributed on an "AS IS" BASIS, 12dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * See the License for the specific language governing permissions and 14dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * limitations under the License. 15dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar */ 16dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 17564e43098c323d1a90be53c190b8fdbdde973505Sumir Katariapackage androidx.work.impl.background.systemalarm; 18dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 19dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumarimport android.content.Context; 20dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumarimport android.content.Intent; 21dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumarimport android.os.PowerManager; 22dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumarimport android.support.annotation.NonNull; 23dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumarimport android.support.annotation.Nullable; 24dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumarimport android.support.annotation.RestrictTo; 25e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumarimport android.support.annotation.WorkerThread; 26697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumarimport android.util.Log; 27dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 28564e43098c323d1a90be53c190b8fdbdde973505Sumir Katariaimport androidx.work.impl.ExecutionListener; 29564e43098c323d1a90be53c190b8fdbdde973505Sumir Katariaimport androidx.work.impl.constraints.WorkConstraintsCallback; 30564e43098c323d1a90be53c190b8fdbdde973505Sumir Katariaimport androidx.work.impl.constraints.WorkConstraintsTracker; 31564e43098c323d1a90be53c190b8fdbdde973505Sumir Katariaimport androidx.work.impl.model.WorkSpec; 32564e43098c323d1a90be53c190b8fdbdde973505Sumir Katariaimport androidx.work.impl.utils.WakeLocks; 33564e43098c323d1a90be53c190b8fdbdde973505Sumir Kataria 34b5728f4e1a4b3f4f1fabf033b1363ca6b1cffdefSumir Katariaimport java.util.Collections; 35b5728f4e1a4b3f4f1fabf033b1363ca6b1cffdefSumir Katariaimport java.util.List; 36b5728f4e1a4b3f4f1fabf033b1363ca6b1cffdefSumir Kataria 37dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar/** 38dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * This is a command handler which attempts to run a work spec given its id. 39dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * Also handles constraints gracefully. 40dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * 41dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar * @hide 42dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar */ 43dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 44dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumarpublic class DelayMetCommandHandler implements 45dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar WorkConstraintsCallback, 46dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar ExecutionListener, 47dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar WorkTimer.TimeLimitExceededListener { 48dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 49dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private static final String TAG = "DelayMetCommandHandler"; 50dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 51dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final Context mContext; 52dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final int mStartId; 53dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final String mWorkSpecId; 54dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final SystemAlarmDispatcher mDispatcher; 55dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final WorkConstraintsTracker mWorkConstraintsTracker; 56dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private final Object mLock; 57e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar private boolean mHasPendingStopWorkCommand; 58dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 59e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar @Nullable private PowerManager.WakeLock mWakeLock; 60e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar private boolean mHasConstraints; 61dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 62dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar DelayMetCommandHandler( 63dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @NonNull Context context, 64dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar int startId, 65dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @NonNull String workSpecId, 66dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @NonNull SystemAlarmDispatcher dispatcher) { 67dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 68dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mContext = context; 69dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mStartId = startId; 70dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mDispatcher = dispatcher; 71dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mWorkSpecId = workSpecId; 72dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mWorkConstraintsTracker = new WorkConstraintsTracker(mContext, this); 73e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar mHasConstraints = false; 74e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar mHasPendingStopWorkCommand = false; 75dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mLock = new Object(); 76dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 77dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 78dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @Override 79dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar public void onAllConstraintsMet(@NonNull List<String> ignored) { 80697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, String.format("onAllConstraintsMet for %s", mWorkSpecId)); 81d70f977a2a312353a82ffefeeef67bb23941f78eRahul Ravikumar // Constraints met, schedule execution 82d70f977a2a312353a82ffefeeef67bb23941f78eRahul Ravikumar 83d70f977a2a312353a82ffefeeef67bb23941f78eRahul Ravikumar // Not using WorkManagerImpl#startWork() here because we need to know if the processor 84d70f977a2a312353a82ffefeeef67bb23941f78eRahul Ravikumar // actually enqueued the work here. 85d70f977a2a312353a82ffefeeef67bb23941f78eRahul Ravikumar // TODO(rahulrav@) Once WorkManagerImpl provides a callback for acknowledging if 86d70f977a2a312353a82ffefeeef67bb23941f78eRahul Ravikumar // work was enqueued, call WorkManagerImpl#startWork(). 879543a50886c5c217ae5616ec834b73274d0c1037Sumir Kataria boolean isEnqueued = mDispatcher.getProcessor().startWork(mWorkSpecId); 88dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 89dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar if (isEnqueued) { 90dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // setup timers to enforce quotas on workers that have 91dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // been enqueued 92dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mDispatcher.getWorkTimer() 93dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar .startTimer(mWorkSpecId, CommandHandler.WORK_PROCESSING_TIME_IN_MS, this); 94dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } else { 95dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // if we did not actually enqueue the work, it was enqueued before 96dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // cleanUp and pretend this never happened. 97dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar cleanUp(); 98dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 99dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 100dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 101dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @Override 102dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar public void onExecuted( 103dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @NonNull String workSpecId, 104dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar boolean isSuccessful, 105dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar boolean needsReschedule) { 106dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 107697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, String.format( 108697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar "onExecuted %s, %s, %s", workSpecId, isSuccessful, needsReschedule)); 109697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar 110dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar cleanUp(); 111e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar 112e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar if (mHasConstraints) { 113e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // The WorkSpec had constraints. Once the execution of the worker is complete, 114e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // we might need to disable constraint proxies which were previously enabled for 115e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // this WorkSpec. Hence, trigger a constraints changed command. 116e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar Intent intent = CommandHandler.createConstraintsChangedIntent(mContext); 117e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar mDispatcher.postOnMainThread( 118e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar new SystemAlarmDispatcher.AddRunnable(mDispatcher, intent, mStartId)); 119e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar } 120dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 121dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 122dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @Override 123dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar public void onTimeLimitExceeded(@NonNull String workSpecId) { 124697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, String.format("Exceeded time limits on execution for %s", workSpecId)); 125e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar stopWork(); 126dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 127dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 128dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar @Override 129dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar public void onAllConstraintsNotMet(@NonNull List<String> ignored) { 130e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar stopWork(); 131dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 132dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 133e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar @WorkerThread 134dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar void handleProcessWork() { 135498888fde0080e29b854e4ba329644ccf5fc60c5Sumir Kataria mWakeLock = WakeLocks.newWakeLock( 136498888fde0080e29b854e4ba329644ccf5fc60c5Sumir Kataria mContext, 137498888fde0080e29b854e4ba329644ccf5fc60c5Sumir Kataria String.format("%s (%s)", mWorkSpecId, mStartId)); 138697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, String.format("Acquiring wakelock %s for WorkSpec %s", mWakeLock, mWorkSpecId)); 139dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mWakeLock.acquire(); 140dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 141dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar WorkSpec workSpec = mDispatcher.getWorkManager() 142dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar .getWorkDatabase() 143dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar .workSpecDao() 144dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar .getWorkSpec(mWorkSpecId); 145dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 146e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // Keep track of whether the WorkSpec had constraints. This is useful for updating the 147e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // state of constraint proxies when onExecuted(). 148e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar mHasConstraints = workSpec.hasConstraints(); 149e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar 150e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar if (!mHasConstraints) { 151697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, String.format("No constraints for %s", mWorkSpecId)); 152dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar onAllConstraintsMet(Collections.singletonList(mWorkSpecId)); 153dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } else { 154e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // Allow tracker to report constraint changes 155dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mWorkConstraintsTracker.replace(Collections.singletonList(workSpec)); 156dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 157dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 158dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 159e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar private void stopWork() { 160e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // No need to release the wake locks here. The stopWork command will eventually call 161e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // onExecuted() if there is a corresponding pending delay met command handler; which in 162e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // turn calls cleanUp(). 163e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar 164e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // Needs to be synchronized, as the stopWork() request can potentially come from the 165e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar // WorkTimer thread as well as the command executor service in SystemAlarmDispatcher. 166e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar synchronized (mLock) { 167e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar if (!mHasPendingStopWorkCommand) { 168697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, String.format("Stopping work for workspec %s", mWorkSpecId)); 169e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar Intent stopWork = CommandHandler.createStopWorkIntent(mContext, mWorkSpecId); 170e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar mDispatcher.postOnMainThread( 171e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar new SystemAlarmDispatcher.AddRunnable(mDispatcher, stopWork, mStartId)); 172b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar // There are cases where the work may not have been enqueued at all, and therefore 173b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar // the processor is completely unaware of such a workSpecId in which case a 174b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar // reschedule should not happen. For e.g. DELAY_MET when constraints are not met, 175b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar // should not result in a reschedule. 176b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar if (mDispatcher.getProcessor().isEnqueued(mWorkSpecId)) { 177697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, String.format("WorkSpec %s needs to be rescheduled", mWorkSpecId)); 178b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar Intent reschedule = CommandHandler.createScheduleWorkIntent(mContext, 179b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar mWorkSpecId); 180b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar mDispatcher.postOnMainThread( 181b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar new SystemAlarmDispatcher.AddRunnable(mDispatcher, reschedule, 182b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar mStartId)); 183b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar } else { 184697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, String.format( 185697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar "Processor does not have WorkSpec %s. No need to reschedule ", 186697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar mWorkSpecId)); 187b035249dbe0cb224080705db57c7e05438bdbe87Rahul Ravikumar } 188e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar mHasPendingStopWorkCommand = true; 189e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar } else { 190697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, String.format("Already stopped work for %s", mWorkSpecId)); 191e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar } 192e92262ff56fedd7753af56e777e38e07894210e6Rahul Ravikumar } 193dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 194dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 195dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar private void cleanUp() { 196dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // cleanUp() may occur from one of 2 threads. 1979543a50886c5c217ae5616ec834b73274d0c1037Sumir Kataria // * In the call to bgProcessor.startWork() returns false, 198dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // it probably means that the worker is already being processed 199dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // so we just need to call cleanUp to release wakelocks on the command processor thread. 200dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // * It could also happen on the onExecutionCompleted() pass of the bgProcessor. 201dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // To avoid calling mWakeLock.release() twice, we are synchronizing here. 202dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar synchronized (mLock) { 203dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // stop timers 204dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mDispatcher.getWorkTimer().stopTimer(mWorkSpecId); 205dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar 206dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar // release wake locks 207dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar if (mWakeLock != null && mWakeLock.isHeld()) { 208697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, String.format( 209697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar "Releasing wakelock %s for WorkSpec %s", mWakeLock, mWorkSpecId)); 210dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar mWakeLock.release(); 211dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 212dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 213dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar } 214dd3c04c8aa64eb9c8d3da1bbac6024e613d39143Rahul Ravikumar} 215