Welp, it turns out my original assumption was false (that the location services on the device don't suffer from the same leak problem). There is an unresolved bug (
public class MyActivity extends Activity implements LocationListener {
private static final String TAG = "LocationLeaker";
LocationManager mLocationManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
}
@Override
protected void onResume() {
super.onResume();
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
@Override
protected void onPause() {
super.onPause();
mLocationManager.removeUpdates(this);
}
@Override
public void onLocationChanged(Location location) {
Log.i(TAG, "LocationChanged");
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.i(TAG, "StatusChanged");
}
@Override
public void onProviderEnabled(String provider) {
Log.i(TAG, "ProviderEnabled");
}
@Override
public void onProviderDisabled(String provider) {
Log.i(TAG, "ProviderDisabled");
}
}
Taking a heap dump even after the activity is destroyed will show the activity/listener still being held hostage from the GC by the binder's Native Stack reference.
Turns out, this is just a bad pattern to model a service after.