mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-20 19:18:37 +00:00
Prevent potential deadlock when canceling jobs.
This commit is contained in:
committed by
Jeffrey Starke
parent
6f051ce4c2
commit
2b56e00e89
@@ -206,33 +206,47 @@ class JobController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
synchronized void cancelJob(@NonNull String id) {
|
void cancelJob(@NonNull String id) {
|
||||||
Job runningJob = runningJobs.get(id);
|
Job inactiveJob = null;
|
||||||
|
List<Job> inactiveJobDependents = Collections.emptyList();
|
||||||
|
|
||||||
if (runningJob != null) {
|
synchronized (this) {
|
||||||
Log.w(TAG, JobLogger.format(runningJob, "Canceling while running."));
|
Job runningJob = runningJobs.get(id);
|
||||||
runningJob.cancel();
|
|
||||||
} else {
|
|
||||||
JobSpec jobSpec = jobStorage.getJobSpec(id);
|
|
||||||
|
|
||||||
if (jobSpec != null) {
|
if (runningJob != null) {
|
||||||
Job job = createJob(jobSpec, jobStorage.getConstraintSpecs(id));
|
Log.w(TAG, JobLogger.format(runningJob, "Canceling while running."));
|
||||||
Log.w(TAG, JobLogger.format(job, "Canceling while inactive."));
|
runningJob.cancel();
|
||||||
Log.w(TAG, JobLogger.format(job, "Job failed."));
|
|
||||||
|
|
||||||
job.cancel();
|
|
||||||
List<Job> dependents = onFailure(job);
|
|
||||||
job.onFailure();
|
|
||||||
Stream.of(dependents).forEach(Job::onFailure);
|
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Tried to cancel JOB::" + id + ", but it could not be found.");
|
JobSpec jobSpec = jobStorage.getJobSpec(id);
|
||||||
|
|
||||||
|
if (jobSpec != null) {
|
||||||
|
inactiveJob = createJob(jobSpec, jobStorage.getConstraintSpecs(id));
|
||||||
|
Log.w(TAG, JobLogger.format(inactiveJob, "Canceling while inactive."));
|
||||||
|
Log.w(TAG, JobLogger.format(inactiveJob, "Job failed."));
|
||||||
|
|
||||||
|
inactiveJob.cancel();
|
||||||
|
inactiveJobDependents = onFailure(inactiveJob);
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Tried to cancel JOB::" + id + ", but it could not be found.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have no control over what happens in jobs' onFailure method, so we drop our lock to reduce the possibility of a deadlock
|
||||||
|
if (inactiveJob != null) {
|
||||||
|
inactiveJob.onFailure();
|
||||||
|
Stream.of(inactiveJobDependents).forEach(Job::onFailure);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
synchronized void cancelAllInQueue(@NonNull String queue) {
|
void cancelAllInQueue(@NonNull String queue) {
|
||||||
Stream.of(jobStorage.getJobsInQueue(queue))
|
List<JobSpec> jobsInQueue;
|
||||||
|
synchronized (this) {
|
||||||
|
jobsInQueue = jobStorage.getJobsInQueue(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream.of(jobsInQueue)
|
||||||
.map(JobSpec::getId)
|
.map(JobSpec::getId)
|
||||||
.forEach(this::cancelJob);
|
.forEach(this::cancelJob);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user