Merge "DO NOT MERGE Race condition in JobServiceContext" into mnc-dr-dev

am: cf43b5523f

* commit 'cf43b5523fd12fdc69ea25cb6dbf5e95724927ec':
  DO NOT MERGE Race condition in JobServiceContext
This commit is contained in:
Matthew Williams
2015-10-20 22:15:36 +00:00
committed by android-build-merger
2 changed files with 33 additions and 10 deletions

View File

@@ -108,7 +108,13 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
int mVerb; int mVerb;
private AtomicBoolean mCancelled = new AtomicBoolean(); private AtomicBoolean mCancelled = new AtomicBoolean();
/** All the information maintained about the job currently being executed. */ /**
* All the information maintained about the job currently being executed.
*
* Any reads (dereferences) not done from the handler thread must be synchronized on
* {@link #mLock}.
* Writes can only be done from the handler thread, or {@link #executeRunnableJob(JobStatus)}.
*/
private JobStatus mRunningJob; private JobStatus mRunningJob;
/** Binder to the client service. */ /** Binder to the client service. */
IJobService service; IJobService service;
@@ -192,7 +198,8 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
*/ */
JobStatus getRunningJob() { JobStatus getRunningJob() {
synchronized (mLock) { synchronized (mLock) {
return mRunningJob; return mRunningJob == null ?
null : new JobStatus(mRunningJob);
} }
} }
@@ -253,15 +260,22 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
*/ */
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
if (!name.equals(mRunningJob.getServiceComponent())) { JobStatus runningJob;
synchronized (mLock) {
// This isn't strictly necessary b/c the JobServiceHandler is running on the main
// looper and at this point we can't get any binder callbacks from the client. Better
// safe than sorry.
runningJob = mRunningJob;
}
if (runningJob == null || !name.equals(runningJob.getServiceComponent())) {
mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget(); mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
return; return;
} }
this.service = IJobService.Stub.asInterface(service); this.service = IJobService.Stub.asInterface(service);
final PowerManager pm = final PowerManager pm =
(PowerManager) mContext.getSystemService(Context.POWER_SERVICE); (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mRunningJob.getTag()); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag());
mWakeLock.setWorkSource(new WorkSource(mRunningJob.getUid())); mWakeLock.setWorkSource(new WorkSource(runningJob.getUid()));
mWakeLock.setReferenceCounted(false); mWakeLock.setReferenceCounted(false);
mWakeLock.acquire(); mWakeLock.acquire();
mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget(); mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
@@ -279,13 +293,15 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
* @return True if the binder calling is coming from the client we expect. * @return True if the binder calling is coming from the client we expect.
*/ */
private boolean verifyCallingUid() { private boolean verifyCallingUid() {
if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) { synchronized (mLock) {
if (DEBUG) { if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) {
Slog.d(TAG, "Stale callback received, ignoring."); if (DEBUG) {
Slog.d(TAG, "Stale callback received, ignoring.");
}
return false;
} }
return false; return true;
} }
return true;
} }
/** /**

View File

@@ -82,6 +82,13 @@ public class JobStatus {
this.numFailures = numFailures; this.numFailures = numFailures;
} }
/** Copy constructor. */
public JobStatus(JobStatus jobStatus) {
this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getNumFailures());
this.earliestRunTimeElapsedMillis = jobStatus.getEarliestRunTime();
this.latestRunTimeElapsedMillis = jobStatus.getLatestRunTimeElapsed();
}
/** Create a newly scheduled job. */ /** Create a newly scheduled job. */
public JobStatus(JobInfo job, int uId) { public JobStatus(JobInfo job, int uId) {
this(job, uId, 0); this(job, uId, 0);