[AltServer] Improves handling of errors when installing apps

This commit is contained in:
Riley Testut
2019-06-18 16:37:54 -07:00
parent 205fb3d7e9
commit e7391a0542
3 changed files with 98 additions and 61 deletions

View File

@@ -9,6 +9,7 @@
#import <Foundation/Foundation.h>
extern NSErrorDomain const AltServerErrorDomain;
extern NSErrorDomain const AltServerInstallationErrorDomain;
typedef NS_ERROR_ENUM(AltServerErrorDomain, ALTServerError)
{
@@ -23,6 +24,8 @@ typedef NS_ERROR_ENUM(AltServerErrorDomain, ALTServerError)
ALTServerErrorInvalidResponse,
ALTServerErrorInvalidApp,
ALTServerErrorInstallationFailed,
ALTServerErrorMaximumFreeAppLimitReached,
};
NS_ASSUME_NONNULL_BEGIN

View File

@@ -9,6 +9,56 @@
#import "NSError+ALTServerError.h"
NSErrorDomain const AltServerErrorDomain = @"com.rileytestut.AltServer";
NSErrorDomain const AltServerInstallationErrorDomain = @"com.rileytestut.AltServer.Installation";
@implementation NSError (ALTServerError)
+ (void)load
{
[NSError setUserInfoValueProviderForDomain:AltServerErrorDomain provider:^id _Nullable(NSError * _Nonnull error, NSErrorUserInfoKey _Nonnull userInfoKey) {
if ([userInfoKey isEqualToString:NSLocalizedFailureReasonErrorKey])
{
return [error alt_localizedDescription];
}
return nil;
}];
}
- (nullable NSString *)alt_localizedDescription
{
switch ((ALTServerError)self.code)
{
case ALTServerErrorUnknown:
return NSLocalizedString(@"An unknown error occured.", @"");
case ALTServerErrorConnectionFailed:
return NSLocalizedString(@"Could not connect to AltServer.", @"");
case ALTServerErrorLostConnection:
return NSLocalizedString(@"Lost connection to AltServer.", @"");
case ALTServerErrorDeviceNotFound:
return NSLocalizedString(@"AltServer could not locate this device", @"");
case ALTServerErrorDeviceWriteFailed:
return NSLocalizedString(@"Failed to write app data to phone.", @"");
case ALTServerErrorInvalidRequest:
return NSLocalizedString(@"AltServer received an invalid request.", @"");
case ALTServerErrorInvalidResponse:
return NSLocalizedString(@"AltServer sent an invalid response.", @"");
case ALTServerErrorInvalidApp:
return NSLocalizedString(@"The app is invalid.", @"");
case ALTServerErrorInstallationFailed:
return NSLocalizedString(@"An error occured while installing the app.", @"");
case ALTServerErrorMaximumFreeAppLimitReached:
return NSLocalizedString(@"You have reached the limit of 3 apps per device.", @"");
}
}
@end

View File

@@ -15,16 +15,14 @@
#include <libimobiledevice/notification_proxy.h>
#include <libimobiledevice/afc.h>
void ALTDeviceManagerDidFinishAppInstallation(const char *notification, void *udid);
void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *udid);
NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError";
@interface ALTDeviceManager ()
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, void (^)(void)> *installationCompletionHandlers;
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, void (^)(NSError *)> *installationCompletionHandlers;
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, NSProgress *> *installationProgress;
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, NSValue *> *installationClients;
@property (nonatomic, readonly) dispatch_queue_t installationQueue;
@end
@@ -49,7 +47,6 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError";
{
_installationCompletionHandlers = [NSMutableDictionary dictionary];
_installationProgress = [NSMutableDictionary dictionary];
_installationClients = [NSMutableDictionary dictionary];
_installationQueue = dispatch_queue_create("com.rileytestut.AltServer.InstallationQueue", DISPATCH_QUEUE_SERIAL);
}
@@ -75,7 +72,7 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError";
lockdownd_service_descriptor_t service = NULL;
void (^finish)(NSError *error) = ^(NSError *error) {
np_client_free(np);
instproxy_client_free(ipc);
afc_client_free(afc);
lockdownd_client_free(client);
@@ -138,28 +135,6 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError";
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
}
/* Connect to Notification Proxy */
if ((lockdownd_start_service(client, "com.apple.mobile.notification_proxy", &service) != LOCKDOWN_E_SUCCESS) || service == NULL)
{
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
}
if (np_client_new(device, service, &np) != NP_E_SUCCESS)
{
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
}
np_set_notify_callback(np, ALTDeviceManagerDidFinishAppInstallation, uuidString);
const char *notifications[2] = { NP_APP_INSTALLED, NULL };
np_observe_notifications(np, notifications);
if (service)
{
lockdownd_service_descriptor_free(service);
service = NULL;
}
/* Connect to Installation Proxy */
if ((lockdownd_start_service(client, "com.apple.mobile.installation_proxy", &service) != LOCKDOWN_E_SUCCESS) || service == NULL)
{
@@ -177,18 +152,12 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError";
service = NULL;
}
lockdownd_service_descriptor_free(service);
service = NULL;
/* Connect to AFC service */
if ((lockdownd_start_service(client, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || service == NULL)
{
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
}
lockdownd_client_free(client);
client = NULL;
if (afc_client_new(device, service, &afc) != AFC_E_SUCCESS)
{
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
@@ -239,12 +208,11 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError";
NSProgress *installationProgress = [NSProgress progressWithTotalUnitCount:100 parent:progress pendingUnitCount:1];
NSValue *value = [NSValue valueWithPointer:(const void *)np];
NSProgress *installationProgress = [NSProgress progressWithTotalUnitCount:100 parent:progress pendingUnitCount:1];
self.installationClients[UUID] = value;
self.installationProgress[UUID] = installationProgress;
self.installationCompletionHandlers[UUID] = ^{
finish(nil);
self.installationCompletionHandlers[UUID] = ^(NSError *error) {
finish(error);
if (temporaryDirectoryURL != nil)
{
@@ -470,29 +438,6 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError";
#pragma mark - Callbacks -
void ALTDeviceManagerDidFinishAppInstallation(const char *notification, void *uuid)
{
NSUUID *UUID = [[NSUUID alloc] initWithUUIDString:[NSString stringWithUTF8String:(const char *)uuid]];
void (^completionHandler)(void) = ALTDeviceManager.sharedManager.installationCompletionHandlers[UUID];
if (completionHandler != nil)
{
completionHandler();
ALTDeviceManager.sharedManager.installationCompletionHandlers[UUID] = nil;
ALTDeviceManager.sharedManager.installationProgress[UUID] = nil;
}
NSValue *value = ALTDeviceManager.sharedManager.installationClients[UUID];
if (value != nil)
{
np_client_t np = (np_client_t)value.pointerValue;
np_set_notify_callback(np, NULL, uuid);
ALTDeviceManager.sharedManager.installationClients[UUID] = nil;
}
}
void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *uuid)
{
NSUUID *UUID = [[NSUUID alloc] initWithUUIDString:[NSString stringWithUTF8String:(const char *)uuid]];
@@ -506,7 +451,46 @@ void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *uuid)
int percent = -1;
instproxy_status_get_percent_complete(status, &percent);
if (progress.completedUnitCount < percent)
char *name = NULL;
char *description = NULL;
uint64_t code = 0;
instproxy_status_get_error(status, &name, &description, &code);
if ((percent == -1 && progress.completedUnitCount > 0) || code != 0)
{
void (^completionHandler)(NSError *) = ALTDeviceManager.sharedManager.installationCompletionHandlers[UUID];
if (completionHandler != nil)
{
if (code != 0)
{
NSLog(@"Error installing app. %@ (%@). %@", @(code), @(name), @(description));
NSError *error = nil;
if (code == 3892346913)
{
error = [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorMaximumFreeAppLimitReached userInfo:nil];
}
else
{
NSError *underlyingError = [NSError errorWithDomain:AltServerInstallationErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: @(description)}];
error = [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorInstallationFailed userInfo:@{NSUnderlyingErrorKey: underlyingError}];
}
completionHandler(error);
}
else
{
NSLog(@"Finished installing app!");
completionHandler(nil);
}
ALTDeviceManager.sharedManager.installationCompletionHandlers[UUID] = nil;
ALTDeviceManager.sharedManager.installationProgress[UUID] = nil;
}
}
else if (progress.completedUnitCount < percent)
{
progress.completedUnitCount = percent;