summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Bingner <sam@bingner.com>2019-05-18 22:15:28 -1000
committerSam Bingner <sam@bingner.com>2019-05-18 22:15:28 -1000
commit8cc4cb5a360131fff8a1ff9da70f9893dca1559c (patch)
treec81253f67edce9bf08d758dd4fd44e409da4d48f
parentb3d0160fb6bcf2b9429907cd6273578f624182ea (diff)
Update uikittools
l---------data/uikittools/_metadata/findutils.dep1
-rw-r--r--data/uikittools/ldrestart-jbd.diff6
-rw-r--r--data/uikittools/uicache.diff1109
-rw-r--r--data/uikittools/world.diff702
4 files changed, 1816 insertions, 2 deletions
diff --git a/data/uikittools/_metadata/findutils.dep b/data/uikittools/_metadata/findutils.dep
new file mode 120000
index 000000000..0cf65ba21
--- /dev/null
+++ b/data/uikittools/_metadata/findutils.dep
@@ -0,0 +1 @@
+../../findutils \ No newline at end of file
diff --git a/data/uikittools/ldrestart-jbd.diff b/data/uikittools/ldrestart-jbd.diff
index 49b86d4b8..43f66a693 100644
--- a/data/uikittools/ldrestart-jbd.diff
+++ b/data/uikittools/ldrestart-jbd.diff
@@ -2,7 +2,7 @@ diff --git a/ldrestart.cpp b/ldrestart.cpp
index a6d6cb6..c9a3b33 100644
--- a/ldrestart.cpp
+++ b/ldrestart.cpp
-@@ -34,6 +34,28 @@
+@@ -34,6 +34,30 @@
#define FLAG_PLATFORMIZE (1 << 1)
#include <dlfcn.h>
@@ -20,10 +20,12 @@ index a6d6cb6..c9a3b33 100644
+
+const char *skip[] = {
+ "jailbreakd",
++ "com.saurik.substrated",
+ "com.apple.MobileFileIntegrity",
+ "com.openssh.sshd.",
+ "com.apple.SpringBoard",
-+ // "com.apple.logd",
++ "com.apple.securityd",
++ "com.apple.trustd",
+ "com.apple.diagnosticd",
+ NULL
+};
diff --git a/data/uikittools/uicache.diff b/data/uikittools/uicache.diff
new file mode 100644
index 000000000..02828f4ed
--- /dev/null
+++ b/data/uikittools/uicache.diff
@@ -0,0 +1,1109 @@
+diff -urN uikittools/sbreload.c uikittools+uicache/sbreload.c
+--- uikittools/sbreload.c 2018-10-04 15:58:42.000000000 -1000
++++ uikittools+uicache/sbreload.c 1969-12-31 14:00:00.000000000 -1000
+@@ -1,270 +0,0 @@
+-/* UIKit Tools - command-line utilities for UIKit
+- * Copyright (C) 2008-2012 Jay Freeman (saurik)
+-*/
+-
+-/* Modified BSD License {{{ */
+-/*
+- * Redistribution and use in source and binary
+- * forms, with or without modification, are permitted
+- * provided that the following conditions are met:
+- *
+- * 1. Redistributions of source code must retain the
+- * above copyright notice, this list of conditions
+- * and the following disclaimer.
+- * 2. Redistributions in binary form must reproduce the
+- * above copyright notice, this list of conditions
+- * and the following disclaimer in the documentation
+- * and/or other materials provided with the
+- * distribution.
+- * 3. The name of the author may not be used to endorse
+- * or promote products derived from this software
+- * without specific prior written permission.
+- *
+- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
+- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-*/
+-/* }}} */
+-
+-#include <launch.h>
+-#include <notify.h>
+-
+-#include <stdio.h>
+-#include <unistd.h>
+-
+-#include <CoreFoundation/CoreFoundation.h>
+-
+-/* Set platform binary flag */
+-#define FLAG_PLATFORMIZE (1 << 1)
+-#include <dlfcn.h>
+-
+-void platformizeme() {
+- void* handle = dlopen("/usr/lib/libjailbreak.dylib", RTLD_LAZY);
+- if (!handle) return;
+-
+- // Reset errors
+- dlerror();
+- typedef void (*fix_entitle_prt_t)(pid_t pid, uint32_t what);
+- fix_entitle_prt_t ptr = (fix_entitle_prt_t)dlsym(handle, "jb_oneshot_entitle_now");
+-
+- const char *dlsym_error = dlerror();
+- if (dlsym_error) {
+- return;
+- }
+-
+- ptr(getpid(), FLAG_PLATFORMIZE);
+-}
+-
+-launch_data_t
+-CF2launch_data(CFTypeRef cfr);
+-
+-void
+-myCFDictionaryApplyFunction(const void *key, const void *value, void *context)
+-{
+- launch_data_t ik, iw, where = context;
+-
+- ik = CF2launch_data(key);
+- iw = CF2launch_data(value);
+-
+- launch_data_dict_insert(where, iw, launch_data_get_string(ik));
+- launch_data_free(ik);
+-}
+-
+-launch_data_t
+-CF2launch_data(CFTypeRef cfr)
+-{
+- launch_data_t r;
+- CFTypeID cft = CFGetTypeID(cfr);
+-
+- if (cft == CFStringGetTypeID()) {
+- char buf[4096];
+- CFStringGetCString(cfr, buf, sizeof(buf), kCFStringEncodingUTF8);
+- r = launch_data_alloc(LAUNCH_DATA_STRING);
+- launch_data_set_string(r, buf);
+- } else if (cft == CFBooleanGetTypeID()) {
+- r = launch_data_alloc(LAUNCH_DATA_BOOL);
+- launch_data_set_bool(r, CFBooleanGetValue(cfr));
+- } else if (cft == CFArrayGetTypeID()) {
+- CFIndex i, ac = CFArrayGetCount(cfr);
+- r = launch_data_alloc(LAUNCH_DATA_ARRAY);
+- for (i = 0; i < ac; i++) {
+- CFTypeRef v = CFArrayGetValueAtIndex(cfr, i);
+- if (v) {
+- launch_data_t iv = CF2launch_data(v);
+- launch_data_array_set_index(r, iv, i);
+- }
+- }
+- } else if (cft == CFDictionaryGetTypeID()) {
+- r = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
+- CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r);
+- } else if (cft == CFDataGetTypeID()) {
+- r = launch_data_alloc(LAUNCH_DATA_ARRAY);
+- launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr));
+- } else if (cft == CFNumberGetTypeID()) {
+- long long n;
+- double d;
+- CFNumberType cfnt = CFNumberGetType(cfr);
+- switch (cfnt) {
+- case kCFNumberSInt8Type:
+- case kCFNumberSInt16Type:
+- case kCFNumberSInt32Type:
+- case kCFNumberSInt64Type:
+- case kCFNumberCharType:
+- case kCFNumberShortType:
+- case kCFNumberIntType:
+- case kCFNumberLongType:
+- case kCFNumberLongLongType:
+- CFNumberGetValue(cfr, kCFNumberLongLongType, &n);
+- r = launch_data_alloc(LAUNCH_DATA_INTEGER);
+- launch_data_set_integer(r, n);
+- break;
+- case kCFNumberFloat32Type:
+- case kCFNumberFloat64Type:
+- case kCFNumberFloatType:
+- case kCFNumberDoubleType:
+- CFNumberGetValue(cfr, kCFNumberDoubleType, &d);
+- r = launch_data_alloc(LAUNCH_DATA_REAL);
+- launch_data_set_real(r, d);
+- break;
+- default:
+- r = NULL;
+- break;
+- }
+- } else {
+- r = NULL;
+- }
+- return r;
+-}
+-
+-CFPropertyListRef
+-CreateMyPropertyListFromFile(const char *posixfile)
+-{
+- CFPropertyListRef propertyList;
+- CFStringRef errorString;
+- CFDataRef resourceData;
+- SInt32 errorCode;
+- CFURLRef fileURL;
+-
+- fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false);
+- if (!fileURL) {
+- fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile);
+- }
+- if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) {
+- fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode);
+- }
+- propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString);
+- if (!propertyList) {
+- fprintf(stderr, "%s: propertyList is NULL\n", getprogname());
+- }
+-
+- return propertyList;
+-}
+-
+-#define _assert(test, format, args...) do { \
+- if (test) break; \
+- fprintf(stderr, format "\n", ##args); \
+- return 1; \
+-} while (false)
+-
+-void stop() {
+- sleep(1);
+-}
+-
+-#define SpringBoard_plist "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"
+-
+-int main(int argc, const char *argv[]) {
+- platformizeme();
+- _assert(argc == 1, "usage: sbreload");
+-
+- CFDictionaryRef plist = CreateMyPropertyListFromFile(SpringBoard_plist);
+- _assert(plist != NULL, "CreateMyPropertyListFromFile() == NULL");
+-
+- launch_data_t job = CF2launch_data(plist);
+- _assert(job != NULL, "CF2launch_data() == NULL");
+-
+- launch_data_t data, request, response;
+-
+- data = launch_data_dict_lookup(job, LAUNCH_JOBKEY_LABEL);
+- _assert(data != NULL, "launch_data_dict_lookup(LABEL) == NULL");
+- const char *label = launch_data_get_string(data);
+-
+- request = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
+- launch_data_dict_insert(request, launch_data_new_string(label), LAUNCH_KEY_GETJOB);
+-
+- response = launch_msg(request);
+- _assert(response != NULL, "launch_msg(GetJob) == NULL");
+- launch_data_free(request);
+-
+- pid_t pid;
+-
+- if (launch_data_get_type(response) == LAUNCH_DATA_ERRNO) {
+- int error = launch_data_get_errno(response);
+- _assert(error == ESRCH, "GetJob(%s): %s", label, strerror(error));
+- pid = -1;
+- } else if (launch_data_get_type(response) == LAUNCH_DATA_DICTIONARY) {
+- data = launch_data_dict_lookup(response, LAUNCH_JOBKEY_PID);
+- _assert(data != NULL, "launch_data_dict_lookup(PID) == NULL");
+- pid = launch_data_get_integer(data);
+- } else _assert(false, "launch_data_get_type() not in (DICTIONARY, ERRNO)");
+-
+- launch_data_free(response);
+-
+- // 600 is being used to approximate 4.x/5.x boundary
+- if (kCFCoreFoundationVersionNumber < 600) {
+- fprintf(stderr, "notify_post(com.apple.mobile.springboard_teardown)\n");
+- notify_post("com.apple.mobile.springboard_teardown");
+- } else {
+- // XXX: this code is preferable to launchctl unoad but it requires libvproc? :(
+- //vproc_err_t *error = _vproc_send_signal_by_label(label, VPROC_MAGIC_UNLOAD_SIGNAL);
+- //_assert(error == NULL, "_vproc_send_signal_by_label(UNLOAD) != NULL");
+-
+- fprintf(stderr, "launchctl unload SpringBoard.plist\n");
+- system("launchctl unload " SpringBoard_plist);
+- }
+-
+- if (pid != -1) {
+- fprintf(stderr, "waiting for kill(%u) != 0...\n", pid);
+- while (kill(pid, 0) == 0)
+- stop();
+-
+- int error = errno;
+- _assert(error == ESRCH, "kill(%u): %s", pid, strerror(error));
+- }
+-
+- request = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
+- launch_data_dict_insert(request, job, LAUNCH_KEY_SUBMITJOB);
+-
+- for (;;) {
+- response = launch_msg(request);
+- _assert(response != NULL, "launch_msg(SubmitJob) == NULL");
+-
+- _assert(launch_data_get_type(response) == LAUNCH_DATA_ERRNO, "launch_data_get_type() != ERRNO");
+- int error = launch_data_get_errno(response);
+- launch_data_free(response);
+-
+- const char *string = strerror(error);
+-
+- if (error == EEXIST) {
+- fprintf(stderr, "SubmitJob(%s): %s, retrying...\n", label, string);
+- stop();
+- } else {
+- _assert(error == 0, "SubmitJob(%s): %s", label, string);
+- break;
+- }
+- }
+-
+- launch_data_free(request);
+-
+- return 0;
+-}
+diff -urN uikittools/sbreload.m uikittools+uicache/sbreload.m
+--- uikittools/sbreload.m 1969-12-31 14:00:00.000000000 -1000
++++ uikittools+uicache/sbreload.m 2019-06-07 22:37:29.000000000 -1000
+@@ -0,0 +1,336 @@
++/* UIKit Tools - command-line utilities for UIKit
++ * Copyright (C) 2008-2012 Jay Freeman (saurik)
++*/
++
++/* Modified BSD License {{{ */
++/*
++ * Redistribution and use in source and binary
++ * forms, with or without modification, are permitted
++ * provided that the following conditions are met:
++ *
++ * 1. Redistributions of source code must retain the
++ * above copyright notice, this list of conditions
++ * and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the
++ * above copyright notice, this list of conditions
++ * and the following disclaimer in the documentation
++ * and/or other materials provided with the
++ * distribution.
++ * 3. The name of the author may not be used to endorse
++ * or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
++ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
++ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
++ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*/
++/* }}} */
++
++#include <launch.h>
++#include <notify.h>
++
++#include <stdio.h>
++#include <unistd.h>
++
++#include <Foundation/Foundation.h>
++
++/* Set platform binary flag */
++#define FLAG_PLATFORMIZE (1 << 1)
++#include <dlfcn.h>
++#include <objc/runtime.h>
++
++@interface FBSSystemService
+++(id)sharedService;
++-(void)sendActions:(NSSet*)actions withResult:(id)result;
++@end
++
++typedef enum {
++ None = 0,
++ RestartRenderServer = (1 << 0), // also relaunch backboardd
++ SnapshotTransition = (1 << 1),
++ FadeToBlackTransition = (1 << 2),
++} SBSRelaunchActionStyle;
++
++@interface SBSRelaunchAction
+++(id)actionWithReason:(id)reason options:(int64_t)options targetURL:(NSURL*)url;
++@end
++
++void platformizeme() {
++ void* handle = dlopen("/usr/lib/libjailbreak.dylib", RTLD_LAZY);
++ if (!handle) return;
++
++ // Reset errors
++ dlerror();
++ typedef void (*fix_entitle_prt_t)(pid_t pid, uint32_t what);
++ fix_entitle_prt_t ptr = (fix_entitle_prt_t)dlsym(handle, "jb_oneshot_entitle_now");
++
++ const char *dlsym_error = dlerror();
++ if (dlsym_error) {
++ return;
++ }
++
++ ptr(getpid(), FLAG_PLATFORMIZE);
++}
++
++launch_data_t
++CF2launch_data(CFTypeRef cfr);
++
++void
++myCFDictionaryApplyFunction(const void *key, const void *value, void *context)
++{
++ launch_data_t ik, iw, where = context;
++
++ ik = CF2launch_data(key);
++ iw = CF2launch_data(value);
++
++ launch_data_dict_insert(where, iw, launch_data_get_string(ik));
++ launch_data_free(ik);
++}
++
++launch_data_t
++CF2launch_data(CFTypeRef cfr)
++{
++ launch_data_t r;
++ CFTypeID cft = CFGetTypeID(cfr);
++
++ if (cft == CFStringGetTypeID()) {
++ char buf[4096];
++ CFStringGetCString(cfr, buf, sizeof(buf), kCFStringEncodingUTF8);
++ r = launch_data_alloc(LAUNCH_DATA_STRING);
++ launch_data_set_string(r, buf);
++ } else if (cft == CFBooleanGetTypeID()) {
++ r = launch_data_alloc(LAUNCH_DATA_BOOL);
++ launch_data_set_bool(r, CFBooleanGetValue(cfr));
++ } else if (cft == CFArrayGetTypeID()) {
++ CFIndex i, ac = CFArrayGetCount(cfr);
++ r = launch_data_alloc(LAUNCH_DATA_ARRAY);
++ for (i = 0; i < ac; i++) {
++ CFTypeRef v = CFArrayGetValueAtIndex(cfr, i);
++ if (v) {
++ launch_data_t iv = CF2launch_data(v);
++ launch_data_array_set_index(r, iv, i);
++ }
++ }
++ } else if (cft == CFDictionaryGetTypeID()) {
++ r = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
++ CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r);
++ } else if (cft == CFDataGetTypeID()) {
++ r = launch_data_alloc(LAUNCH_DATA_ARRAY);
++ launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr));
++ } else if (cft == CFNumberGetTypeID()) {
++ long long n;
++ double d;
++ CFNumberType cfnt = CFNumberGetType(cfr);
++ switch (cfnt) {
++ case kCFNumberSInt8Type:
++ case kCFNumberSInt16Type:
++ case kCFNumberSInt32Type:
++ case kCFNumberSInt64Type:
++ case kCFNumberCharType:
++ case kCFNumberShortType:
++ case kCFNumberIntType:
++ case kCFNumberLongType:
++ case kCFNumberLongLongType:
++ CFNumberGetValue(cfr, kCFNumberLongLongType, &n);
++ r = launch_data_alloc(LAUNCH_DATA_INTEGER);
++ launch_data_set_integer(r, n);
++ break;
++ case kCFNumberFloat32Type:
++ case kCFNumberFloat64Type:
++ case kCFNumberFloatType:
++ case kCFNumberDoubleType:
++ CFNumberGetValue(cfr, kCFNumberDoubleType, &d);
++ r = launch_data_alloc(LAUNCH_DATA_REAL);
++ launch_data_set_real(r, d);
++ break;
++ default:
++ r = NULL;
++ break;
++ }
++ } else {
++ r = NULL;
++ }
++ return r;
++}
++
++CFPropertyListRef
++CreateMyPropertyListFromFile(const char *posixfile)
++{
++ CFPropertyListRef propertyList;
++ CFStringRef errorString;
++ CFDataRef resourceData;
++ SInt32 errorCode;
++ CFURLRef fileURL;
++
++ fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false);
++ if (!fileURL) {
++ fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile);
++ }
++ if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) {
++ fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode);
++ }
++ propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString);
++ if (!propertyList) {
++ fprintf(stderr, "%s: propertyList is NULL\n", getprogname());
++ }
++
++ return propertyList;
++}
++
++#define _assert(test, format, args...) do { \
++ if (test) break; \
++ fprintf(stderr, format "\n", ##args); \
++ return 1; \
++} while (false)
++
++void stop() {
++ sleep(1);
++}
++
++#define SpringBoard_plist "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"
++
++pid_t launch_get_job_pid(const char * job)
++{
++ launch_data_t resp;
++ launch_data_t msg;
++
++ msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
++ if (msg == NULL) {
++ return -1;
++ }
++
++ launch_data_dict_insert(msg, launch_data_new_string(job), LAUNCH_KEY_GETJOB);
++
++ resp = launch_msg(msg);
++ launch_data_free(msg);
++
++ if (resp == NULL) {
++ return -1;
++ }
++
++ if (launch_data_get_type(resp) != LAUNCH_DATA_DICTIONARY) return -1;
++
++ launch_data_t pid_data = launch_data_dict_lookup(resp, "PID");
++ if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) return -1;
++
++ pid_t pid = (pid_t)launch_data_get_integer(pid_data);
++ launch_data_free(resp);
++ return pid;
++}
++
++int main(int argc, const char *argv[]) {
++ platformizeme();
++ _assert(argc == 1, "usage: sbreload");
++
++ if (kCFCoreFoundationVersionNumber >= 1443.00) {
++ dlopen("/System/Library/PrivateFrameworks/FrontBoardServices.framework/FrontBoardServices", RTLD_LAZY);
++ dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY);
++ Class $SBSRelaunchAction = objc_getClass("SBSRelaunchAction");
++ Class $FBSSystemService = objc_getClass("FBSSystemService");
++ pid_t sb_pid = launch_get_job_pid("com.apple.SpringBoard");
++ if ($SBSRelaunchAction && $FBSSystemService) {
++ @autoreleasepool {
++ id action = [$SBSRelaunchAction actionWithReason:@"respring" options:RestartRenderServer targetURL:nil];
++ id sharedService = [$FBSSystemService sharedService];
++ [sharedService sendActions:[NSSet setWithObject:action] withResult:nil];
++ for (int i=0; i<100; i++) {
++ if (kill(sb_pid, 0)) {
++ return 0;
++ }
++ usleep(1000);
++ }
++ }
++ }
++ }
++ CFDictionaryRef plist = CreateMyPropertyListFromFile(SpringBoard_plist);
++ _assert(plist != NULL, "CreateMyPropertyListFromFile() == NULL");
++
++ launch_data_t job = CF2launch_data(plist);
++ _assert(job != NULL, "CF2launch_data() == NULL");
++
++ launch_data_t data, request, response;
++
++ data = launch_data_dict_lookup(job, LAUNCH_JOBKEY_LABEL);
++ _assert(data != NULL, "launch_data_dict_lookup(LABEL) == NULL");
++ const char *label = launch_data_get_string(data);
++
++ request = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
++ launch_data_dict_insert(request, launch_data_new_string(label), LAUNCH_KEY_GETJOB);
++
++ response = launch_msg(request);
++ _assert(response != NULL, "launch_msg(GetJob) == NULL");
++ launch_data_free(request);
++
++ pid_t pid;
++
++ if (launch_data_get_type(response) == LAUNCH_DATA_ERRNO) {
++ int error = launch_data_get_errno(response);
++ _assert(error == ESRCH, "GetJob(%s): %s", label, strerror(error));
++ pid = -1;
++ } else if (launch_data_get_type(response) == LAUNCH_DATA_DICTIONARY) {
++ data = launch_data_dict_lookup(response, LAUNCH_JOBKEY_PID);
++ _assert(data != NULL, "launch_data_dict_lookup(PID) == NULL");
++ pid = launch_data_get_integer(data);
++ } else _assert(false, "launch_data_get_type() not in (DICTIONARY, ERRNO)");
++
++ launch_data_free(response);
++
++ // 600 is being used to approximate 4.x/5.x boundary
++ if (kCFCoreFoundationVersionNumber < 600) {
++ fprintf(stderr, "notify_post(com.apple.mobile.springboard_teardown)\n");
++ notify_post("com.apple.mobile.springboard_teardown");
++ } else {
++ // XXX: this code is preferable to launchctl unoad but it requires libvproc? :(
++ //vproc_err_t *error = _vproc_send_signal_by_label(label, VPROC_MAGIC_UNLOAD_SIGNAL);
++ //_assert(error == NULL, "_vproc_send_signal_by_label(UNLOAD) != NULL");
++
++ fprintf(stderr, "launchctl unload SpringBoard.plist\n");
++ system("launchctl unload " SpringBoard_plist);
++ }
++
++ if (pid != -1) {
++ fprintf(stderr, "waiting for kill(%u) != 0...\n", pid);
++ while (kill(pid, 0) == 0)
++ stop();
++
++ int error = errno;
++ _assert(error == ESRCH, "kill(%u): %s", pid, strerror(error));
++ }
++
++ request = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
++ launch_data_dict_insert(request, job, LAUNCH_KEY_SUBMITJOB);
++
++ for (;;) {
++ response = launch_msg(request);
++ _assert(response != NULL, "launch_msg(SubmitJob) == NULL");
++
++ _assert(launch_data_get_type(response) == LAUNCH_DATA_ERRNO, "launch_data_get_type() != ERRNO");
++ int error = launch_data_get_errno(response);
++ launch_data_free(response);
++
++ const char *string = strerror(error);
++
++ if (error == EEXIST) {
++ fprintf(stderr, "SubmitJob(%s): %s, retrying...\n", label, string);
++ stop();
++ } else {
++ _assert(error == 0, "SubmitJob(%s): %s", label, string);
++ break;
++ }
++ }
++
++ launch_data_free(request);
++
++ return 0;
++}
+diff -urN uikittools/sbreload.xml uikittools+uicache/sbreload.xml
+--- uikittools/sbreload.xml 1969-12-31 14:00:00.000000000 -1000
++++ uikittools+uicache/sbreload.xml 2019-06-07 22:37:29.000000000 -1000
+@@ -0,0 +1,13 @@
++<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
++<plist version="1.0">
++<dict>
++ <key>com.apple.frontboard.launchapplications</key>
++ <true/>
++ <key>com.apple.frontboard.shutdown</key>
++ <true/>
++ <key>platform-application</key>
++ <true/>
++ <key>com.apple.private.skip-library-validation</key>
++ <true/>
++</dict>
++</plist>
+diff -urN uikittools/uicache.mm uikittools+uicache/uicache.mm
+--- uikittools/uicache.mm 2018-10-04 15:58:19.000000000 -1000
++++ uikittools+uicache/uicache.mm 2019-06-07 22:37:39.000000000 -1000
+@@ -1,7 +1,17 @@
+ /* UIKit Tools - command-line utilities for UIKit
+ * Copyright (C) 2008-2012 Jay Freeman (saurik)
++ * Portions Copyright (C) 2019 Sam Bingner
+ */
+
++/* uicache.mm
++ *
++ * Licensed under GPL v2.0 license as available at:
++ * https://www.gnu.org/licenses/gpl2.txt
++ *
++ * In adition, usage must meet the following
++ * Modified BSD terms:
++ */
++
+ /* Modified BSD License {{{ */
+ /*
+ * Redistribution and use in source and binary
+@@ -38,13 +48,14 @@
+ /* }}} */
+
+ #import <Foundation/Foundation.h>
+-
+-#include <notify.h>
+-#include <sys/types.h>
+-#include <sys/stat.h>
+-#include <unistd.h>
+-
+-#include <objc/runtime.h>
++#import <dlfcn.h>
++#import <notify.h>
++#import <sys/types.h>
++#import <sys/stat.h>
++#import <unistd.h>
++#import <getopt.h>
++#import <launch.h>
++#import <objc/runtime.h>
+
+ #include "csstore.hpp"
+
+@@ -81,6 +92,12 @@
+
+ @end
+
++@interface LSApplicationProxy : NSObject
++- (NSString*) applicationIdentifier;
++- (NSURL*) resourcesDirectoryURL;
++- (NSDate*) registeredDate;
++@end
++
+ @interface LSApplicationWorkspace : NSObject
+ + (id) defaultWorkspace;
+ - (BOOL) registerApplication:(id)application;
+@@ -89,16 +106,188 @@
+ - (BOOL) registerApplicationDictionary:(id)application;
+ - (BOOL) installApplication:(id)application withOptions:(id)options;
+ - (BOOL) _LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)system internal:(BOOL)internal user:(BOOL)user;
++- (NSArray<LSApplicationProxy*>*) allApplications;
++@end
++
++@interface MCMAppDataContainer
+++(id)containerWithIdentifier:(NSString*)identifier createIfNecessary:(bool)create existed:(bool*)existed error:(NSError*)error;
++-(NSURL*)url;
+ @end
+
+-int main(int argc, const char *argv[]) {
+- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
++@interface FBSSystemService
+++(id)sharedService;
++-(void)sendActions:(NSSet*)actions withResult:(id)result;
++@end
++
++typedef enum {
++ None = 0,
++ RestartRenderServer = (1 << 0), // also relaunch backboardd
++ SnapshotTransition = (1 << 1),
++ FadeToBlackTransition = (1 << 2),
++} SBSRelaunchActionStyle;
++
++@interface SBSRelaunchAction
+++(id)actionWithReason:(id)reason options:(int64_t)options targetURL:(NSURL*)url;
++@end
++
++static int verbose=0;
++static int standard_uicache(void);
++static Class $MCMPluginKitPluginDataContainer;
++static Class $MCMAppDataContainer;
++static Class $LSApplicationWorkspace;
++LSApplicationWorkspace *workspace=nil;
++
++NSString *getAppPath(NSString *path)
++{
++ path = [path stringByResolvingSymlinksInPath];
++ if (![path hasPrefix:@"/Applications/"]) {
++ fprintf(stderr, "Error: Path must be within /Applications/\n");
++ return nil;
++ }
++ return [NSString pathWithComponents:[[path pathComponents] subarrayWithRange:NSMakeRange(0, 3)]];
++}
++
++bool appIsRegistered(NSString *path)
++{
++ @autoreleasepool {
++ path = getAppPath(path);
++ if (!path) return false;
++ for (LSApplicationProxy *app in [workspace allApplications]) {
++ if ([path isEqualToString:[[app resourcesDirectoryURL] path]]) return true;
++ }
++ return false;
++ }
++}
++
++bool unregisterPath(NSString *path)
++{
++ @autoreleasepool {
++ if (verbose) fprintf(stderr, "Unregistering %s\n", path.lastPathComponent.UTF8String);
++ path = getAppPath(path);
++ if (!path) return false;
++ if (appIsRegistered(path) && ![workspace unregisterApplication:[NSURL fileURLWithPath:path]]) {
++ fprintf(stderr, "Error: unregisterApplication failed for %s\n", path.lastPathComponent.UTF8String);
++ return false;
++ }
++ }
++ return true;
++}
++
++// Credit to coolstar for finding how to do this and not sharing with the community thereby forcing me to figure out how to do the same thing.
++bool registerPath(NSString *path)
++{
++ if (!path) {
++ if (verbose) fprintf(stderr, "registerPath called with no path\n");
++ return false;
++ }
++ NSString *realPath = getAppPath(path);
++ if (!realPath) {
++ if (verbose) fprintf(stderr, "unable to determine path for %s\n", path.UTF8String);
++ return false;
++ }
++ NSDictionary *infoDictionary = [NSDictionary dictionaryWithContentsOfFile:
++ [realPath stringByAppendingPathComponent:@"Info.plist"]];
++ NSString *bundleID = [infoDictionary objectForKey:@"CFBundleIdentifier"];
++
++ if (bundleID) {
++ NSFileManager *fm = [NSFileManager defaultManager];
++
++ if ([infoDictionary objectForKey:@"CFBundleExecutable"]) {
++ NSString *executable = [realPath stringByAppendingPathComponent:[infoDictionary objectForKey:@"CFBundleExecutable"]];
++ if (![fm fileExistsAtPath:executable]) {
++ fprintf(stderr, "Error: CFBundleExecutable defined but missing for %s - this is a fatal error. Aborting.\n", realPath.lastPathComponent.UTF8String);
++ return false;
++ }
++ }
++
++ NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
++ @"System", @"ApplicationType",
++ @YES, @"BundleNameIsLocalized",
++ bundleID, @"CFBundleIdentifier",
++ @NO, @"CompatibilityState",
++ @NO, @"IsDeletable",
++ realPath, @"Path",
++ [NSMutableDictionary dictionary], @"_LSBundlePlugins",
++ nil];
++
++ id appContainer = [$MCMAppDataContainer containerWithIdentifier:bundleID
++ createIfNecessary:YES existed:NULL error:nil];
++
++ NSString *appContainerPath = [[appContainer url] path];
++ if (appContainerPath) {
++ dict[@"Container"] = appContainerPath;
++ }
++ NSString *pluginsPath = [realPath stringByAppendingPathComponent:@"PlugIns"];
++ for (NSString *plugin in [fm contentsOfDirectoryAtPath:pluginsPath error:nil]) {
++ NSString *pluginPath = [pluginsPath stringByAppendingPathComponent:plugin];
++ NSString *pluginInfoPlistPath = [pluginPath stringByAppendingPathComponent:@"Info.plist"];
++ NSString *pluginBundleIdentifier = [[NSDictionary dictionaryWithContentsOfFile:pluginInfoPlistPath] objectForKey:@"CFBundleIdentifier"];
++ if (pluginBundleIdentifier) {
++ id pluginContainer = [$MCMPluginKitPluginDataContainer containerWithIdentifier:pluginBundleIdentifier
++ createIfNecessary:YES existed:NULL error:nil];
++ NSURL *pluginContainerURL = [pluginContainer url];
++ NSString *pluginContainerPath = [pluginContainerURL path];
++ dict[@"_LSBundlePlugins"][pluginBundleIdentifier] = @{
++ @"ApplicationType": @"PluginKitPlugin",
++ @"BundleNameIsLocalized": @YES,
++ @"CFBundleIdentifier": pluginBundleIdentifier,
++ @"CompatibilityState": @NO,
++ @"Container": pluginContainerPath,
++ @"Path": pluginPath,
++ @"PluginOwnerBundleID": bundleID
++ };
++ }
++ }
++ if (![workspace registerApplicationDictionary:dict]) {
++ fprintf(stderr, "Error: registerApplicationDictionary failed for %s\n", path.lastPathComponent.UTF8String);
++ return false;
++ }
++ } else {
++ return unregisterPath(realPath);
++ }
++ return true;
++}
++
++void usage(void)
++{
++ fprintf(stderr, "Usage: %s [-hrv] [[-p | -u] /Applications/App.app]]\n", getprogname());
++ exit(EXIT_FAILURE);
++}
+
+- Class $LSApplicationWorkspace(objc_getClass("LSApplicationWorkspace"));
+- LSApplicationWorkspace *workspace($LSApplicationWorkspace == nil ? nil : [$LSApplicationWorkspace defaultWorkspace]);
++pid_t launch_get_job_pid(const char * job)
++{
++ launch_data_t resp;
++ launch_data_t msg;
++
++ msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
++ if (msg == NULL) {
++ return -1;
++ }
++
++ launch_data_dict_insert(msg, launch_data_new_string(job), LAUNCH_KEY_GETJOB);
++
++ resp = launch_msg(msg);
++ launch_data_free(msg);
++
++ if (resp == NULL) {
++ return -1;
++ }
++
++ if (launch_data_get_type(resp) != LAUNCH_DATA_DICTIONARY) return -1;
++
++ launch_data_t pid_data = launch_data_dict_lookup(resp, "PID");
++ if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) return -1;
++
++ pid_t pid = (pid_t)launch_data_get_integer(pid_data);
++ launch_data_free(resp);
++ return pid;
++}
+
+- if (kCFCoreFoundationVersionNumber > 1000) // this API is on iOS 7 but invaliding the icon cache is harder there
+- if ([workspace respondsToSelector:@selector(_LSPrivateRebuildApplicationDatabasesForSystemApps:internal:user:)]) {
++int standard_uicache(void)
++{
++ @autoreleasepool {
++ if (kCFCoreFoundationVersionNumber > 1000 && // this API is on iOS 7 but invaliding the icon cache is harder there
++ [workspace respondsToSelector:@selector(_LSPrivateRebuildApplicationDatabasesForSystemApps:internal:user:)]) {
+ if (![workspace _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:NO])
+ fprintf(stderr, "failed to rebuild application databases");
+ return 0;
+@@ -226,12 +415,188 @@
+ system("killall -SIGCONT SpringBoard");
+ }
+
+- if (respring)
+- system("launchctl stop com.apple.SpringBoard");
+- else
+- notify_post("com.apple.mobile.application_installed");
+-
+- [pool release];
++ notify_post("com.apple.mobile.application_installed");
+
+ return 0;
++ }
++}
++
++int optimized_uicache(void) {
++ __block int rv=0;
++ NSMutableDictionary *registered = [NSMutableDictionary new];
++ static void (^readHandler)(NSFileHandle*) = ^(NSFileHandle *fh) {
++ NSData *output = [fh readDataToEndOfFile];
++ if (output.length==0) return;
++ const char *found_path = (const char *)[output bytes];
++ NSArray *found = [@(found_path) pathComponents];
++ if (found.count >= 3) {
++ NSString *appPath = [@"/Applications" stringByAppendingPathComponent:found[2]];
++ @synchronized (registered) {
++ if (registered[appPath]) return;
++ if (verbose) fprintf(stderr, "Updating %s\n", appPath.lastPathComponent.UTF8String);
++ registered[appPath] = @YES;
++ }
++ if (!registerPath(appPath)) rv++;
++ }
++ };
++ NSFileManager *fm = [NSFileManager defaultManager];
++ NSMutableDictionary *apps = [NSMutableDictionary new];
++ NSMutableArray *cleanup = [NSMutableArray new];
++ NSMutableArray *finds = [NSMutableArray new];
++ if (verbose>1) fprintf(stderr, "Enumerating apps\n");
++ for (LSApplicationProxy *app in [workspace allApplications]) {
++ NSString *path = [[app resourcesDirectoryURL] path];
++ if (![path hasPrefix:@"/Applications/"]) continue;
++ if (verbose>1) fprintf(stderr, "Checking %s\n", path.lastPathComponent.UTF8String);
++
++ NSDate *lastRegistered = [app registeredDate];
++
++ if ([fm fileExistsAtPath:path]) {
++ // Check for updated components
++ NSTask *find = [NSTask new];
++ [find setLaunchPath:@"/usr/bin/find"];
++ [find setStandardOutput:[NSPipe pipe]];
++ NSString *stampPath = [NSString stringWithFormat:@"/var/tmp/uicache.stamp.%@", app.applicationIdentifier];
++ [fm createFileAtPath:stampPath contents:nil attributes:@{NSFileModificationDate: lastRegistered}];
++ [cleanup addObject:stampPath];
++ [find setArguments:@[ path, @"-newer", stampPath, @"-print0", @"-quit"]];
++ [finds addObject:find];
++ [find launch];
++ apps[path.lastPathComponent] = app;
++ } else {
++ if (verbose) fprintf(stderr, "De-registering removed app: %s\n", path.lastPathComponent.UTF8String);
++ @synchronized (registered) {
++ if (registered[path]) continue;
++ registered[path] = @YES;
++ }
++ if (!unregisterPath(path)) rv++;
++ }
++ }
++
++ for (NSString* existing in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/Applications" error:nil]) {
++ NSString *path = [@"/Applications" stringByAppendingPathComponent:existing];
++ if (apps[existing] || registered[path] || ![existing hasSuffix:@".app"]) continue;
++ if (verbose) fprintf(stderr, "Registering new app: %s\n", existing.UTF8String);
++ @synchronized (registered) {
++ registered[path] = @YES;
++ }
++ if (!registerPath(path)) rv++;
++ }
++ for (NSTask *find in finds) {
++ if (verbose>2) fprintf(stderr, "waiting for find %s\n", [find.arguments componentsJoinedByString:@" "].UTF8String);
++ readHandler([find.standardOutput fileHandleForReading]);
++ [find waitUntilExit];
++ }
++ for (NSString *path in cleanup) {
++ [fm removeItemAtPath:path error:nil];
++ }
++ return rv;
++}
++
++int main(int argc, const char *argv[])
++{
++ if (getuid() == 0) {
++ // Be mobile
++ if (setuid(501)) {
++ fprintf(stderr, "Error: unable to become mobile");
++ return -1;
++ }
++ }
++ dlopen("/System/Library/PrivateFrameworks/MobileContainerManager.framework/MobileContainerManager", RTLD_LAZY);
++ dlopen("/System/Library/PrivateFrameworks/FrontBoardServices.framework/FrontBoardServices", RTLD_LAZY);
++ dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY);
++ Class $SBSRelaunchAction = objc_getClass("SBSRelaunchAction");
++ Class $FBSSystemService = objc_getClass("FBSSystemService");
++ $MCMPluginKitPluginDataContainer = objc_getClass("MCMPluginKitPluginDataContainer");
++ $MCMAppDataContainer = objc_getClass("MCMAppDataContainer");
++ $LSApplicationWorkspace = objc_getClass("LSApplicationWorkspace");
++ workspace = [$LSApplicationWorkspace defaultWorkspace];
++
++ static int rv=0;
++ @autoreleasepool {
++ bool respring=false, do_all=false;
++ void (*jb_oneshot_entitle_now)(pid_t a, uint64_t b);
++ void *libjb = dlopen("/usr/lib/libjailbreak.dylib", RTLD_LAZY);
++
++ if (libjb) {
++ dlerror();
++ jb_oneshot_entitle_now = (void (*)(pid_t, uint64_t))dlsym(libjb, "jb_oneshot_entitle_now");
++ if (!dlerror()) jb_oneshot_entitle_now(getpid(), 2);
++ }
++
++ NSMutableDictionary *paths = [NSMutableDictionary new];
++ NSMutableDictionary *unregister_paths = [NSMutableDictionary new];
++ static struct option long_options[] =
++ {
++ {"all", no_argument, 0, 'a'},
++ {"help", no_argument, 0, 'h'},
++ {"path", required_argument, 0, 'p'},
++ {"unregister", required_argument, 0, 'u'},
++ {"respring", no_argument, 0, 'r'},
++ {"verbose", no_argument, 0, 'v'},
++ {0, 0, 0, 0}
++ };
++ int option_index = 0;
++ char ch;
++ bool have_path = false;
++ while ((ch = getopt_long(argc, (char *const *)argv, "ap:ru:vh?", long_options, &option_index)) != -1) {
++ switch (ch)
++ {
++ case 'a':
++ do_all = true;
++ break;
++ case 'h':
++ usage();
++ break;
++ case 'p':
++ paths[@(optarg)] = @YES;
++ have_path = true;
++ break;
++ case 'r':
++ respring = true;
++ break;
++ case 'u':
++ unregister_paths[@(optarg)] = @YES;
++ have_path = true;
++ break;
++ case 'v':
++ verbose++;
++ break;
++ default:
++ break;
++ }
++ }
++ if (do_all || !$MCMPluginKitPluginDataContainer || !$MCMAppDataContainer || !$LSApplicationWorkspace) {
++ rv = standard_uicache();
++ } else if (have_path) {
++ for (NSString *path in [paths allKeys]) {
++ if (verbose) fprintf(stderr, "Refreshing %s\n", path.UTF8String);
++ if (!registerPath(path)) rv++;
++ }
++ for (NSString *path in [unregister_paths allKeys]) {
++ if (!unregisterPath(path)) rv++;
++ }
++ } else {
++ rv += optimized_uicache();
++ }
++ if ( respring )
++ {
++ pid_t sb_pid = launch_get_job_pid("com.apple.SpringBoard");
++ if ($SBSRelaunchAction && $FBSSystemService) {
++ id action = [$SBSRelaunchAction actionWithReason:@"respring" options:RestartRenderServer targetURL:nil];
++ id sharedService = [$FBSSystemService sharedService];
++ [sharedService sendActions:[NSSet setWithObject:action] withResult:nil];
++ for (int i=0; i<100; i++) {
++ if (kill(sb_pid, 0)) {
++ break;
++ }
++ usleep(1000);
++ }
++ } else {
++ system("launchctl stop com.apple.SpringBoard");
++ system("launchctl stop com.apple.backboardd");
++ }
++ }
++ } // @autoreleasepool
++ return rv;
+ }
+diff -urN uikittools/uicache.xml uikittools+uicache/uicache.xml
+--- uikittools/uicache.xml 2018-10-04 15:58:37.000000000 -1000
++++ uikittools+uicache/uicache.xml 2019-06-07 22:37:29.000000000 -1000
+@@ -4,23 +4,22 @@
+ <key>com.apple.private.mobileinstall.allowedSPI</key>
+ <array>
+ <string>InstallForLaunchServices</string>
++ <string>UninstallForLaunchServices</string>
+ </array>
+-
+ <key>com.apple.lsapplicationworkspace.rebuildappdatabases</key>
+ <true/>
+-
+ <key>com.apple.private.MobileContainerManager.allowed</key>
+ <true/>
+-
+ <key>com.apple.private.kernel.override-cpumon</key>
+ <true/>
+-
+ <key>com.apple.vpn.installer_events</key>
+ <true/>
+-
++ <key>com.apple.frontboard.launchapplications</key>
++ <true/>
++ <key>com.apple.frontboard.shutdown</key>
++ <true/>
+ <key>platform-application</key>
+ <true/>
+-
+ <key>com.apple.private.skip-library-validation</key>
+ <true/>
+ </dict>
diff --git a/data/uikittools/world.diff b/data/uikittools/world.diff
new file mode 100644
index 000000000..6b0811b1b
--- /dev/null
+++ b/data/uikittools/world.diff
@@ -0,0 +1,702 @@
+diff -ur uikittools/gssc.mm uikittools+subtype/gssc.mm
+--- uikittools/gssc.mm 2018-10-04 15:58:19.000000000 -1000
++++ uikittools+subtype/gssc.mm 2019-05-10 13:56:03.000000000 -1000
+@@ -98,133 +98,280 @@
+ if (CFTypeRef (*$MGCopyAnswer)(CFStringRef) = reinterpret_cast<CFTypeRef (*)(CFStringRef)>(dlsym(libMobileGestalt, "MGCopyAnswer"))) {
+ NSMutableDictionary *answers([NSMutableDictionary dictionary]);
+ for (NSString *name in [NSArray arrayWithObjects:
+- @"HasSEP",
+- @"HasThinBezel",
+- @"apple-internal-install",
+- @"cameraRestriction",
+- @"data-plan",
+- @"multitasking-gestures",
+- @"rear-facing-camera",
+- @"wapi",
+- @"watch-companion",
+-
+- @"AirDropCapability",
+- @"CarrierInstallCapability",
+- @"CellularTelephonyCapability",
+- @"UIParallaxCapability",
+- @"ambient-light-sensor",
+- @"personal-hotspot",
+- @"shoebox",
+- @"hall-effect-sensor",
++ @"1080p",
++ @"3GProximityCapability",
+ @"3Gvenice",
+-
++ @"3d-imagery",
++ @"3d-maps",
++ @"64-bit",
++ @"720p",
++ @"ASTC",
++ @"AWDID",
++ @"AWDLCapability",
++ @"ActivationProtocol",
+ @"ActiveWirelessTechnology",
+- //@"AirplaneMode",
++ @"AggregateDevicePhotoZoomFactor",
++ @"AggregateDeviceVideoZoomFactor",
++ @"AirDropCapability",
++ @"AirplayMirroringCapability",
+ @"AllDeviceCapabilities",
++ @"Allow32BitApps",
++ @"AllowOnlyATVCPSDKApps",
+ @"AllowYouTube",
+ @"AllowYouTubePlugin",
+- //@"ApNonce",
+- //@"AppleInternalInstallCapability",
+- @"assistant",
+- //@"BasebandBoardSnum",
+- //@"BasebandCertId",
+- //@"BasebandChipId",
+- //@"BasebandFirmwareManifestData",
++ @"AppCapacityTVOS",
++ @"AppStore",
++ @"AudioPlaybackCapability",
++ @"AutoFocusCameraCapability",
++ @"BacklightCapability",
++ @"BasebandChipId",
++ @"BasebandChipset",
++ @"BasebandClass",
++ @"BasebandFirmwareManifestData",
+ @"BasebandFirmwareVersion",
+- //@"BasebandKeyHashInformation",
+- //@"BasebandRegionSKU",
+- //@"BasebandSerialNumber",
++ @"BasebandPostponementStatus",
++ @"BasebandStatus",
+ @"BatteryCurrentCapacity",
+ @"BatteryIsCharging",
+ @"BatteryIsFullyCharged",
+- //@"BluetoothAddress",
++ @"BlueLightReductionSupported",
+ @"BoardId",
++ @"BridgeBuild",
++ @"BridgeRestoreVersion",
++ @"BuddyLanguagesAnimationRequiresOptimization",
++ @"BuildID",
+ @"BuildVersion",
+ @"CPUArchitecture",
+- //@"CarrierBundleInfoArray",
++ @"CPUSubType",
++ @"CPUType",
++ @"CameraFlashCapability",
++ @"CameraFrontFlashCapability",
++ @"CameraHDR2Capability",
++ @"CameraLiveEffectsCapability",
++ @"CameraMaxBurstLength",
+ @"CarrierInstallCapability",
+- @"cellular-data",
++ @"CellularTelephonyCapability",
+ @"ChipID",
+- //@"CompassCalibration",
+- //@"CompassCalibrationDictionary",
+- //@"ComputerName",
+- @"contains-cellular-radio",
++ @"CloudPhotoLibraryCapability",
++ @"CoastlineGlowRenderingCapability",
++ @"CompassType",
++ @"ContinuityCapability",
++ @"CoreRoutineCapability",
++ @"DMin",
++ @"DebugBoardRevision",
++ @"DesenseBuild",
++ @"DeviceBackGlassMaterial",
++ @"DeviceBackingColor",
++ @"DeviceBrand",
+ @"DeviceClass",
+ @"DeviceClassNumber",
+ @"DeviceColor",
++ @"DeviceColorMapPolicy",
++ @"DeviceCornerRadius",
++ @"DeviceCoverGlassColor",
++ @"DeviceCoverGlassMaterial",
++ @"DeviceCoverMaterial",
+ @"DeviceEnclosureColor",
+- //@"DeviceName",
++ @"DeviceEnclosureMaterial",
++ @"DeviceEnclosureRGBColor",
++ @"DeviceHasAggregateCamera",
++ @"DeviceHousingColor",
++ @"DeviceLaunchTimeLimitScale",
++ @"DeviceName",
++ @"DevicePrefers3DBuildingStrokes",
++ @"DevicePrefersBuildingStrokes",
++ @"DevicePrefersCheapTrafficShaders",
++ @"DevicePrefersProceduralAntiAliasing",
++ @"DevicePrefersTrafficAlpha",
++ @"DeviceRGBColor",
++ @"DeviceRequiresPetalOptimization",
++ @"DeviceRequiresProximityAmeliorations",
++ @"DeviceRequiresSoftwareBrightnessCalculations",
++ @"DeviceSceneUpdateTimeLimitScale",
++ @"DeviceSubBrand",
+ @"DeviceSupports1080p",
+ @"DeviceSupports3DImagery",
+ @"DeviceSupports3DMaps",
+ @"DeviceSupports4G",
++ @"DeviceSupports4k",
+ @"DeviceSupports720p",
+ @"DeviceSupports9Pin",
++ @"DeviceSupportsAOP",
++ @"DeviceSupportsASTC",
++ @"DeviceSupportsAdaptiveMapsUI",
++ @"DeviceSupportsAlwaysListening",
++ @"DeviceSupportsAlwaysOnCompass",
++ @"DeviceSupportsApplePencil",
++ @"DeviceSupportsAutoLowLightVideo",
++ @"DeviceSupportsBatteryModuleAuthentication",
++ @"DeviceSupportsBerkelium2",
++ @"DeviceSupportsCCK",
++ @"DeviceSupportsCameraCaptureOnTouchDown",
++ @"DeviceSupportsCameraHaptics",
++ @"DeviceSupportsCarIntegration",
++ @"DeviceSupportsCinnamon",
++ @"DeviceSupportsClosedLoopHaptics",
++ @"DeviceSupportsCrudeProx",
++ @"DeviceSupportsDClr",
++ @"DeviceSupportsDoNotDisturbWhileDriving",
++ @"DeviceSupportsELabel",
++ @"DeviceSupportsEnhancedAC3",
+ @"DeviceSupportsFaceTime",
++ @"DeviceSupportsFloorCounting",
++ @"DeviceSupportsHaptics",
++ @"DeviceSupportsHeartHealthAlerts",
++ @"DeviceSupportsHeartRateVariability",
++ @"DeviceSupportsHiResBuildings",
+ @"DeviceSupportsLineIn",
++ @"DeviceSupportsLiquidDetection_CorrosionMitigation",
++ @"DeviceSupportsLivePhotoAuto",
++ @"DeviceSupportsMapsBlurredUI",
+ @"DeviceSupportsNavigation",
++ @"DeviceSupportsNewton",
++ @"DeviceSupportsPeriodicALSUpdates",
++ @"DeviceSupportsPortraitLightEffectFilters",
++ @"DeviceSupportsRGB10",
++ @"DeviceSupportsRaiseToSpeak",
++ @"DeviceSupportsSiDP",
+ @"DeviceSupportsSimplisticRoadMesh",
++ @"DeviceSupportsSingleCameraPortrait",
++ @"DeviceSupportsSiriSpeaks",
++ @"DeviceSupportsStereoAudioRecording",
++ @"DeviceSupportsStudioLightPortraitPreview",
++ @"DeviceSupportsSwimmingWorkouts",
++ @"DeviceSupportsTapToWake",
+ @"DeviceSupportsTethering",
++ @"DeviceSupportsToneMapping",
++ @"DeviceSupportsUSBTypeC",
++ @"DeviceSupportsWebkit",
++ @"DeviceSupportsYCbCr10",
+ @"DeviceVariant",
+- //@"DiagData",
+- @"dictation",
+- //@"DieId",
+- //@"DiskUsage",
+- @"encrypted-data-partition",
+- //@"EthernetMacAddress",
++ @"DeviceVariantGuess",
++ @"DisplayMirroringCapability",
+ @"ExternalChargeCapability",
+ @"ExternalPowerSourceConnected",
+- //@"FaceTimeBitRate2G",
+- //@"FaceTimeBitRate3G",
+- //@"FaceTimeBitRateLTE",
+- //@"FaceTimeBitRateWiFi",
+- //@"FaceTimeDecodings",
+- //@"FaceTimeEncodings",
+- //@"FaceTimePreferredDecoding",
+- //@"FaceTimePreferredEncoding",
+- //@"FirmwareNonce",
+- //@"FirmwarePreflightInfo",
++ @"FDRSealingStatus",
++ @"FMFAllowed",
++ @"FaceTimeBackCameraTemporalNoiseReductionMode",
++ @"FaceTimeCameraRequiresFastSwitchOptions",
++ @"FaceTimeCameraSupportsHardwareFaceDetection",
++ @"FaceTimeFrontCameraTemporalNoiseReductionMode",
++ @"FaceTimePhotosOptIn",
+ @"FirmwareVersion",
++ @"FirstPartyLaunchTimeLimitScale",
+ @"ForwardCameraCapability",
+- @"gps",
+- @"green-tea",
++ @"FrontCameraOffsetFromDisplayCenter",
++ @"FrontFacingCameraAutoHDRCapability",
++ @"FrontFacingCameraBurstCapability",
++ @"FrontFacingCameraHDRCapability",
++ @"FrontFacingCameraHDROnCapability",
++ @"FrontFacingCameraHFRCapability",
++ @"FrontFacingCameraMaxVideoZoomFactor",
++ @"FrontFacingCameraStillDurationForBurst",
++ @"FrontFacingCameraVideoCapture1080pMaxFPS",
++ @"FrontFacingCameraVideoCapture4kMaxFPS",
++ @"FrontFacingCameraVideoCapture720pMaxFPS",
++ @"GPSCapability",
++ @"GSDeviceName",
++ @"H264EncoderCapability",
++ @"HEVCDecoder10bitSupported",
++ @"HEVCDecoder12bitSupported",
++ @"HEVCDecoder8bitSupported",
++ @"HEVCEncodingCapability",
+ @"HWModelStr",
++ @"HallEffectSensorCapability",
+ @"HardwarePlatform",
+- //@"HasAllFeaturesCapability",
++ @"HasAppleNeuralEngine",
+ @"HasBaseband",
++ @"HasBattery",
++ @"HasDaliMode",
++ @"HasExtendedColorDisplay",
++ @"HasIcefall",
+ @"HasInternalSettingsBundle",
++ @"HasMesa",
++ @"HasPKA",
++ @"HasSEP",
+ @"HasSpringBoard",
+- //@"IntegratedCircuitCardIdentifier",
+- //@"InternalBuild",
+- //@"InternationalMobileEquipmentIdentity",
+- //@"InverseDeviceID",
+- //@"IsSimulator",
+- //@"IsThereEnoughBatteryLevelForSoftwareUpdate",
+- //@"IsUIBuild",
+- //@"MLBSerialNumber",
+- @"main-screen-class",
+- @"main-screen-height",
+- @"main-screen-orientation",
+- @"main-screen-pitch",
+- @"main-screen-scale",
+- @"main-screen-width",
++ @"HasThinBezel",
++ @"HearingAidAudioEqualizationCapability",
++ @"HearingAidLowEnergyAudioCapability",
++ @"HearingAidPowerReductionCapability",
++ @"HighestSupportedVideoMode",
++ @"HomeButtonType",
++ @"IDAMCapability",
++ @"IcefallInRestrictedMode",
++ @"Image4CryptoHashMethod",
++ @"Image4Supported",
++ @"IsEmulatedDevice",
++ @"IsLargeFormatPhone",
++ @"IsPwrOpposedVol",
++ @"IsSimulator",
++ @"IsUIBuild",
++ @"LaunchTimeLimitScaleSupported",
++ @"LisaCapability",
++ @"LocationRemindersCapability",
++ @"LynxPublicKey",
++ @"MainDisplayRotation",
++ @"MarketingProductName",
++ @"MarketingVersion",
++ @"MaxH264PlaybackLevel",
++ @"MaximumScreenScale",
++ @"MedusaFloatingLiveAppCapability",
++ @"MedusaOverlayAppCapability",
++ @"MedusaPIPCapability",
++ @"MedusaPinnedAppCapability",
++ @"MicrophoneCount",
+ @"MinimumSupportediTunesVersion",
+- //@"MobileEquipmentIdentifier",
+- //@"MobileSubscriberCountryCode",
+- //@"MobileSubscriberNetworkCode",
+- @"wi-fi",
++ @"MixAndMatchPrevention",
++ @"MobileDeviceMinimumVersion",
+ @"ModelNumber",
+- @"not-green-tea",
++ @"MonarchLowEndHardware",
++ @"MusicStore",
++ @"N78aHack",
++ @"NFCRadioCalibrationDataPresent",
++ @"NavajoFusingState",
++ @"NikeIpodCapability",
++ @"OLEDDisplay",
++ @"OfflineDictationCapability",
++ @"OpenGLESVersion",
++ @"PTPLargeFilesCapability",
+ @"PanoramaCameraCapability",
+ @"PartitionType",
++ @"PearlIDCapability",
++ @"PeekUICapability",
++ @"PeekUIWidth",
++ @"PersonalHotspotCapability",
++ @"PhoneNumber",
++ @"PhosphorusCapability",
++ @"PhotoCapability",
++ @"PhotoSharingCapability",
++ @"PhotosPostEffectsCapability",
++ @"PipelinedStillImageProcessingCapability",
++ @"PlatinumCapability",
+ @"ProductName",
+ @"ProductType",
+ @"ProductVersion",
+- //@"ProximitySensorCalibration",
++ @"RF-exposure-separation-distance",
++ @"RFExposureSeparationDistance",
+ @"RearCameraCapability",
++ @"RearCameraOffsetFromDisplayCenter",
++ @"RearFacingCamera60fpsVideoCaptureCapability",
++ @"RearFacingCameraAutoHDRCapability",
++ @"RearFacingCameraBurstCapability",
++ @"RearFacingCameraHDRCapability",
++ @"RearFacingCameraHDROnCapability",
++ @"RearFacingCameraHFRCapability",
++ @"RearFacingCameraHFRVideoCapture1080pMaxFPS",
++ @"RearFacingCameraHFRVideoCapture720pMaxFPS",
++ @"RearFacingCameraMaxVideoZoomFactor",
++ @"RearFacingCameraStillDurationForBurst",
++ @"RearFacingCameraVideoCapture1080pMaxFPS",
++ @"RearFacingCameraVideoCapture4kMaxFPS",
++ @"RearFacingCameraVideoCapture720pMaxFPS",
++ @"RearFacingCameraVideoCaptureFPS",
++ @"RearFacingTelephotoCameraCapability",
+ @"RegionCode",
+ @"RegionInfo",
+- //@"RegionalBehaviorAll",
+ @"RegionalBehaviorChinaBrick",
+ @"RegionalBehaviorEUVolumeLimit",
+ @"RegionalBehaviorGB18030",
+@@ -234,109 +381,316 @@
+ @"RegionalBehaviorNoVOIP",
+ @"RegionalBehaviorNoWiFi",
+ @"RegionalBehaviorShutterClick",
++ @"RegionalBehaviorValid",
+ @"RegionalBehaviorVolumeLimit",
+ @"RegulatoryIdentifiers",
+- //@"ReleaseType",
++ @"RegulatoryModelNumber",
++ @"ReleaseType",
++ @"RenderWideGamutImagesAtDisplayTime",
++ @"RendersLetterPressSlowly",
+ @"RequiredBatteryLevelForSoftwareUpdate",
++ @"RestoreOSBuild",
++ @"RestrictedCountryCodes",
++ @"RingerSwitchCapability",
++ @"RotateToWakeStatus",
+ @"SBAllowSensitiveUI",
+ @"SBCanForceDebuggingInfo",
+ @"SDIOManufacturerTuple",
+ @"SDIOProductInfo",
+- //@"SIMTrayStatus",
+- //@"ScreenDimensions",
+- //@"screen-dimensions",
+- //@"SerialNumber",
++ @"SavageUID",
++ @"ScreenRecorderCapability",
++ @"SecureElement",
+ @"ShouldHactivate",
++ @"SiKACapability",
+ @"SigningFuse",
+- //@"SoftwareBehavior",
+- //@"SoftwareBundleVersion",
++ @"SiliconBringupBoard",
++ @"SiriGestureCapability",
++ @"SiriOfflineCapability",
++ @"Skey",
++ @"SoftwareBundleVersion",
++ @"SoftwareDimmingAlpha",
++ @"SphereCapability",
++ @"StarkCapability",
++ @"StrictWakeKeyboardCases",
+ @"SupportedDeviceFamilies",
+- //@"SupportedKeyboards",
+- //@"SysCfg",
+- //@"UniqueChipID",
+- //@"UniqueDeviceID",
+- //@"UniqueDeviceIDData",
+- //@"UserAssignedDeviceName",
+- //@"WifiAddress",
+- //@"WifiAddressData",
+- //@"WifiVendor",
+- //@"WirelessBoardSnum",
+- @"iTunesFamilyID",
+-
+- @"720p",
+- @"1080p",
++ @"SupportsBurninMitigation",
++ @"SupportsEDUMU",
++ @"SupportsForceTouch",
++ @"SupportsIrisCapture",
++ @"SupportsLowPowerMode",
++ @"SupportsPerseus",
++ @"SupportsRotateToWake",
++ @"SupportsSOS",
++ @"SupportsSSHBButtonType",
++ @"SupportsTouchRemote",
++ @"TimeSyncCapability",
++ @"TouchDelivery120Hz",
++ @"UIBackgroundQuality",
++ @"UIParallaxCapability",
++ @"UIProceduralWallpaperCapability",
++ @"UIReachability",
++ @"UserIntentPhysicalButtonCGRect",
++ @"UserIntentPhysicalButtonCGRectString",
++ @"UserIntentPhysicalButtonNormalizedCGRect",
++ @"VibratorCapability",
++ @"VideoStillsCapability",
++ @"WAGraphicQuality",
++ @"WLANBkgScanCache",
++ @"WSKU",
++ @"WiFiCallingCapability",
++ @"WifiAntennaSKUVersion",
++ @"WifiCallingSecondaryDeviceCapability",
++ @"WifiChipset",
++ @"WifiFirmwareVersion",
++ @"WifiVendor",
++ @"WirelessChargingCapability",
++ @"YonkersUID",
+ @"accelerometer",
+ @"accessibility",
+ @"additional-text-tones",
++ @"aggregate-cam-photo-zoom",
++ @"aggregate-cam-video-zoom",
++ @"airDropRestriction",
++ @"airplay-mirroring",
++ @"airplay-no-mirroring",
+ @"all-features",
++ @"allow-32bit-apps",
++ @"ambient-light-sensor",
++ @"ane",
+ @"any-telephony",
++ @"apn",
+ @"app-store",
++ @"apple-internal-install",
+ @"application-installation",
++ @"applicationInstallation",
++ @"arkit",
++ @"arm64",
+ @"armv6",
+ @"armv7",
++ @"armv7s",
+ @"assistant",
++ @"auto-focus",
+ @"auto-focus-camera",
++ @"baseband-chipset",
+ @"bluetooth",
+ @"bluetooth-le",
++ @"builtin-mics",
++ @"c2k-device",
++ @"call-forwarding",
++ @"call-waiting",
++ @"caller-id",
+ @"camera-flash",
++ @"camera-front",
++ @"camera-front-flash",
++ @"camera-rear",
++ @"cameraRestriction",
++ @"car-integration",
++ @"cell-broadcast",
+ @"cellular-data",
++ @"class",
++ @"closed-loop",
+ @"contains-cellular-radio",
++ @"crypto-hash-method",
++ @"data-plan",
++ @"debug-board-revision",
++ @"delay-sleep-for-headset-click",
++ @"device-color-policy",
++ @"device-colors",
++ @"device-name",
++ @"device-name-localized",
+ @"dictation",
+ @"display-mirroring",
++ @"display-rotation",
+ @"displayport",
++ @"does-not-support-gamekit",
++ @"enc-top-type",
+ @"encode-aac",
+ @"encrypted-data-partition",
++ @"enforce-googlemail",
++ @"enforce-shutter-click",
++ @"explicitContentRestriction",
++ @"face-detection-support",
++ @"fast-switch-options",
+ @"fcc-logos-via-software",
++ @"fcm-type",
++ @"firmware-version",
++ @"flash",
++ @"front-auto-hdr",
++ @"front-burst",
++ @"front-burst-image-duration",
+ @"front-facing-camera",
++ @"front-flash-capability",
++ @"front-hdr",
++ @"front-hdr-on",
++ @"front-max-video-fps-1080p",
++ @"front-max-video-fps-4k",
++ @"front-max-video-fps-720p",
++ @"front-max-video-zoom",
++ @"front-slowmo",
++ @"full-6",
++ @"function-button_halleffect",
++ @"function-button_ringerab",
+ @"gamekit",
+ @"gas-gauge-battery",
+ @"gps",
++ @"gps-capable",
++ @"green-tea",
+ @"gyroscope",
+ @"h264-encoder",
++ @"hall-effect-sensor",
++ @"haptics",
+ @"hardware-keyboard",
++ @"has-sphere",
+ @"hd-video-capture",
+ @"hdr-image-capture",
++ @"healthkit",
++ @"hearingaid-audio-equalization",
++ @"hearingaid-low-energy-audio",
++ @"hearingaid-power-reduction",
+ @"hiccough-interval",
++ @"hide-non-default-apps",
+ @"hidpi",
++ @"home-button-type",
+ @"homescreen-wallpaper",
+ @"hw-encode-snapshots",
++ @"hw-snapshots-need-purplegfx",
++ @"iAP2Capability",
++ @"iTunesFamilyID",
++ @"iap2-protocol-supported",
++ @"image4-supported",
+ @"international-settings",
+ @"io-surface-backed-images",
++ @"ipad",
++ @"kConferenceCallType",
++ @"kSimultaneousCallAndDataCurrentlySupported",
++ @"kSimultaneousCallAndDataSupported",
++ @"large-format-phone",
++ @"live-effects",
++ @"live-photo-capture",
+ @"load-thumbnails-while-scrolling",
++ @"location-reminders",
+ @"location-services",
++ @"lte-device",
+ @"magnetometer",
++ @"main-screen-class",
++ @"main-screen-height",
++ @"main-screen-orientation",
++ @"main-screen-pitch",
++ @"main-screen-scale",
++ @"main-screen-width",
++ @"marketing-name",
++ @"mesa",
++ @"metal",
+ @"microphone",
++ @"mix-n-match-prevention-status",
+ @"mms",
++ @"modelIdentifier",
++ @"multi-touch",
+ @"multitasking",
++ @"multitasking-gestures",
+ @"music-store",
++ @"n78a-mode",
++ @"name",
++ @"navigation",
++ @"nfc",
++ @"nfcWithRadio",
+ @"nike-ipod",
++ @"nike-support",
++ @"no-coreroutine",
++ @"no-hi-res-buildings",
++ @"no-simplistic-road-mesh",
+ @"not-green-tea",
++ @"offline-dictation",
++ @"opal",
+ @"opengles-1",
+ @"opengles-2",
++ @"opengles-3",
++ @"opposed-power-vol-buttons",
++ @"ota-activation",
++ @"panorama",
++ @"peek-ui-width",
+ @"peer-peer",
++ @"personal-hotspot",
+ @"photo-adjustments",
+ @"photo-stream",
++ @"piezo-clicker",
++ @"pipelined-stillimage-capability",
++ @"platinum",
++ @"post-effects",
++ @"pressure",
++ @"prox-sensor",
+ @"proximity-sensor",
+ @"ptp-large-files",
++ @"public-key-accelerator",
++ @"rear-auto-hdr",
++ @"rear-burst",
++ @"rear-burst-image-duration",
++ @"rear-cam-telephoto-capability",
++ @"rear-facing-camera",
++ @"rear-hdr",
++ @"rear-hdr-on",
++ @"rear-max-slomo-video-fps-1080p",
++ @"rear-max-slomo-video-fps-720p",
++ @"rear-max-video-fps-1080p",
++ @"rear-max-video-fps-4k",
++ @"rear-max-video-fps-720p",
++ @"rear-max-video-frame_rate",
++ @"rear-max-video-zoom",
++ @"rear-slowmo",
++ @"regulatory-model-number",
+ @"ringer-switch",
++ @"role",
++ @"sandman-support",
++ @"screen-dimensions",
++ @"sensitive-ui",
++ @"shoebox",
++ @"sika-support",
++ @"sim",
++ @"sim-phonebook",
++ @"siri-gesture",
++ @"slow-letterpress-rendering",
+ @"sms",
++ @"software-bundle-version",
++ @"software-dimming-alpha",
+ @"stand-alone-contacts",
+ @"still-camera",
++ @"stockholm",
++ @"supports-always-listening",
+ @"telephony",
+ @"telephony-maximum-generation",
++ @"thin-bezel",
++ @"tnr-mode-back",
++ @"tnr-mode-front",
++ @"touch-id",
+ @"tv-out-crossfade",
+ @"tv-out-settings",
++ @"ui-background-quality",
++ @"ui-no-parallax",
++ @"ui-no-procedural-wallpaper",
++ @"ui-pip",
++ @"ui-reachability",
++ @"ui-traffic-cheap-shaders",
++ @"ui-weather-quality",
++ @"umts-device",
+ @"unified-ipod",
+ @"venice",
+ @"video-camera",
++ @"video-cap",
++ @"video-stills",
+ @"voice-control",
+ @"voip",
+ @"volume-buttons",
++ @"wapi",
++ @"watch-companion",
++ @"wi-fi",
+ @"wifi",
++ @"wifi-chipset",
++ @"wifi-module-sn",
++ @"wildcat",
++ @"wlan",
+ @"youtube",
+ @"youtube-plugin",
+- @"ipad",
+- @"wildcat",
++ @"youtubePlugin",
+ nil])
+ if (CFTypeRef answer = $MGCopyAnswer(reinterpret_cast<CFStringRef>(name))) {
+ [answers setObject:(id)answer forKey:name];