From 79b80ba7768e2ea42ac65b1f063d625e9d5f5f6c Mon Sep 17 00:00:00 2001 From: TongTongStudio Date: Wed, 5 Aug 2026 10:53:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(dialer):=20=E6=89=A9=E5=B1=95=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E4=BF=A1=E6=81=AF=E9=87=87=E9=9B=86=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=EF=BC=8C=E5=AF=B9=E9=BD=90=E5=90=8E=E7=AB=AF=20DeviceSystemInf?= =?UTF-8?q?oVO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除旧的 IMEI/IMSI/MAC 等字段,新增设备名称、品牌、型号、制造商、硬件、Host、Android ID、Build 信息、语言、时区、启动时间、屏幕信息、内核/ROM 版本、产品信息、主板平台、设备类型、平板标识、发布/显示版本、Bootloader/基带/Radio 版本、操作系统类型/版本/固件版本等字段,并新增移动网络 IP/MAC/子类型、渠道/广告标识、应用列表 MD5 等采集逻辑 --- .../dialer/bean/req/SnSystemInfoReq.java | 457 +++++++++++++++--- .../ttstd/dialer/mdm/DeviceInfoCollector.java | 114 ++++- .../com/ttstd/dialer/utils/SystemUtils.java | 409 ++++++++++++++++ 3 files changed, 903 insertions(+), 77 deletions(-) diff --git a/app/src/main/java/com/ttstd/dialer/bean/req/SnSystemInfoReq.java b/app/src/main/java/com/ttstd/dialer/bean/req/SnSystemInfoReq.java index f2571e1..e7a2841 100644 --- a/app/src/main/java/com/ttstd/dialer/bean/req/SnSystemInfoReq.java +++ b/app/src/main/java/com/ttstd/dialer/bean/req/SnSystemInfoReq.java @@ -3,118 +3,197 @@ package com.ttstd.dialer.bean.req; import com.google.gson.annotations.SerializedName; import java.io.Serializable; +import java.math.BigDecimal; /** * 设备基本信息上传请求。 *

* 对应后端 {@code POST /api/v1/sn/update_system_info}, - * 字段与后端 {@code SnSystemInfoReq} 一一对应。 - *

- * 注意:该类原名为 SnHardwareInfoReq,但其字段(sn_imei/sn_model/sn_brand 等) - * 实际对应的是后端的「基本信息」而非「硬件信息」,故更名以避免与新增的 - * {@link SnHardwareInfoReq}(CPU/内存/电池/GPU)混淆。 + * 字段与后端 {@code DeviceSystemInfoVO} / {@code SnDeviceSystemInfo} 一一对应。 */ public class SnSystemInfoReq implements Serializable { private static final long serialVersionUID = 2728925136862797858L; - @SerializedName("sn_imei") - private String imei; + @SerializedName("device_name") + private String deviceName; - @SerializedName("sn_imsi") - private String imsi; + @SerializedName("device_brand") + private String deviceBrand; - @SerializedName("sn_wlan_mac") - private String wlanMac; + @SerializedName("device_model") + private String deviceModel; - @SerializedName("sn_device_mac") - private String deviceMac; + @SerializedName("device_board") + private String deviceBoard; - @SerializedName("sn_bluetooth_mac") - private String bluetoothMac; + @SerializedName("device_manufacturer") + private String deviceManufacturer; - @SerializedName("sn_model") - private String model; + @SerializedName("hardware") + private String hardware; - @SerializedName("sn_brand") - private String brand; + @SerializedName("host") + private String host; - @SerializedName("sn_board") - private String board; - - @SerializedName("sn_android_version") + @SerializedName("android_version") private String androidVersion; - @SerializedName("sn_android_api") - private int androidApi; + @SerializedName("android_api") + private Integer androidApi; - @SerializedName("sn_build_id") + @SerializedName("android_id") + private String androidId; + + @SerializedName("build_id") private String buildId; - @SerializedName("sn_build_display_id") + @SerializedName("build_display_id") private String buildDisplayId; - public String getImei() { - return imei; + @SerializedName("build_fingerprint") + private String buildFingerprint; + + @SerializedName("build_type") + private String buildType; + + @SerializedName("build_user") + private String buildUser; + + @SerializedName("build_host") + private String buildHost; + + @SerializedName("build_tags") + private String buildTags; + + @SerializedName("build_time") + private String buildTime; + + @SerializedName("language") + private String language; + + @SerializedName("timezone") + private String timezone; + + @SerializedName("boot_time") + private String bootTime; + + @SerializedName("screen_resolution") + private String screenResolution; + + @SerializedName("screen_density") + private Integer screenDensity; + + @SerializedName("kernel_version") + private String kernelVersion; + + @SerializedName("rom_version") + private String romVersion; + + @SerializedName("product_name") + private String productName; + + @SerializedName("product_model") + private String productModel; + + @SerializedName("product_device") + private String productDevice; + + @SerializedName("board_platform") + private String boardPlatform; + + @SerializedName("device_type") + private String deviceType; + + @SerializedName("is_tablet") + private Integer isTablet; + + @SerializedName("release_version") + private String releaseVersion; + + @SerializedName("display_version") + private String displayVersion; + + @SerializedName("bootloader") + private String bootloader; + + @SerializedName("baseband_version") + private String basebandVersion; + + @SerializedName("radio_version") + private String radioVersion; + + @SerializedName("screen_size") + private String screenSize; + + @SerializedName("screen_inch") + private BigDecimal screenInch; + + @SerializedName("refresh_rate") + private Integer refreshRate; + + @SerializedName("os_type") + private String osType; + + @SerializedName("os_version") + private String osVersion; + + @SerializedName("firmware_version") + private String firmwareVersion; + + public String getDeviceName() { + return deviceName; } - public void setImei(String imei) { - this.imei = imei; + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; } - public String getImsi() { - return imsi; + public String getDeviceBrand() { + return deviceBrand; } - public void setImsi(String imsi) { - this.imsi = imsi; + public void setDeviceBrand(String deviceBrand) { + this.deviceBrand = deviceBrand; } - public String getWlanMac() { - return wlanMac; + public String getDeviceModel() { + return deviceModel; } - public void setWlanMac(String wlanMac) { - this.wlanMac = wlanMac; + public void setDeviceModel(String deviceModel) { + this.deviceModel = deviceModel; } - public String getDeviceMac() { - return deviceMac; + public String getDeviceBoard() { + return deviceBoard; } - public void setDeviceMac(String deviceMac) { - this.deviceMac = deviceMac; + public void setDeviceBoard(String deviceBoard) { + this.deviceBoard = deviceBoard; } - public String getBluetoothMac() { - return bluetoothMac; + public String getDeviceManufacturer() { + return deviceManufacturer; } - public void setBluetoothMac(String bluetoothMac) { - this.bluetoothMac = bluetoothMac; + public void setDeviceManufacturer(String deviceManufacturer) { + this.deviceManufacturer = deviceManufacturer; } - public String getModel() { - return model; + public String getHardware() { + return hardware; } - public void setModel(String model) { - this.model = model; + public void setHardware(String hardware) { + this.hardware = hardware; } - public String getBrand() { - return brand; + public String getHost() { + return host; } - public void setBrand(String brand) { - this.brand = brand; - } - - public String getBoard() { - return board; - } - - public void setBoard(String board) { - this.board = board; + public void setHost(String host) { + this.host = host; } public String getAndroidVersion() { @@ -125,14 +204,22 @@ public class SnSystemInfoReq implements Serializable { this.androidVersion = androidVersion; } - public int getAndroidApi() { + public Integer getAndroidApi() { return androidApi; } - public void setAndroidApi(int androidApi) { + public void setAndroidApi(Integer androidApi) { this.androidApi = androidApi; } + public String getAndroidId() { + return androidId; + } + + public void setAndroidId(String androidId) { + this.androidId = androidId; + } + public String getBuildId() { return buildId; } @@ -148,4 +235,244 @@ public class SnSystemInfoReq implements Serializable { public void setBuildDisplayId(String buildDisplayId) { this.buildDisplayId = buildDisplayId; } + + public String getBuildFingerprint() { + return buildFingerprint; + } + + public void setBuildFingerprint(String buildFingerprint) { + this.buildFingerprint = buildFingerprint; + } + + public String getBuildType() { + return buildType; + } + + public void setBuildType(String buildType) { + this.buildType = buildType; + } + + public String getBuildUser() { + return buildUser; + } + + public void setBuildUser(String buildUser) { + this.buildUser = buildUser; + } + + public String getBuildHost() { + return buildHost; + } + + public void setBuildHost(String buildHost) { + this.buildHost = buildHost; + } + + public String getBuildTags() { + return buildTags; + } + + public void setBuildTags(String buildTags) { + this.buildTags = buildTags; + } + + public String getBuildTime() { + return buildTime; + } + + public void setBuildTime(String buildTime) { + this.buildTime = buildTime; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getTimezone() { + return timezone; + } + + public void setTimezone(String timezone) { + this.timezone = timezone; + } + + public String getBootTime() { + return bootTime; + } + + public void setBootTime(String bootTime) { + this.bootTime = bootTime; + } + + public String getScreenResolution() { + return screenResolution; + } + + public void setScreenResolution(String screenResolution) { + this.screenResolution = screenResolution; + } + + public Integer getScreenDensity() { + return screenDensity; + } + + public void setScreenDensity(Integer screenDensity) { + this.screenDensity = screenDensity; + } + + public String getKernelVersion() { + return kernelVersion; + } + + public void setKernelVersion(String kernelVersion) { + this.kernelVersion = kernelVersion; + } + + public String getRomVersion() { + return romVersion; + } + + public void setRomVersion(String romVersion) { + this.romVersion = romVersion; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getProductModel() { + return productModel; + } + + public void setProductModel(String productModel) { + this.productModel = productModel; + } + + public String getProductDevice() { + return productDevice; + } + + public void setProductDevice(String productDevice) { + this.productDevice = productDevice; + } + + public String getBoardPlatform() { + return boardPlatform; + } + + public void setBoardPlatform(String boardPlatform) { + this.boardPlatform = boardPlatform; + } + + public String getDeviceType() { + return deviceType; + } + + public void setDeviceType(String deviceType) { + this.deviceType = deviceType; + } + + public Integer getIsTablet() { + return isTablet; + } + + public void setIsTablet(Integer isTablet) { + this.isTablet = isTablet; + } + + public String getReleaseVersion() { + return releaseVersion; + } + + public void setReleaseVersion(String releaseVersion) { + this.releaseVersion = releaseVersion; + } + + public String getDisplayVersion() { + return displayVersion; + } + + public void setDisplayVersion(String displayVersion) { + this.displayVersion = displayVersion; + } + + public String getBootloader() { + return bootloader; + } + + public void setBootloader(String bootloader) { + this.bootloader = bootloader; + } + + public String getBasebandVersion() { + return basebandVersion; + } + + public void setBasebandVersion(String basebandVersion) { + this.basebandVersion = basebandVersion; + } + + public String getRadioVersion() { + return radioVersion; + } + + public void setRadioVersion(String radioVersion) { + this.radioVersion = radioVersion; + } + + public String getScreenSize() { + return screenSize; + } + + public void setScreenSize(String screenSize) { + this.screenSize = screenSize; + } + + public BigDecimal getScreenInch() { + return screenInch; + } + + public void setScreenInch(BigDecimal screenInch) { + this.screenInch = screenInch; + } + + public Integer getRefreshRate() { + return refreshRate; + } + + public void setRefreshRate(Integer refreshRate) { + this.refreshRate = refreshRate; + } + + public String getOsType() { + return osType; + } + + public void setOsType(String osType) { + this.osType = osType; + } + + public String getOsVersion() { + return osVersion; + } + + public void setOsVersion(String osVersion) { + this.osVersion = osVersion; + } + + public String getFirmwareVersion() { + return firmwareVersion; + } + + public void setFirmwareVersion(String firmwareVersion) { + this.firmwareVersion = firmwareVersion; + } } diff --git a/app/src/main/java/com/ttstd/dialer/mdm/DeviceInfoCollector.java b/app/src/main/java/com/ttstd/dialer/mdm/DeviceInfoCollector.java index 64cc502..5aac5f9 100644 --- a/app/src/main/java/com/ttstd/dialer/mdm/DeviceInfoCollector.java +++ b/app/src/main/java/com/ttstd/dialer/mdm/DeviceInfoCollector.java @@ -35,6 +35,7 @@ import com.ttstd.dialer.bean.req.SnOtherInfoReq; import com.ttstd.dialer.bean.req.SnSecurityInfoReq; import com.ttstd.dialer.bean.req.SnSystemInfoReq; import com.ttstd.dialer.utils.Logger; +import com.ttstd.dialer.utils.SystemUtils; import java.io.BufferedReader; import java.io.File; @@ -112,25 +113,88 @@ public class DeviceInfoCollector { // ================================================================== /** - * 采集设备基本信息。 + * 采集设备基本信息(对齐后端 DeviceSystemInfoVO / SnDeviceSystemInfo)。 */ public SnSystemInfoReq collectSystemInfo() { SnSystemInfoReq req = new SnSystemInfoReq(); DeviceManagerService dms = DeviceManagerService.getInstance(); - req.setImei(safeString(dms::getImei)); - req.setImsi(safeString(dms::getImsi)); - req.setWlanMac(safeString(dms::getWlanMac)); - req.setDeviceMac(safeString(dms::getDeviceMac)); - req.setBluetoothMac(safeString(dms::getBluetoothMac)); - - req.setModel(Build.MODEL); - req.setBrand(Build.BRAND); - req.setBoard(Build.BOARD); + // ---- 基本信息 ---- + req.setDeviceName(safeString(() -> SystemUtils.getDeviceName(mContext))); + req.setDeviceBrand(Build.BRAND); + req.setDeviceModel(Build.MODEL); + req.setDeviceBoard(Build.BOARD); + req.setDeviceManufacturer(Build.MANUFACTURER); + req.setHardware(safeString(() -> SystemUtils.getHardware())); + req.setHost(safeString(() -> SystemUtils.getHost())); req.setAndroidVersion(Build.VERSION.RELEASE); req.setAndroidApi(Build.VERSION.SDK_INT); - req.setBuildId(Build.ID); - req.setBuildDisplayId(Build.DISPLAY); + req.setAndroidId(safeString(() -> SystemUtils.getAndroidId(mContext))); + + // ---- Build 信息 ---- + req.setBuildId(safeString(() -> SystemUtils.getBuildId())); + req.setBuildDisplayId(safeString(() -> SystemUtils.getBuildDisplayId())); + req.setBuildFingerprint(safeString(() -> SystemUtils.getBuildFingerprint())); + req.setBuildType(safeString(() -> SystemUtils.getBuildType())); + req.setBuildUser(safeString(() -> SystemUtils.getBuildUser())); + req.setBuildHost(safeString(() -> SystemUtils.getBuildHost())); + req.setBuildTags(safeString(() -> SystemUtils.getBuildTags())); + try { + long buildTime = SystemUtils.getBuildTime(); + if (buildTime > 0) { + req.setBuildTime(formatDateTime(buildTime)); + } + } catch (Throwable t) { + Logger.e(TAG, "collect buildTime failed: " + t.getMessage()); + } + + // ---- 语言 / 时区 / 开机时间 ---- + req.setLanguage(safeString(() -> SystemUtils.getLanguage())); + req.setTimezone(safeString(() -> SystemUtils.getTimezone())); + try { + long bootTime = SystemUtils.getBootTime(); + if (bootTime > 0) { + req.setBootTime(formatDateTime(bootTime)); + } + } catch (Throwable t) { + Logger.e(TAG, "collect bootTime failed: " + t.getMessage()); + } + + // ---- 屏幕信息 ---- + req.setScreenResolution(safeString(() -> SystemUtils.getScreenResolution(mContext))); + req.setScreenDensity(SystemUtils.getScreenDensity(mContext)); + req.setScreenSize(safeString(() -> SystemUtils.getScreenSize(mContext))); + req.setScreenInch(java.math.BigDecimal.valueOf(SystemUtils.getScreenInch(mContext))); + req.setRefreshRate(SystemUtils.getRefreshRate(mContext)); + + // ---- 内核 / ROM ---- + req.setKernelVersion(safeString(() -> SystemUtils.getKernelVersion())); + req.setRomVersion(safeString(() -> SystemUtils.getRomVersion())); + + // ---- 产品 / 主板平台 ---- + req.setProductName(safeString(() -> SystemUtils.getProductName())); + req.setProductModel(safeString(() -> SystemUtils.getProductModel())); + req.setProductDevice(safeString(() -> SystemUtils.getProductDevice())); + req.setBoardPlatform(safeString(() -> SystemUtils.getBoardPlatform())); + + // ---- 设备类型 / 平板标识 ---- + req.setDeviceType(safeString(() -> SystemUtils.getDeviceType(mContext))); + req.setIsTablet(SystemUtils.getIsTablet(mContext)); + + // ---- 发布 / 显示版本 ---- + req.setReleaseVersion(safeString(() -> SystemUtils.getReleaseVersion())); + req.setDisplayVersion(safeString(() -> SystemUtils.getDisplayVersion())); + + // ---- Bootloader / 基带 / Radio ---- + req.setBootloader(safeString(() -> SystemUtils.getBootloader())); + req.setBasebandVersion(safeString(() -> SystemUtils.getBasebandVersion())); + req.setRadioVersion(safeString(() -> SystemUtils.getRadioVersion())); + + // ---- 操作系统 ---- + req.setOsType(safeString(() -> SystemUtils.getOsType())); + req.setOsVersion(safeString(() -> SystemUtils.getOsVersion())); + req.setFirmwareVersion(safeString(() -> SystemUtils.getFirmwareVersion())); + return req; } @@ -354,6 +418,12 @@ public class DeviceInfoCollector { if (tm != null) { req.setMobileOperator(tm.getNetworkOperatorName()); req.setMobileNetworkType(networkTypeName(tm)); + // 移动数据网络子类型(LTE/HSPA/EDGE 等) + req.setNetworkSubtype(safeString(() -> SystemUtils.getNetworkSubtype(tm))); + // 移动数据网络 IP(接入数据网络时才有值) + req.setMobileIp(safeString(() -> SystemUtils.getMobileIp(mContext))); + // 移动数据网络 MAC(Android 6+ 受隐私限制多为空,尽力而为) + req.setMobileMac(safeString(() -> SystemUtils.getMobileMac())); if (hasPermission(Manifest.permission.READ_PHONE_STATE)) { req.setMobileSimSerial(safeString(tm::getSimSerialNumber)); } @@ -622,6 +692,26 @@ public class DeviceInfoCollector { Logger.e(TAG, "collect ram snapshot failed: " + t.getMessage()); } + // ---- 运营 / 广告标识(无对应系统 API 时留空,由打包/渠道/广告 SDK 注入)---- + try { + // 发布渠道:通常由构建脚本 / 渠道包注入,采集器无系统来源,默认空串。 + req.setChannel(""); + // GAID(Google Advertising ID):需 Google Play Services AdvertisingIdClient, + // 本项目未依赖 GMS,默认空串;接入后可在此补全。 + req.setGaid(""); + // OAID(国内移动广告标识):需移动安全联盟(MSA)SDK,本项目未集成,默认空串。 + req.setOaid(""); + } catch (Throwable t) { + Logger.e(TAG, "collect channel/gaid/oaid failed: " + t.getMessage()); + } + + // ---- 应用列表 MD5(与 SnSecurityInfoReq.mobileAppList 口径一致)---- + try { + req.setAppListMd5(SystemUtils.getAppListMd5(mContext.getPackageManager())); + } catch (Throwable t) { + Logger.e(TAG, "collect appListMd5 failed: " + t.getMessage()); + } + return req; } diff --git a/app/src/main/java/com/ttstd/dialer/utils/SystemUtils.java b/app/src/main/java/com/ttstd/dialer/utils/SystemUtils.java index 2e91cb9..0114c2d 100644 --- a/app/src/main/java/com/ttstd/dialer/utils/SystemUtils.java +++ b/app/src/main/java/com/ttstd/dialer/utils/SystemUtils.java @@ -11,6 +11,8 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; @@ -51,6 +53,7 @@ import java.util.Locale; import java.util.Optional; import java.util.concurrent.Callable; import java.util.concurrent.Executor; +import java.security.MessageDigest; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -278,6 +281,182 @@ public class SystemUtils { return "未获取到设备Mac地址"; } + /** + * 获取当前移动网络(数据网络)的 IP 地址 + * + * @return 形如 "10.x.x.x" 的 IPv4 地址,未连接数据网络或获取失败返回空串 + */ + @SuppressLint("MissingPermission") + public static String getMobileIp(Context context) { + try { + // 优先通过 TrafficStats / 网络接口遍历移动网络接口(rmnet0 / ccmni0 等) + List interfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); + for (NetworkInterface nif : interfaces) { + String name = nif.getName(); + if (name == null) { + continue; + } + // 移动数据网络接口通常以 rmnet / ccmni / mnet 开头 + if (name.startsWith("rmnet") || name.startsWith("ccmni") || name.startsWith("mnet")) { + for (java.net.InterfaceAddress addr : nif.getInterfaceAddresses()) { + java.net.InetAddress inet = addr.getAddress(); + if (inet instanceof java.net.Inet4Address && !inet.isLoopbackAddress()) { + return inet.getHostAddress(); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + /** + * 获取移动数据网络的 MAC 地址 + * 注意:Android 6.0+ 出于隐私限制,通过 API 只能拿到 02:00:00:00:00:00, + * 系统签名应用可尝试读取 /sys/class/net/rmnet0/address(多数情况下为空)。 + * + * @return MAC 地址字符串,无法获取时返回空串 + */ + @SuppressLint("MissingPermission") + public static String getMobileMac() { + // 移动网络接口通常没有独立 MAC,部分设备通过 rmnet 暴露 + String[] candidates = {"rmnet0", "rmnet_data0", "ccmni0"}; + for (String ifName : candidates) { + try { + NetworkInterface nif = NetworkInterface.getByName(ifName); + if (nif != null) { + byte[] mac = nif.getHardwareAddress(); + if (mac != null && mac.length > 0) { + StringBuilder sb = new StringBuilder(); + for (byte b : mac) { + sb.append(String.format("%02X:", b)); + } + if (sb.length() > 0) { + sb.deleteCharAt(sb.length() - 1); + } + return sb.toString(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + return ""; + } + + /** + * 获取移动网络子类型名称(如 LTE / HSPA / EDGE 等) + * + * @param tm TelephonyManager + * @return 网络子类型描述,未接入数据网络返回空串 + */ + @SuppressLint("MissingPermission") + public static String getNetworkSubtype(TelephonyManager tm) { + try { + if (tm != null) { + int subtype = tm.getNetworkType(); + return getNetworkTypeName(subtype); + } + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + private static String getNetworkTypeName(int networkType) { + switch (networkType) { + case TelephonyManager.NETWORK_TYPE_GPRS: + return "GPRS"; + case TelephonyManager.NETWORK_TYPE_EDGE: + return "EDGE"; + case TelephonyManager.NETWORK_TYPE_UMTS: + return "UMTS"; + case TelephonyManager.NETWORK_TYPE_HSDPA: + return "HSDPA"; + case TelephonyManager.NETWORK_TYPE_HSUPA: + return "HSUPA"; + case TelephonyManager.NETWORK_TYPE_HSPA: + return "HSPA"; + case TelephonyManager.NETWORK_TYPE_CDMA: + return "CDMA"; + case TelephonyManager.NETWORK_TYPE_EVDO_0: + return "EVDO_0"; + case TelephonyManager.NETWORK_TYPE_EVDO_A: + return "EVDO_A"; + case TelephonyManager.NETWORK_TYPE_1xRTT: + return "1xRTT"; + case TelephonyManager.NETWORK_TYPE_EHRPD: + return "eHRPD"; + case TelephonyManager.NETWORK_TYPE_LTE: + return "LTE"; + case TelephonyManager.NETWORK_TYPE_HSPAP: + return "HSPA+"; + case TelephonyManager.NETWORK_TYPE_GSM: + return "GSM"; + case TelephonyManager.NETWORK_TYPE_TD_SCDMA: + return "TD_SCDMA"; + case TelephonyManager.NETWORK_TYPE_IWLAN: + return "IWLAN"; + case TelephonyManager.NETWORK_TYPE_NR: + return "NR"; + default: + return "UNKNOWN"; + } + } + + /** + * 计算已安装应用包名列表的 MD5(与 SnSecurityInfoReq.mobileAppList 口径保持一致: + * 取所有非系统应用包名,按字母排序后用逗号拼接再取 MD5)。 + * + * @param pm PackageManager + * @return 32 位小写 MD5 字符串;无应用或异常时返回空串 + */ + public static String getAppListMd5(PackageManager pm) { + try { + if (pm == null) { + return ""; + } + List installedApps = pm.getInstalledPackages(0); + List pkgNames = new ArrayList<>(); + for (PackageInfo info : installedApps) { + // 仅统计第三方(非系统)应用,与常规应用列表统计口径一致 + if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0 + && info.packageName != null) { + pkgNames.add(info.packageName); + } + } + Collections.sort(pkgNames); + StringBuilder sb = new StringBuilder(); + for (String name : pkgNames) { + if (sb.length() > 0) { + sb.append(","); + } + sb.append(name); + } + return md5(sb.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + private static String md5(String input) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] digest = md.digest(input.getBytes()); + StringBuilder sb = new StringBuilder(); + for (byte b : digest) { + sb.append(String.format("%02x", b & 0xff)); + } + return sb.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + public static String getFactoryMacAddresses(Context context) { WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); String[] factoryMacAddresses = wifiManager.getFactoryMacAddresses(); @@ -331,6 +510,236 @@ public class SystemUtils { return getProperty(Build.DISPLAY, Build.UNKNOWN); } + // ================================================================== + // 设备基本信息(对齐后端 DeviceSystemInfoVO) + // ================================================================== + + public static String getDeviceName(Context context) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + return Settings.Global.getString(context.getContentResolver(), Settings.Global.DEVICE_NAME); + } + } catch (Throwable t) { + // ignore + } + return Build.UNKNOWN; + } + + public static String getDeviceManufacturer() { + return getProperty(Build.MANUFACTURER, Build.UNKNOWN); + } + + public static String getHardware() { + return getProperty("ro.hardware", Build.UNKNOWN); + } + + public static String getHost() { + return getProperty(Build.HOST, Build.UNKNOWN); + } + + public static String getAndroidId(Context context) { + try { + return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); + } catch (Throwable t) { + return ""; + } + } + + public static String getBuildFingerprint() { + return getProperty(Build.FINGERPRINT, Build.UNKNOWN); + } + + public static String getBuildType() { + return getProperty(Build.TYPE, Build.UNKNOWN); + } + + public static String getBuildUser() { + return getProperty(Build.USER, Build.UNKNOWN); + } + + public static String getBuildHost() { + return getProperty(Build.HOST, Build.UNKNOWN); + } + + public static String getBuildTags() { + return getProperty(Build.TAGS, Build.UNKNOWN); + } + + public static long getBuildTime() { + try { + return Build.TIME; + } catch (Throwable t) { + return 0L; + } + } + + public static String getLanguage() { + try { + return Locale.getDefault().getLanguage(); + } catch (Throwable t) { + return ""; + } + } + + public static String getTimezone() { + try { + return java.util.TimeZone.getDefault().getID(); + } catch (Throwable t) { + return ""; + } + } + + public static long getBootTime() { + try { + return System.currentTimeMillis() - android.os.SystemClock.elapsedRealtime(); + } catch (Throwable t) { + return 0L; + } + } + + public static String getScreenResolution(Context context) { + try { + android.util.DisplayMetrics dm = context.getResources().getDisplayMetrics(); + return dm.widthPixels + "x" + dm.heightPixels; + } catch (Throwable t) { + return ""; + } + } + + public static int getScreenDensity(Context context) { + try { + return (int) Math.round(context.getResources().getDisplayMetrics().density); + } catch (Throwable t) { + return 0; + } + } + + public static int getScreenDensityDpi(Context context) { + try { + return context.getResources().getDisplayMetrics().densityDpi; + } catch (Throwable t) { + return 0; + } + } + + public static String getKernelVersion() { + return getProperty("sys.kernel.version", ""); + } + + public static String getRomVersion() { + return getProperty("ro.build.version.emui", + getProperty("ro.build.version.miui", + getProperty("ro.build.version.opporom", + getProperty("ro.vivo.os.version", "")))); + } + + public static String getProductName() { + return getProperty(Build.PRODUCT, Build.UNKNOWN); + } + + public static String getProductModel() { + return getProperty("ro.product.model", Build.UNKNOWN); + } + + public static String getProductDevice() { + return getProperty("ro.product.device", Build.UNKNOWN); + } + + public static String getBoardPlatform() { + return getProperty("ro.board.platform", Build.UNKNOWN); + } + + public static String getDeviceType(Context context) { + try { + int layout = context.getResources().getConfiguration().screenLayout + & android.content.res.Configuration.SCREENLAYOUT_SIZE_MASK; + if (layout >= android.content.res.Configuration.SCREENLAYOUT_SIZE_LARGE) { + return "tablet"; + } + return "phone"; + } catch (Throwable t) { + return "phone"; + } + } + + public static int getIsTablet(Context context) { + try { + int layout = context.getResources().getConfiguration().screenLayout + & android.content.res.Configuration.SCREENLAYOUT_SIZE_MASK; + return layout >= android.content.res.Configuration.SCREENLAYOUT_SIZE_LARGE ? 1 : 0; + } catch (Throwable t) { + return 0; + } + } + + public static String getReleaseVersion() { + return getProperty("ro.build.version.release", Build.VERSION.RELEASE); + } + + public static String getDisplayVersion() { + return getProperty("ro.build.display.id", Build.DISPLAY); + } + + public static String getBootloader() { + return getProperty(Build.BOOTLOADER, Build.UNKNOWN); + } + + public static String getBasebandVersion() { + return getProperty("gsm.version.baseband", Build.UNKNOWN); + } + + public static String getRadioVersion() { + try { + return Build.getRadioVersion() != null ? Build.getRadioVersion() : Build.UNKNOWN; + } catch (Throwable t) { + return Build.UNKNOWN; + } + } + + public static String getScreenSize(Context context) { + try { + android.util.DisplayMetrics dm = context.getResources().getDisplayMetrics(); + double diagonal = Math.sqrt(Math.pow(dm.widthPixels / dm.xdpi, 2) + + Math.pow(dm.heightPixels / dm.ydpi, 2)); + return String.format(Locale.US, "%.1f", diagonal); + } catch (Throwable t) { + return ""; + } + } + + public static double getScreenInch(Context context) { + try { + android.util.DisplayMetrics dm = context.getResources().getDisplayMetrics(); + double diagonal = Math.sqrt(Math.pow(dm.widthPixels / dm.xdpi, 2) + + Math.pow(dm.heightPixels / dm.ydpi, 2)); + return Math.round(diagonal * 10.0) / 10.0; + } catch (Throwable t) { + return 0.0; + } + } + + public static int getRefreshRate(Context context) { + try { + android.view.Display display = ((android.view.WindowManager) + context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + return Math.round(display.getRefreshRate()); + } catch (Throwable t) { + return 0; + } + } + + public static String getOsType() { + return "Android"; + } + + public static String getOsVersion() { + return Build.VERSION.RELEASE; + } + + public static String getFirmwareVersion() { + return getProperty("ro.build.version.incremental", Build.UNKNOWN); + } + public static boolean isMainProcessName(Context cxt, int pid) { String packageName = cxt.getPackageName(); ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);