Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LeakCanary reports AudioManager leak #432

Closed
1 task done
stanmots opened this issue Apr 19, 2017 · 4 comments
Closed
1 task done

LeakCanary reports AudioManager leak #432

stanmots opened this issue Apr 19, 2017 · 4 comments
Milestone

Comments

@stanmots
Copy link
Contributor

stanmots commented Apr 19, 2017

  • I have verified there are no duplicate active or recent bugs, questions, or requests
Include the following:
  • ExoMedia version: 4.0.0-preview4 and 3.1.1
  • Android Emulator with 19
Reproduction Steps
  • Launch/close an Activity with ExoMedia video player several times when LeakCanary is enabled.

This is a known issue of the Android's AudioManager. It was added to the LeakCanary excluded list since it was officially fixed in Android M. More info here. However, there is a fix for older API which you can find here.

I've looked through the ExoMedia source code and it seems that you just need to replace this line with

audioManager = (AudioManager) context.getApplicationContext()
                .getSystemService(Context.AUDIO_SERVICE);

i.d. the audio manager should use the application context.

Here is the LeakCanary relevant logcat snippet:

: * EXCLUDED LEAK.
: * com.test.VideoActivity has leaked:
: * GC ROOT android.media.AudioManager$1.this$0 (anonymous subclass of android.media.IAudioFocusDispatcher$Stub) , matching exclusion field android.media.AudioManager$1#this$0
: * references android.media.AudioManager.mContext
: * references android.app.ContextImpl.mOuterContext
: * leaks com.test.VideoActivity instance
: * Retaining: 83KB.
: * Reference Key: f1899298-cc39-44c1-92d3-6d7d2a329421
: * Device: unknown generic_x86 Android SDK built for x86 google_sdk_x86
: * Android Version: 4.4.2 API: 19 LeakCanary: 1.5 00f37f5
: * Durations: watch=6084ms, gc=129ms, heap dump=200ms, analysis=6601ms
: * Details:
: * Instance of android.media.AudioManager$1
: |   this$0 = android.media.AudioManager@2907338536 (0xad4a7728)
: |   mDescriptor = java.lang.String@2900754184 (0xace5ff08)
: |   mOwner = android.media.AudioManager$1@2907338776 (0xad4a7818)
: |   mObject = -1213348400
: * Instance of android.media.AudioManager
: |   static ACTION_SCO_AUDIO_STATE_UPDATED = java.lang.String@2900750592 (0xace5f100)
: |   static sService = android.media.IAudioService$Stub$Proxy@2902817792 (0xad057c00)
: |   static MODE_IN_COMMUNICATION = 3
: |   static MASTER_MUTE_CHANGED_ACTION = java.lang.String@2900752112 (0xace5f6f0)
: |   static EXTRA_PREV_MASTER_VOLUME_VALUE = java.lang.String@2900750984 (0xace5f288)
: |   static DEVICE_OUT_USB_ACCESSORY = 8192
: |   static FLAG_PLAY_SOUND = 4
: |   static $staticOverhead = byte[2616]@2900747561 (0xace5e529)
: |   static DEVICE_OUT_DEFAULT = 1073741824
: |   static DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 512
: |   static AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4
: |   static FX_KEYPRESS_INVALID = 9
: |   static ROUTE_SPEAKER = 2
: |   static STREAM_VOICE_CALL = 0
: |   static VIBRATE_SETTING_CHANGED_ACTION = java.lang.String@2900752776 (0xace5f988)
: |   static STREAM_MUSIC = 3
: |   static PROPERTY_OUTPUT_SAMPLE_RATE = java.lang.String@2900752520 (0xace5f888)
: |   static AUDIOFOCUS_GAIN_TRANSIENT = 2
: |   static MODE_IN_CALL = 2
: |   static ROUTE_EARPIECE = 1
: |   static RINGER_MODE_CHANGED_ACTION = java.lang.String@2900752656 (0xace5f910)
: |   static SCO_AUDIO_STATE_CONNECTING = 2
: |   static TAG = java.lang.String@2900753024 (0xace5fa80)
: |   static STREAM_SYSTEM_ENFORCED = 7
: |   static FLAG_BLUETOOTH_ABS_VOLUME = 64
: |   static ADJUST_LOWER = -1
: |   static FX_FOCUS_NAVIGATION_UP = 1
: |   static STREAM_RING = 2
: |   static ADJUST_SAME = 0
: |   static RINGER_MODE_MAX = 2
: |   static ROUTE_HEADSET = 8
: |   static AUDIOFOCUS_LOSS = -1
: |   static EXTRA_VIBRATE_TYPE = java.lang.String@2900751744 (0xace5f580)
: |   static RINGER_MODE_VIBRATE = 1
: |   static FLAG_ALLOW_RINGER_MODES = 2
: |   static AUDIOFOCUS_GAIN = 1
: |   static VIBRATE_SETTING_ONLY_SILENT = 2
: |   static STREAM_ALARM = 4
: |   static FX_FOCUS_NAVIGATION_DOWN = 2
: |   static EXTRA_MASTER_VOLUME_MUTED = java.lang.String@2900750728 (0xace5f188)
: |   static VIBRATE_SETTING_ON = 1
: |   static AUDIOFOCUS_REQUEST_GRANTED = 1
: |   static STREAM_TTS = 9
: |   static DEVICE_OUT_EARPIECE = 1
: |   static FX_FOCUS_NAVIGATION_LEFT = 3
: |   static EXTRA_SCO_AUDIO_STATE = java.lang.String@2900751504 (0xace5f490)
: |   static RINGER_MODE_NORMAL = 2
: |   static FX_KEYPRESS_SPACEBAR = 6
: |   static DEVICE_OUT_DGTL_DOCK_HEADSET = 4096
: |   static EXTRA_VOLUME_STREAM_VALUE = java.lang.String@2900751984 (0xace5f670)
: |   static EXTRA_PREV_VOLUME_STREAM_VALUE = java.lang.String@2900751120 (0xace5f310)
: |   static EXTRA_MASTER_VOLUME_VALUE = java.lang.String@2900750856 (0xace5f208)
: |   static ROUTE_BLUETOOTH = 4
: |   static DEVICE_OUT_AUX_DIGITAL = 1024
: |   static STREAM_SYSTEM = 1
: |   static DEFAULT_STREAM_VOLUME = int[10]@2900753096 (0xace5fac8)
: |   static FLAG_SHOW_UI = 1
: |   static ADJUST_RAISE = 1
: |   static DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 256
: |   static STREAM_DTMF = 8
: |   static STREAM_NOTIFICATION = 5
: |   static SCO_AUDIO_STATE_DISCONNECTED = 0
: |   static FX_KEYPRESS_DELETE = 7
: |   static FLAG_FIXED_VOLUME = 32
: |   static ACTION_SCO_AUDIO_STATE_CHANGED = java.lang.String@2900750464 (0xace5f080)
: |   static AUDIOFOCUS_LOSS_TRANSIENT = -2
: |   static MODE_RINGTONE = 1
: |   static DEVICE_OUT_WIRED_HEADSET = 4
: |   static VIBRATE_SETTING_OFF = 0
: |   static MODE_NORMAL = 0
: |   static SCO_AUDIO_STATE_ERROR = -1
: |   static RINGER_MODE_SILENT = 0
: |   static AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3
: |   static DEVICE_OUT_BLUETOOTH_A2DP = 128
: |   static DEVICE_OUT_ANLG_DOCK_HEADSET = 2048
: |   static USE_DEFAULT_STREAM_TYPE = -2147483648
: |   static ROUTE_BLUETOOTH_SCO = 4
: |   static VIBRATE_TYPE_NOTIFICATION = 1
: |   static SCO_AUDIO_STATE_CONNECTED = 1
: |   static DEVICE_OUT_BLUETOOTH_SCO = 16
: |   static ACTION_AUDIO_BECOMING_NOISY = java.lang.String@2900750344 (0xace5f008)
: |   static VOLUME_CHANGED_ACTION = java.lang.String@2900752904 (0xace5fa08)
: |   static FX_FOCUS_NAVIGATION_RIGHT = 4
: |   static EXTRA_VIBRATE_SETTING = java.lang.String@2900751624 (0xace5f508)
: |   static FLAG_VIBRATE = 16
: |   static FLAG_REMOVE_SOUND_AND_VIBRATE = 8
: |   static FX_KEYPRESS_STANDARD = 5
: |   static DEVICE_OUT_SPEAKER = 2
: |   static DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 32
: |   static ROUTE_BLUETOOTH_A2DP = 16
: |   static PROPERTY_OUTPUT_FRAMES_PER_BUFFER = java.lang.String@2900752376 (0xace5f7f8)
: |   static STREAM_BLUETOOTH_SCO = 6
: |   static DEVICE_OUT_USB_DEVICE = 16384
: |   static DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 64
: |   static FX_KEY_CLICK = 0
: |   static MASTER_VOLUME_CHANGED_ACTION = java.lang.String@2900752240 (0xace5f770)
: |   static AUDIOFOCUS_REQUEST_FAILED = 0
: |   static NUM_SOUND_EFFECTS = 10
: |   static NUM_STREAMS = 5
: |   static AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3
: |   static FX_KEYPRESS_RETURN = 8
: |   static MODE_CURRENT = -1
: |   static EXTRA_VOLUME_STREAM_TYPE = java.lang.String@2900751856 (0xace5f5f0)
: |   static EXTRA_SCO_AUDIO_PREVIOUS_STATE = java.lang.String@2900751368 (0xace5f408)
: |   static ROUTE_ALL = -1
: |   static MODE_INVALID = -2
: |   static VIBRATE_TYPE_RINGER = 0
: |   static DEVICE_OUT_WIRED_HEADPHONE = 8
: |   static AUDIOFOCUS_NONE = 0
: |   static EXTRA_RINGER_MODE = java.lang.String@2900751256 (0xace5f398)
: |   mAudioFocusDispatcher = android.media.AudioManager$1@2907338776 (0xad4a7818)
: |   mAudioFocusEventHandlerDelegate = android.media.AudioManager$FocusEventHandlerDelegate@2907338712 (0xad4a77d8)
: |   mAudioFocusIdListenerMap = java.util.HashMap@2907338656 (0xad4a77a0)
: |   mContext = android.app.ContextImpl@2909980064 (0xad72c5a0)
: |   mFocusListenerLock = java.lang.Object@2909937776 (0xad722070)
: |   mICallBack = android.os.Binder@2907338848 (0xad4a7860)
: |   mToken = android.os.Binder@2907338592 (0xad4a7760)
: |   mUseMasterVolume = false
: |   mVolumeKeyUpTime = 0
: |   mUseVolumeKeySounds = true
: * Instance of android.app.ContextImpl
: |   static sSharedPrefs = null
: |   static sNextPerContextServiceCacheIndex = 39
: |   static SYSTEM_SERVICE_MAP = java.util.HashMap@2900513928 (0xace25488)
: |   static WALLPAPER_FETCHER = android.app.ContextImpl$1@2900351896 (0xacdfdb98)
: |   static $staticOverhead = byte[168]@2900469497 (0xace1a6f9)
: |   static TAG = java.lang.String@2900513856 (0xace25440)
: |   static EMPTY_FILE_LIST = java.lang.String[0]@2900336392 (0xacdf9f08)
: |   static DEBUG = false
: |   mActivityToken = android.os.BinderProxy@2907165080 (0xad47d198)
: |   mBasePackageName = java.lang.String@2902656888 (0xad030778)
: |   mCacheDir = null
: |   mContentResolver = android.app.ContextImpl$ApplicationContentResolver@2903362440 (0xad0dcb88)
: |   mDatabasesDir = null
: |   mDisplay = null
: |   mDisplayAdjustments = android.view.DisplayAdjustments@2907538064 (0xad4d8290)
: |   mExternalCacheDirs = null
: |   mExternalFilesDirs = null
: |   mExternalObbDirs = null
: |   mFilesDir = null
: |   mMainThread = android.app.ActivityThread@2902654384 (0xad02fdb0)
: |   mOpPackageName = java.lang.String@2902656888 (0xad030778)
: |   mOuterContext = com.test.VideoActivity@2903352256 (0xad0da3c0)
: |   mPackageInfo = android.app.LoadedApk@2902670056 (0xad033ae8)
: |   mPackageManager = android.app.ApplicationPackageManager@2907528496 (0xad4d5d30)
: |   mPreferencesDir = null
: |   mReceiverRestrictedContext = null
: |   mResources = android.content.res.Resources@2902671208 (0xad033f68)
: |   mResourcesManager = android.app.ResourcesManager@2902655248 (0xad030110)
: |   mUser = android.os.UserHandle@2907208904 (0xad487cc8)
: |   mServiceCache = java.util.ArrayList@2907534568 (0xad4d74e8)
: |   mSync = java.lang.Object@2907219520 (0xad48a640)
: |   mTheme = android.content.res.Resources$Theme@2907337608 (0xad4a7388)
: |   mThemeResource = 16974120
: |   mRestricted = false
: * Excluded Refs:
: | Field: android.app.ActivityThread$ActivityClientRecord.nextIdle
: | Field: android.widget.Editor$EasyEditSpanController.this$0
: | Field: android.widget.Editor$SpanController.this$0
: | Field: android.os.Message.obj
: | Field: android.os.Message.next
: | Field: android.os.Message.target
: | Field: android.view.inputmethod.InputMethodManager.mNextServedView
: | Field: android.view.inputmethod.InputMethodManager.mServedView
: | Field: android.view.inputmethod.InputMethodManager.mServedInputConnection
: | Field: android.view.inputmethod.InputMethodManager.mCurRootView
: | Field: android.animation.LayoutTransition$1.val$parent
: | Field: android.view.textservice.SpellCheckerSession$1.this$0
: | Field: android.support.v7.internal.widget.ActivityChooserModel.mActivityChoserModelPolicy
: | Field: android.widget.ActivityChooserModel.mActivityChoserModelPolicy
: | Field: android.speech.SpeechRecognizer$InternalListener.this$0
: | Field: android.accounts.AccountManager$AmsTask$Response.this$1
: | Field: android.media.MediaScannerConnection.mContext
: | Field: android.os.UserManager.mContext
: | Field: android.appwidget.AppWidgetHost$Callbacks.this$0
: | Field: android.media.AudioManager$1.this$0
: | Field: android.widget.Editor$Blink.this$0
: | Field: android.net.ConnectivityManager.sInstance
: | Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
: | Static field: android.text.TextLine.sCached
: | Thread:FinalizerWatchdogDaemon (always)
: | Thread:main (always)
: | Thread:LeakCanary-Heap-Dump (always)
: | Class:java.lang.ref.WeakReference (always)
: | Class:java.lang.ref.SoftReference (always)
: | Class:java.lang.ref.PhantomReference (always)
: | Class:java.lang.ref.Finalizer (always)
: | Class:java.lang.ref.FinalizerReference (always)
@brianwernick
Copy link
Owner

This isn't an issue in ExoMedia itself, nor is the fix something that would be owned by ExoMedia (as it requires Activity modifications). I can make the changes to the demo app though

@stanmots
Copy link
Contributor Author

stanmots commented Apr 21, 2017

Yes, you are right. It's one of the Android's bugs. I just thought it would be better to change the context to the application context to prevent LeakCanary warnings.

Currently I'm using a VideoView subclass where I'm overriding the setup method for this purpose:

    override fun setup(context: Context, attrs: AttributeSet?) {
        if (isInEditMode) {
            return
        }

        audioManager = context.applicationContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager

        val attributeContainer = AttributeContainer(context, attrs)
        initView(context, attributeContainer)
        postInit(attributeContainer)
    }

@brianwernick
Copy link
Owner

Oh, yeah I can do that; or you can change it in the dev_v4 branch and create a PR

@brianwernick brianwernick added this to the 4.0.0 milestone Apr 21, 2017
@stanmots
Copy link
Contributor Author

Ok, I'll do it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants