2013-08-19 03:17:33 +00:00
|
|
|
// main.mm boilerplate
|
2013-02-17 14:04:44 +00:00
|
|
|
|
|
|
|
#import <UIKit/UIKit.h>
|
2020-02-23 09:27:25 +00:00
|
|
|
#import <dlfcn.h>
|
|
|
|
#import <mach/mach.h>
|
|
|
|
#import <pthread.h>
|
2022-04-02 23:07:51 +00:00
|
|
|
#import <signal.h>
|
2013-08-19 03:17:33 +00:00
|
|
|
#import <string>
|
2014-02-12 09:26:53 +00:00
|
|
|
#import <stdio.h>
|
|
|
|
#import <stdlib.h>
|
2016-08-28 16:10:26 +00:00
|
|
|
#import <sys/syscall.h>
|
2014-05-22 06:20:43 +00:00
|
|
|
#import <AudioToolbox/AudioToolbox.h>
|
2013-02-17 14:04:44 +00:00
|
|
|
|
|
|
|
#import "AppDelegate.h"
|
2017-09-04 07:05:46 +00:00
|
|
|
#import "PPSSPPUIApplication.h"
|
2018-02-22 11:04:12 +00:00
|
|
|
#import "ViewController.h"
|
2013-02-17 14:04:44 +00:00
|
|
|
|
2021-02-21 21:02:11 +00:00
|
|
|
#include "Common/MemoryUtil.h"
|
2020-10-04 08:30:18 +00:00
|
|
|
#include "Common/System/NativeApp.h"
|
|
|
|
#include "Common/System/System.h"
|
2023-03-22 15:20:30 +00:00
|
|
|
#include "Common/System/Request.h"
|
2021-02-21 21:02:11 +00:00
|
|
|
#include "Common/StringUtils.h"
|
2020-10-04 08:04:01 +00:00
|
|
|
#include "Common/Profiler/Profiler.h"
|
2023-07-20 09:26:20 +00:00
|
|
|
#include "Core/Config.h"
|
2023-02-01 16:03:12 +00:00
|
|
|
#include "UI/DarwinFileSystemServices.h"
|
2013-09-06 08:12:48 +00:00
|
|
|
|
2020-02-23 09:27:25 +00:00
|
|
|
static int (*csops)(pid_t pid, unsigned int ops, void * useraddr, size_t usersize);
|
|
|
|
static boolean_t (*exc_server)(mach_msg_header_t *, mach_msg_header_t *);
|
|
|
|
static int (*ptrace)(int request, pid_t pid, caddr_t addr, int data);
|
|
|
|
|
2021-03-01 21:40:55 +00:00
|
|
|
#define CS_OPS_STATUS 0 /* return status */
|
|
|
|
#define CS_DEBUGGED 0x10000000 /* process is currently or has previously been debugged and allowed to run with invalid pages */
|
|
|
|
#define PT_ATTACHEXC 14 /* attach to running process with signal exception */
|
|
|
|
#define PT_DETACH 11 /* stop tracing a process */
|
|
|
|
#define ptrace(a, b, c, d) syscall(SYS_ptrace, a, b, c, d)
|
|
|
|
|
|
|
|
bool get_debugged() {
|
2019-10-15 01:22:00 +00:00
|
|
|
int flags;
|
2021-03-01 21:40:55 +00:00
|
|
|
int rv = csops(getpid(), CS_OPS_STATUS, &flags, sizeof(flags));
|
|
|
|
if (rv==0 && flags&CS_DEBUGGED) return true;
|
|
|
|
|
|
|
|
pid_t pid = fork();
|
|
|
|
if (pid > 0) {
|
|
|
|
int st,rv,i=0;
|
|
|
|
do {
|
|
|
|
usleep(500);
|
|
|
|
rv = waitpid(pid, &st, 0);
|
|
|
|
} while (rv<0 && i++<10);
|
|
|
|
if (rv<0) fprintf(stderr, "Unable to wait for child?\n");
|
|
|
|
} else if (pid == 0) {
|
|
|
|
pid_t ppid = getppid();
|
|
|
|
int rv = ptrace(PT_ATTACHEXC, ppid, 0, 0);
|
|
|
|
if (rv) {
|
|
|
|
perror("Unable to attach to process");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
for (int i=0; i<100; i++) {
|
|
|
|
usleep(1000);
|
|
|
|
errno = 0;
|
|
|
|
rv = ptrace(PT_DETACH, ppid, 0, 0);
|
|
|
|
if (rv==0) break;
|
|
|
|
}
|
|
|
|
if (rv) {
|
|
|
|
perror("Unable to detach from process");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
exit(0);
|
|
|
|
} else {
|
|
|
|
perror("Unable to fork");
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = csops(getpid(), CS_OPS_STATUS, &flags, sizeof(flags));
|
|
|
|
if (rv==0 && flags&CS_DEBUGGED) return true;
|
|
|
|
|
|
|
|
return false;
|
2020-02-23 09:27:25 +00:00
|
|
|
}
|
2019-10-15 01:22:00 +00:00
|
|
|
|
2020-02-23 09:27:25 +00:00
|
|
|
kern_return_t catch_exception_raise(mach_port_t exception_port,
|
|
|
|
mach_port_t thread,
|
|
|
|
mach_port_t task,
|
|
|
|
exception_type_t exception,
|
|
|
|
exception_data_t code,
|
|
|
|
mach_msg_type_number_t code_count) {
|
|
|
|
return KERN_FAILURE;
|
|
|
|
}
|
2019-10-15 01:22:00 +00:00
|
|
|
|
2020-02-23 09:27:25 +00:00
|
|
|
void *exception_handler(void *argument) {
|
|
|
|
auto port = *reinterpret_cast<mach_port_t *>(argument);
|
|
|
|
mach_msg_server(exc_server, 2048, port, 0);
|
|
|
|
return NULL;
|
2019-10-15 01:22:00 +00:00
|
|
|
}
|
2015-11-03 18:57:10 +00:00
|
|
|
|
2023-03-22 22:25:00 +00:00
|
|
|
float g_safeInsetLeft = 0.0;
|
|
|
|
float g_safeInsetRight = 0.0;
|
|
|
|
float g_safeInsetTop = 0.0;
|
|
|
|
float g_safeInsetBottom = 0.0;
|
2020-03-31 16:45:39 +00:00
|
|
|
|
2022-08-13 09:15:21 +00:00
|
|
|
// We no longer need to judge if jit is usable or not by according to the ios version.
|
|
|
|
/*
|
2021-02-21 21:02:11 +00:00
|
|
|
static bool g_jitAvailable = false;
|
|
|
|
static int g_iosVersionMinor;
|
2022-08-13 09:15:21 +00:00
|
|
|
*/
|
2022-08-13 09:56:27 +00:00
|
|
|
static int g_iosVersionMajor;
|
2022-08-13 18:42:05 +00:00
|
|
|
static std::string version;
|
2015-11-03 18:57:10 +00:00
|
|
|
|
2013-09-04 09:29:38 +00:00
|
|
|
std::string System_GetProperty(SystemProperty prop) {
|
|
|
|
switch (prop) {
|
2019-03-27 02:01:20 +00:00
|
|
|
case SYSPROP_NAME:
|
2022-08-13 09:56:27 +00:00
|
|
|
return StringFromFormat("iOS %s", version.c_str());
|
2019-03-27 02:01:20 +00:00
|
|
|
case SYSPROP_LANGREGION:
|
2022-08-13 09:15:21 +00:00
|
|
|
return [[[NSLocale currentLocale] objectForKey:NSLocaleIdentifier] UTF8String];
|
2023-07-20 07:56:51 +00:00
|
|
|
case SYSPROP_BUILD_VERSION:
|
|
|
|
return PPSSPP_GIT_VERSION;
|
2019-03-27 02:01:20 +00:00
|
|
|
default:
|
|
|
|
return "";
|
2013-09-04 09:29:38 +00:00
|
|
|
}
|
2013-08-19 03:17:33 +00:00
|
|
|
}
|
|
|
|
|
2021-01-06 15:37:04 +00:00
|
|
|
std::vector<std::string> System_GetPropertyStringVec(SystemProperty prop) {
|
|
|
|
switch (prop) {
|
2021-01-09 22:45:49 +00:00
|
|
|
case SYSPROP_TEMP_DIRS:
|
2021-01-06 15:37:04 +00:00
|
|
|
default:
|
|
|
|
return std::vector<std::string>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-11 18:30:25 +00:00
|
|
|
int System_GetPropertyInt(SystemProperty prop) {
|
2016-08-28 16:07:54 +00:00
|
|
|
switch (prop) {
|
2019-03-27 02:01:20 +00:00
|
|
|
case SYSPROP_AUDIO_SAMPLE_RATE:
|
|
|
|
return 44100;
|
|
|
|
case SYSPROP_DEVICE_TYPE:
|
|
|
|
return DEVICE_TYPE_MOBILE;
|
2021-02-21 21:02:11 +00:00
|
|
|
case SYSPROP_SYSTEMVERSION:
|
|
|
|
return g_iosVersionMajor;
|
2019-03-27 02:01:20 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
2017-04-30 00:35:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-05 17:04:07 +00:00
|
|
|
float System_GetPropertyFloat(SystemProperty prop) {
|
|
|
|
switch (prop) {
|
|
|
|
case SYSPROP_DISPLAY_REFRESH_RATE:
|
|
|
|
return 60.f;
|
2020-03-31 16:45:39 +00:00
|
|
|
case SYSPROP_DISPLAY_SAFE_INSET_LEFT:
|
|
|
|
return g_safeInsetLeft;
|
|
|
|
case SYSPROP_DISPLAY_SAFE_INSET_RIGHT:
|
|
|
|
return g_safeInsetRight;
|
|
|
|
case SYSPROP_DISPLAY_SAFE_INSET_TOP:
|
|
|
|
return g_safeInsetTop;
|
|
|
|
case SYSPROP_DISPLAY_SAFE_INSET_BOTTOM:
|
|
|
|
return g_safeInsetBottom;
|
2020-01-05 17:04:07 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-30 00:35:12 +00:00
|
|
|
bool System_GetPropertyBool(SystemProperty prop) {
|
|
|
|
switch (prop) {
|
2023-02-02 13:54:50 +00:00
|
|
|
case SYSPROP_HAS_OPEN_DIRECTORY:
|
|
|
|
return false;
|
2019-03-27 02:01:20 +00:00
|
|
|
case SYSPROP_HAS_BACK_BUTTON:
|
|
|
|
return false;
|
2023-11-06 23:44:43 +00:00
|
|
|
case SYSPROP_HAS_ACCELEROMETER:
|
|
|
|
return true;
|
2019-03-27 02:01:20 +00:00
|
|
|
case SYSPROP_APP_GOLD:
|
2017-04-05 14:21:08 +00:00
|
|
|
#ifdef GOLD
|
2019-03-27 02:01:20 +00:00
|
|
|
return true;
|
2017-04-05 14:21:08 +00:00
|
|
|
#else
|
2019-03-27 02:01:20 +00:00
|
|
|
return false;
|
2017-04-05 14:21:08 +00:00
|
|
|
#endif
|
2021-02-21 21:02:11 +00:00
|
|
|
case SYSPROP_CAN_JIT:
|
2022-08-13 09:15:21 +00:00
|
|
|
return get_debugged();
|
2023-07-20 14:01:51 +00:00
|
|
|
#ifndef HTTPS_NOT_AVAILABLE
|
|
|
|
case SYSPROP_SUPPORTS_HTTPS:
|
|
|
|
return true;
|
|
|
|
#endif
|
2019-03-27 02:01:20 +00:00
|
|
|
default:
|
|
|
|
return false;
|
2016-08-28 16:07:54 +00:00
|
|
|
}
|
2015-01-11 18:30:25 +00:00
|
|
|
}
|
2014-07-20 10:11:50 +00:00
|
|
|
|
2023-03-21 10:10:09 +00:00
|
|
|
void System_Notify(SystemNotification notification) {
|
|
|
|
switch (notification) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-22 15:58:32 +00:00
|
|
|
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3) {
|
2023-03-22 15:20:30 +00:00
|
|
|
switch (type) {
|
2023-03-22 21:07:29 +00:00
|
|
|
case SystemRequestType::EXIT_APP:
|
|
|
|
exit(0);
|
|
|
|
// The below seems right, but causes hangs. See #12140.
|
|
|
|
// dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
// [sharedViewController shutdown];
|
|
|
|
// exit(0);
|
|
|
|
// });
|
|
|
|
break;
|
2023-03-22 16:57:28 +00:00
|
|
|
case SystemRequestType::BROWSE_FOR_FILE:
|
2023-03-22 15:20:30 +00:00
|
|
|
{
|
2023-03-22 16:57:28 +00:00
|
|
|
DarwinDirectoryPanelCallback callback = [requestId] (bool success, Path path) {
|
2023-03-22 15:20:30 +00:00
|
|
|
if (success) {
|
2023-03-22 16:57:28 +00:00
|
|
|
g_requestManager.PostSystemSuccess(requestId, path.c_str());
|
2023-03-22 15:20:30 +00:00
|
|
|
} else {
|
|
|
|
g_requestManager.PostSystemFailure(requestId);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
DarwinFileSystemServices services;
|
2023-03-22 16:57:28 +00:00
|
|
|
services.presentDirectoryPanel(callback, /* allowFiles = */ true, /* allowDirectories = */ false);
|
|
|
|
return true;
|
2023-03-22 15:20:30 +00:00
|
|
|
}
|
2023-03-22 16:57:28 +00:00
|
|
|
case SystemRequestType::BROWSE_FOR_FOLDER:
|
|
|
|
{
|
|
|
|
DarwinDirectoryPanelCallback callback = [requestId] (bool success, Path path) {
|
|
|
|
if (success) {
|
|
|
|
g_requestManager.PostSystemSuccess(requestId, path.c_str());
|
|
|
|
} else {
|
|
|
|
g_requestManager.PostSystemFailure(requestId);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
DarwinFileSystemServices services;
|
|
|
|
services.presentDirectoryPanel(callback, /* allowFiles = */ false, /* allowDirectories = */ true);
|
|
|
|
return true;
|
2023-03-22 15:20:30 +00:00
|
|
|
}
|
2023-03-22 21:49:38 +00:00
|
|
|
case SystemRequestType::CAMERA_COMMAND:
|
|
|
|
if (!strncmp(param1.c_str(), "startVideo", 10)) {
|
|
|
|
int width = 0, height = 0;
|
|
|
|
sscanf(param1.c_str(), "startVideo_%dx%d", &width, &height);
|
|
|
|
setCameraSize(width, height);
|
|
|
|
startVideo();
|
|
|
|
} else if (!strcmp(param1.c_str(), "stopVideo")) {
|
|
|
|
stopVideo();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
case SystemRequestType::GPS_COMMAND:
|
|
|
|
if (param1 == "open") {
|
|
|
|
startLocation();
|
2023-03-22 22:25:00 +00:00
|
|
|
} else if (param1 == "close") {
|
2023-03-22 21:49:38 +00:00
|
|
|
stopLocation();
|
|
|
|
}
|
|
|
|
return true;
|
2023-03-22 21:55:53 +00:00
|
|
|
case SystemRequestType::SHARE_TEXT:
|
|
|
|
{
|
|
|
|
NSString *text = [NSString stringWithUTF8String:param1.c_str()];
|
|
|
|
[sharedViewController shareText:text];
|
|
|
|
return true;
|
|
|
|
}
|
2023-03-22 21:49:38 +00:00
|
|
|
default:
|
|
|
|
return false;
|
2023-03-22 15:20:30 +00:00
|
|
|
}
|
2023-03-22 11:26:14 +00:00
|
|
|
}
|
|
|
|
|
2022-07-10 20:34:44 +00:00
|
|
|
void System_Toast(const char *text) {}
|
2015-12-17 21:41:50 +00:00
|
|
|
void System_AskForPermission(SystemPermission permission) {}
|
2022-07-10 20:34:44 +00:00
|
|
|
|
2015-12-17 21:41:50 +00:00
|
|
|
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
|
|
|
|
|
2014-05-22 07:54:09 +00:00
|
|
|
FOUNDATION_EXTERN void AudioServicesPlaySystemSoundWithVibration(unsigned long, objc_object*, NSDictionary*);
|
|
|
|
|
2021-03-01 21:40:55 +00:00
|
|
|
BOOL SupportsTaptic() {
|
2019-03-27 02:01:20 +00:00
|
|
|
// we're on an iOS version that cannot instantiate UISelectionFeedbackGenerator, so no.
|
2021-03-01 21:40:55 +00:00
|
|
|
if(!NSClassFromString(@"UISelectionFeedbackGenerator")) {
|
2019-03-27 02:01:20 +00:00
|
|
|
return NO;
|
|
|
|
}
|
2020-01-05 17:04:07 +00:00
|
|
|
|
2019-03-27 02:01:20 +00:00
|
|
|
// http://www.mikitamanko.com/blog/2017/01/29/haptic-feedback-with-uifeedbackgenerator/
|
|
|
|
// use private API against UIDevice to determine the haptic stepping
|
|
|
|
// 2 - iPhone 7 or above, full taptic feedback
|
|
|
|
// 1 - iPhone 6S, limited taptic feedback
|
|
|
|
// 0 - iPhone 6 or below, no taptic feedback
|
|
|
|
NSNumber* val = (NSNumber*)[[UIDevice currentDevice] valueForKey:@"feedbackSupportLevel"];
|
|
|
|
return [val intValue] >= 2;
|
2018-01-14 18:38:04 +00:00
|
|
|
}
|
|
|
|
|
2023-03-21 09:42:23 +00:00
|
|
|
void System_Vibrate(int mode) {
|
2021-03-01 21:40:55 +00:00
|
|
|
if (SupportsTaptic()) {
|
2019-03-27 02:01:20 +00:00
|
|
|
PPSSPPUIApplication* app = (PPSSPPUIApplication*)[UIApplication sharedApplication];
|
|
|
|
if(app.feedbackGenerator == nil)
|
|
|
|
{
|
|
|
|
app.feedbackGenerator = [[UISelectionFeedbackGenerator alloc] init];
|
|
|
|
[app.feedbackGenerator prepare];
|
|
|
|
}
|
|
|
|
[app.feedbackGenerator selectionChanged];
|
2021-03-01 21:40:55 +00:00
|
|
|
} else {
|
2019-03-27 02:01:20 +00:00
|
|
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
|
|
|
NSArray *pattern = @[@YES, @30, @NO, @2];
|
2020-01-05 17:04:07 +00:00
|
|
|
|
2019-03-27 02:01:20 +00:00
|
|
|
dictionary[@"VibePattern"] = pattern;
|
|
|
|
dictionary[@"Intensity"] = @2;
|
2020-01-05 17:04:07 +00:00
|
|
|
|
2019-03-27 02:01:20 +00:00
|
|
|
AudioServicesPlaySystemSoundWithVibration(kSystemSoundID_Vibrate, nil, dictionary);
|
|
|
|
}
|
2013-10-13 19:12:36 +00:00
|
|
|
}
|
|
|
|
|
2013-02-17 14:04:44 +00:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2021-02-21 21:02:11 +00:00
|
|
|
// Hacky hacks to try to enable JIT by pretending to be a debugger.
|
2020-02-23 09:27:25 +00:00
|
|
|
csops = reinterpret_cast<decltype(csops)>(dlsym(dlopen(nullptr, RTLD_LAZY), "csops"));
|
|
|
|
exc_server = reinterpret_cast<decltype(exc_server)>(dlsym(dlopen(NULL, RTLD_LAZY), "exc_server"));
|
|
|
|
ptrace = reinterpret_cast<decltype(ptrace)>(dlsym(dlopen(NULL, RTLD_LAZY), "ptrace"));
|
2019-10-15 01:22:00 +00:00
|
|
|
// see https://github.com/hrydgard/ppsspp/issues/11905
|
2021-02-21 21:02:11 +00:00
|
|
|
|
|
|
|
// Tried checking for JIT support here with AllocateExecutableMemory and ProtectMemoryPages,
|
|
|
|
// but it just succeeds, and then fails when you try to execute from it.
|
|
|
|
|
|
|
|
// So, we'll just resort to a version check.
|
|
|
|
|
2022-08-13 18:42:05 +00:00
|
|
|
version = [[[UIDevice currentDevice] systemVersion] UTF8String];
|
2022-08-13 09:56:27 +00:00
|
|
|
if (2 != sscanf(version.c_str(), "%d", &g_iosVersionMajor)) {
|
2021-02-21 21:02:11 +00:00
|
|
|
// Just set it to 14.0 if the parsing fails for whatever reason.
|
|
|
|
g_iosVersionMajor = 14;
|
|
|
|
}
|
|
|
|
|
2022-08-13 09:56:27 +00:00
|
|
|
/*
|
2021-03-01 21:40:55 +00:00
|
|
|
g_jitAvailable = get_debugged();
|
2022-08-13 09:15:21 +00:00
|
|
|
|
2021-03-01 12:04:55 +00:00
|
|
|
if (g_iosVersionMajor > 14 || (g_iosVersionMajor == 14 && g_iosVersionMinor >= 4)) {
|
2021-02-21 21:02:11 +00:00
|
|
|
g_jitAvailable = false;
|
|
|
|
} else {
|
|
|
|
g_jitAvailable = true;
|
|
|
|
}
|
2021-03-01 21:40:55 +00:00
|
|
|
*/
|
2020-01-05 17:04:07 +00:00
|
|
|
|
2018-01-02 03:01:10 +00:00
|
|
|
PROFILE_INIT();
|
2020-01-05 17:04:07 +00:00
|
|
|
|
2022-04-02 23:07:51 +00:00
|
|
|
// Ignore sigpipe.
|
|
|
|
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
|
|
|
perror("Unable to ignore SIGPIPE");
|
|
|
|
}
|
|
|
|
|
2013-02-17 14:04:44 +00:00
|
|
|
@autoreleasepool {
|
2018-01-02 02:51:18 +00:00
|
|
|
return UIApplicationMain(argc, argv, NSStringFromClass([PPSSPPUIApplication class]), NSStringFromClass([AppDelegate class]));
|
2013-02-17 14:04:44 +00:00
|
|
|
}
|
|
|
|
}
|