2021-06-27 20:44:35 +00:00
|
|
|
package androidx.core.app;
|
|
|
|
|
|
|
|
import android.app.Service;
|
|
|
|
import android.app.job.JobInfo;
|
|
|
|
import android.app.job.JobParameters;
|
|
|
|
import android.app.job.JobScheduler;
|
|
|
|
import android.app.job.JobServiceEngine;
|
|
|
|
import android.app.job.JobWorkItem;
|
|
|
|
import android.content.ComponentName;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.os.AsyncTask;
|
|
|
|
import android.os.Build;
|
|
|
|
import android.os.IBinder;
|
|
|
|
import android.os.PowerManager;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
import androidx.annotation.RequiresApi;
|
|
|
|
import c.d.b.a.a;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.HashMap;
|
|
|
|
public abstract class JobIntentService extends Service {
|
|
|
|
public static final boolean DEBUG = false;
|
|
|
|
public static final String TAG = "JobIntentService";
|
|
|
|
public static final HashMap<ComponentName, WorkEnqueuer> sClassWorkEnqueuer = new HashMap<>();
|
|
|
|
public static final Object sLock = new Object();
|
|
|
|
public final ArrayList<CompatWorkItem> mCompatQueue;
|
|
|
|
public WorkEnqueuer mCompatWorkEnqueuer;
|
|
|
|
public CommandProcessor mCurProcessor;
|
|
|
|
public boolean mDestroyed = false;
|
|
|
|
public boolean mInterruptIfStopped = false;
|
|
|
|
public CompatJobEngine mJobImpl;
|
|
|
|
public boolean mStopped = false;
|
|
|
|
|
|
|
|
public final class CommandProcessor extends AsyncTask<Void, Void, Void> {
|
|
|
|
public CommandProcessor() {
|
|
|
|
}
|
|
|
|
|
|
|
|
public Void doInBackground(Void... voidArr) {
|
|
|
|
while (true) {
|
|
|
|
GenericWorkItem dequeueWork = JobIntentService.this.dequeueWork();
|
|
|
|
if (dequeueWork == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
JobIntentService.this.onHandleWork(dequeueWork.getIntent());
|
|
|
|
dequeueWork.complete();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onCancelled(Void r1) {
|
|
|
|
JobIntentService.this.processorFinished();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onPostExecute(Void r1) {
|
|
|
|
JobIntentService.this.processorFinished();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public interface CompatJobEngine {
|
|
|
|
IBinder compatGetBinder();
|
|
|
|
|
|
|
|
GenericWorkItem dequeueWork();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static final class CompatWorkEnqueuer extends WorkEnqueuer {
|
|
|
|
private final Context mContext;
|
|
|
|
private final PowerManager.WakeLock mLaunchWakeLock;
|
|
|
|
public boolean mLaunchingService;
|
|
|
|
private final PowerManager.WakeLock mRunWakeLock;
|
|
|
|
public boolean mServiceProcessing;
|
|
|
|
|
|
|
|
public CompatWorkEnqueuer(Context context, ComponentName componentName) {
|
|
|
|
super(componentName);
|
|
|
|
this.mContext = context.getApplicationContext();
|
|
|
|
PowerManager powerManager = (PowerManager) context.getSystemService("power");
|
|
|
|
PowerManager.WakeLock newWakeLock = powerManager.newWakeLock(1, componentName.getClassName() + ":launch");
|
|
|
|
this.mLaunchWakeLock = newWakeLock;
|
|
|
|
newWakeLock.setReferenceCounted(false);
|
|
|
|
PowerManager.WakeLock newWakeLock2 = powerManager.newWakeLock(1, componentName.getClassName() + ":run");
|
|
|
|
this.mRunWakeLock = newWakeLock2;
|
|
|
|
newWakeLock2.setReferenceCounted(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.WorkEnqueuer
|
|
|
|
public void enqueueWork(Intent intent) {
|
|
|
|
Intent intent2 = new Intent(intent);
|
|
|
|
intent2.setComponent(this.mComponentName);
|
|
|
|
if (this.mContext.startService(intent2) != null) {
|
|
|
|
synchronized (this) {
|
|
|
|
if (!this.mLaunchingService) {
|
|
|
|
this.mLaunchingService = true;
|
|
|
|
if (!this.mServiceProcessing) {
|
|
|
|
this.mLaunchWakeLock.acquire(60000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.WorkEnqueuer
|
|
|
|
public void serviceProcessingFinished() {
|
|
|
|
synchronized (this) {
|
|
|
|
if (this.mServiceProcessing) {
|
|
|
|
if (this.mLaunchingService) {
|
|
|
|
this.mLaunchWakeLock.acquire(60000);
|
|
|
|
}
|
|
|
|
this.mServiceProcessing = false;
|
|
|
|
this.mRunWakeLock.release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.WorkEnqueuer
|
|
|
|
public void serviceProcessingStarted() {
|
|
|
|
synchronized (this) {
|
|
|
|
if (!this.mServiceProcessing) {
|
|
|
|
this.mServiceProcessing = true;
|
|
|
|
this.mRunWakeLock.acquire(600000);
|
|
|
|
this.mLaunchWakeLock.release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.WorkEnqueuer
|
|
|
|
public void serviceStartReceived() {
|
|
|
|
synchronized (this) {
|
|
|
|
this.mLaunchingService = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public final class CompatWorkItem implements GenericWorkItem {
|
|
|
|
public final Intent mIntent;
|
|
|
|
public final int mStartId;
|
|
|
|
|
|
|
|
public CompatWorkItem(Intent intent, int i) {
|
|
|
|
this.mIntent = intent;
|
|
|
|
this.mStartId = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.GenericWorkItem
|
|
|
|
public void complete() {
|
|
|
|
JobIntentService.this.stopSelf(this.mStartId);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.GenericWorkItem
|
|
|
|
public Intent getIntent() {
|
|
|
|
return this.mIntent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public interface GenericWorkItem {
|
|
|
|
void complete();
|
|
|
|
|
|
|
|
Intent getIntent();
|
|
|
|
}
|
|
|
|
|
|
|
|
@RequiresApi(26)
|
|
|
|
public static final class JobServiceEngineImpl extends JobServiceEngine implements CompatJobEngine {
|
|
|
|
public static final boolean DEBUG = false;
|
|
|
|
public static final String TAG = "JobServiceEngineImpl";
|
|
|
|
public final Object mLock = new Object();
|
|
|
|
public JobParameters mParams;
|
|
|
|
public final JobIntentService mService;
|
|
|
|
|
|
|
|
public final class WrapperWorkItem implements GenericWorkItem {
|
|
|
|
public final JobWorkItem mJobWork;
|
|
|
|
|
|
|
|
public WrapperWorkItem(JobWorkItem jobWorkItem) {
|
|
|
|
this.mJobWork = jobWorkItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.GenericWorkItem
|
|
|
|
public void complete() {
|
|
|
|
synchronized (JobServiceEngineImpl.this.mLock) {
|
|
|
|
JobParameters jobParameters = JobServiceEngineImpl.this.mParams;
|
|
|
|
if (jobParameters != null) {
|
|
|
|
jobParameters.completeWork(this.mJobWork);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.GenericWorkItem
|
|
|
|
public Intent getIntent() {
|
|
|
|
return this.mJobWork.getIntent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public JobServiceEngineImpl(JobIntentService jobIntentService) {
|
|
|
|
super(jobIntentService);
|
|
|
|
this.mService = jobIntentService;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.CompatJobEngine
|
|
|
|
public IBinder compatGetBinder() {
|
|
|
|
return getBinder();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.CompatJobEngine
|
|
|
|
public GenericWorkItem dequeueWork() {
|
|
|
|
JobWorkItem dequeueWork;
|
|
|
|
synchronized (this.mLock) {
|
|
|
|
JobParameters jobParameters = this.mParams;
|
|
|
|
if (jobParameters == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
dequeueWork = jobParameters.dequeueWork();
|
|
|
|
}
|
|
|
|
if (dequeueWork == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
dequeueWork.getIntent().setExtrasClassLoader(this.mService.getClassLoader());
|
|
|
|
return new WrapperWorkItem(dequeueWork);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // android.app.job.JobServiceEngine
|
|
|
|
public boolean onStartJob(JobParameters jobParameters) {
|
|
|
|
this.mParams = jobParameters;
|
|
|
|
this.mService.ensureProcessorRunningLocked(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // android.app.job.JobServiceEngine
|
|
|
|
public boolean onStopJob(JobParameters jobParameters) {
|
|
|
|
boolean doStopCurrentWork = this.mService.doStopCurrentWork();
|
|
|
|
synchronized (this.mLock) {
|
|
|
|
this.mParams = null;
|
|
|
|
}
|
|
|
|
return doStopCurrentWork;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@RequiresApi(26)
|
|
|
|
public static final class JobWorkEnqueuer extends WorkEnqueuer {
|
|
|
|
private final JobInfo mJobInfo;
|
|
|
|
private final JobScheduler mJobScheduler;
|
|
|
|
|
|
|
|
public JobWorkEnqueuer(Context context, ComponentName componentName, int i) {
|
|
|
|
super(componentName);
|
|
|
|
ensureJobId(i);
|
|
|
|
this.mJobInfo = new JobInfo.Builder(i, this.mComponentName).setOverrideDeadline(0).build();
|
|
|
|
this.mJobScheduler = (JobScheduler) context.getApplicationContext().getSystemService("jobscheduler");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // androidx.core.app.JobIntentService.WorkEnqueuer
|
|
|
|
public void enqueueWork(Intent intent) {
|
|
|
|
this.mJobScheduler.enqueue(this.mJobInfo, new JobWorkItem(intent));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static abstract class WorkEnqueuer {
|
|
|
|
public final ComponentName mComponentName;
|
|
|
|
public boolean mHasJobId;
|
|
|
|
public int mJobId;
|
|
|
|
|
|
|
|
public WorkEnqueuer(ComponentName componentName) {
|
|
|
|
this.mComponentName = componentName;
|
|
|
|
}
|
|
|
|
|
|
|
|
public abstract void enqueueWork(Intent intent);
|
|
|
|
|
|
|
|
public void ensureJobId(int i) {
|
|
|
|
if (!this.mHasJobId) {
|
|
|
|
this.mHasJobId = true;
|
|
|
|
this.mJobId = i;
|
|
|
|
} else if (this.mJobId != i) {
|
2021-07-27 04:36:47 +00:00
|
|
|
StringBuilder L = a.L("Given job ID ", i, " is different than previous ");
|
|
|
|
L.append(this.mJobId);
|
|
|
|
throw new IllegalArgumentException(L.toString());
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void serviceProcessingFinished() {
|
|
|
|
}
|
|
|
|
|
|
|
|
public void serviceProcessingStarted() {
|
|
|
|
}
|
|
|
|
|
|
|
|
public void serviceStartReceived() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public JobIntentService() {
|
|
|
|
if (Build.VERSION.SDK_INT >= 26) {
|
|
|
|
this.mCompatQueue = null;
|
|
|
|
} else {
|
|
|
|
this.mCompatQueue = new ArrayList<>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void enqueueWork(@NonNull Context context, @NonNull ComponentName componentName, int i, @NonNull Intent intent) {
|
|
|
|
if (intent != null) {
|
|
|
|
synchronized (sLock) {
|
|
|
|
WorkEnqueuer workEnqueuer = getWorkEnqueuer(context, componentName, true, i);
|
|
|
|
workEnqueuer.ensureJobId(i);
|
|
|
|
workEnqueuer.enqueueWork(intent);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
throw new IllegalArgumentException("work must not be null");
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void enqueueWork(@NonNull Context context, @NonNull Class<?> cls, int i, @NonNull Intent intent) {
|
|
|
|
enqueueWork(context, new ComponentName(context, cls), i, intent);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static WorkEnqueuer getWorkEnqueuer(Context context, ComponentName componentName, boolean z2, int i) {
|
|
|
|
WorkEnqueuer workEnqueuer;
|
|
|
|
HashMap<ComponentName, WorkEnqueuer> hashMap = sClassWorkEnqueuer;
|
|
|
|
WorkEnqueuer workEnqueuer2 = hashMap.get(componentName);
|
|
|
|
if (workEnqueuer2 != null) {
|
|
|
|
return workEnqueuer2;
|
|
|
|
}
|
|
|
|
if (Build.VERSION.SDK_INT < 26) {
|
|
|
|
workEnqueuer = new CompatWorkEnqueuer(context, componentName);
|
|
|
|
} else if (z2) {
|
|
|
|
workEnqueuer = new JobWorkEnqueuer(context, componentName, i);
|
|
|
|
} else {
|
|
|
|
throw new IllegalArgumentException("Can't be here without a job id");
|
|
|
|
}
|
|
|
|
hashMap.put(componentName, workEnqueuer);
|
|
|
|
return workEnqueuer;
|
|
|
|
}
|
|
|
|
|
|
|
|
public GenericWorkItem dequeueWork() {
|
|
|
|
CompatJobEngine compatJobEngine = this.mJobImpl;
|
|
|
|
if (compatJobEngine != null) {
|
|
|
|
return compatJobEngine.dequeueWork();
|
|
|
|
}
|
|
|
|
synchronized (this.mCompatQueue) {
|
|
|
|
if (this.mCompatQueue.size() <= 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return this.mCompatQueue.remove(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean doStopCurrentWork() {
|
|
|
|
CommandProcessor commandProcessor = this.mCurProcessor;
|
|
|
|
if (commandProcessor != null) {
|
|
|
|
commandProcessor.cancel(this.mInterruptIfStopped);
|
|
|
|
}
|
|
|
|
this.mStopped = true;
|
|
|
|
return onStopCurrentWork();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ensureProcessorRunningLocked(boolean z2) {
|
|
|
|
if (this.mCurProcessor == null) {
|
|
|
|
this.mCurProcessor = new CommandProcessor();
|
|
|
|
WorkEnqueuer workEnqueuer = this.mCompatWorkEnqueuer;
|
|
|
|
if (workEnqueuer != null && z2) {
|
|
|
|
workEnqueuer.serviceProcessingStarted();
|
|
|
|
}
|
|
|
|
this.mCurProcessor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Void[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isStopped() {
|
|
|
|
return this.mStopped;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // android.app.Service
|
|
|
|
public IBinder onBind(@NonNull Intent intent) {
|
|
|
|
CompatJobEngine compatJobEngine = this.mJobImpl;
|
|
|
|
if (compatJobEngine != null) {
|
|
|
|
return compatJobEngine.compatGetBinder();
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // android.app.Service
|
|
|
|
public void onCreate() {
|
|
|
|
super.onCreate();
|
|
|
|
if (Build.VERSION.SDK_INT >= 26) {
|
|
|
|
this.mJobImpl = new JobServiceEngineImpl(this);
|
|
|
|
this.mCompatWorkEnqueuer = null;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.mJobImpl = null;
|
|
|
|
this.mCompatWorkEnqueuer = getWorkEnqueuer(this, new ComponentName(this, getClass()), false, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // android.app.Service
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
|
|
|
ArrayList<CompatWorkItem> arrayList = this.mCompatQueue;
|
|
|
|
if (arrayList != null) {
|
|
|
|
synchronized (arrayList) {
|
|
|
|
this.mDestroyed = true;
|
|
|
|
this.mCompatWorkEnqueuer.serviceProcessingFinished();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public abstract void onHandleWork(@NonNull Intent intent);
|
|
|
|
|
|
|
|
@Override // android.app.Service
|
|
|
|
public int onStartCommand(@Nullable Intent intent, int i, int i2) {
|
|
|
|
if (this.mCompatQueue == null) {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
this.mCompatWorkEnqueuer.serviceStartReceived();
|
|
|
|
synchronized (this.mCompatQueue) {
|
|
|
|
ArrayList<CompatWorkItem> arrayList = this.mCompatQueue;
|
|
|
|
if (intent == null) {
|
|
|
|
intent = new Intent();
|
|
|
|
}
|
|
|
|
arrayList.add(new CompatWorkItem(intent, i2));
|
|
|
|
ensureProcessorRunningLocked(true);
|
|
|
|
}
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean onStopCurrentWork() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void processorFinished() {
|
|
|
|
ArrayList<CompatWorkItem> arrayList = this.mCompatQueue;
|
|
|
|
if (arrayList != null) {
|
|
|
|
synchronized (arrayList) {
|
|
|
|
this.mCurProcessor = null;
|
|
|
|
ArrayList<CompatWorkItem> arrayList2 = this.mCompatQueue;
|
|
|
|
if (arrayList2 != null && arrayList2.size() > 0) {
|
|
|
|
ensureProcessorRunningLocked(false);
|
|
|
|
} else if (!this.mDestroyed) {
|
|
|
|
this.mCompatWorkEnqueuer.serviceProcessingFinished();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setInterruptIfStopped(boolean z2) {
|
|
|
|
this.mInterruptIfStopped = z2;
|
|
|
|
}
|
|
|
|
}
|