Only update backend helpers on actual changes

This commit is contained in:
Marvin W 2022-04-20 20:58:08 +02:00
parent 9c32fc7619
commit 876181e0d8
No known key found for this signature in database
GPG Key ID: 072E9235DB996F2A
3 changed files with 85 additions and 70 deletions

View File

@ -14,6 +14,7 @@ public class AbstractBackendHelper {
protected final Context context; protected final Context context;
protected State state = State.DISABLED; protected State state = State.DISABLED;
protected boolean currentDataUsed = true; protected boolean currentDataUsed = true;
protected long lastUpdate = 0;
public AbstractBackendHelper(Context context) { public AbstractBackendHelper(Context context) {
if (context == null) if (context == null)

View File

@ -38,8 +38,6 @@ import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION;
@ -57,13 +55,15 @@ import static android.Manifest.permission.READ_PHONE_STATE;
public class CellBackendHelper extends AbstractBackendHelper { public class CellBackendHelper extends AbstractBackendHelper {
private final Listener listener; private final Listener listener;
private final TelephonyManager telephonyManager; private final TelephonyManager telephonyManager;
private final Set<Cell> cells = new HashSet<>(); private Set<Cell> cells = new HashSet<>();
private PhoneStateListener phoneStateListener; private PhoneStateListener phoneStateListener;
private boolean supportsCellInfoChanged = true; private boolean supportsCellInfoChanged = true;
public static final int MIN_UPDATE_INTERVAL = 30 * 1000; public static final int MIN_UPDATE_INTERVAL = 30 * 1000;
public static final int FALLBACK_UPDATE_INTERVAL = 5 * 60 * 1000; public static final int FALLBACK_UPDATE_INTERVAL = 5 * 60 * 1000;
private final static int MAX_AGE = 300000;
private long lastScan = 0; private long lastScan = 0;
private boolean forceNextUpdate = false;
/** /**
* Create a new instance of {@link CellBackendHelper}. Call this in * Create a new instance of {@link CellBackendHelper}. Call this in
@ -180,6 +180,8 @@ public class CellBackendHelper extends AbstractBackendHelper {
lastScan = System.currentTimeMillis(); lastScan = System.currentTimeMillis();
if (loadCells(cellInfo)) { if (loadCells(cellInfo)) {
listener.onCellsChanged(getCells()); listener.onCellsChanged(getCells());
} else {
Log.d(TAG, "No change in Cell networks");
} }
} }
@ -187,9 +189,8 @@ public class CellBackendHelper extends AbstractBackendHelper {
* This will fix empty MNC since Android 9 with 0-prefixed MNCs. * This will fix empty MNC since Android 9 with 0-prefixed MNCs.
* Issue: https://issuetracker.google.com/issues/113560852 * Issue: https://issuetracker.google.com/issues/113560852
*/ */
@SuppressLint("SoonBlockedPrivateApi") private void fixEmptyMnc(Set<Cell> cells) {
private void fixEmptyMnc(List<CellInfo> cellInfo) { if (Build.VERSION.SDK_INT < 28 || cells == null) {
if (Build.VERSION.SDK_INT < 28 || cellInfo == null) {
return; return;
} }
@ -201,32 +202,36 @@ public class CellBackendHelper extends AbstractBackendHelper {
String mnc = networkOperator.substring(3); String mnc = networkOperator.substring(3);
for (CellInfo info : cellInfo) { for (Cell cell : cells) {
if (!info.isRegistered()) { if (!cell.info.isRegistered()) {
continue; continue;
} }
Object identity = null; Object identity = null;
if (info instanceof CellInfoGsm) { if (cell.info instanceof CellInfoGsm) {
identity = ((CellInfoGsm) info).getCellIdentity(); identity = ((CellInfoGsm) cell.info).getCellIdentity();
} else if (info instanceof CellInfoWcdma) { } else if (cell.info instanceof CellInfoWcdma) {
identity = ((CellInfoWcdma) info).getCellIdentity(); identity = ((CellInfoWcdma) cell.info).getCellIdentity();
} else if (info instanceof CellInfoLte) { } else if (cell.info instanceof CellInfoLte) {
identity = ((CellInfoLte) info).getCellIdentity(); identity = ((CellInfoLte) cell.info).getCellIdentity();
} }
if (identity == null) { if (identity == null) {
continue; continue;
} }
try { String mncString = null;
Field mncField = CellIdentity.class.getDeclaredField("mMncStr"); if (identity instanceof CellIdentityGsm) {
mncField.setAccessible(true); mncString = ((CellIdentityGsm) identity).getMncString();
if (mncField.get(identity) == null) { } else if (identity instanceof CellIdentityWcdma) {
mncField.set(identity, mnc); mncString = ((CellIdentityWcdma) identity).getMncString();
} } else if (identity instanceof CellIdentityLte) {
} catch (Exception ignored) { mncString = ((CellIdentityLte) identity).getMncString();
}
if (mncString == null) {
cell.mnc = Integer.parseInt(mnc);
} }
} }
} }
@ -235,19 +240,15 @@ public class CellBackendHelper extends AbstractBackendHelper {
* This will fix values returned by {@link TelephonyManager#getAllCellInfo()} as described * This will fix values returned by {@link TelephonyManager#getAllCellInfo()} as described
* here: https://github.com/mozilla/ichnaea/issues/340 * here: https://github.com/mozilla/ichnaea/issues/340
*/ */
@SuppressWarnings({"ChainOfInstanceofChecks", "MagicNumber", "ConstantConditions"}) private void fixShortMncBug(Set<Cell> cells) {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) if (cells == null) return;
private void fixShortMncBug(List<CellInfo> cellInfo) {
if (cellInfo == null) return;
String networkOperator = telephonyManager.getNetworkOperator(); String networkOperator = telephonyManager.getNetworkOperator();
if (networkOperator.length() != 5) return; if (networkOperator.length() != 5) return;
int realMnc = Integer.parseInt(networkOperator.substring(3)); int realMnc = Integer.parseInt(networkOperator.substring(3));
boolean theBug = false; boolean theBug = false;
for (CellInfo info : cellInfo) { for (Cell cell : cells) {
if (info instanceof CellInfoCdma) return; if (cell.info instanceof CellInfoCdma) return;
if (info.isRegistered()) { if (cell.info.isRegistered()) {
Cell cell = parseCellInfo(info);
if (cell == null) continue;
int infoMnc = cell.getMnc(); int infoMnc = cell.getMnc();
if (infoMnc == (realMnc * 10 + 15)) { if (infoMnc == (realMnc * 10 + 15)) {
theBug = true; theBug = true;
@ -255,25 +256,25 @@ public class CellBackendHelper extends AbstractBackendHelper {
} }
} }
if (theBug) { if (theBug) {
for (CellInfo info : cellInfo) { for (Cell cell : cells) {
Object identity = null; Object identity = null;
if (info instanceof CellInfoGsm) if (cell.info instanceof CellInfoGsm)
identity = ((CellInfoGsm) info).getCellIdentity(); identity = ((CellInfoGsm) cell.info).getCellIdentity();
else if (info instanceof CellInfoLte) else if (cell.info instanceof CellInfoLte)
identity = ((CellInfoLte) info).getCellIdentity(); identity = ((CellInfoLte) cell.info).getCellIdentity();
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && else if (Build.VERSION.SDK_INT >= 18 && cell.info instanceof CellInfoWcdma)
info instanceof CellInfoWcdma) identity = ((CellInfoWcdma) cell.info).getCellIdentity();
identity = ((CellInfoWcdma) info).getCellIdentity();
if (identity == null) continue; if (identity == null) continue;
try { int mnc = -1;
Field mncField = identity.getClass().getDeclaredField("mMnc"); if (identity instanceof CellIdentityGsm) {
mncField.setAccessible(true); mnc = ((CellIdentityGsm) identity).getMnc();
int mnc = (Integer) mncField.get(identity); } else if (Build.VERSION.SDK_INT >= 18 && identity instanceof CellIdentityWcdma) {
if (mnc >= 25 && mnc <= 1005) { mnc = ((CellIdentityWcdma) identity).getMnc();
mnc = (mnc - 15) / 10; } else if (identity instanceof CellIdentityLte) {
mncField.setInt(identity, mnc); mnc = ((CellIdentityLte) identity).getMnc();
} }
} catch (Exception ignored) { if (mnc >= 25 && mnc <= 1005) {
cell.mnc = (mnc - 15) / 10;
} }
} }
} }
@ -321,18 +322,16 @@ public class CellBackendHelper extends AbstractBackendHelper {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@SuppressLint({"DiscouragedPrivateApi", "deprecation"}) @SuppressLint({"DiscouragedPrivateApi", "deprecation"})
private synchronized boolean loadCells(List<CellInfo> cellInfo) { private synchronized boolean loadCells(List<CellInfo> cellInfo) {
int oldHash = cells.hashCode(); Set<Cell> cells = new HashSet<>();
cells.clear();
currentDataUsed = false;
try { try {
if (cellInfo != null) { if (cellInfo != null) {
fixEmptyMnc(cellInfo);
fixShortMncBug(cellInfo);
for (CellInfo info : cellInfo) { for (CellInfo info : cellInfo) {
Cell cell = parseCellInfo(info); Cell cell = parseCellInfo(info);
if (cell == null) continue; if (cell == null) continue;
cells.add(cell); cells.add(cell);
} }
fixEmptyMnc(cells);
fixShortMncBug(cells);
} }
Method getNeighboringCellInfo = TelephonyManager.class.getDeclaredMethod("getNeighboringCellInfo"); Method getNeighboringCellInfo = TelephonyManager.class.getDeclaredMethod("getNeighboringCellInfo");
List<android.telephony.NeighboringCellInfo> neighboringCellInfo = (List<android.telephony.NeighboringCellInfo>) getNeighboringCellInfo.invoke(telephonyManager); List<android.telephony.NeighboringCellInfo> neighboringCellInfo = (List<android.telephony.NeighboringCellInfo>) getNeighboringCellInfo.invoke(telephonyManager);
@ -349,14 +348,17 @@ public class CellBackendHelper extends AbstractBackendHelper {
} }
if (state == State.DISABLING) if (state == State.DISABLING)
state = State.DISABLED; state = State.DISABLED;
switch (state) { if (!cells.equals(this.cells) || lastUpdate == 0 || forceNextUpdate) {
default: this.cells = cells;
case DISABLED: lastUpdate = System.currentTimeMillis();
return false; currentDataUsed = false;
case SCANNING: forceNextUpdate = false;
if (state == State.SCANNING) {
state = State.WAITING; state = State.WAITING;
return cells.hashCode() != oldHash; }
return state != State.DISABLED;
} }
return false;
} }
public synchronized Set<Cell> getCells() { public synchronized Set<Cell> getCells() {
@ -379,6 +381,7 @@ public class CellBackendHelper extends AbstractBackendHelper {
@Override @Override
public void onCellInfoChanged(List<CellInfo> cellInfo) { public void onCellInfoChanged(List<CellInfo> cellInfo) {
if (cellInfo != null && !cellInfo.isEmpty()) { if (cellInfo != null && !cellInfo.isEmpty()) {
forceNextUpdate = true;
onCellsChanged(cellInfo); onCellsChanged(cellInfo);
} else if (supportsCellInfoChanged) { } else if (supportsCellInfoChanged) {
supportsCellInfoChanged = false; supportsCellInfoChanged = false;
@ -409,6 +412,7 @@ public class CellBackendHelper extends AbstractBackendHelper {
}, new TelephonyManager.CellInfoCallback() { }, new TelephonyManager.CellInfoCallback() {
@Override @Override
public void onCellInfo(List<CellInfo> cellInfo) { public void onCellInfo(List<CellInfo> cellInfo) {
forceNextUpdate = true;
handleAllCellInfo(cellInfo); handleAllCellInfo(cellInfo);
} }
}); });
@ -450,7 +454,7 @@ public class CellBackendHelper extends AbstractBackendHelper {
@Override @Override
public synchronized void onUpdate() { public synchronized void onUpdate() {
if (!currentDataUsed) { if (!currentDataUsed && System.currentTimeMillis() - lastUpdate < MAX_AGE) {
listener.onCellsChanged(getCells()); listener.onCellsChanged(getCells());
} else { } else {
state = State.SCANNING; state = State.SCANNING;
@ -470,6 +474,7 @@ public class CellBackendHelper extends AbstractBackendHelper {
} }
public static class Cell { public static class Cell {
private CellInfo info;
private CellType type; private CellType type;
private int mcc; private int mcc;
private int mnc; private int mnc;
@ -478,6 +483,11 @@ public class CellBackendHelper extends AbstractBackendHelper {
private int psc; private int psc;
private int signal; private int signal;
private Cell(CellInfo info, CellType type, int mcc, int mnc, int lac, long cid, int psc, int signal) {
this(type, mcc, mnc, lac, cid, psc, signal);
this.info = info;
}
public Cell(CellType type, int mcc, int mnc, int lac, long cid, int psc, int signal) { public Cell(CellType type, int mcc, int mnc, int lac, long cid, int psc, int signal) {
if (type == null) if (type == null)
throw new IllegalArgumentException("Each cell has an type!"); throw new IllegalArgumentException("Each cell has an type!");

View File

@ -13,6 +13,7 @@ import android.content.IntentFilter;
import android.net.wifi.ScanResult; import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.Build; import android.os.Build;
import android.util.Log;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -31,10 +32,10 @@ import static android.Manifest.permission.CHANGE_WIFI_STATE;
public class WiFiBackendHelper extends AbstractBackendHelper { public class WiFiBackendHelper extends AbstractBackendHelper {
private final static IntentFilter wifiBroadcastFilter = private final static IntentFilter wifiBroadcastFilter =
new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
private final static int MAX_AGE = 60000;
private final Listener listener; private final Listener listener;
private final WifiManager wifiManager; private final WifiManager wifiManager;
private final Set<WiFi> wiFis = new HashSet<>();
private final BroadcastReceiver wifiBroadcastReceiver = new BroadcastReceiver() { private final BroadcastReceiver wifiBroadcastReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -42,6 +43,7 @@ public class WiFiBackendHelper extends AbstractBackendHelper {
} }
}; };
private Set<WiFi> wiFis = new HashSet<>();
private boolean ignoreNomap = true; private boolean ignoreNomap = true;
/** /**
@ -90,7 +92,7 @@ public class WiFiBackendHelper extends AbstractBackendHelper {
* Call this in {@link LocationBackendService#update()}. * Call this in {@link LocationBackendService#update()}.
*/ */
public synchronized void onUpdate() { public synchronized void onUpdate() {
if (!currentDataUsed) { if (!currentDataUsed && System.currentTimeMillis() - lastUpdate < MAX_AGE) {
listener.onWiFisChanged(getWiFis()); listener.onWiFisChanged(getWiFis());
} else { } else {
scanWiFis(); scanWiFis();
@ -105,6 +107,8 @@ public class WiFiBackendHelper extends AbstractBackendHelper {
private void onWiFisChanged() { private void onWiFisChanged() {
if (loadWiFis()) { if (loadWiFis()) {
listener.onWiFisChanged(getWiFis()); listener.onWiFisChanged(getWiFis());
} else {
Log.d(TAG, "No change in WiFi networks");
} }
} }
@ -128,9 +132,7 @@ public class WiFiBackendHelper extends AbstractBackendHelper {
} }
private synchronized boolean loadWiFis() { private synchronized boolean loadWiFis() {
int oldHash = wiFis.hashCode(); Set<WiFi> wiFis = new HashSet<>();
wiFis.clear();
currentDataUsed = false;
List<ScanResult> scanResults = wifiManager.getScanResults(); List<ScanResult> scanResults = wifiManager.getScanResults();
for (ScanResult scanResult : scanResults) { for (ScanResult scanResult : scanResults) {
if (ignoreNomap && scanResult.SSID.toLowerCase(Locale.US).endsWith("_nomap")) continue; if (ignoreNomap && scanResult.SSID.toLowerCase(Locale.US).endsWith("_nomap")) continue;
@ -138,14 +140,16 @@ public class WiFiBackendHelper extends AbstractBackendHelper {
} }
if (state == State.DISABLING) if (state == State.DISABLING)
state = State.DISABLED; state = State.DISABLED;
switch (state) { if (!wiFis.equals(this.wiFis) || lastUpdate == 0) {
default: this.wiFis = wiFis;
case DISABLED: lastUpdate = System.currentTimeMillis();
return false; currentDataUsed = false;
case SCANNING: if (state == State.SCANNING) {
state = State.WAITING; state = State.WAITING;
return wiFis.hashCode() != oldHash; }
return state != State.DISABLED;
} }
return false;
} }
@SuppressWarnings("MagicNumber") @SuppressWarnings("MagicNumber")