Merge "Only allow completion callback to be run once for PIs" into sc-qpr1-dev am: b53041d1eb am: 0a0cb88bba

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15890710

Change-Id: Ie1420e0065a763cfed304be1b116d8718f5544a2
This commit is contained in:
Soonil Nagarkar
2021-09-23 15:34:06 +00:00
committed by Automerger Merge Worker

View File

@@ -243,15 +243,24 @@ public class LocationProviderManager extends
intent.putExtra(KEY_LOCATIONS, locationResult.asList().toArray(new Location[0])); intent.putExtra(KEY_LOCATIONS, locationResult.asList().toArray(new Location[0]));
} }
// send() SHOULD only run the completion callback if it completes successfully. however,
// b/199464864 (which could not be fixed in the S timeframe) means that it's possible
// for send() to throw an exception AND run the completion callback. if this happens, we
// would over-release the wakelock... we take matters into our own hands to ensure that
// the completion callback can only be run if send() completes successfully. this means
// the completion callback may be run inline - but as we've never specified what thread
// the callback is run on, this is fine.
GatedCallback gatedCallback = new GatedCallback(onCompleteCallback);
mPendingIntent.send( mPendingIntent.send(
mContext, mContext,
0, 0,
intent, intent,
onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run() (pI, i, rC, rD, rE) -> gatedCallback.run(),
: null,
null, null,
null, null,
options.toBundle()); options.toBundle());
gatedCallback.allow();
} }
@Override @Override
@@ -2734,4 +2743,49 @@ public class LocationProviderManager extends
} }
} }
} }
private static class GatedCallback implements Runnable {
private @Nullable Runnable mCallback;
@GuardedBy("this")
private boolean mGate;
@GuardedBy("this")
private boolean mRun;
GatedCallback(Runnable callback) {
mCallback = callback;
}
public void allow() {
Runnable callback = null;
synchronized (this) {
mGate = true;
if (mRun && mCallback != null) {
callback = mCallback;
mCallback = null;
}
}
if (callback != null) {
callback.run();
}
}
@Override
public void run() {
Runnable callback = null;
synchronized (this) {
mRun = true;
if (mGate && mCallback != null) {
callback = mCallback;
mCallback = null;
}
}
if (callback != null) {
callback.run();
}
}
}
} }