Fix context leak
Using an activity context with AudioManager could cause that context to be held on to longer than desired, for example if the caller acquired audio focus but never abandoned it. Fix acquire/abandon in VideoView, and use the application context in AudioManager to mitigate the issue for other misbehaving code. Bug: https://code.google.com/p/android/issues/detail?id=152173 Change-Id: I0fb8390207422c784800dda25b1f2c03d4574bcd
This commit is contained in:
@@ -311,6 +311,8 @@ public class VideoView extends SurfaceView
|
||||
mMediaPlayer = null;
|
||||
mCurrentState = STATE_IDLE;
|
||||
mTargetState = STATE_IDLE;
|
||||
AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
am.abandonAudioFocus(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,12 +321,13 @@ public class VideoView extends SurfaceView
|
||||
// not ready for playback just yet, will try again later
|
||||
return;
|
||||
}
|
||||
AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
||||
// we shouldn't clear the target state, because somebody might have
|
||||
// called start() previously
|
||||
release(false);
|
||||
|
||||
AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
||||
try {
|
||||
mMediaPlayer = new MediaPlayer();
|
||||
// TODO: create SubtitleController in MediaPlayer, but we need
|
||||
@@ -650,6 +653,8 @@ public class VideoView extends SurfaceView
|
||||
if (cleartargetstate) {
|
||||
mTargetState = STATE_IDLE;
|
||||
}
|
||||
AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
am.abandonAudioFocus(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ import java.util.Iterator;
|
||||
*/
|
||||
public class AudioManager {
|
||||
|
||||
private final Context mContext;
|
||||
private final Context mApplicationContext;
|
||||
private long mVolumeKeyUpTime;
|
||||
private final boolean mUseMasterVolume;
|
||||
private final boolean mUseVolumeKeySounds;
|
||||
@@ -641,12 +641,12 @@ public class AudioManager {
|
||||
* @hide
|
||||
*/
|
||||
public AudioManager(Context context) {
|
||||
mContext = context;
|
||||
mUseMasterVolume = mContext.getResources().getBoolean(
|
||||
mApplicationContext = context.getApplicationContext();
|
||||
mUseMasterVolume = mApplicationContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_useMasterVolume);
|
||||
mUseVolumeKeySounds = mContext.getResources().getBoolean(
|
||||
mUseVolumeKeySounds = mApplicationContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_useVolumeKeySounds);
|
||||
mUseFixedVolume = mContext.getResources().getBoolean(
|
||||
mUseFixedVolume = mApplicationContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_useFixedVolume);
|
||||
sAudioPortEventHandler.init();
|
||||
}
|
||||
@@ -685,7 +685,7 @@ public class AudioManager {
|
||||
* or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
|
||||
*/
|
||||
public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
|
||||
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
|
||||
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
|
||||
helper.sendMediaButtonEvent(keyEvent, false);
|
||||
}
|
||||
|
||||
@@ -746,7 +746,8 @@ public class AudioManager {
|
||||
break;
|
||||
case KeyEvent.KEYCODE_VOLUME_MUTE:
|
||||
if (event.getRepeatCount() == 0) {
|
||||
MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
|
||||
MediaSessionLegacyHelper.getHelper(mApplicationContext)
|
||||
.sendVolumeKeyEvent(event, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -778,7 +779,8 @@ public class AudioManager {
|
||||
mVolumeKeyUpTime = SystemClock.uptimeMillis();
|
||||
break;
|
||||
case KeyEvent.KEYCODE_VOLUME_MUTE:
|
||||
MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
|
||||
MediaSessionLegacyHelper.getHelper(mApplicationContext)
|
||||
.sendVolumeKeyEvent(event, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -823,10 +825,11 @@ public class AudioManager {
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
if (mUseMasterVolume) {
|
||||
service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
|
||||
service.adjustMasterVolume(direction, flags,
|
||||
mApplicationContext.getOpPackageName());
|
||||
} else {
|
||||
service.adjustStreamVolume(streamType, direction, flags,
|
||||
mContext.getOpPackageName());
|
||||
mApplicationContext.getOpPackageName());
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead object in adjustStreamVolume", e);
|
||||
@@ -856,9 +859,11 @@ public class AudioManager {
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
if (mUseMasterVolume) {
|
||||
service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
|
||||
service.adjustMasterVolume(direction, flags,
|
||||
mApplicationContext.getOpPackageName());
|
||||
} else {
|
||||
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
|
||||
MediaSessionLegacyHelper helper =
|
||||
MediaSessionLegacyHelper.getHelper(mApplicationContext);
|
||||
helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
@@ -890,9 +895,11 @@ public class AudioManager {
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
if (mUseMasterVolume) {
|
||||
service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
|
||||
service.adjustMasterVolume(direction, flags,
|
||||
mApplicationContext.getOpPackageName());
|
||||
} else {
|
||||
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
|
||||
MediaSessionLegacyHelper helper =
|
||||
MediaSessionLegacyHelper.getHelper(mApplicationContext);
|
||||
helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
@@ -912,7 +919,7 @@ public class AudioManager {
|
||||
public void adjustMasterVolume(int steps, int flags) {
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
service.adjustMasterVolume(steps, flags, mContext.getOpPackageName());
|
||||
service.adjustMasterVolume(steps, flags, mApplicationContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead object in adjustMasterVolume", e);
|
||||
}
|
||||
@@ -1053,7 +1060,7 @@ public class AudioManager {
|
||||
}
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
service.setRingerModeExternal(ringerMode, mContext.getOpPackageName());
|
||||
service.setRingerModeExternal(ringerMode, mApplicationContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead object in setRingerMode", e);
|
||||
}
|
||||
@@ -1075,9 +1082,10 @@ public class AudioManager {
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
if (mUseMasterVolume) {
|
||||
service.setMasterVolume(index, flags, mContext.getOpPackageName());
|
||||
service.setMasterVolume(index, flags, mApplicationContext.getOpPackageName());
|
||||
} else {
|
||||
service.setStreamVolume(streamType, index, flags, mContext.getOpPackageName());
|
||||
service.setStreamVolume(streamType, index, flags,
|
||||
mApplicationContext.getOpPackageName());
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead object in setStreamVolume", e);
|
||||
@@ -1143,7 +1151,7 @@ public class AudioManager {
|
||||
public void setMasterVolume(int index, int flags) {
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
service.setMasterVolume(index, flags, mContext.getOpPackageName());
|
||||
service.setMasterVolume(index, flags, mApplicationContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead object in setMasterVolume", e);
|
||||
}
|
||||
@@ -1244,7 +1252,7 @@ public class AudioManager {
|
||||
public void setMasterMute(boolean state, int flags) {
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
service.setMasterMute(state, flags, mContext.getOpPackageName(), mICallBack);
|
||||
service.setMasterMute(state, flags, mApplicationContext.getOpPackageName(), mICallBack);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead object in setMasterMute", e);
|
||||
}
|
||||
@@ -1482,7 +1490,7 @@ public class AudioManager {
|
||||
* @see #startBluetoothSco()
|
||||
*/
|
||||
public boolean isBluetoothScoAvailableOffCall() {
|
||||
return mContext.getResources().getBoolean(
|
||||
return mApplicationContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_bluetooth_sco_off_call);
|
||||
}
|
||||
|
||||
@@ -1534,7 +1542,8 @@ public class AudioManager {
|
||||
public void startBluetoothSco(){
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
service.startBluetoothSco(mICallBack, mContext.getApplicationInfo().targetSdkVersion);
|
||||
service.startBluetoothSco(mICallBack,
|
||||
mApplicationContext.getApplicationInfo().targetSdkVersion);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead object in startBluetoothSco", e);
|
||||
}
|
||||
@@ -1682,7 +1691,7 @@ public class AudioManager {
|
||||
public void setMicrophoneMute(boolean on){
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
service.setMicrophoneMute(on, mContext.getOpPackageName());
|
||||
service.setMicrophoneMute(on, mApplicationContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead object in setMicrophoneMute", e);
|
||||
}
|
||||
@@ -2113,7 +2122,7 @@ public class AudioManager {
|
||||
* Settings has an in memory cache, so this is fast.
|
||||
*/
|
||||
private boolean querySoundEffectsEnabled(int user) {
|
||||
return Settings.System.getIntForUser(mContext.getContentResolver(),
|
||||
return Settings.System.getIntForUser(mApplicationContext.getContentResolver(),
|
||||
Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0;
|
||||
}
|
||||
|
||||
@@ -2525,7 +2534,7 @@ public class AudioManager {
|
||||
try {
|
||||
status = service.requestAudioFocus(requestAttributes, durationHint, mICallBack,
|
||||
mAudioFocusDispatcher, getIdForAudioFocusListener(l),
|
||||
mContext.getOpPackageName() /* package name */, flags,
|
||||
mApplicationContext.getOpPackageName() /* package name */, flags,
|
||||
ap != null ? ap.cb() : null);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Can't call requestAudioFocus() on AudioService:", e);
|
||||
@@ -2550,7 +2559,7 @@ public class AudioManager {
|
||||
.setInternalLegacyStreamType(streamType).build(),
|
||||
durationHint, mICallBack, null,
|
||||
MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
|
||||
mContext.getOpPackageName(),
|
||||
mApplicationContext.getOpPackageName(),
|
||||
AUDIOFOCUS_FLAG_LOCK,
|
||||
null /* policy token */);
|
||||
} catch (RemoteException e) {
|
||||
@@ -2619,7 +2628,7 @@ public class AudioManager {
|
||||
if (eventReceiver == null) {
|
||||
return;
|
||||
}
|
||||
if (!eventReceiver.getPackageName().equals(mContext.getPackageName())) {
|
||||
if (!eventReceiver.getPackageName().equals(mApplicationContext.getPackageName())) {
|
||||
Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
|
||||
"receiver and context package names don't match");
|
||||
return;
|
||||
@@ -2628,7 +2637,7 @@ public class AudioManager {
|
||||
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
||||
// the associated intent will be handled by the component being registered
|
||||
mediaButtonIntent.setComponent(eventReceiver);
|
||||
PendingIntent pi = PendingIntent.getBroadcast(mContext,
|
||||
PendingIntent pi = PendingIntent.getBroadcast(mApplicationContext,
|
||||
0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
|
||||
registerMediaButtonIntent(pi, eventReceiver);
|
||||
}
|
||||
@@ -2662,8 +2671,8 @@ public class AudioManager {
|
||||
Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
|
||||
return;
|
||||
}
|
||||
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
|
||||
helper.addMediaButtonListener(pi, eventReceiver, mContext);
|
||||
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
|
||||
helper.addMediaButtonListener(pi, eventReceiver, mApplicationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2681,7 +2690,7 @@ public class AudioManager {
|
||||
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
||||
// the associated intent will be handled by the component being registered
|
||||
mediaButtonIntent.setComponent(eventReceiver);
|
||||
PendingIntent pi = PendingIntent.getBroadcast(mContext,
|
||||
PendingIntent pi = PendingIntent.getBroadcast(mApplicationContext,
|
||||
0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
|
||||
unregisterMediaButtonIntent(pi);
|
||||
}
|
||||
@@ -2704,7 +2713,7 @@ public class AudioManager {
|
||||
* @hide
|
||||
*/
|
||||
public void unregisterMediaButtonIntent(PendingIntent pi) {
|
||||
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
|
||||
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
|
||||
helper.removeMediaButtonListener(pi);
|
||||
}
|
||||
|
||||
@@ -2721,7 +2730,7 @@ public class AudioManager {
|
||||
if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
|
||||
return;
|
||||
}
|
||||
rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext));
|
||||
rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mApplicationContext));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2736,7 +2745,7 @@ public class AudioManager {
|
||||
if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
|
||||
return;
|
||||
}
|
||||
rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext));
|
||||
rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mApplicationContext));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3397,7 +3406,7 @@ public class AudioManager {
|
||||
*/
|
||||
public void setRingerModeInternal(int ringerMode) {
|
||||
try {
|
||||
getService().setRingerModeInternal(ringerMode, mContext.getOpPackageName());
|
||||
getService().setRingerModeInternal(ringerMode, mApplicationContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Error calling setRingerModeInternal", e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user