From d1e21877b3d83850376df1795b94d4bda2dfe876 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 9 Dec 2019 13:59:11 +0000 Subject: [PATCH] Use reflection to get local Bluetooth address. This is expected to work on Android 8 but not 8.1+. --- .../bramble/util/AndroidUtils.java | 61 ++++++++++-- .../android/reporting/BriarReportPrimer.java | 99 +++++++++---------- 2 files changed, 99 insertions(+), 61 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java b/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java index d54ad4ea3..385a01aec 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java @@ -6,15 +6,25 @@ import android.content.Context; import android.os.Build; import android.provider.Settings; +import org.briarproject.bramble.api.Pair; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; +import javax.annotation.Nullable; + import static android.content.Context.MODE_PRIVATE; import static android.os.Build.VERSION.SDK_INT; +import static java.util.Arrays.asList; +import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; +@NotNullByDefault public class AndroidUtils { // Fake Bluetooth address returned by BluetoothAdapter on API 23 and later @@ -22,11 +32,10 @@ public class AndroidUtils { private static final String STORED_REPORTS = "dev-reports"; - @SuppressWarnings("deprecation") public static Collection getSupportedArchitectures() { List abis = new ArrayList<>(); if (SDK_INT >= 21) { - abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS)); + abis.addAll(asList(Build.SUPPORTED_ABIS)); } else { abis.add(Build.CPU_ABI); if (Build.CPU_ABI2 != null) abis.add(Build.CPU_ABI2); @@ -36,24 +45,62 @@ public class AndroidUtils { public static String getBluetoothAddress(Context ctx, BluetoothAdapter adapter) { + return getBluetoothAddressAndMethod(ctx, adapter).getFirst(); + } + + public static Pair getBluetoothAddressAndMethod(Context ctx, + BluetoothAdapter adapter) { // Return the adapter's address if it's valid and not fake @SuppressLint("HardwareIds") String address = adapter.getAddress(); - if (isValidBluetoothAddress(address)) return address; + if (isValidBluetoothAddress(address)) { + return new Pair<>(address, "adapter"); + } // Return the address from settings if it's valid and not fake address = Settings.Secure.getString(ctx.getContentResolver(), "bluetooth_address"); - if (isValidBluetoothAddress(address)) return address; + if (isValidBluetoothAddress(address)) { + return new Pair<>(address, "settings"); + } + // Try to get the address via reflection + address = getBluetoothAddressByReflection(adapter); + if (isValidBluetoothAddress(address)) { + return new Pair<>(requireNonNull(address), "reflection"); + } // Let the caller know we can't find the address - return ""; + return new Pair<>("", ""); } - private static boolean isValidBluetoothAddress(String address) { + private static boolean isValidBluetoothAddress(@Nullable String address) { return !StringUtils.isNullOrEmpty(address) && BluetoothAdapter.checkBluetoothAddress(address) && !address.equals(FAKE_BLUETOOTH_ADDRESS); } + @Nullable + private static String getBluetoothAddressByReflection( + BluetoothAdapter adapter) { + try { + Field mServiceField = + adapter.getClass().getDeclaredField("mService"); + mServiceField.setAccessible(true); + Object mService = mServiceField.get(adapter); + // mService may be null when Bluetooth is disabled + if (mService == null) throw new NoSuchFieldException(); + Method getAddressMethod = + mService.getClass().getMethod("getAddress"); + return (String) getAddressMethod.invoke(mService); + } catch (NoSuchFieldException e) { + return null; + } catch (IllegalAccessException e) { + return null; + } catch (NoSuchMethodException e) { + return null; + } catch (InvocationTargetException e) { + return null; + } + } + public static File getReportDir(Context ctx) { return ctx.getDir(STORED_REPORTS, MODE_PRIVATE); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportPrimer.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportPrimer.java index 827838cb6..253c3a94f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportPrimer.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportPrimer.java @@ -7,15 +7,13 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.Looper; -import android.provider.Settings; import org.acra.builder.ReportBuilder; import org.acra.builder.ReportPrimer; -import org.briarproject.bramble.util.StringUtils; +import org.briarproject.bramble.api.Pair; import org.briarproject.briar.BuildConfig; import org.briarproject.briar.android.BriarApplication; import org.briarproject.briar.android.logging.BriefLogFormatter; @@ -23,7 +21,6 @@ import org.briarproject.briar.android.logging.BriefLogFormatter; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.Callable; @@ -43,8 +40,12 @@ import static android.content.Context.WIFI_SERVICE; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; +import static android.os.Build.VERSION.SDK_INT; +import static java.util.Collections.unmodifiableMap; +import static org.briarproject.bramble.util.AndroidUtils.getBluetoothAddressAndMethod; import static org.briarproject.bramble.util.PrivacyUtils.scrubInetAddress; import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress; +import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; public class BriarReportPrimer implements ReportPrimer { @@ -195,63 +196,53 @@ public class BriarReportPrimer implements ReportPrimer { // Is Bluetooth available? BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); - boolean btAvailable = bt != null; - // Is Bluetooth enabled? - boolean btEnabled = bt != null && bt.isEnabled() && - !StringUtils.isNullOrEmpty(bt.getAddress()); - // Is Bluetooth connectable? - boolean btConnectable = bt != null && - (bt.getScanMode() == SCAN_MODE_CONNECTABLE || - bt.getScanMode() == - SCAN_MODE_CONNECTABLE_DISCOVERABLE); - // Is Bluetooth discoverable? - boolean btDiscoverable = bt != null && - bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE; - // Is Bluetooth LE scanning and advertising supported? - boolean btLeApi = false, btLeScan = false, btLeAdvertise = false; - if (bt != null && Build.VERSION.SDK_INT >= 21) { - btLeApi = true; - btLeScan = bt.getBluetoothLeScanner() != null; - btLeAdvertise = bt.getBluetoothLeAdvertiser() != null; - } + if (bt == null) { + customData.put("Bluetooth status", "Not available"); + } else { + // Is Bluetooth enabled? + boolean btEnabled = bt.isEnabled() + && !isNullOrEmpty(bt.getAddress()); + // Is Bluetooth connectable? + int scanMode = bt.getScanMode(); + boolean btConnectable = scanMode == SCAN_MODE_CONNECTABLE || + scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE; + // Is Bluetooth discoverable? + boolean btDiscoverable = + scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE; - String btStatus; - if (btAvailable) btStatus = "Available, "; - else btStatus = "Not available, "; - if (btEnabled) btStatus += "enabled, "; - else btStatus += "not enabled, "; - if (btConnectable) btStatus += "connectable, "; - else btStatus += "not connectable, "; - if (btDiscoverable) btStatus += "discoverable"; - else btStatus += "not discoverable"; - customData.put("Bluetooth status", btStatus); - if (btLeApi) { - String btLeStatus; - if (btLeScan) btLeStatus = "Scanning, "; - else btLeStatus = "No scanning, "; - if (btLeAdvertise) btLeStatus += "advertising"; - else btLeStatus += "no advertising"; - customData.put("Bluetooth LE status", btLeStatus); - } + String btStatus; + if (btEnabled) btStatus = "Available, enabled, "; + else btStatus = "Available, not enabled, "; + if (btConnectable) btStatus += "connectable, "; + else btStatus += "not connectable, "; + if (btDiscoverable) btStatus += "discoverable"; + else btStatus += "not discoverable"; + customData.put("Bluetooth status", btStatus); - if (bt != null) { - customData.put("Bluetooth address", - scrubMacAddress(bt.getAddress())); + if (SDK_INT >= 21) { + // Is Bluetooth LE scanning and advertising supported? + boolean btLeScan = bt.getBluetoothLeScanner() != null; + boolean btLeAdvertise = + bt.getBluetoothLeAdvertiser() != null; + String btLeStatus; + if (btLeScan) btLeStatus = "Scanning, "; + else btLeStatus = "No scanning, "; + if (btLeAdvertise) btLeStatus += "advertising"; + else btLeStatus += "no advertising"; + customData.put("Bluetooth LE status", btLeStatus); + } + + Pair p = getBluetoothAddressAndMethod(ctx, bt); + String address = p.getFirst(); + String method = p.getSecond(); + customData.put("Bluetooth address", scrubMacAddress(address)); + customData.put("Bluetooth address method", method); } - String btSettingsAddr; - try { - btSettingsAddr = Settings.Secure.getString( - ctx.getContentResolver(), "bluetooth_address"); - } catch (SecurityException e) { - btSettingsAddr = "Could not get address from settings"; - } - customData.put("Bluetooth address from settings", - scrubMacAddress(btSettingsAddr)); // Git commit ID customData.put("Commit ID", BuildConfig.GitHash); - return Collections.unmodifiableMap(customData); + return unmodifiableMap(customData); } }