Use reflection to get local Bluetooth address.

This is expected to work on Android 8 but not 8.1+.
This commit is contained in:
akwizgran
2019-12-09 13:59:11 +00:00
parent 5ba64577bd
commit d1e21877b3
2 changed files with 99 additions and 61 deletions

View File

@@ -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<String> getSupportedArchitectures() {
List<String> 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<String, String> 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);
}

View File

@@ -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<String, String> 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);
}
}