Bug 1505685 - Part 3 - Register HeadSetStateReceiver on the main thread; r=JanH
authorPetru Lingurar <petru.lingurar@softvision.ro>
Wed, 21 Nov 2018 12:16:34 +0200
changeset 503954 be4f0249121820f15551de0d21e6e3626526f997
parent 503953 2a75f31dcd5f81888cd5695cce9cc03d93ec8d3b
child 503955 99c2d9a02b38a9dd89219629301e62853f58f171
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersJanH
bugs1505685
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1505685 - Part 3 - Register HeadSetStateReceiver on the main thread; r=JanH Summary: Speculative fix. initialize() is called by Gecko on it's background thread after it started. The value for the "dom.audiochannel.mediaControl" preference also comes on a background thread. This both can end up registering the HeadSetStateReceiver while unregistering it happens only on the main thread. The patch tries to avoid the race condition by making sure Receiver's registering and unregistering is done serially on the main thread. Depends on D12032 Reviewers: JanH Reviewed By: JanH Subscribers: jya Bug #: 1505685 Differential Revision: https://phabricator.services.mozilla.com/D12033
mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
mobile/android/base/java/org/mozilla/gecko/media/GeckoMediaControlAgent.java
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
@@ -440,17 +440,17 @@ public class GeckoApplication extends Ap
             ThreadUtils.postToBackgroundThread(new Runnable() {
                 @Override
                 public void run() {
                     initPushService();
                 }
             });
         }
 
-        AudioFocusAgent.getInstance().attachToContext(this);
+        ThreadUtils.postToUiThread(() -> AudioFocusAgent.getInstance().attachToContext(this));
     }
 
     private class EventListener implements BundleEventListener
     {
         private void onProfileCreate(final String name, final String path) {
             // Add everything when we're done loading the distribution.
             final Context context = GeckoApplication.this;
             final GeckoProfile profile = GeckoProfile.get(context, name);
--- a/mobile/android/base/java/org/mozilla/gecko/media/GeckoMediaControlAgent.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/GeckoMediaControlAgent.java
@@ -117,16 +117,20 @@ public class GeckoMediaControlAgent {
         initialize();
     }
 
     private boolean isAttachedToContext() {
         return (mContext != null);
     }
 
     private void initialize() {
+        // Need to make sure the receiver is registered and mInitialized has it's value set
+        // serially, on the main thread.
+        ThreadUtils.assertOnUiThread();
+
         if (mInitialized) {
             return;
         }
 
         if (!isAndroidVersionLollipopOrHigher()) {
             return;
         }
 
@@ -151,31 +155,33 @@ public class GeckoMediaControlAgent {
         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
     }
 
     private void getGeckoPreference() {
         mPrefsObserver = new PrefsHelper.PrefHandlerBase() {
             @Override
             public void prefValue(String pref, boolean value) {
                 if (pref.equals(MEDIA_CONTROL_PREF)) {
-                    mIsMediaControlPrefOn = value;
+                    ThreadUtils.postToUiThread(() -> {
+                        mIsMediaControlPrefOn = value;
 
-                    // If media is playing, we just need to create or remove
-                    // the media control interface.
-                    if (sMediaState.equals(State.PLAYING)) {
-                        setState(mIsMediaControlPrefOn ? State.PLAYING : State.STOPPED);
-                    }
+                        // If media is playing, we just need to create or remove
+                        // the media control interface.
+                        if (sMediaState.equals(State.PLAYING)) {
+                            setState(mIsMediaControlPrefOn ? State.PLAYING : State.STOPPED);
+                        }
 
-                    // If turn off pref during pausing, except removing media
-                    // interface, we also need to stop the service and notify
-                    // gecko about that.
-                    if (sMediaState.equals(State.PAUSED) &&
-                            !mIsMediaControlPrefOn) {
-                        handleAction(ACTION_STOP);
-                    }
+                        // If turn off pref during pausing, except removing media
+                        // interface, we also need to stop the service and notify
+                        // gecko about that.
+                        if (sMediaState.equals(State.PAUSED) &&
+                                !mIsMediaControlPrefOn) {
+                            handleAction(ACTION_STOP);
+                        }
+                    });
                 }
             }
         };
         PrefsHelper.addObserver(mPrefs, mPrefsObserver);
     }
 
     private boolean initMediaSession() {
         // Android MediaSession is introduced since version L.
@@ -536,26 +542,17 @@ public class GeckoMediaControlAgent {
         @CheckResult(suggest = "new HeadSetStateReceiver().registerReceiver(Context)")
         HeadSetStateReceiver registerReceiver(Context context) {
             IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
             context.registerReceiver(this, intentFilter);
             return this;
         }
 
         void unregisterReceiver(Context context) {
-            try {
-                // TODO investigate why the receiver would not be registered - bug 1505685
-                context.unregisterReceiver(HeadSetStateReceiver.this);
-            } catch (IllegalArgumentException e) {
-                if (AppConstants.RELEASE_OR_BETA) {
-                    Log.w(LOGTAG, "bug 1505685", e);
-                } else {
-                    throw e;
-                }
-            }
+            context.unregisterReceiver(HeadSetStateReceiver.this);
         }
 
         @Override
         public void onReceive(Context context, Intent intent) {
             if (isMediaPlaying()) {
                 handleAction(ACTION_PAUSE);
             }
         }