diff options
| author | 2012-04-12 12:21:04 +0200 | |
|---|---|---|
| committer | 2012-10-21 14:19:50 +0200 | |
| commit | 046093a4ba12d374006c1ea3a7a5a4bfe8bc4c3d (patch) | |
| tree | 13ec9c07736a9f850114d36edefafef82b36883a /src | |
| parent | 446f1b8dbd65c95c7cb37ceca5e907181b9b6169 (diff) | |
| download | libimobiledevice-046093a4ba12d374006c1ea3a7a5a4bfe8bc4c3d.tar.gz libimobiledevice-046093a4ba12d374006c1ea3a7a5a4bfe8bc4c3d.tar.bz2 | |
diagnostics_relay: Implement sleep, restart, shutdown and request_diagnostics
Diffstat (limited to 'src')
| -rw-r--r-- | src/diagnostics_relay.c | 216 |
1 files changed, 121 insertions, 95 deletions
diff --git a/src/diagnostics_relay.c b/src/diagnostics_relay.c index 4cde230..f289fd9 100644 --- a/src/diagnostics_relay.c +++ b/src/diagnostics_relay.c | |||
| @@ -32,36 +32,15 @@ | |||
| 32 | * plist to a previously sent request. | 32 | * plist to a previously sent request. |
| 33 | * | 33 | * |
| 34 | * @param dict The plist to evaluate. | 34 | * @param dict The plist to evaluate. |
| 35 | * @param query_match Name of the request to match or NULL if no match is | ||
| 36 | * required. | ||
| 37 | * | 35 | * |
| 38 | * @return RESULT_SUCCESS when the result is 'Success', | 36 | * @return RESULT_SUCCESS when the result is 'Success', |
| 39 | * RESULT_FAILURE when the result is 'Failure', | 37 | * RESULT_FAILURE when the result is 'Failure', |
| 40 | * or a negative value if an error occured during evaluation. | 38 | * or a negative value if an error occured during evaluation. |
| 41 | */ | 39 | */ |
| 42 | static int diagnostics_relay_check_result(plist_t dict, const char *query_match) | 40 | static int diagnostics_relay_check_result(plist_t dict) |
| 43 | { | 41 | { |
| 44 | int ret = -1; | 42 | int ret = -1; |
| 45 | 43 | ||
| 46 | plist_t query_node = plist_dict_get_item(dict, "Request"); | ||
| 47 | if (!query_node) { | ||
| 48 | return ret; | ||
| 49 | } | ||
| 50 | if (plist_get_node_type(query_node) != PLIST_STRING) { | ||
| 51 | return ret; | ||
| 52 | } else { | ||
| 53 | char *query_value = NULL; | ||
| 54 | plist_get_string_val(query_node, &query_value); | ||
| 55 | if (!query_value) { | ||
| 56 | return ret; | ||
| 57 | } | ||
| 58 | if (query_match && (strcmp(query_value, query_match) != 0)) { | ||
| 59 | free(query_value); | ||
| 60 | return ret; | ||
| 61 | } | ||
| 62 | free(query_value); | ||
| 63 | } | ||
| 64 | |||
| 65 | plist_t result_node = plist_dict_get_item(dict, "Status"); | 44 | plist_t result_node = plist_dict_get_item(dict, "Status"); |
| 66 | if (!result_node) | 45 | if (!result_node) |
| 67 | return ret; | 46 | return ret; |
| @@ -226,7 +205,7 @@ diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t c | |||
| 226 | return DIAGNOSTICS_RELAY_E_PLIST_ERROR; | 205 | return DIAGNOSTICS_RELAY_E_PLIST_ERROR; |
| 227 | } | 206 | } |
| 228 | 207 | ||
| 229 | if (diagnostics_relay_check_result(dict, "Goodbye") == RESULT_SUCCESS) { | 208 | if (diagnostics_relay_check_result(dict) == RESULT_SUCCESS) { |
| 230 | debug_info("success"); | 209 | debug_info("success"); |
| 231 | ret = DIAGNOSTICS_RELAY_E_SUCCESS; | 210 | ret = DIAGNOSTICS_RELAY_E_SUCCESS; |
| 232 | } | 211 | } |
| @@ -235,93 +214,141 @@ diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t c | |||
| 235 | return ret; | 214 | return ret; |
| 236 | } | 215 | } |
| 237 | 216 | ||
| 238 | diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, plist_t* diagnostics) | 217 | /** |
| 218 | * Puts the device into deep sleep mode and disconnects from host. | ||
| 219 | * | ||
| 220 | * @param client The diagnostics_relay client | ||
| 221 | * | ||
| 222 | * @return DIAGNOSTICS_RELAY_E_SUCCESS on success, | ||
| 223 | * DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL, | ||
| 224 | * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the | ||
| 225 | * request | ||
| 226 | */ | ||
| 227 | diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client) | ||
| 239 | { | 228 | { |
| 240 | if (!client || diagnostics == NULL) | 229 | if (!client) |
| 241 | return DIAGNOSTICS_RELAY_E_INVALID_ARG; | 230 | return DIAGNOSTICS_RELAY_E_INVALID_ARG; |
| 242 | 231 | ||
| 243 | diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; | 232 | diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; |
| 244 | 233 | ||
| 245 | plist_t dict = plist_new_dict(); | 234 | plist_t dict = plist_new_dict(); |
| 246 | /* | 235 | |
| 247 | Provides a diagnostics interface. Some stuff is only available on iOS 5+ | ||
| 248 | |||
| 249 | Protocol: | ||
| 250 | |||
| 251 | Request: | ||
| 252 | <key>Request</key><string>IORegistry</string> | ||
| 253 | [<key>CurrentPlane</key><string>IODeviceTree</string>] | ||
| 254 | Response: | ||
| 255 | [Diagnostics] | ||
| 256 | IORegistry | ||
| 257 | ... | ||
| 258 | Status | ||
| 259 | "Success" | "UnknownRequest" | ||
| 260 | [ErrorCode] | ||
| 261 | %d | ||
| 262 | |||
| 263 | Unknown Strings: | ||
| 264 | |||
| 265 | ? IO80211Interface | ||
| 266 | ? InternalBuild | ||
| 267 | ? DisplayFail | ||
| 268 | ? DisplayPass | ||
| 269 | ? WaitForDisconnect | ||
| 270 | |||
| 271 | Known/Tested Requests: | ||
| 272 | |||
| 273 | // wifi: Show wifi status | ||
| 274 | plist_dict_insert_item(dict,"Request", plist_new_string("WiFi")); | ||
| 275 | |||
| 276 | // gas_gauge: Show battery load cycles and more | ||
| 277 | plist_dict_insert_item(dict,"Request", plist_new_string("GasGauge")); | ||
| 278 | plist_dict_insert_item(dict,"Request", plist_new_string("NAND")); | ||
| 279 | plist_dict_insert_item(dict,"Request", plist_new_string("Sleep")); | 236 | plist_dict_insert_item(dict,"Request", plist_new_string("Sleep")); |
| 280 | plist_dict_insert_item(dict,"Request", plist_new_string("Shutdown")); | ||
| 281 | plist_dict_insert_item(dict,"Request", plist_new_string("Restart")); | ||
| 282 | |||
| 283 | // obliberate: Wipe data on device | ||
| 284 | // @note: Currently yields: "iPhone mobile_diagnostics_relay[253] <Error>: do_obliterate: obliteration denied: not running internal build." | ||
| 285 | plist_dict_insert_item(dict,"Request", plist_new_string("Obliterate")); | ||
| 286 | ? DataPartitionOnly | ||
| 287 | ? ObliterationType | ||
| 288 | ? ObliterateDataPartition | ||
| 289 | ? ObliterationTypeWipeAndBrick | ||
| 290 | ? DisplayProgressBar | ||
| 291 | ? SkipDataObliteration | ||
| 292 | ? ObliterationMessage | ||
| 293 | |||
| 294 | // mobile_gestalt: read out managed keys | ||
| 295 | plist_t keys = plist_new_array(); | ||
| 296 | plist_array_append_item(keys, plist_new_string("UserAssignedDeviceName")); | ||
| 297 | plist_array_append_item(keys, plist_new_string("BasebandSecurityInfo")); | ||
| 298 | plist_array_append_item(keys, plist_new_string("BasebandSerialNumber")); | ||
| 299 | plist_array_append_item(keys, plist_new_string("MyPhoneNumber")); | ||
| 300 | plist_array_append_item(keys, plist_new_string("SNUM")); | ||
| 301 | plist_dict_insert_item(dict,"MobileGestaltKeys", keys); | ||
| 302 | plist_dict_insert_item(dict,"Request", plist_new_string("MobileGestalt")); | ||
| 303 | |||
| 304 | // io registry: dump by plane or name and class | ||
| 305 | plist_dict_insert_item(dict,"CurrentPlane", plist_new_string("IODeviceTree")); | ||
| 306 | or | ||
| 307 | plist_dict_insert_item(dict,"EntryName", plist_new_string("baseband")); | ||
| 308 | plist_dict_insert_item(dict,"EntryClass", plist_new_string("IOPlatformDevice")); | ||
| 309 | plist_dict_insert_item(dict,"Request", plist_new_string("IORegistry")); | ||
| 310 | */ | ||
| 311 | plist_dict_insert_item(dict,"Request", plist_new_string("IORegistry")); | ||
| 312 | plist_dict_insert_item(dict,"CurrentPlane", plist_new_string("")); | ||
| 313 | ret = diagnostics_relay_send(client, dict); | 237 | ret = diagnostics_relay_send(client, dict); |
| 314 | plist_free(dict); | 238 | plist_free(dict); |
| 315 | dict = NULL; | 239 | dict = NULL; |
| 316 | 240 | ||
| 317 | ret = diagnostics_relay_receive(client, &dict); | 241 | ret = diagnostics_relay_receive(client, &dict); |
| 318 | if (!dict) { | 242 | if (!dict) { |
| 319 | debug_info("did not get response back"); | ||
| 320 | return DIAGNOSTICS_RELAY_E_PLIST_ERROR; | 243 | return DIAGNOSTICS_RELAY_E_PLIST_ERROR; |
| 321 | } | 244 | } |
| 322 | 245 | ||
| 323 | if (diagnostics_relay_check_result(dict, "Diagnostics") == RESULT_SUCCESS) { | 246 | if (diagnostics_relay_check_result(dict) == RESULT_SUCCESS) { |
| 324 | debug_info("success"); | 247 | ret = DIAGNOSTICS_RELAY_E_SUCCESS; |
| 248 | } | ||
| 249 | |||
| 250 | plist_free(dict); | ||
| 251 | return ret; | ||
| 252 | } | ||
| 253 | |||
| 254 | static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_relay_client_t client, const char* name, int flags) | ||
| 255 | { | ||
| 256 | if (!client) | ||
| 257 | return DIAGNOSTICS_RELAY_E_INVALID_ARG; | ||
| 258 | |||
| 259 | diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; | ||
| 260 | |||
| 261 | plist_t dict = plist_new_dict(); | ||
| 262 | plist_dict_insert_item(dict,"Request", plist_new_string(name)); | ||
| 263 | |||
| 264 | if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) { | ||
| 265 | plist_dict_insert_item(dict, "WaitForDisconnect", plist_new_bool(1)); | ||
| 266 | } | ||
| 267 | |||
| 268 | if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS) { | ||
| 269 | plist_dict_insert_item(dict, "DisplayPass", plist_new_bool(1)); | ||
| 270 | } | ||
| 271 | |||
| 272 | if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL) { | ||
| 273 | plist_dict_insert_item(dict, "DisplayFail", plist_new_bool(1)); | ||
| 274 | } | ||
| 275 | |||
| 276 | ret = diagnostics_relay_send(client, dict); | ||
| 277 | plist_free(dict); | ||
| 278 | dict = NULL; | ||
| 279 | |||
| 280 | ret = diagnostics_relay_receive(client, &dict); | ||
| 281 | if (!dict) { | ||
| 282 | return DIAGNOSTICS_RELAY_E_PLIST_ERROR; | ||
| 283 | } | ||
| 284 | |||
| 285 | if (diagnostics_relay_check_result(dict) == RESULT_SUCCESS) { | ||
| 286 | ret = DIAGNOSTICS_RELAY_E_SUCCESS; | ||
| 287 | } | ||
| 288 | |||
| 289 | plist_free(dict); | ||
| 290 | return ret; | ||
| 291 | } | ||
| 292 | |||
| 293 | /** | ||
| 294 | * Restart the device and optionally show a user notification. | ||
| 295 | * | ||
| 296 | * @param client The diagnostics_relay client | ||
| 297 | * @param flags A binary flag combination of | ||
| 298 | * DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT to wait until | ||
| 299 | * diagnostics_relay_client_free() disconnects before execution and | ||
| 300 | * DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL to show a "FAIL" dialog | ||
| 301 | * or DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS to show an "OK" dialog | ||
| 302 | * | ||
| 303 | * @return DIAGNOSTICS_RELAY_E_SUCCESS on success, | ||
| 304 | * DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL, | ||
| 305 | * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the | ||
| 306 | * request | ||
| 307 | */ | ||
| 308 | diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, int flags) | ||
| 309 | { | ||
| 310 | return internal_diagnostics_relay_action(client, "Restart", flags); | ||
| 311 | } | ||
| 312 | |||
| 313 | /** | ||
| 314 | * Shutdown of the device and optionally show a user notification. | ||
| 315 | * | ||
| 316 | * @param client The diagnostics_relay client | ||
| 317 | * @param flags A binary flag combination of | ||
| 318 | * DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT to wait until | ||
| 319 | * diagnostics_relay_client_free() disconnects before execution and | ||
| 320 | * DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL to show a "FAIL" dialog | ||
| 321 | * or DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS to show an "OK" dialog | ||
| 322 | * | ||
| 323 | * @return DIAGNOSTICS_RELAY_E_SUCCESS on success, | ||
| 324 | * DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL, | ||
| 325 | * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the | ||
| 326 | * request | ||
| 327 | */ | ||
| 328 | diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, int flags) | ||
| 329 | { | ||
| 330 | return internal_diagnostics_relay_action(client, "Shutdown", flags); | ||
| 331 | } | ||
| 332 | |||
| 333 | diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics) | ||
| 334 | { | ||
| 335 | if (!client || diagnostics == NULL) | ||
| 336 | return DIAGNOSTICS_RELAY_E_INVALID_ARG; | ||
| 337 | |||
| 338 | diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; | ||
| 339 | |||
| 340 | plist_t dict = plist_new_dict(); | ||
| 341 | plist_dict_insert_item(dict,"Request", plist_new_string(type)); | ||
| 342 | ret = diagnostics_relay_send(client, dict); | ||
| 343 | plist_free(dict); | ||
| 344 | dict = NULL; | ||
| 345 | |||
| 346 | ret = diagnostics_relay_receive(client, &dict); | ||
| 347 | if (!dict) { | ||
| 348 | return DIAGNOSTICS_RELAY_E_PLIST_ERROR; | ||
| 349 | } | ||
| 350 | |||
| 351 | if (diagnostics_relay_check_result(dict) == RESULT_SUCCESS) { | ||
| 325 | ret = DIAGNOSTICS_RELAY_E_SUCCESS; | 352 | ret = DIAGNOSTICS_RELAY_E_SUCCESS; |
| 326 | } | 353 | } |
| 327 | if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) { | 354 | if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) { |
| @@ -331,7 +358,6 @@ diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_rela | |||
| 331 | 358 | ||
| 332 | plist_t value_node = plist_dict_get_item(dict, "Diagnostics"); | 359 | plist_t value_node = plist_dict_get_item(dict, "Diagnostics"); |
| 333 | if (value_node) { | 360 | if (value_node) { |
| 334 | debug_info("has a value"); | ||
| 335 | *diagnostics = plist_copy(value_node); | 361 | *diagnostics = plist_copy(value_node); |
| 336 | } | 362 | } |
| 337 | 363 | ||
