Files
iDescriptor/src/core/services/init_device.cpp
T
uncor3 c84276eabc various enhancements
- add helper function declarations to iDescriptor.h
- remove unnessery mountDevImage
- single instance lock for devdiskimages (may be removed in future)
-  implement  safe_afc_read_directory to make sure client is long lived ( for now ony for  afc_read_directory needs to be wrapped)
- remove some cleanup code for testing (init_device.cpp)
- clean leave label for mount_dev_image.cpp
2025-08-24 01:46:49 +00:00

258 lines
9.5 KiB
C++

#include "../../iDescriptor.h"
#include "./detect_jailbroken.cpp"
#include "./get-device-info.cpp"
#include "libirecovery.h"
#include <QDebug>
#include <libimobiledevice/diagnostics_relay.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <pugixml.hpp>
DeviceInfo fullDeviceInfo(const pugi::xml_document &doc,
afc_client_t &afcClient, plist_t &diagnostics,
DeviceInfo &d)
{
pugi::xml_node dict = doc.child("plist").child("dict");
auto safeGet = [&](const char *key) -> std::string {
for (pugi::xml_node child = dict.first_child(); child;
child = child.next_sibling()) {
if (strcmp(child.name(), "key") == 0 &&
strcmp(child.text().as_string(), key) == 0) {
pugi::xml_node value = child.next_sibling();
if (value)
return value.text().as_string();
}
}
return "";
};
d.deviceName = safeGet("DeviceName");
d.deviceClass = safeGet("DeviceClass");
d.deviceColor = safeGet("DeviceColor");
d.modelNumber = safeGet("ModelNumber");
d.cpuArchitecture = safeGet("CPUArchitecture");
d.buildVersion = safeGet("BuildVersion");
d.hardwareModel = safeGet("HardwareModel");
d.hardwarePlatform = safeGet("HardwarePlatform");
d.ethernetAddress = safeGet("EthernetAddress");
d.bluetoothAddress = safeGet("BluetoothAddress");
d.firmwareVersion = safeGet("FirmwareVersion");
d.productVersion = safeGet("ProductVersion");
/*DiskInfo*/
try {
d.diskInfo.totalDiskCapacity =
std::stoull(safeGet("TotalDiskCapacity"));
d.diskInfo.totalDataCapacity =
std::stoull(safeGet("TotalDataCapacity"));
d.diskInfo.totalSystemCapacity =
std::stoull(safeGet("TotalSystemCapacity"));
d.diskInfo.totalDataAvailable =
std::stoull(safeGet("TotalDataAvailable"));
} catch (const std::exception &e) {
qDebug() << e.what();
/*It's ok if any of those fails*/
}
std::string _activationState = safeGet("ActivationState");
// TODO: does "ProductionSOC: true" work as well ?
d.productionDevice = std::stoi(safeGet("FusingStatus")) == 3;
if (_activationState == "Activated") {
d.activationState = DeviceInfo::ActivationState::Activated;
} else if (_activationState == "FactoryActivated") {
d.activationState = DeviceInfo::ActivationState::FactoryActivated;
} else if (_activationState == "Unactivated") {
d.activationState = DeviceInfo::ActivationState::Unactivated;
} else {
d.activationState =
DeviceInfo::ActivationState::Unactivated; // Default value
}
// TODO:RegionInfo: LL/A
d.productType = parse_product_type(safeGet("ProductType"));
d.jailbroken = detect_jailbroken(afcClient);
uint64_t cycleCount;
plist_get_uint_val(
PlistNavigator(diagnostics)["IORegistry"]["BatteryData"]["CycleCount"],
&cycleCount);
char *batterySerialNumber;
plist_get_string_val(
PlistNavigator(
diagnostics)["IORegistry"]["BatteryData"]["BatterySerialNumber"],
&batterySerialNumber);
uint64_t designCapacity;
plist_get_uint_val(
PlistNavigator(
diagnostics)["IORegistry"]["BatteryData"]["DesignCapacity"],
&designCapacity);
uint64_t absoluteCapacity;
plist_get_uint_val(
PlistNavigator(diagnostics)["IORegistry"]["AbsoluteCapacity"],
&absoluteCapacity);
d.batteryInfo.health =
QString::number((absoluteCapacity * 100) / designCapacity) + "%";
d.batteryInfo.cycleCount = cycleCount;
d.batteryInfo.serialNumber = batterySerialNumber
? batterySerialNumber
: "Error retrieving serial number";
plist_free(diagnostics);
diagnostics = nullptr;
return d;
}
// TODO: need to handle errors and free resources properly
IDescriptorInitDeviceResult init_idescriptor_device(const char *udid)
{
// TODO:on a broken usb cable this can hang for a long time
// causing the UI to freeze
qDebug() << "Initializing iDescriptor device with UDID: "
<< QString::fromUtf8(udid);
IDescriptorInitDeviceResult result = {};
lockdownd_client_t client;
lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
lockdownd_service_descriptor_t lockdownService = nullptr;
diagnostics_relay_client_t diagnostics_client = nullptr;
afc_client_t afcClient = nullptr;
try {
idevice_error_t ret = idevice_new_with_options(&result.device, udid,
IDEVICE_LOOKUP_USBMUX);
if (ret != IDEVICE_E_SUCCESS) {
qDebug() << "Failed to connect to device: " << ret;
return result;
}
if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(
result.device, &client, APP_LABEL))) {
result.error = ldret;
qDebug() << "Failed to create lockdown client: " << ldret;
idevice_free(result.device);
return result;
}
if (LOCKDOWN_E_SUCCESS !=
(ldret = lockdownd_start_service(client, "com.apple.afc",
&lockdownService))) {
lockdownd_client_free(client);
idevice_free(result.device);
qDebug() << "Failed to start AFC service: " << ldret;
return result;
}
if (lockdownService) {
qDebug() << "AFC service started successfully.";
} else {
qDebug() << "AFC service descriptor is null.";
// lockdownd_client_free(result.client);
// idevice_free(result.device);
// return result;
}
if (afc_client_new(result.device, lockdownService, &afcClient) !=
AFC_E_SUCCESS) {
lockdownd_service_descriptor_free(lockdownService);
lockdownd_client_free(client);
idevice_free(result.device);
qDebug() << "Failed to create AFC client: " << ldret;
return result;
}
if (diagnostics_relay_client_start_service(
result.device, &diagnostics_client, nullptr) !=
DIAGNOSTICS_RELAY_E_SUCCESS) {
qDebug() << "Failed to start diagnostics relay service.";
return result;
}
plist_t diagnostics = nullptr;
// TODO: iPhone 8 and above should query AppleSmartBattery
if (diagnostics_relay_query_ioregistry_entry(
diagnostics_client, nullptr, "AppleARMPMUCharger",
&diagnostics) != DIAGNOSTICS_RELAY_E_SUCCESS &&
!diagnostics) {
qDebug()
<< "Failed to query diagnostics relay for AppleARMPMUCharger.";
// Clean up resources before returning
// if (afcClient)
// afc_client_free(afcClient);
if (lockdownService)
lockdownd_service_descriptor_free(lockdownService);
if (client)
lockdownd_client_free(client);
if (diagnostics_client)
diagnostics_relay_client_free(diagnostics_client);
return result;
}
pugi::xml_document infoXml;
get_device_info_xml(udid, 0, 0, infoXml, client, result.device);
if (infoXml.empty()) {
qDebug() << "Failed to retrieve device info XML for UDID: "
<< QString::fromUtf8(udid);
// Clean up resources before returning
// afc_client_free(result.afcClient);
// lockdownd_service_descriptor_free(result.lockdownService);
// lockdownd_client_free(result.client);
idevice_free(result.device);
return result;
}
// if (result.device) idevice_free(result.device);
fullDeviceInfo(infoXml, afcClient, diagnostics, result.deviceInfo);
result.afcClient = afcClient;
result.success = true;
// TODO: cleanup needed ?
// if (afcClient)
// afc_client_free(afcClient);
// if (lockdownService)
// lockdownd_service_descriptor_free(lockdownService);
// if (client)
// lockdownd_client_free(client);
// if (diagnostics_client)
// diagnostics_relay_client_free(diagnostics_client);
return result;
} catch (const std::exception &e) {
qDebug() << "Exception in init_idescriptor_device: " << e.what();
// Clean up any allocated resources
// if (result.afcClient) afc_client_free(result.afcClient);
// if (result.lockdownService)
// lockdownd_service_descriptor_free(result.lockdownService);
if (client)
lockdownd_client_free(client);
if (result.device)
idevice_free(result.device);
return result;
}
}
IDescriptorInitDeviceResultRecovery
init_idescriptor_recovery_device(irecv_device_info *info)
{
IDescriptorInitDeviceResultRecovery result;
result.deviceInfo = *info;
uint64_t ecid = info->ecid;
// irecv_client_t client = nullptr;
// Docs say that clients are not long-lived, so instead of storing, we
// create a new one each time we need it. irecv_error_t ret =
// irecv_open_with_ecid_and_attempts(&client, ecid,
// RECOVERY_CLIENT_CONNECTION_TRIES);
// if (ret != IRECV_E_SUCCESS)
// {
// return result;
// }
result.success = true;
return result;
}