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:
@@ -72,6 +72,7 @@ import android.os.Process;
|
|||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.internal.util.test.BroadcastInterceptingContext;
|
||||||
import com.android.testutils.DevSdkIgnoreRule;
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
import com.android.testutils.DevSdkIgnoreRunner;
|
import com.android.testutils.DevSdkIgnoreRunner;
|
||||||
|
|
||||||
@@ -82,6 +83,8 @@ import org.mockito.ArgumentCaptor;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
@RunWith(DevSdkIgnoreRunner.class)
|
@RunWith(DevSdkIgnoreRunner.class)
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@DevSdkIgnoreRule.IgnoreUpTo(VERSION_CODES.R)
|
@DevSdkIgnoreRule.IgnoreUpTo(VERSION_CODES.R)
|
||||||
@@ -461,4 +464,50 @@ public class ConnectivityManagerTest {
|
|||||||
}
|
}
|
||||||
fail("expected exception of type " + throwableType);
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user