Loading services/core/java/com/android/server/location/provider/LocationProviderManager.java +56 −2 Original line number Diff line number Diff line Loading @@ -243,15 +243,24 @@ public class LocationProviderManager extends 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( mContext, 0, intent, onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run() : null, (pI, i, rC, rD, rE) -> gatedCallback.run(), null, null, options.toBundle()); gatedCallback.allow(); } @Override Loading Loading @@ -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(); } } } } Loading
services/core/java/com/android/server/location/provider/LocationProviderManager.java +56 −2 Original line number Diff line number Diff line Loading @@ -243,15 +243,24 @@ public class LocationProviderManager extends 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( mContext, 0, intent, onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run() : null, (pI, i, rC, rD, rE) -> gatedCallback.run(), null, null, options.toBundle()); gatedCallback.allow(); } @Override Loading Loading @@ -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(); } } } }