From 3b9df7577bbf701a9482d1bc5080ec2ff3464fb5 Mon Sep 17 00:00:00 2001 From: uncor3 Date: Sat, 27 Sep 2025 11:31:25 +0000 Subject: [PATCH] Refactor battery information handling for old and new devices --- src/core/services/get_battery_info.cpp | 10 +- src/core/services/init_device.cpp | 174 ++++++++++++++++++------- src/deviceinfowidget.cpp | 34 +---- src/iDescriptor.h | 11 +- 4 files changed, 141 insertions(+), 88 deletions(-) diff --git a/src/core/services/get_battery_info.cpp b/src/core/services/get_battery_info.cpp index 987980b..c2f800e 100644 --- a/src/core/services/get_battery_info.cpp +++ b/src/core/services/get_battery_info.cpp @@ -17,16 +17,8 @@ void get_battery_info(std::string productType, idevice_t idevice, return; } - bool newerThaniPhone8 = - is_product_type_newer(productType, std::string("iPhone8,1")); - - const char *batteryQuery = - is_iphone - ? newerThaniPhone8 ? "AppleSmartBattery" : "AppleARMPMUCharger" - : "AppleARMPMUCharger"; - if (diagnostics_relay_query_ioregistry_entry( - diagnostics_client, nullptr, batteryQuery, &diagnostics) != + diagnostics_client, nullptr, "IOPMPowerSource", &diagnostics) != DIAGNOSTICS_RELAY_E_SUCCESS && !diagnostics) { diff --git a/src/core/services/init_device.cpp b/src/core/services/init_device.cpp index 9c1bc07..00070b6 100644 --- a/src/core/services/init_device.cpp +++ b/src/core/services/init_device.cpp @@ -34,6 +34,87 @@ std::string safeGetXML(const char *key, pugi::xml_node dict) return ""; } +// this is reused in the ui in deviceinfowidget +void parseOldDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d) +{ + d.batteryInfo.isCharging = ioreg["IsCharging"].getBool(); + + d.batteryInfo.fullyCharged = ioreg["FullyCharged"].getBool(); + + uint64_t appleRawCurrentCapacity = + ioreg["AppleRawCurrentCapacity"].getUInt(); + uint64_t appleRawMaxCapacity = ioreg["AppleRawMaxCapacity"].getUInt(); + + qDebug() << "appleRawCurrentCapacity" << appleRawCurrentCapacity; + qDebug() << "appleRawMaxCapacity" << appleRawMaxCapacity; + + uint64_t oldCurrrentBatteryLevel = + (appleRawCurrentCapacity && appleRawMaxCapacity) + ? (appleRawCurrentCapacity * 100 / appleRawMaxCapacity) + : 0; + qDebug() << "oldCurrrentBatteryLevel" << oldCurrrentBatteryLevel; + + d.batteryInfo.currentBatteryLevel = oldCurrrentBatteryLevel; + + // adaptor details + d.batteryInfo.usbConnectionType = + ioreg["AdapterDetails"]["Description"].getString() == "usb type-c" + ? BatteryInfo::ConnectionType::USB_TYPEC + : BatteryInfo::ConnectionType::USB; + d.batteryInfo.adapterVoltage = 0; + + // watt + d.batteryInfo.watts = ioreg["AdapterDetails"]["Watts"].getUInt(); +} + +void parseOldDevice(PlistNavigator &ioreg, DeviceInfo &d) +{ + uint64_t cycleCount = ioreg["CycleCount"].getUInt(); + + // skipping on very old devices for now + std::string batterySerialNumber = ""; + uint64_t designCapacity = ioreg["DesignCapacity"].getUInt(); + + uint64_t maxCapacity = ioreg["MaxCapacity"].getUInt(); + + qDebug() << "Design capacity: " << designCapacity; + qDebug() << "Max capacity: " << maxCapacity; + + // Compat + int healthPercent = + (designCapacity != 0) ? (maxCapacity * 100) / designCapacity : 0; + healthPercent = std::min(healthPercent, 100); + d.batteryInfo.health = QString::number(healthPercent) + "%"; + d.batteryInfo.cycleCount = cycleCount; + d.batteryInfo.serialNumber = !batterySerialNumber.empty() + ? batterySerialNumber + : "Error retrieving serial number"; + + parseOldDeviceBattery(ioreg, d); +} + +// this is reused in the ui in deviceinfowidget +void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d) +{ + d.batteryInfo.isCharging = ioreg["IsCharging"].getBool(); + + d.batteryInfo.fullyCharged = ioreg["FullyCharged"].getBool(); + + d.batteryInfo.currentBatteryLevel = + ioreg["BatteryData"]["StateOfCharge"].getUInt(); + + d.batteryInfo.usbConnectionType = + ioreg["AdapterDetails"]["Description"].getString() == "usb type-c" + ? BatteryInfo::ConnectionType::USB_TYPEC + : BatteryInfo::ConnectionType::USB; + + // adaptor details + d.batteryInfo.adapterVoltage = + ioreg["AppleRawAdapterDetails"][0]["AdapterVoltage"].getUInt(); + + d.batteryInfo.watts = ioreg["AppleRawAdapterDetails"][0]["Watts"].getUInt(); +} + // TODO: return tyype DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, afc_client_t &afcClient, @@ -106,6 +187,10 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, d.productionDevice = safeGetBool("ProductionSOC"); if (_activationState == "Activated") { d.activationState = DeviceInfo::ActivationState::Activated; + // IOS 6 + } else if (_activationState == "WildcardActivated") { + d.activationState = + DeviceInfo::ActivationState::Activated; // Treat as activated } else if (_activationState == "FactoryActivated") { d.activationState = DeviceInfo::ActivationState::FactoryActivated; } else if (_activationState == "Unactivated") { @@ -124,66 +209,61 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, /*BatteryInfo*/ plist_t diagnostics = nullptr; get_battery_info(rawProductType, result.device, d.is_iPhone, diagnostics); + plist_print(diagnostics); + if (!diagnostics) { qDebug() << "Failed to get diagnostics plist."; return d; } + try { + PlistNavigator ioreg = PlistNavigator(diagnostics)["IORegistry"]; - plist_print(diagnostics); - uint64_t cycleCount = - PlistNavigator(diagnostics)["IORegistry"]["BatteryData"]["CycleCount"] - .getUInt(); + // old devices do not have "BatteryData" + d.oldDevice = !ioreg["BatteryData"]; + if (d.oldDevice) { + parseOldDevice(ioreg, d); + plist_free(diagnostics); + diagnostics = nullptr; + return d; + } - std::string batterySerialNumber = - PlistNavigator( - diagnostics)["IORegistry"]["BatteryData"]["BatterySerialNumber"] - .getString(); - uint64_t designCapacity = - PlistNavigator( - diagnostics)["IORegistry"]["BatteryData"]["DesignCapacity"] - .getUInt(); + bool newerThaniPhone8 = + is_product_type_newer(rawProductType, std::string("iPhone8,1")); - uint64_t appleRawCurrentCapacity = - PlistNavigator(diagnostics)["IORegistry"]["AppleRawCurrentCapacity"] - .getUInt(); + uint64_t cycleCount = ioreg["BatteryData"]["CycleCount"].getUInt(); - d.batteryInfo.health = - QString::number((appleRawCurrentCapacity * 100) / designCapacity) + "%"; - d.batteryInfo.cycleCount = cycleCount; - d.batteryInfo.serialNumber = !batterySerialNumber.empty() - ? batterySerialNumber - : "Error retrieving serial number"; + // Battery serial number + std::string batterySerialNumber = + ioreg["BatteryData"]["BatterySerialNumber"].getString(); - d.batteryInfo.isCharging = - PlistNavigator(diagnostics)["IORegistry"]["IsCharging"].getBool(); + uint64_t designCapacity = + ioreg["BatteryData"]["DesignCapacity"].getUInt(); - d.batteryInfo.fullyCharged = - PlistNavigator(diagnostics)["IORegistry"]["FullyCharged"].getBool(); + uint64_t maxCapacity = + d.is_iPhone ? newerThaniPhone8 + ? ioreg["AppleRawMaxCapacity"].getUInt() + : ioreg["BatteryData"]["MaxCapacity"].getUInt() + : ioreg["BatteryData"]["MaxCapacity"].getUInt(); - d.batteryInfo.currentBatteryLevel = - PlistNavigator(diagnostics)["IORegistry"]["CurrentCapacity"].getUInt(); + qDebug() << "Design capacity: " << designCapacity; + qDebug() << "Max capacity: " << maxCapacity; - d.batteryInfo.usbConnectionType = - PlistNavigator( - diagnostics)["IORegistry"]["AdapterDetails"]["Description"] - .getString() == "usb type-c" - ? BatteryInfo::ConnectionType::USB_TYPEC - : BatteryInfo::ConnectionType::USB; + // seems to be to the most accurate way to get health + d.batteryInfo.health = + QString::number((maxCapacity * 100) / designCapacity) + "%"; + d.batteryInfo.cycleCount = cycleCount; + d.batteryInfo.serialNumber = !batterySerialNumber.empty() + ? batterySerialNumber + : "Error retrieving serial number"; + parseDeviceBattery(ioreg, d); + plist_free(diagnostics); + diagnostics = nullptr; - d.batteryInfo.adapterVoltage = - PlistNavigator(diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0] - ["AdapterVoltage"] - .getUInt(); - - d.batteryInfo.watts = - PlistNavigator( - diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0]["Watts"] - .getUInt(); - - plist_free(diagnostics); - diagnostics = nullptr; - - return d; + return d; + } catch (const std::exception &e) { + qDebug() << "Error occurred: " << e.what(); + return d; + } } // TODO: need to handle errors and free resources properly diff --git a/src/deviceinfowidget.cpp b/src/deviceinfowidget.cpp index 1fbdfed..d1ae27c 100644 --- a/src/deviceinfowidget.cpp +++ b/src/deviceinfowidget.cpp @@ -322,35 +322,13 @@ void DeviceInfoWidget::updateBatteryInfo() } /*DATA*/ DeviceInfo &d = m_device->deviceInfo; - - d.batteryInfo.isCharging = - PlistNavigator(diagnostics)["IORegistry"]["IsCharging"].getBool(); - - d.batteryInfo.fullyCharged = - PlistNavigator(diagnostics)["IORegistry"]["FullyCharged"].getBool(); - - d.batteryInfo.currentBatteryLevel = - PlistNavigator(diagnostics)["IORegistry"]["CurrentCapacity"].getUInt(); - - d.batteryInfo.usbConnectionType = - PlistNavigator( - diagnostics)["IORegistry"]["AdapterDetails"]["Description"] - .getString() == "usb type-c" - ? BatteryInfo::ConnectionType::USB_TYPEC - : BatteryInfo::ConnectionType::USB; - - d.batteryInfo.adapterVoltage = - PlistNavigator(diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0] - ["AdapterVoltage"] - .getUInt(); - - d.batteryInfo.watts = - PlistNavigator( - diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0]["Watts"] - .getUInt(); - + qDebug() << "old device" << d.oldDevice; + PlistNavigator ioreg = PlistNavigator(diagnostics)["IORegistry"]; + if (d.oldDevice) + parseOldDeviceBattery(ioreg, d); + else + parseDeviceBattery(ioreg, d); /*UI*/ - m_chargingStatusLabel->setText(d.batteryInfo.isCharging ? "Charging" : "Not Charging"); m_chargingWattsLabel->setText(QString::number(d.batteryInfo.watts) + "W"); diff --git a/src/iDescriptor.h b/src/iDescriptor.h index 283b0ce..b1d0723 100644 --- a/src/iDescriptor.h +++ b/src/iDescriptor.h @@ -131,6 +131,7 @@ struct DeviceInfo { BatteryInfo batteryInfo; DiskInfo diskInfo; bool is_iPhone; + bool oldDevice; }; struct iDescriptorDevice { @@ -260,7 +261,7 @@ private: public: PlistNavigator(plist_t node) : current_node(node) {} - // Existing dictionary key access + // dict key access PlistNavigator operator[](const char *key) { if (!current_node || plist_get_node_type(current_node) != PLIST_DICT) { @@ -270,7 +271,7 @@ public: return PlistNavigator(next); } - // Add array index access + // array index access PlistNavigator operator[](int index) { if (!current_node || plist_get_node_type(current_node) != PLIST_ARRAY) { @@ -287,7 +288,6 @@ public: operator plist_t() const { return current_node; } bool valid() const { return current_node != nullptr; } - // Your existing helper methods bool getBool() const { if (!current_node) @@ -437,4 +437,7 @@ bool query_mobile_gestalt(iDescriptorDevice *id_device, const QStringList &keys, std::string safeGetXML(const char *key, pugi::xml_node dict); void get_battery_info(std::string productType, idevice_t idevice, - bool is_iphone, plist_t &diagnostics); \ No newline at end of file + bool is_iphone, plist_t &diagnostics); + +void parseOldDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d); +void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d); \ No newline at end of file