diff options
| author | 2017-04-15 00:55:50 +0000 | |
|---|---|---|
| committer | 2017-04-15 00:55:55 +0000 | |
| commit | aaeb51233145762bdb418b3584fc6d4df9a09c8e (patch) | |
| tree | 4a1bd60f42360370c8f8be46cbea072ded625ace | |
| parent | a05f1fdd9339f1e13d47208beb1c389a2d3e2009 (diff) | |
| parent | 579f75c8a41faf69164ddfd5be45d4d5f50d02e5 (diff) | |
Merge "Introduce a new JobServiceEngine class." into oc-dev
| -rw-r--r-- | api/current.txt | 8 | ||||
| -rw-r--r-- | api/system-current.txt | 8 | ||||
| -rw-r--r-- | api/test-current.txt | 8 | ||||
| -rw-r--r-- | core/java/android/app/job/JobService.java | 166 | ||||
| -rw-r--r-- | core/java/android/app/job/JobServiceEngine.java | 223 |
5 files changed, 260 insertions, 153 deletions
diff --git a/api/current.txt b/api/current.txt index 3540b26291f7..ddce8aea75b3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6870,6 +6870,14 @@ package android.app.job { field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE"; } + public abstract class JobServiceEngine { + ctor public JobServiceEngine(android.content.Context); + method public final android.os.IBinder getBinder(); + method public final void jobFinished(android.app.job.JobParameters, boolean); + method public abstract boolean onStartJob(android.app.job.JobParameters); + method public abstract boolean onStopJob(android.app.job.JobParameters); + } + public final class JobWorkItem implements android.os.Parcelable { ctor public JobWorkItem(android.content.Intent); ctor public JobWorkItem(android.os.Parcel); diff --git a/api/system-current.txt b/api/system-current.txt index 44dabb75ea56..53babc5bf28b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -7304,6 +7304,14 @@ package android.app.job { field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE"; } + public abstract class JobServiceEngine { + ctor public JobServiceEngine(android.content.Context); + method public final android.os.IBinder getBinder(); + method public final void jobFinished(android.app.job.JobParameters, boolean); + method public abstract boolean onStartJob(android.app.job.JobParameters); + method public abstract boolean onStopJob(android.app.job.JobParameters); + } + public final class JobWorkItem implements android.os.Parcelable { ctor public JobWorkItem(android.content.Intent); ctor public JobWorkItem(android.os.Parcel); diff --git a/api/test-current.txt b/api/test-current.txt index d83bd7b75543..9b7bd5eb11fa 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -6900,6 +6900,14 @@ package android.app.job { field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE"; } + public abstract class JobServiceEngine { + ctor public JobServiceEngine(android.content.Context); + method public final android.os.IBinder getBinder(); + method public final void jobFinished(android.app.job.JobParameters, boolean); + method public abstract boolean onStartJob(android.app.job.JobParameters); + method public abstract boolean onStopJob(android.app.job.JobParameters); + } + public final class JobWorkItem implements android.os.Parcelable { ctor public JobWorkItem(android.content.Intent); ctor public JobWorkItem(android.os.Parcel); diff --git a/core/java/android/app/job/JobService.java b/core/java/android/app/job/JobService.java index f4019ce446f7..9096b47b8d4d 100644 --- a/core/java/android/app/job/JobService.java +++ b/core/java/android/app/job/JobService.java @@ -60,161 +60,24 @@ public abstract class JobService extends Service { public static final String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE"; - /** - * Identifier for a message that will result in a call to - * {@link #onStartJob(android.app.job.JobParameters)}. - */ - private static final int MSG_EXECUTE_JOB = 0; - /** - * Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}. - */ - private static final int MSG_STOP_JOB = 1; - /** - * Message that the client has completed execution of this job. - */ - private static final int MSG_JOB_FINISHED = 2; - - /** Lock object for {@link #mHandler}. */ - private final Object mHandlerLock = new Object(); - - /** - * Handler we post jobs to. Responsible for calling into the client logic, and handling the - * callback to the system. - */ - @GuardedBy("mHandlerLock") - JobHandler mHandler; - - static final class JobInterface extends IJobService.Stub { - final WeakReference<JobService> mService; - - JobInterface(JobService service) { - mService = new WeakReference<>(service); - } - - @Override - public void startJob(JobParameters jobParams) throws RemoteException { - JobService service = mService.get(); - if (service != null) { - service.ensureHandler(); - Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams); - m.sendToTarget(); - } - } - - @Override - public void stopJob(JobParameters jobParams) throws RemoteException { - JobService service = mService.get(); - if (service != null) { - service.ensureHandler(); - Message m = Message.obtain(service.mHandler, MSG_STOP_JOB, jobParams); - m.sendToTarget(); - } - - } - } - - IJobService mBinder; + private JobServiceEngine mEngine; /** @hide */ - void ensureHandler() { - synchronized (mHandlerLock) { - if (mHandler == null) { - mHandler = new JobHandler(getMainLooper()); - } - } - } - - /** - * Runs on application's main thread - callbacks are meant to offboard work to some other - * (app-specified) mechanism. - * @hide - */ - class JobHandler extends Handler { - JobHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - final JobParameters params = (JobParameters) msg.obj; - switch (msg.what) { - case MSG_EXECUTE_JOB: - try { - boolean workOngoing = JobService.this.onStartJob(params); - ackStartMessage(params, workOngoing); - } catch (Exception e) { - Log.e(TAG, "Error while executing job: " + params.getJobId()); - throw new RuntimeException(e); - } - break; - case MSG_STOP_JOB: - try { - boolean ret = JobService.this.onStopJob(params); - ackStopMessage(params, ret); - } catch (Exception e) { - Log.e(TAG, "Application unable to handle onStopJob.", e); - throw new RuntimeException(e); - } - break; - case MSG_JOB_FINISHED: - final boolean needsReschedule = (msg.arg2 == 1); - IJobCallback callback = params.getCallback(); - if (callback != null) { - try { - callback.jobFinished(params.getJobId(), needsReschedule); - } catch (RemoteException e) { - Log.e(TAG, "Error reporting job finish to system: binder has gone" + - "away."); - } - } else { - Log.e(TAG, "finishJob() called for a nonexistent job id."); - } - break; - default: - Log.e(TAG, "Unrecognised message received."); - break; - } - } - - private void ackStartMessage(JobParameters params, boolean workOngoing) { - final IJobCallback callback = params.getCallback(); - final int jobId = params.getJobId(); - if (callback != null) { - try { - callback.acknowledgeStartMessage(jobId, workOngoing); - } catch(RemoteException e) { - Log.e(TAG, "System unreachable for starting job."); - } - } else { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Attempting to ack a job that has already been processed."); + public final IBinder onBind(Intent intent) { + if (mEngine == null) { + mEngine = new JobServiceEngine(this) { + @Override + public boolean onStartJob(JobParameters params) { + return JobService.this.onStartJob(params); } - } - } - private void ackStopMessage(JobParameters params, boolean reschedule) { - final IJobCallback callback = params.getCallback(); - final int jobId = params.getJobId(); - if (callback != null) { - try { - callback.acknowledgeStopMessage(jobId, reschedule); - } catch(RemoteException e) { - Log.e(TAG, "System unreachable for stopping job."); + @Override + public boolean onStopJob(JobParameters params) { + return JobService.this.onStopJob(params); } - } else { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Attempting to ack a job that has already been processed."); - } - } - } - } - - /** @hide */ - public final IBinder onBind(Intent intent) { - if (mBinder == null) { - mBinder = new JobInterface(this); + }; } - return mBinder.asBinder(); + return mEngine.getBinder(); } /** @@ -269,9 +132,6 @@ public abstract class JobService extends Service { * criteria specified at schedule-time. False otherwise. */ public final void jobFinished(JobParameters params, boolean needsReschedule) { - ensureHandler(); - Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params); - m.arg2 = needsReschedule ? 1 : 0; - m.sendToTarget(); + mEngine.jobFinished(params, needsReschedule); } }
\ No newline at end of file diff --git a/core/java/android/app/job/JobServiceEngine.java b/core/java/android/app/job/JobServiceEngine.java new file mode 100644 index 000000000000..879212ea1fb3 --- /dev/null +++ b/core/java/android/app/job/JobServiceEngine.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.app.job; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; + +import java.lang.ref.WeakReference; + +/** + * Helper for implementing a {@link android.app.Service} that interacts with + * {@link JobScheduler}. + */ +public abstract class JobServiceEngine { + private static final String TAG = "JobServiceEngine"; + + /** + * Identifier for a message that will result in a call to + * {@link #onStartJob(android.app.job.JobParameters)}. + */ + private static final int MSG_EXECUTE_JOB = 0; + /** + * Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}. + */ + private static final int MSG_STOP_JOB = 1; + /** + * Message that the client has completed execution of this job. + */ + private static final int MSG_JOB_FINISHED = 2; + + /** + * Context we are running in. + */ + private final Context mContext; + + private final IJobService mBinder; + + /** Lock object for {@link #mHandler}. */ + private final Object mHandlerLock = new Object(); + + /** + * Handler we post jobs to. Responsible for calling into the client logic, and handling the + * callback to the system. + */ + @GuardedBy("mHandlerLock") + JobHandler mHandler; + + static final class JobInterface extends IJobService.Stub { + final WeakReference<JobServiceEngine> mService; + + JobInterface(JobServiceEngine service) { + mService = new WeakReference<>(service); + } + + @Override + public void startJob(JobParameters jobParams) throws RemoteException { + JobServiceEngine service = mService.get(); + if (service != null) { + Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams); + m.sendToTarget(); + } + } + + @Override + public void stopJob(JobParameters jobParams) throws RemoteException { + JobServiceEngine service = mService.get(); + if (service != null) { + Message m = Message.obtain(service.mHandler, MSG_STOP_JOB, jobParams); + m.sendToTarget(); + } + } + } + + /** + * Runs on application's main thread - callbacks are meant to offboard work to some other + * (app-specified) mechanism. + * @hide + */ + class JobHandler extends Handler { + JobHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + final JobParameters params = (JobParameters) msg.obj; + switch (msg.what) { + case MSG_EXECUTE_JOB: + try { + boolean workOngoing = JobServiceEngine.this.onStartJob(params); + ackStartMessage(params, workOngoing); + } catch (Exception e) { + Log.e(TAG, "Error while executing job: " + params.getJobId()); + throw new RuntimeException(e); + } + break; + case MSG_STOP_JOB: + try { + boolean ret = JobServiceEngine.this.onStopJob(params); + ackStopMessage(params, ret); + } catch (Exception e) { + Log.e(TAG, "Application unable to handle onStopJob.", e); + throw new RuntimeException(e); + } + break; + case MSG_JOB_FINISHED: + final boolean needsReschedule = (msg.arg2 == 1); + IJobCallback callback = params.getCallback(); + if (callback != null) { + try { + callback.jobFinished(params.getJobId(), needsReschedule); + } catch (RemoteException e) { + Log.e(TAG, "Error reporting job finish to system: binder has gone" + + "away."); + } + } else { + Log.e(TAG, "finishJob() called for a nonexistent job id."); + } + break; + default: + Log.e(TAG, "Unrecognised message received."); + break; + } + } + + private void ackStartMessage(JobParameters params, boolean workOngoing) { + final IJobCallback callback = params.getCallback(); + final int jobId = params.getJobId(); + if (callback != null) { + try { + callback.acknowledgeStartMessage(jobId, workOngoing); + } catch(RemoteException e) { + Log.e(TAG, "System unreachable for starting job."); + } + } else { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Attempting to ack a job that has already been processed."); + } + } + } + + private void ackStopMessage(JobParameters params, boolean reschedule) { + final IJobCallback callback = params.getCallback(); + final int jobId = params.getJobId(); + if (callback != null) { + try { + callback.acknowledgeStopMessage(jobId, reschedule); + } catch(RemoteException e) { + Log.e(TAG, "System unreachable for stopping job."); + } + } else { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Attempting to ack a job that has already been processed."); + } + } + } + } + + /** + * Create a new engine, ready for use. + * + * @param context The {@link Service} that is creating this engine. + */ + public JobServiceEngine(Context context) { + mContext = context; + mBinder = new JobInterface(this); + mHandler = new JobHandler(mContext.getMainLooper()); + } + + /** + * Retrieve the engine's IPC interface that should be returned by + * {@link Service#onBind(Intent)}. + */ + public final IBinder getBinder() { + return mBinder.asBinder(); + } + + /** + * Engine's report that a job has started. See + * {@link JobService#onStartJob(JobParameters) JobService.onStartJob} for more information. + */ + public abstract boolean onStartJob(JobParameters params); + + /** + * Engine's report that a job has stopped. See + * {@link JobService#onStopJob(JobParameters) JobService.onStopJob} for more information. + */ + public abstract boolean onStopJob(JobParameters params); + + /** + * Call in to engine to report that a job has finished executing. See + * {@link JobService#jobFinished(JobParameters, boolean)} JobService.jobFinished} for more + * information. + */ + public final void jobFinished(JobParameters params, boolean needsReschedule) { + Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params); + m.arg2 = needsReschedule ? 1 : 0; + m.sendToTarget(); + } +}
\ No newline at end of file |