Use JSON bools and numbers, use fixed format for dates, normalise JSON keys.

This commit is contained in:
akwizgran
2020-12-11 16:30:29 +00:00
parent db90f75d2e
commit b81495eac1
3 changed files with 62 additions and 87 deletions

View File

@@ -13,6 +13,7 @@ import android.content.Context;
import android.content.pm.FeatureInfo; import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo;
@@ -38,6 +39,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.logging.Formatter; import java.util.logging.Formatter;
import java.util.logging.LogRecord; import java.util.logging.LogRecord;
@@ -54,7 +56,9 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION.SDK_INT;
import static androidx.core.content.ContextCompat.getSystemService; import static androidx.core.content.ContextCompat.getSystemService;
import static java.util.Locale.US;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static java.util.TimeZone.getTimeZone;
import static org.briarproject.bramble.util.AndroidUtils.getBluetoothAddressAndMethod; import static org.briarproject.bramble.util.AndroidUtils.getBluetoothAddressAndMethod;
import static org.briarproject.bramble.util.PrivacyUtils.scrubInetAddress; import static org.briarproject.bramble.util.PrivacyUtils.scrubInetAddress;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress; import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@@ -89,20 +93,21 @@ class BriarReportCollector {
private ReportItem getBasicInfo(@Nullable Throwable t) { private ReportItem getBasicInfo(@Nullable Throwable t) {
String packageName = ctx.getPackageName(); String packageName = ctx.getPackageName();
PackageManager pm = ctx.getPackageManager(); PackageManager pm = ctx.getPackageManager();
String versionName, versionCode; String versionName;
int versionCode;
try { try {
PackageInfo packageInfo = pm.getPackageInfo(packageName, 0); PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
versionName = packageInfo.versionName; versionName = packageInfo.versionName;
versionCode = String.valueOf(packageInfo.versionCode); versionCode = packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) { } catch (NameNotFoundException e) {
versionName = e.toString(); versionName = e.toString();
versionCode = "?"; versionCode = 0;
} }
MultiReportInfo basicInfo = new MultiReportInfo() MultiReportInfo basicInfo = new MultiReportInfo()
.add("PackageName", packageName) .add("PackageName", packageName)
.add("VersionName", versionName) .add("VersionName", versionName)
.add("VersionCode", versionCode) .add("VersionCode", versionCode)
.add("isCrashReport", String.valueOf(t != null)); .add("IsCrashReport", t != null);
return new ReportItem("BasicInfo", R.string.dev_report_basic_info, return new ReportItem("BasicInfo", R.string.dev_report_basic_info,
basicInfo, false); basicInfo, false);
} }
@@ -110,7 +115,7 @@ class BriarReportCollector {
private ReportItem getDeviceInfo() { private ReportItem getDeviceInfo() {
MultiReportInfo deviceInfo = new MultiReportInfo() MultiReportInfo deviceInfo = new MultiReportInfo()
.add("AndroidVersion", Build.VERSION.RELEASE) .add("AndroidVersion", Build.VERSION.RELEASE)
.add("AndroidApi", String.valueOf(SDK_INT)) .add("AndroidApi", SDK_INT)
.add("Product", Build.PRODUCT) .add("Product", Build.PRODUCT)
.add("Model", Build.MODEL) .add("Model", Build.MODEL)
.add("Brand", Build.BRAND); .add("Brand", Build.BRAND);
@@ -141,7 +146,10 @@ class BriarReportCollector {
} }
private String formatTime(long time) { private String formatTime(long time) {
return new Date(time) + " (" + time + ")"; SimpleDateFormat format =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", US);
format.setTimeZone(getTimeZone("UTC"));
return format.format(new Date(time));
} }
private ReportItem getMemory() { private ReportItem getMemory() {
@@ -151,24 +159,15 @@ class BriarReportCollector {
ActivityManager am = getSystemService(ctx, ActivityManager.class); ActivityManager am = getSystemService(ctx, ActivityManager.class);
ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo(); ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo();
requireNonNull(am).getMemoryInfo(mem); requireNonNull(am).getMemoryInfo(mem);
String systemTotal = (mem.totalMem / 1024 / 1024) + " MiB"; memInfo.add("SystemMemoryTotal", mem.totalMem);
String systemFree = (mem.availMem / 1024 / 1024) + " MiB"; memInfo.add("SystemMemoryFree", mem.availMem);
String systemThreshold = (mem.threshold / 1024 / 1024) + " MiB"; memInfo.add("SystemMemoryThreshold", mem.threshold);
memInfo.add("SystemMemoryTotal", systemTotal);
memInfo.add("SystemMemoryFree", systemFree);
memInfo.add("SystemMemoryThreshold", systemThreshold);
// Virtual machine memory // Virtual machine memory
Runtime runtime = Runtime.getRuntime(); Runtime runtime = Runtime.getRuntime();
long heap = runtime.totalMemory(); memInfo.add("VirtualMachineMemoryAllocated", runtime.totalMemory());
long heapFree = runtime.freeMemory(); memInfo.add("VirtualMachineMemoryFree", runtime.freeMemory());
long heapMax = runtime.maxMemory(); memInfo.add("VirtualMachineMemoryMaximum", runtime.maxMemory());
String vmMemoryAllocated = (heap / 1024 / 1024) + " MiB";
String vmMemoryFree = (heapFree / 1024 / 1024) + " MiB";
String vmMemoryMax = (heapMax / 1024 / 1024) + " MiB";
memInfo.add("VirtualMachineMemoryAllocated", vmMemoryAllocated);
memInfo.add("VirtualMachineMemoryFree", vmMemoryFree);
memInfo.add("VirtualMachineMemoryMaximum", vmMemoryMax);
return new ReportItem("Memory", R.string.dev_report_memory, memInfo); return new ReportItem("Memory", R.string.dev_report_memory, memInfo);
} }
@@ -178,21 +177,13 @@ class BriarReportCollector {
// Internal storage // Internal storage
File root = Environment.getRootDirectory(); File root = Environment.getRootDirectory();
long rootTotal = root.getTotalSpace(); storageInfo.add("InternalStorageTotal", root.getTotalSpace());
long rootFree = root.getFreeSpace(); storageInfo.add("InternalStorageFree", root.getFreeSpace());
storageInfo.add("InternalStorageTotal",
(rootTotal / 1024 / 1024) + " MiB");
storageInfo.add("InternalStorageFree",
(rootFree / 1024 / 1024) + " MiB");
// External storage (SD card) // External storage (SD card)
File sd = Environment.getExternalStorageDirectory(); File sd = Environment.getExternalStorageDirectory();
long sdTotal = sd.getTotalSpace(); storageInfo.add("ExternalStorageTotal", sd.getTotalSpace());
long sdFree = sd.getFreeSpace(); storageInfo.add("ExternalStorageFree", sd.getFreeSpace());
storageInfo.add("ExternalStorageTotal",
(sdTotal / 1024 / 1024) + " MiB");
storageInfo.add("ExternalStorageFree",
(sdFree / 1024 / 1024) + " MiB");
return new ReportItem("Storage", R.string.dev_report_storage, return new ReportItem("Storage", R.string.dev_report_storage,
storageInfo); storageInfo);
@@ -206,13 +197,15 @@ class BriarReportCollector {
getSystemService(ctx, ConnectivityManager.class)); getSystemService(ctx, ConnectivityManager.class));
NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE); NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE);
boolean mobileAvailable = mobile != null && mobile.isAvailable(); boolean mobileAvailable = mobile != null && mobile.isAvailable();
connectivityInfo.add("MobileDataAvailable", mobileAvailable);
// Is mobile data enabled? // Is mobile data enabled?
boolean mobileEnabled = false; boolean mobileEnabled = false;
try { try {
Class<?> clazz = Class.forName(cm.getClass().getName()); Class<?> clazz = Class.forName(cm.getClass().getName());
Method method = clazz.getDeclaredMethod("getMobileDataEnabled"); Method method = clazz.getDeclaredMethod("getMobileDataEnabled");
method.setAccessible(true); method.setAccessible(true);
mobileEnabled = (Boolean) method.invoke(cm); mobileEnabled = (Boolean) requireNonNull(method.invoke(cm));
} catch (ClassNotFoundException } catch (ClassNotFoundException
| NoSuchMethodException | NoSuchMethodException
| IllegalArgumentException | IllegalArgumentException
@@ -221,42 +214,30 @@ class BriarReportCollector {
connectivityInfo connectivityInfo
.add("MobileDataReflectionException", e.toString()); .add("MobileDataReflectionException", e.toString());
} }
connectivityInfo.add("MobileDataEnabled", mobileEnabled);
// Is mobile data connected ? // Is mobile data connected ?
boolean mobileConnected = mobile != null && mobile.isConnected(); boolean mobileConnected = mobile != null && mobile.isConnected();
connectivityInfo.add("MobileDataConnected", mobileConnected);
String mobileStatus;
if (mobileAvailable) mobileStatus = "Available, ";
else mobileStatus = "Not available, ";
if (mobileEnabled) mobileStatus += "enabled, ";
else mobileStatus += "not enabled, ";
if (mobileConnected) mobileStatus += "connected";
else mobileStatus += "not connected";
connectivityInfo.add("MobileDataStatus", mobileStatus);
// Is wifi available? // Is wifi available?
NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI); NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI);
boolean wifiAvailable = wifi != null && wifi.isAvailable(); boolean wifiAvailable = wifi != null && wifi.isAvailable();
connectivityInfo.add("WifiAvailable", wifiAvailable);
// Is wifi enabled? // Is wifi enabled?
WifiManager wm = getSystemService(ctx, WifiManager.class); WifiManager wm = getSystemService(ctx, WifiManager.class);
boolean wifiEnabled = wm != null && boolean wifiEnabled = wm != null &&
wm.getWifiState() == WIFI_STATE_ENABLED; wm.getWifiState() == WIFI_STATE_ENABLED;
connectivityInfo.add("WifiEnabled", wifiEnabled);
// Is wifi connected? // Is wifi connected?
boolean wifiConnected = wifi != null && wifi.isConnected(); boolean wifiConnected = wifi != null && wifi.isConnected();
connectivityInfo.add("WifiConnected", wifiConnected);
String wifiStatus;
if (wifiAvailable) wifiStatus = "Available, ";
else wifiStatus = "Not available, ";
if (wifiEnabled) wifiStatus += "enabled, ";
else wifiStatus += "not enabled, ";
if (wifiConnected) wifiStatus += "connected";
else wifiStatus += "not connected";
connectivityInfo.add("WiFiStatus", wifiStatus);
// Is wifi direct supported? // Is wifi direct supported?
String wifiDirectStatus = "Supported"; boolean wifiDirect = ctx.getSystemService(WIFI_P2P_SERVICE) != null;
if (ctx.getSystemService(WIFI_P2P_SERVICE) == null) connectivityInfo.add("WiFiDirectSupported", wifiDirect);
wifiDirectStatus = "NotSupported";
connectivityInfo.add("WiFiDirect", wifiDirectStatus);
if (wm != null) { if (wm != null) {
WifiInfo wifiInfo = wm.getConnectionInfo(); WifiInfo wifiInfo = wm.getConnectionInfo();
@@ -269,8 +250,8 @@ class BriarReportCollector {
ipBytes[3] = (byte) ((ip >> 24) & 0xFF); ipBytes[3] = (byte) ((ip >> 24) & 0xFF);
try { try {
InetAddress address = InetAddress.getByAddress(ipBytes); InetAddress address = InetAddress.getByAddress(ipBytes);
connectivityInfo connectivityInfo.add("WiFiAddress",
.add("Wi-FiAddress", scrubInetAddress(address)); scrubInetAddress(address));
} catch (UnknownHostException ignored) { } catch (UnknownHostException ignored) {
// Should only be thrown if address has illegal length // Should only be thrown if address has illegal length
} }
@@ -280,40 +261,35 @@ class BriarReportCollector {
// Is Bluetooth available? // Is Bluetooth available?
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt == null) { if (bt == null) {
connectivityInfo.add("BluetoothStatus", "Not available"); connectivityInfo.add("BluetoothAvailable", false);
} else { } else {
connectivityInfo.add("BluetoothAvailable", true);
// Is Bluetooth enabled? // Is Bluetooth enabled?
@SuppressLint("HardwareIds") @SuppressLint("HardwareIds")
boolean btEnabled = bt.isEnabled() boolean btEnabled = bt.isEnabled()
&& !isNullOrEmpty(bt.getAddress()); && !isNullOrEmpty(bt.getAddress());
connectivityInfo.add("BluetoothEnabled", btEnabled);
// Is Bluetooth connectable? // Is Bluetooth connectable?
int scanMode = bt.getScanMode(); int scanMode = bt.getScanMode();
boolean btConnectable = scanMode == SCAN_MODE_CONNECTABLE || boolean btConnectable = scanMode == SCAN_MODE_CONNECTABLE ||
scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE; scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE;
connectivityInfo.add("BluetoothConnectable", btConnectable);
// Is Bluetooth discoverable? // Is Bluetooth discoverable?
boolean btDiscoverable = boolean btDiscoverable =
scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE; scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE;
connectivityInfo.add("BluetoothDiscoverable", btDiscoverable);
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";
connectivityInfo.add("BluetoothStatus", btStatus);
if (SDK_INT >= 21) { if (SDK_INT >= 21) {
// Is Bluetooth LE scanning and advertising supported? // Is Bluetooth LE scanning and advertising supported?
boolean btLeScan = bt.getBluetoothLeScanner() != null; boolean btLeScan = bt.getBluetoothLeScanner() != null;
connectivityInfo.add("BluetoothLeScanningSupported", btLeScan);
boolean btLeAdvertise = boolean btLeAdvertise =
bt.getBluetoothLeAdvertiser() != null; bt.getBluetoothLeAdvertiser() != null;
String btLeStatus; connectivityInfo.add("BluetoothLeAdvertisingSupported",
if (btLeScan) btLeStatus = "Scanning, "; btLeAdvertise);
else btLeStatus = "No scanning, ";
if (btLeAdvertise) btLeStatus += "advertising";
else btLeStatus += "no advertising";
connectivityInfo.add("BluetoothLeStatus", btLeStatus);
} }
Pair<String, String> p = getBluetoothAddressAndMethod(ctx, bt); Pair<String, String> p = getBluetoothAddressAndMethod(ctx, bt);
@@ -329,11 +305,10 @@ class BriarReportCollector {
private ReportItem getBuildConfig() { private ReportItem getBuildConfig() {
MultiReportInfo buildConfig = new MultiReportInfo() MultiReportInfo buildConfig = new MultiReportInfo()
.add("GitHash", BuildConfig.GitHash) .add("GitHash", BuildConfig.GitHash)
.add("BUILD_TYPE", BuildConfig.BUILD_TYPE) .add("BuildType", BuildConfig.BUILD_TYPE)
.add("FLAVOR", BuildConfig.FLAVOR) .add("Flavor", BuildConfig.FLAVOR)
.add("DEBUG", String.valueOf(BuildConfig.DEBUG)) .add("Debug", BuildConfig.DEBUG)
.add("BuildTimestamp", .add("BuildTimestamp", formatTime(BuildConfig.BuildTimestamp));
String.valueOf(BuildConfig.BuildTimestamp));
return new ReportItem("BuildConfig", R.string.dev_report_build_config, return new ReportItem("BuildConfig", R.string.dev_report_build_config,
buildConfig); buildConfig);
} }
@@ -356,7 +331,7 @@ class BriarReportCollector {
for (FeatureInfo feature : features) { for (FeatureInfo feature : features) {
String featureName = feature.name; String featureName = feature.name;
if (featureName != null) { if (featureName != null) {
deviceFeatures.add(featureName, "true"); deviceFeatures.add(featureName, true);
} else { } else {
deviceFeatures.add("glEsVersion", feature.getGlEsVersion()); deviceFeatures.add("glEsVersion", feature.getGlEsVersion());
} }

View File

@@ -94,9 +94,9 @@ class ReportData {
@NotNullByDefault @NotNullByDefault
static class MultiReportInfo implements ReportInfo { static class MultiReportInfo implements ReportInfo {
private final Map<String, String> map = new TreeMap<>(); private final Map<String, Object> map = new TreeMap<>();
MultiReportInfo add(String key, @Nullable String value) { MultiReportInfo add(String key, @Nullable Object value) {
map.put(key, value == null ? "null" : value); map.put(key, value == null ? "null" : value);
return this; return this;
} }
@@ -104,10 +104,10 @@ class ReportData {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : map.entrySet()) { for (Map.Entry<String, Object> entry : map.entrySet()) {
sb sb
.append(entry.getKey()) .append(entry.getKey())
.append("=") .append(": ")
.append(entry.getValue()) .append(entry.getValue())
.append("\n"); .append("\n");
} }

View File

@@ -126,8 +126,8 @@ public class ReportViewModel extends AndroidViewModel {
ReportData data = requireNonNull(reportData.getValue()); ReportData data = requireNonNull(reportData.getValue());
if (!isNullOrEmpty(comment) || isNullOrEmpty(email)) { if (!isNullOrEmpty(comment) || isNullOrEmpty(email)) {
MultiReportInfo userInfo = new MultiReportInfo(); MultiReportInfo userInfo = new MultiReportInfo();
if (!isNullOrEmpty(comment)) userInfo.add("comment", comment); if (!isNullOrEmpty(comment)) userInfo.add("Comment", comment);
if (!isNullOrEmpty(email)) userInfo.add("email", email); if (!isNullOrEmpty(email)) userInfo.add("Email", email);
data.add(new ReportData.ReportItem("UserInfo", 0, userInfo, false)); data.add(new ReportData.ReportItem("UserInfo", 0, userInfo, false));
} }