201 lines
9.4 KiB
Java
201 lines
9.4 KiB
Java
|
package androidx.work.impl.background.systemjob;
|
||
|
|
||
|
import android.app.job.JobInfo;
|
||
|
import android.app.job.JobScheduler;
|
||
|
import android.content.ComponentName;
|
||
|
import android.content.Context;
|
||
|
import android.os.Build;
|
||
|
import android.os.PersistableBundle;
|
||
|
import androidx.annotation.NonNull;
|
||
|
import androidx.annotation.Nullable;
|
||
|
import androidx.annotation.RequiresApi;
|
||
|
import androidx.annotation.RestrictTo;
|
||
|
import androidx.annotation.VisibleForTesting;
|
||
|
import androidx.work.Logger;
|
||
|
import androidx.work.WorkInfo;
|
||
|
import androidx.work.impl.Scheduler;
|
||
|
import androidx.work.impl.WorkDatabase;
|
||
|
import androidx.work.impl.WorkManagerImpl;
|
||
|
import androidx.work.impl.model.SystemIdInfo;
|
||
|
import androidx.work.impl.model.WorkSpec;
|
||
|
import androidx.work.impl.utils.IdGenerator;
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.List;
|
||
|
import java.util.Locale;
|
||
|
@RequiresApi(23)
|
||
|
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
|
||
|
public class SystemJobScheduler implements Scheduler {
|
||
|
private static final String TAG = Logger.tagWithPrefix("SystemJobScheduler");
|
||
|
private final Context mContext;
|
||
|
private final JobScheduler mJobScheduler;
|
||
|
private final SystemJobInfoConverter mSystemJobInfoConverter;
|
||
|
private final WorkManagerImpl mWorkManager;
|
||
|
|
||
|
public SystemJobScheduler(@NonNull Context context, @NonNull WorkManagerImpl workManagerImpl) {
|
||
|
this(context, workManagerImpl, (JobScheduler) context.getSystemService("jobscheduler"), new SystemJobInfoConverter(context));
|
||
|
}
|
||
|
|
||
|
@VisibleForTesting
|
||
|
public SystemJobScheduler(Context context, WorkManagerImpl workManagerImpl, JobScheduler jobScheduler, SystemJobInfoConverter systemJobInfoConverter) {
|
||
|
this.mContext = context;
|
||
|
this.mWorkManager = workManagerImpl;
|
||
|
this.mJobScheduler = jobScheduler;
|
||
|
this.mSystemJobInfoConverter = systemJobInfoConverter;
|
||
|
}
|
||
|
|
||
|
public static void cancelAll(@NonNull Context context) {
|
||
|
List<JobInfo> pendingJobs;
|
||
|
JobScheduler jobScheduler = (JobScheduler) context.getSystemService("jobscheduler");
|
||
|
if (!(jobScheduler == null || (pendingJobs = getPendingJobs(context, jobScheduler)) == null || pendingJobs.isEmpty())) {
|
||
|
for (JobInfo jobInfo : pendingJobs) {
|
||
|
cancelJobById(jobScheduler, jobInfo.getId());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void cancelInvalidJobs(@NonNull Context context) {
|
||
|
List<JobInfo> pendingJobs;
|
||
|
JobScheduler jobScheduler = (JobScheduler) context.getSystemService("jobscheduler");
|
||
|
if (!(jobScheduler == null || (pendingJobs = getPendingJobs(context, jobScheduler)) == null || pendingJobs.isEmpty())) {
|
||
|
for (JobInfo jobInfo : pendingJobs) {
|
||
|
if (getWorkSpecIdFromJobInfo(jobInfo) == null) {
|
||
|
cancelJobById(jobScheduler, jobInfo.getId());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void cancelJobById(@NonNull JobScheduler jobScheduler, int i) {
|
||
|
try {
|
||
|
jobScheduler.cancel(i);
|
||
|
} catch (Throwable th) {
|
||
|
Logger.get().error(TAG, String.format(Locale.getDefault(), "Exception while trying to cancel job (%d)", Integer.valueOf(i)), th);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
private static List<Integer> getPendingJobIds(@NonNull Context context, @NonNull JobScheduler jobScheduler, @NonNull String str) {
|
||
|
List<JobInfo> pendingJobs = getPendingJobs(context, jobScheduler);
|
||
|
if (pendingJobs == null) {
|
||
|
return null;
|
||
|
}
|
||
|
ArrayList arrayList = new ArrayList(2);
|
||
|
for (JobInfo jobInfo : pendingJobs) {
|
||
|
if (str.equals(getWorkSpecIdFromJobInfo(jobInfo))) {
|
||
|
arrayList.add(Integer.valueOf(jobInfo.getId()));
|
||
|
}
|
||
|
}
|
||
|
return arrayList;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
private static List<JobInfo> getPendingJobs(@NonNull Context context, @NonNull JobScheduler jobScheduler) {
|
||
|
List<JobInfo> list;
|
||
|
try {
|
||
|
list = jobScheduler.getAllPendingJobs();
|
||
|
} catch (Throwable th) {
|
||
|
Logger.get().error(TAG, "getAllPendingJobs() is not reliable on this device.", th);
|
||
|
list = null;
|
||
|
}
|
||
|
if (list == null) {
|
||
|
return null;
|
||
|
}
|
||
|
ArrayList arrayList = new ArrayList(list.size());
|
||
|
ComponentName componentName = new ComponentName(context, SystemJobService.class);
|
||
|
for (JobInfo jobInfo : list) {
|
||
|
if (componentName.equals(jobInfo.getService())) {
|
||
|
arrayList.add(jobInfo);
|
||
|
}
|
||
|
}
|
||
|
return arrayList;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
private static String getWorkSpecIdFromJobInfo(@NonNull JobInfo jobInfo) {
|
||
|
PersistableBundle extras = jobInfo.getExtras();
|
||
|
if (extras == null) {
|
||
|
return null;
|
||
|
}
|
||
|
try {
|
||
|
if (extras.containsKey("EXTRA_WORK_SPEC_ID")) {
|
||
|
return extras.getString("EXTRA_WORK_SPEC_ID");
|
||
|
}
|
||
|
return null;
|
||
|
} catch (NullPointerException unused) {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override // androidx.work.impl.Scheduler
|
||
|
public void cancel(@NonNull String str) {
|
||
|
List<Integer> pendingJobIds = getPendingJobIds(this.mContext, this.mJobScheduler, str);
|
||
|
if (!(pendingJobIds == null || pendingJobIds.isEmpty())) {
|
||
|
for (Integer num : pendingJobIds) {
|
||
|
cancelJobById(this.mJobScheduler, num.intValue());
|
||
|
}
|
||
|
this.mWorkManager.getWorkDatabase().systemIdInfoDao().removeSystemIdInfo(str);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override // androidx.work.impl.Scheduler
|
||
|
public boolean hasLimitedSchedulingSlots() {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: finally extract failed */
|
||
|
@Override // androidx.work.impl.Scheduler
|
||
|
public void schedule(@NonNull WorkSpec... workSpecArr) {
|
||
|
List<Integer> pendingJobIds;
|
||
|
WorkDatabase workDatabase = this.mWorkManager.getWorkDatabase();
|
||
|
IdGenerator idGenerator = new IdGenerator(workDatabase);
|
||
|
for (WorkSpec workSpec : workSpecArr) {
|
||
|
workDatabase.beginTransaction();
|
||
|
try {
|
||
|
WorkSpec workSpec2 = workDatabase.workSpecDao().getWorkSpec(workSpec.f28id);
|
||
|
if (workSpec2 == null) {
|
||
|
Logger.get().warning(TAG, "Skipping scheduling " + workSpec.f28id + " because it's no longer in the DB", new Throwable[0]);
|
||
|
workDatabase.setTransactionSuccessful();
|
||
|
} else if (workSpec2.state != WorkInfo.State.ENQUEUED) {
|
||
|
Logger.get().warning(TAG, "Skipping scheduling " + workSpec.f28id + " because it is no longer enqueued", new Throwable[0]);
|
||
|
workDatabase.setTransactionSuccessful();
|
||
|
} else {
|
||
|
SystemIdInfo systemIdInfo = workDatabase.systemIdInfoDao().getSystemIdInfo(workSpec.f28id);
|
||
|
int nextJobSchedulerIdWithRange = systemIdInfo != null ? systemIdInfo.systemId : idGenerator.nextJobSchedulerIdWithRange(this.mWorkManager.getConfiguration().getMinJobSchedulerId(), this.mWorkManager.getConfiguration().getMaxJobSchedulerId());
|
||
|
if (systemIdInfo == null) {
|
||
|
this.mWorkManager.getWorkDatabase().systemIdInfoDao().insertSystemIdInfo(new SystemIdInfo(workSpec.f28id, nextJobSchedulerIdWithRange));
|
||
|
}
|
||
|
scheduleInternal(workSpec, nextJobSchedulerIdWithRange);
|
||
|
if (Build.VERSION.SDK_INT == 23 && (pendingJobIds = getPendingJobIds(this.mContext, this.mJobScheduler, workSpec.f28id)) != null) {
|
||
|
int indexOf = pendingJobIds.indexOf(Integer.valueOf(nextJobSchedulerIdWithRange));
|
||
|
if (indexOf >= 0) {
|
||
|
pendingJobIds.remove(indexOf);
|
||
|
}
|
||
|
scheduleInternal(workSpec, !pendingJobIds.isEmpty() ? pendingJobIds.get(0).intValue() : idGenerator.nextJobSchedulerIdWithRange(this.mWorkManager.getConfiguration().getMinJobSchedulerId(), this.mWorkManager.getConfiguration().getMaxJobSchedulerId()));
|
||
|
}
|
||
|
workDatabase.setTransactionSuccessful();
|
||
|
}
|
||
|
workDatabase.endTransaction();
|
||
|
} catch (Throwable th) {
|
||
|
workDatabase.endTransaction();
|
||
|
throw th;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@VisibleForTesting
|
||
|
public void scheduleInternal(WorkSpec workSpec, int i) {
|
||
|
JobInfo convert = this.mSystemJobInfoConverter.convert(workSpec, i);
|
||
|
Logger.get().debug(TAG, String.format("Scheduling work ID %s Job ID %s", workSpec.f28id, Integer.valueOf(i)), new Throwable[0]);
|
||
|
try {
|
||
|
this.mJobScheduler.schedule(convert);
|
||
|
} catch (IllegalStateException e) {
|
||
|
List<JobInfo> pendingJobs = getPendingJobs(this.mContext, this.mJobScheduler);
|
||
|
String format = String.format(Locale.getDefault(), "JobScheduler 100 job limit exceeded. We count %d WorkManager jobs in JobScheduler; we have %d tracked jobs in our DB; our Configuration limit is %d.", Integer.valueOf(pendingJobs != null ? pendingJobs.size() : 0), Integer.valueOf(this.mWorkManager.getWorkDatabase().workSpecDao().getScheduledWork().size()), Integer.valueOf(this.mWorkManager.getConfiguration().getMaxSchedulerLimit()));
|
||
|
Logger.get().error(TAG, format, new Throwable[0]);
|
||
|
throw new IllegalStateException(format, e);
|
||
|
} catch (Throwable th) {
|
||
|
Logger.get().error(TAG, String.format("Unable to schedule %s", workSpec), th);
|
||
|
}
|
||
|
}
|
||
|
}
|