Add a test to identify memory leak in ConnectivityManager

The sInstance static instance which self reference to
ConnectivityManager which holds a reference to a ConnectivityManager
instance causes the Context referenced by that instance to never be
GCed.

Bug: 202978965
Test: atest ConnectivityManagerTest
Change-Id: I0227f63dbc27688ea5f4ef9275fd0f9c247ad14c
This commit is contained in:
markchien
2022-04-26 16:33:47 +08:00
parent 310ca20b33
commit ed0fab0356

View File

@@ -72,6 +72,7 @@ import android.os.Process;
import androidx.test.filters.SmallTest;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
@@ -82,6 +83,8 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.lang.ref.WeakReference;
@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
@DevSdkIgnoreRule.IgnoreUpTo(VERSION_CODES.R)
@@ -461,4 +464,50 @@ public class ConnectivityManagerTest {
}
fail("expected exception of type " + throwableType);
}
private static class MockContext extends BroadcastInterceptingContext {
MockContext(Context base) {
super(base);
}
@Override
public Context getApplicationContext() {
return mock(Context.class);
}
}
private WeakReference<Context> makeConnectivityManagerAndReturnContext() {
// Mockito may have an internal reference to the mock, creating MockContext for testing.
final Context c = new MockContext(mock(Context.class));
new ConnectivityManager(c, mService);
return new WeakReference<>(c);
}
private void forceGC() {
// First GC ensures that objects are collected for finalization, then second GC ensures
// they're garbage-collected after being finalized.
System.gc();
System.runFinalization();
System.gc();
}
@Test
public void testConnectivityManagerDoesNotLeakContext() throws Exception {
final WeakReference<Context> ref = makeConnectivityManagerAndReturnContext();
final int attempts = 100;
final long waitIntervalMs = 50;
for (int i = 0; i < attempts; i++) {
forceGC();
if (ref.get() == null) break;
Thread.sleep(waitIntervalMs);
}
// TODO: fix memory leak then assertNull here.
assertNotNull("Couldn't find the Context leak in ConnectivityManager after " + attempts
+ " attempts", ref.get());
}
}