diff options
author | Fan Zhang <zhfan@google.com> | 2017-03-03 17:59:23 -0800 |
---|---|---|
committer | Fan Zhang <zhfan@google.com> | 2017-03-03 18:01:19 -0800 |
commit | f5f71a9be218e9a3c992573fb8acd6eae114cc81 (patch) | |
tree | cd665b4d9e0d9e0177034469653006c373ec7270 | |
parent | 50aa0008fc47d6250c6f30bf894f6fc0d472d8a3 (diff) | |
download | packages_apps_Settings-f5f71a9be218e9a3c992573fb8acd6eae114cc81.tar.gz packages_apps_Settings-f5f71a9be218e9a3c992573fb8acd6eae114cc81.tar.bz2 packages_apps_Settings-f5f71a9be218e9a3c992573fb8acd6eae114cc81.zip |
Fix ServiceConnectionLeak in network fragment
Change-Id: I43efe9ae31fc2f58361abdb034b0205a3f3e2b71
Fix: 35957226
Test: make RunSettingsRoboTests
4 files changed, 44 insertions, 6 deletions
diff --git a/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java b/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java index 0a1a6281fe..abe14273bb 100644 --- a/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java +++ b/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java @@ -88,4 +88,11 @@ public abstract class ObservablePreferenceFragment extends PreferenceFragment { super.onPause(); } + @CallSuper + @Override + public void onDestroy() { + mLifecycle.onDestroy(); + super.onDestroy(); + } + } diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java index f52230b61d..6add7868e3 100644 --- a/src/com/android/settings/network/NetworkDashboardFragment.java +++ b/src/com/android/settings/network/NetworkDashboardFragment.java @@ -95,7 +95,7 @@ public class NetworkDashboardFragment extends DashboardFragment implements final List<PreferenceController> controllers = new ArrayList<>(); controllers.add(airplaneModePreferenceController); controllers.add(mobileNetworkPreferenceController); - controllers.add(new TetherPreferenceController(context)); + controllers.add(new TetherPreferenceController(context, lifecycle)); controllers.add(vpnPreferenceController); controllers.add(new ProxyPreferenceController(context)); controllers.add(mobilePlanPreferenceController); diff --git a/src/com/android/settings/network/TetherPreferenceController.java b/src/com/android/settings/network/TetherPreferenceController.java index 5b8d55eee2..f23118a3fa 100644 --- a/src/com/android/settings/network/TetherPreferenceController.java +++ b/src/com/android/settings/network/TetherPreferenceController.java @@ -28,6 +28,9 @@ import android.support.v7.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.TetherSettings; import com.android.settings.core.PreferenceController; +import com.android.settings.core.lifecycle.Lifecycle; +import com.android.settings.core.lifecycle.LifecycleObserver; +import com.android.settings.core.lifecycle.events.OnDestroy; import java.util.concurrent.atomic.AtomicReference; @@ -35,7 +38,8 @@ import static android.os.UserManager.DISALLOW_CONFIG_TETHERING; import static com.android.settingslib.RestrictedLockUtils.checkIfRestrictionEnforced; import static com.android.settingslib.RestrictedLockUtils.hasBaseUserRestriction; -public class TetherPreferenceController extends PreferenceController { +public class TetherPreferenceController extends PreferenceController + implements LifecycleObserver, OnDestroy { private static final String KEY_TETHER_SETTINGS = "tether_settings"; @@ -62,12 +66,12 @@ public class TetherPreferenceController extends PreferenceController { TetherPreferenceController() { super(null); mAdminDisallowedTetherConfig = false; - mBluetoothPan = null; + mBluetoothPan = new AtomicReference<>(); mConnectivityManager = null; - mBluetoothAdapter = null; + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } - public TetherPreferenceController(Context context) { + public TetherPreferenceController(Context context, Lifecycle lifecycle) { super(context); mBluetoothPan = new AtomicReference<>(); mAdminDisallowedTetherConfig = checkIfRestrictionEnforced( @@ -75,6 +79,9 @@ public class TetherPreferenceController extends PreferenceController { mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (lifecycle != null) { + lifecycle.addObserver(this); + } if (mBluetoothAdapter != null) { mBluetoothAdapter.getProfileProxy(context, mBtProfileServiceListener, BluetoothProfile.PAN); @@ -113,6 +120,14 @@ public class TetherPreferenceController extends PreferenceController { return KEY_TETHER_SETTINGS; } + @Override + public void onDestroy() { + final BluetoothProfile profile = mBluetoothPan.getAndSet(null); + if (profile != null && mBluetoothAdapter != null) { + mBluetoothAdapter.closeProfileProxy(BluetoothProfile.PAN, profile); + } + } + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) void updateSummary() { if (mPreference == null) { diff --git a/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java index a856e8c9a5..6f751eb87a 100644 --- a/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java @@ -18,9 +18,10 @@ package com.android.settings.network; import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothPan; +import android.bluetooth.BluetoothProfile; import android.content.Context; import android.net.ConnectivityManager; -import android.os.UserManager; import android.support.v7.preference.Preference; import com.android.settings.R; @@ -35,6 +36,9 @@ import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; +import java.util.concurrent.atomic.AtomicReference; + +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -65,6 +69,18 @@ public class TetherPreferenceControllerTest { } @Test + public void goThroughLifecycle_shouldDestoryBluetoothProfile() { + final BluetoothPan pan = mock(BluetoothPan.class); + final AtomicReference<BluetoothPan> panRef = + ReflectionHelpers.getField(mController, "mBluetoothPan"); + panRef.set(pan); + + mController.onDestroy(); + + verify(mBluetoothAdapter).closeProfileProxy(BluetoothProfile.PAN, pan); + } + + @Test public void updateSummary_noPreference_noInteractionWithConnectivityManager() { mController.updateSummary(); verifyNoMoreInteractions(mConnectivityManager); |