diff options
| author | 2016-09-23 20:07:48 +0200 | |
|---|---|---|
| committer | 2016-09-23 20:07:48 +0200 | |
| commit | 00424f40574641d1360c9b1115770f5cc5d19a72 (patch) | |
| tree | 0188e67ffc798aeddab2d75848b715dcb707bf28 | |
| parent | 3fc7a85778d85a1dda1c0c4bedc8467470468476 (diff) | |
| download | libimobiledevice-00424f40574641d1360c9b1115770f5cc5d19a72.tar.gz libimobiledevice-00424f40574641d1360c9b1115770f5cc5d19a72.tar.bz2 | |
idevicebackup2: Add installed application info to Info.plist during backup
For newer iOS versions, apparently >= iOS 8, iTunes stores information
about installed applications inside of the Info.plist file. This
commit mimics that behavior.
| -rw-r--r-- | tools/idevicebackup2.c | 115 |
1 files changed, 110 insertions, 5 deletions
diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c index 3b2c0af..2c868d7 100644 --- a/tools/idevicebackup2.c +++ b/tools/idevicebackup2.c | |||
| @@ -40,6 +40,8 @@ | |||
| 40 | #include <libimobiledevice/mobilebackup2.h> | 40 | #include <libimobiledevice/mobilebackup2.h> |
| 41 | #include <libimobiledevice/notification_proxy.h> | 41 | #include <libimobiledevice/notification_proxy.h> |
| 42 | #include <libimobiledevice/afc.h> | 42 | #include <libimobiledevice/afc.h> |
| 43 | #include <libimobiledevice/installation_proxy.h> | ||
| 44 | #include <libimobiledevice/sbservices.h> | ||
| 43 | #include "common/utils.h" | 45 | #include "common/utils.h" |
| 44 | 46 | ||
| 45 | #include <endianness.h> | 47 | #include <endianness.h> |
| @@ -274,7 +276,24 @@ static int rmdir_recursive(const char* path) | |||
| 274 | return remove_directory(path); | 276 | return remove_directory(path); |
| 275 | } | 277 | } |
| 276 | 278 | ||
| 277 | static plist_t mobilebackup_factory_info_plist_new(const char* udid, lockdownd_client_t lockdown, afc_client_t afc) | 279 | static char* get_uuid() |
| 280 | { | ||
| 281 | const char *chars = "ABCDEF0123456789"; | ||
| 282 | int i = 0; | ||
| 283 | char *uuid = (char*)malloc(sizeof(char) * 32); | ||
| 284 | |||
| 285 | srand(time(NULL)); | ||
| 286 | |||
| 287 | for (i = 0; i < 32; i++) { | ||
| 288 | uuid[i] = chars[rand() % 16]; | ||
| 289 | } | ||
| 290 | |||
| 291 | uuid[32] = '\0'; | ||
| 292 | |||
| 293 | return uuid; | ||
| 294 | } | ||
| 295 | |||
| 296 | static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t device, lockdownd_client_t lockdown, afc_client_t afc) | ||
| 278 | { | 297 | { |
| 279 | /* gather data from lockdown */ | 298 | /* gather data from lockdown */ |
| 280 | plist_t value_node = NULL; | 299 | plist_t value_node = NULL; |
| @@ -286,6 +305,74 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, lockdownd_c | |||
| 286 | /* get basic device information in one go */ | 305 | /* get basic device information in one go */ |
| 287 | lockdownd_get_value(lockdown, NULL, NULL, &root_node); | 306 | lockdownd_get_value(lockdown, NULL, NULL, &root_node); |
| 288 | 307 | ||
| 308 | /* get a list of installed user applications */ | ||
| 309 | plist_t app_dict = plist_new_dict(); | ||
| 310 | plist_t installed_apps = plist_new_array(); | ||
| 311 | instproxy_client_t ip = NULL; | ||
| 312 | if (instproxy_client_start_service(device, &ip, "idevicebackup2") == INSTPROXY_E_SUCCESS) { | ||
| 313 | plist_t client_opts = instproxy_client_options_new(); | ||
| 314 | instproxy_client_options_add(client_opts, "ApplicationType", "User", NULL); | ||
| 315 | instproxy_client_options_set_return_attributes(client_opts, "CFBundleIdentifier", "ApplicationSINF", "iTunesMetadata", NULL); | ||
| 316 | |||
| 317 | plist_t apps = NULL; | ||
| 318 | instproxy_browse(ip, client_opts, &apps); | ||
| 319 | |||
| 320 | sbservices_client_t sbs = NULL; | ||
| 321 | if (sbservices_client_start_service(device, &sbs, "idevicebackup2") != SBSERVICES_E_SUCCESS) { | ||
| 322 | printf("Couldn't establish sbservices connection. Continuing anyway.\n"); | ||
| 323 | } | ||
| 324 | |||
| 325 | if (apps && (plist_get_node_type(apps) == PLIST_ARRAY)) { | ||
| 326 | uint32_t app_count = plist_array_get_size(apps); | ||
| 327 | uint32_t i; | ||
| 328 | time_t starttime = time(NULL); | ||
| 329 | for (i = 0; i < app_count; i++) { | ||
| 330 | plist_t app_entry = plist_array_get_item(apps, i); | ||
| 331 | plist_t bundle_id = plist_dict_get_item(app_entry, "CFBundleIdentifier"); | ||
| 332 | if (bundle_id) { | ||
| 333 | char *bundle_id_str = NULL; | ||
| 334 | plist_array_append_item(installed_apps, plist_copy(bundle_id)); | ||
| 335 | |||
| 336 | plist_get_string_val(bundle_id, &bundle_id_str); | ||
| 337 | plist_t sinf = plist_dict_get_item(app_entry, "ApplicationSINF"); | ||
| 338 | plist_t meta = plist_dict_get_item(app_entry, "iTunesMetadata"); | ||
| 339 | if (sinf && meta) { | ||
| 340 | plist_t adict = plist_new_dict(); | ||
| 341 | plist_dict_set_item(adict, "ApplicationSINF", plist_copy(sinf)); | ||
| 342 | if (sbs) { | ||
| 343 | char *pngdata = NULL; | ||
| 344 | uint64_t pngsize = 0; | ||
| 345 | sbservices_get_icon_pngdata(sbs, bundle_id_str, &pngdata, &pngsize); | ||
| 346 | if (pngdata) { | ||
| 347 | plist_dict_set_item(adict, "PlaceholderIcon", plist_new_data(pngdata, pngsize)); | ||
| 348 | free(pngdata); | ||
| 349 | } | ||
| 350 | } | ||
| 351 | plist_dict_set_item(adict, "iTunesMetadata", plist_copy(meta)); | ||
| 352 | plist_dict_set_item(app_dict, bundle_id_str, adict); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | if ((time(NULL) - starttime) > 5) { | ||
| 356 | // make sure our lockdown connection doesn't time out in case this takes longer | ||
| 357 | lockdownd_query_type(lockdown, NULL); | ||
| 358 | starttime = time(NULL); | ||
| 359 | } | ||
| 360 | } | ||
| 361 | } | ||
| 362 | plist_free(apps); | ||
| 363 | |||
| 364 | if (sbs) { | ||
| 365 | sbservices_client_free(sbs); | ||
| 366 | } | ||
| 367 | |||
| 368 | instproxy_client_options_free(client_opts); | ||
| 369 | |||
| 370 | instproxy_client_free(ip); | ||
| 371 | } | ||
| 372 | |||
| 373 | /* Applications */ | ||
| 374 | plist_dict_set_item(ret, "Applications", app_dict); | ||
| 375 | |||
| 289 | /* set fields we understand */ | 376 | /* set fields we understand */ |
| 290 | value_node = plist_dict_get_item(root_node, "BuildVersion"); | 377 | value_node = plist_dict_get_item(root_node, "BuildVersion"); |
| 291 | plist_dict_set_item(ret, "Build Version", plist_copy(value_node)); | 378 | plist_dict_set_item(ret, "Build Version", plist_copy(value_node)); |
| @@ -294,8 +381,9 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, lockdownd_c | |||
| 294 | plist_dict_set_item(ret, "Device Name", plist_copy(value_node)); | 381 | plist_dict_set_item(ret, "Device Name", plist_copy(value_node)); |
| 295 | plist_dict_set_item(ret, "Display Name", plist_copy(value_node)); | 382 | plist_dict_set_item(ret, "Display Name", plist_copy(value_node)); |
| 296 | 383 | ||
| 297 | /* FIXME: How is the GUID generated? */ | 384 | char *uuid = get_uuid(); |
| 298 | plist_dict_set_item(ret, "GUID", plist_new_string("---")); | 385 | plist_dict_set_item(ret, "GUID", plist_new_string(uuid)); |
| 386 | free(uuid); | ||
| 299 | 387 | ||
| 300 | value_node = plist_dict_get_item(root_node, "IntegratedCircuitCardIdentity"); | 388 | value_node = plist_dict_get_item(root_node, "IntegratedCircuitCardIdentity"); |
| 301 | if (value_node) | 389 | if (value_node) |
| @@ -305,13 +393,21 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, lockdownd_c | |||
| 305 | if (value_node) | 393 | if (value_node) |
| 306 | plist_dict_set_item(ret, "IMEI", plist_copy(value_node)); | 394 | plist_dict_set_item(ret, "IMEI", plist_copy(value_node)); |
| 307 | 395 | ||
| 396 | /* Installed Applications */ | ||
| 397 | plist_dict_set_item(ret, "Installed Applications", installed_apps); | ||
| 398 | |||
| 308 | plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0)); | 399 | plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0)); |
| 309 | 400 | ||
| 401 | value_node = plist_dict_get_item(root_node, "MobileEquipmentIdentifier"); | ||
| 402 | plist_dict_set_item(ret, "MEID", plist_copy(value_node)); | ||
| 403 | |||
| 310 | value_node = plist_dict_get_item(root_node, "PhoneNumber"); | 404 | value_node = plist_dict_get_item(root_node, "PhoneNumber"); |
| 311 | if (value_node && (plist_get_node_type(value_node) == PLIST_STRING)) { | 405 | if (value_node && (plist_get_node_type(value_node) == PLIST_STRING)) { |
| 312 | plist_dict_set_item(ret, "Phone Number", plist_copy(value_node)); | 406 | plist_dict_set_item(ret, "Phone Number", plist_copy(value_node)); |
| 313 | } | 407 | } |
| 314 | 408 | ||
| 409 | /* FIXME Product Name */ | ||
| 410 | |||
| 315 | value_node = plist_dict_get_item(root_node, "ProductType"); | 411 | value_node = plist_dict_get_item(root_node, "ProductType"); |
| 316 | plist_dict_set_item(ret, "Product Type", plist_copy(value_node)); | 412 | plist_dict_set_item(ret, "Product Type", plist_copy(value_node)); |
| 317 | 413 | ||
| @@ -349,6 +445,7 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, lockdownd_c | |||
| 349 | "PhotosFolderAlbums", | 445 | "PhotosFolderAlbums", |
| 350 | "PhotosFolderName", | 446 | "PhotosFolderName", |
| 351 | "PhotosFolderPrefs", | 447 | "PhotosFolderPrefs", |
| 448 | "VoiceMemos.plist", | ||
| 352 | "iPhotoAlbumPrefs", | 449 | "iPhotoAlbumPrefs", |
| 353 | "iTunesApplicationIDs", | 450 | "iTunesApplicationIDs", |
| 354 | "iTunesPrefs", | 451 | "iTunesPrefs", |
| @@ -375,7 +472,15 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, lockdownd_c | |||
| 375 | lockdownd_get_value(lockdown, "com.apple.iTunes", NULL, &itunes_settings); | 472 | lockdownd_get_value(lockdown, "com.apple.iTunes", NULL, &itunes_settings); |
| 376 | plist_dict_set_item(ret, "iTunes Settings", itunes_settings ? itunes_settings : plist_new_dict()); | 473 | plist_dict_set_item(ret, "iTunes Settings", itunes_settings ? itunes_settings : plist_new_dict()); |
| 377 | 474 | ||
| 378 | plist_dict_set_item(ret, "iTunes Version", plist_new_string("10.0.1")); | 475 | /* since we usually don't have iTunes, let's get the minimum required iTunes version from the device */ |
| 476 | value_node = NULL; | ||
| 477 | lockdownd_get_value(lockdown, "com.apple.mobile.iTunes", "MinITunesVersion", &value_node); | ||
| 478 | if (value_node) { | ||
| 479 | plist_dict_set_item(ret, "iTunes Version", plist_copy(value_node)); | ||
| 480 | plist_free(value_node); | ||
| 481 | } else { | ||
| 482 | plist_dict_set_item(ret, "iTunes Version", plist_new_string("10.0.1")); | ||
| 483 | } | ||
| 379 | 484 | ||
| 380 | plist_free(root_node); | 485 | plist_free(root_node); |
| 381 | 486 | ||
| @@ -1688,7 +1793,7 @@ checkpoint: | |||
| 1688 | plist_free(info_plist); | 1793 | plist_free(info_plist); |
| 1689 | info_plist = NULL; | 1794 | info_plist = NULL; |
| 1690 | } | 1795 | } |
| 1691 | info_plist = mobilebackup_factory_info_plist_new(udid, lockdown, afc); | 1796 | info_plist = mobilebackup_factory_info_plist_new(udid, device, lockdown, afc); |
| 1692 | remove(info_path); | 1797 | remove(info_path); |
| 1693 | plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); | 1798 | plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); |
| 1694 | free(info_path); | 1799 | free(info_path); |
