summaryrefslogtreecommitdiff
path: root/data/uikittools/1_uicache.diff
diff options
context:
space:
mode:
Diffstat (limited to 'data/uikittools/1_uicache.diff')
-rw-r--r--data/uikittools/1_uicache.diff1170
1 files changed, 1170 insertions, 0 deletions
diff --git a/data/uikittools/1_uicache.diff b/data/uikittools/1_uicache.diff
new file mode 100644
index 000000000..8a01dd2e3
--- /dev/null
+++ b/data/uikittools/1_uicache.diff
@@ -0,0 +1,1170 @@
+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,16 @@
+ /* }}} */
+
+ #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>
++#import <crt_externs.h>
++#import <xpc/xpc.h>
+
+ #include "csstore.hpp"
+
+@@ -81,6 +94,12 @@
+
+ @end
+
++@interface LSApplicationProxy : NSObject
++- (NSString*) applicationIdentifier;
++- (NSURL*) resourcesDirectoryURL;
++- (NSDate*) registeredDate;
++@end
++
+ @interface LSApplicationWorkspace : NSObject
+ + (id) defaultWorkspace;
+ - (BOOL) registerApplication:(id)application;
+@@ -89,16 +108,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
++
++@interface FBSSystemService
+++(id)sharedService;
++-(void)sendActions:(NSSet*)actions withResult:(id)result;
+ @end
+
+-int main(int argc, const char *argv[]) {
+- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
++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)]];
++}
+
+- Class $LSApplicationWorkspace(objc_getClass("LSApplicationWorkspace"));
+- LSApplicationWorkspace *workspace($LSApplicationWorkspace == nil ? nil : [$LSApplicationWorkspace defaultWorkspace]);
++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;
++ }
++}
+
+- if (kCFCoreFoundationVersionNumber > 1000) // this API is on iOS 7 but invaliding the icon cache is harder there
+- if ([workspace respondsToSelector:@selector(_LSPrivateRebuildApplicationDatabasesForSystemApps:internal:user:)]) {
++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 (![[$LSApplicationWorkspace defaultWorkspace] 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);
++}
++
++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 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 +417,247 @@
+ 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;
++ }
++}
++
++pid_t pidOfCydia(void) {
++ launch_data_t request = launch_data_new_string(LAUNCH_KEY_GETJOBS);
++ launch_data_t response = launch_msg(request);
++ launch_data_free(request);
++ __block pid_t pid=-1;
++
++ if (response == NULL || launch_data_get_type(response) != LAUNCH_DATA_DICTIONARY) return -1;
++
++ xpc_dictionary_apply((xpc_object_t)response, ^bool(const char *key, xpc_object_t value) {
++ if (xpc_get_type(value) == XPC_TYPE_DICTIONARY) {
++ const char *program = xpc_dictionary_get_string(value, "Program");
++ if (program && strcmp(program, "/Applications/Cydia.app/Cydia") == 0) {
++ pid = (pid_t)xpc_dictionary_get_int64(value, "PID");
++ if (verbose) fprintf(stderr, "Found Cydia running with PID: %d\n", pid);
++ return false;
++ }
++ }
++ return true;
++ });
++
++ if (pid>0) {
++ return pid;
++ }
++ return -1;
++}
++
++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;
++ }
++ pid_t cydia_pid;
++ if ([found[2] isEqualToString:@"Cydia.app"] &&
++ (cydia_pid = pidOfCydia()) > 0) {
++ // We are in cydia and trying to refresh it - this will kill it. Let's schedule it for later.
++ if (verbose) fprintf(stderr, "Waiting to refresh Cydia...\n");
++ pid_t pid = fork();
++ if (pid == 0) {
++ setpgrp();
++ signal(SIGHUP, SIG_IGN);
++ signal(SIGPIPE, SIG_IGN);
++ fclose(stdin);
++ freopen("/dev/null", "a", stderr);
++ freopen("/dev/null", "a", stdout);
++ pid = fork();
++ if (pid == 0) {
++ while (kill(cydia_pid, 0)==0) {
++ sleep(1);
++ }
++ const char *uicache = (*_NSGetArgv())[0];
++ execl(uicache, uicache, "-vvvvvvv", NULL);
++ fprintf(stderr, "Unable to exec\n");
++ fflush(stderr);
++ exit(-1);
++ }
++ exit(0);
++ } else if (pid > 0) {
++ int stat;
++ waitpid(pid, &stat, 0);
++ return;
++ } else {
++ fprintf(stderr, "Unable to fork\n");
++ }
++ }
++ 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>