Bug 1505685 - Part 3 - Register HeadSetStateReceiver on the main thread; r=JanH
☠☠ backed out by 86d8ead0b9a5 ☠ ☠
authorPetru Lingurar <petru.lingurar@softvision.ro>
Wed, 21 Nov 2018 11:21:52 +0200
changeset 506729 6e2a67a9a9c9b5d15e9231716f869fc522dfa99b
parent 506728 a46710b7723fc89bc3e51b437d59f5c169bab1f6
child 506730 86d8ead0b9a51d9cd0f780e0c279f8a86d2b187e
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [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);
             }
         }