mirror of
https://github.com/SoPat712/YTLitePlus.git
synced 2025-08-25 03:48:52 -04:00
added files via upload
This commit is contained in:
209
Tweaks/FLEX/GlobalStateExplorers/SystemLog/ActivityStreamAPI.h
Normal file
209
Tweaks/FLEX/GlobalStateExplorers/SystemLog/ActivityStreamAPI.h
Normal file
@@ -0,0 +1,209 @@
|
||||
//
|
||||
// Taken from https://github.com/llvm-mirror/lldb/blob/master/tools/debugserver/source/MacOSX/DarwinLog/ActivityStreamSPI.h
|
||||
// by Tanner Bennett on 03/03/2019 with minimal modifications.
|
||||
//
|
||||
|
||||
//===-- ActivityStreamAPI.h -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ActivityStreamSPI_h
|
||||
#define ActivityStreamSPI_h
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
// #include <xpc/xpc.h>
|
||||
|
||||
/* By default, XPC objects are declared as Objective-C types when building with
|
||||
* an Objective-C compiler. This allows them to participate in ARC, in RR
|
||||
* management by the Blocks runtime and in leaks checking by the static
|
||||
* analyzer, and enables them to be added to Cocoa collections.
|
||||
*
|
||||
* See <os/object.h> for details.
|
||||
*/
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
#if OS_OBJECT_USE_OBJC
|
||||
OS_OBJECT_DECL(xpc_object);
|
||||
#else
|
||||
typedef void * xpc_object_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define OS_ACTIVITY_MAX_CALLSTACK 32
|
||||
|
||||
// Enums
|
||||
|
||||
typedef NS_ENUM(uint32_t, os_activity_stream_flag_t) {
|
||||
OS_ACTIVITY_STREAM_PROCESS_ONLY = 0x00000001,
|
||||
OS_ACTIVITY_STREAM_SKIP_DECODE = 0x00000002,
|
||||
OS_ACTIVITY_STREAM_PAYLOAD = 0x00000004,
|
||||
OS_ACTIVITY_STREAM_HISTORICAL = 0x00000008,
|
||||
OS_ACTIVITY_STREAM_CALLSTACK = 0x00000010,
|
||||
OS_ACTIVITY_STREAM_DEBUG = 0x00000020,
|
||||
OS_ACTIVITY_STREAM_BUFFERED = 0x00000040,
|
||||
OS_ACTIVITY_STREAM_NO_SENSITIVE = 0x00000080,
|
||||
OS_ACTIVITY_STREAM_INFO = 0x00000100,
|
||||
OS_ACTIVITY_STREAM_PROMISCUOUS = 0x00000200,
|
||||
OS_ACTIVITY_STREAM_PRECISE_TIMESTAMPS = 0x00000200
|
||||
};
|
||||
|
||||
typedef NS_ENUM(uint32_t, os_activity_stream_type_t) {
|
||||
OS_ACTIVITY_STREAM_TYPE_ACTIVITY_CREATE = 0x0201,
|
||||
OS_ACTIVITY_STREAM_TYPE_ACTIVITY_TRANSITION = 0x0202,
|
||||
OS_ACTIVITY_STREAM_TYPE_ACTIVITY_USERACTION = 0x0203,
|
||||
|
||||
OS_ACTIVITY_STREAM_TYPE_TRACE_MESSAGE = 0x0300,
|
||||
|
||||
OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE = 0x0400,
|
||||
OS_ACTIVITY_STREAM_TYPE_LEGACY_LOG_MESSAGE = 0x0480,
|
||||
|
||||
OS_ACTIVITY_STREAM_TYPE_SIGNPOST_BEGIN = 0x0601,
|
||||
OS_ACTIVITY_STREAM_TYPE_SIGNPOST_END = 0x0602,
|
||||
OS_ACTIVITY_STREAM_TYPE_SIGNPOST_EVENT = 0x0603,
|
||||
|
||||
OS_ACTIVITY_STREAM_TYPE_STATEDUMP_EVENT = 0x0A00,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(uint32_t, os_activity_stream_event_t) {
|
||||
OS_ACTIVITY_STREAM_EVENT_STARTED = 1,
|
||||
OS_ACTIVITY_STREAM_EVENT_STOPPED = 2,
|
||||
OS_ACTIVITY_STREAM_EVENT_FAILED = 3,
|
||||
OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED = 4,
|
||||
OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED = 5,
|
||||
};
|
||||
|
||||
// Types
|
||||
|
||||
typedef uint64_t os_activity_id_t;
|
||||
typedef struct os_activity_stream_s *os_activity_stream_t;
|
||||
typedef struct os_activity_stream_entry_s *os_activity_stream_entry_t;
|
||||
|
||||
#define OS_ACTIVITY_STREAM_COMMON() \
|
||||
uint64_t trace_id; \
|
||||
uint64_t timestamp; \
|
||||
uint64_t thread; \
|
||||
const uint8_t *image_uuid; \
|
||||
const char *image_path; \
|
||||
struct timeval tv_gmt; \
|
||||
struct timezone tz; \
|
||||
uint32_t offset
|
||||
|
||||
typedef struct os_activity_stream_common_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
} * os_activity_stream_common_t;
|
||||
|
||||
struct os_activity_create_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
const char *name;
|
||||
os_activity_id_t creator_aid;
|
||||
uint64_t unique_pid;
|
||||
};
|
||||
|
||||
struct os_activity_transition_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
os_activity_id_t transition_id;
|
||||
};
|
||||
|
||||
typedef struct os_log_message_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
const char *format;
|
||||
const uint8_t *buffer;
|
||||
size_t buffer_sz;
|
||||
const uint8_t *privdata;
|
||||
size_t privdata_sz;
|
||||
const char *subsystem;
|
||||
const char *category;
|
||||
uint32_t oversize_id;
|
||||
uint8_t ttl;
|
||||
bool persisted;
|
||||
} * os_log_message_t;
|
||||
|
||||
typedef struct os_trace_message_v2_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
const char *format;
|
||||
const void *buffer;
|
||||
size_t bufferLen;
|
||||
xpc_object_t __unsafe_unretained payload;
|
||||
} * os_trace_message_v2_t;
|
||||
|
||||
typedef struct os_activity_useraction_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
const char *action;
|
||||
bool persisted;
|
||||
} * os_activity_useraction_t;
|
||||
|
||||
typedef struct os_signpost_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
const char *format;
|
||||
const uint8_t *buffer;
|
||||
size_t buffer_sz;
|
||||
const uint8_t *privdata;
|
||||
size_t privdata_sz;
|
||||
const char *subsystem;
|
||||
const char *category;
|
||||
uint64_t duration_nsec;
|
||||
uint32_t callstack_depth;
|
||||
uint64_t callstack[OS_ACTIVITY_MAX_CALLSTACK];
|
||||
} * os_signpost_t;
|
||||
|
||||
typedef struct os_activity_statedump_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
char *message;
|
||||
size_t message_size;
|
||||
char image_path_buffer[PATH_MAX];
|
||||
} * os_activity_statedump_t;
|
||||
|
||||
struct os_activity_stream_entry_s {
|
||||
os_activity_stream_type_t type;
|
||||
|
||||
// information about the process streaming the data
|
||||
pid_t pid;
|
||||
uint64_t proc_id;
|
||||
const uint8_t *proc_imageuuid;
|
||||
const char *proc_imagepath;
|
||||
|
||||
// the activity associated with this streamed event
|
||||
os_activity_id_t activity_id;
|
||||
os_activity_id_t parent_id;
|
||||
|
||||
union {
|
||||
struct os_activity_stream_common_s common;
|
||||
struct os_activity_create_s activity_create;
|
||||
struct os_activity_transition_s activity_transition;
|
||||
struct os_log_message_s log_message;
|
||||
struct os_trace_message_v2_s trace_message;
|
||||
struct os_activity_useraction_s useraction;
|
||||
struct os_signpost_s signpost;
|
||||
struct os_activity_statedump_s statedump;
|
||||
};
|
||||
};
|
||||
|
||||
// Blocks
|
||||
|
||||
typedef bool (^os_activity_stream_block_t)(os_activity_stream_entry_t entry,
|
||||
int error);
|
||||
|
||||
typedef void (^os_activity_stream_event_block_t)(
|
||||
os_activity_stream_t stream, os_activity_stream_event_t event);
|
||||
|
||||
// SPI entry point prototypes
|
||||
|
||||
typedef os_activity_stream_t (*os_activity_stream_for_pid_t)(
|
||||
pid_t pid, os_activity_stream_flag_t flags,
|
||||
os_activity_stream_block_t stream_block);
|
||||
|
||||
typedef void (*os_activity_stream_resume_t)(os_activity_stream_t stream);
|
||||
|
||||
typedef void (*os_activity_stream_cancel_t)(os_activity_stream_t stream);
|
||||
|
||||
typedef char *(*os_log_copy_formatted_message_t)(os_log_message_t log_message);
|
||||
|
||||
typedef void (*os_activity_stream_set_event_handler_t)(
|
||||
os_activity_stream_t stream, os_activity_stream_event_block_t block);
|
||||
|
||||
#endif /* ActivityStreamSPI_h */
|
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// FLEXASLLogController.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 3/14/19.
|
||||
// Copyright © 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXLogController.h"
|
||||
|
||||
@interface FLEXASLLogController : NSObject <FLEXLogController>
|
||||
|
||||
/// Guaranteed to call back on the main thread.
|
||||
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler;
|
||||
|
||||
- (BOOL)startMonitoring;
|
||||
|
||||
@end
|
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// FLEXASLLogController.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 3/14/19.
|
||||
// Copyright © 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXASLLogController.h"
|
||||
#import <asl.h>
|
||||
|
||||
// Querying the ASL is much slower in the simulator. We need a longer polling interval to keep things responsive.
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
#define updateInterval 5.0
|
||||
#else
|
||||
#define updateInterval 0.5
|
||||
#endif
|
||||
|
||||
@interface FLEXASLLogController ()
|
||||
|
||||
@property (nonatomic, readonly) void (^updateHandler)(NSArray<FLEXSystemLogMessage *> *);
|
||||
|
||||
@property (nonatomic) NSTimer *logUpdateTimer;
|
||||
@property (nonatomic, readonly) NSMutableIndexSet *logMessageIdentifiers;
|
||||
|
||||
// ASL stuff
|
||||
|
||||
@property (nonatomic) NSUInteger heapSize;
|
||||
@property (nonatomic) dispatch_queue_t logQueue;
|
||||
@property (nonatomic) dispatch_io_t io;
|
||||
@property (nonatomic) NSString *remaining;
|
||||
@property (nonatomic) int stderror;
|
||||
@property (nonatomic) NSString *lastTimestamp;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXASLLogController
|
||||
|
||||
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler {
|
||||
return [[self alloc] initWithUpdateHandler:newMessagesHandler];
|
||||
}
|
||||
|
||||
- (id)initWithUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler {
|
||||
NSParameterAssert(newMessagesHandler);
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_updateHandler = newMessagesHandler;
|
||||
_logMessageIdentifiers = [NSMutableIndexSet new];
|
||||
self.logUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:updateInterval
|
||||
target:self
|
||||
selector:@selector(updateLogMessages)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self.logUpdateTimer invalidate];
|
||||
}
|
||||
|
||||
- (BOOL)startMonitoring {
|
||||
[self.logUpdateTimer fire];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)updateLogMessages {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSArray<FLEXSystemLogMessage *> *newMessages;
|
||||
@synchronized (self) {
|
||||
newMessages = [self newLogMessagesForCurrentProcess];
|
||||
if (!newMessages.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (FLEXSystemLogMessage *message in newMessages) {
|
||||
[self.logMessageIdentifiers addIndex:(NSUInteger)message.messageID];
|
||||
}
|
||||
|
||||
self.lastTimestamp = @(asl_get(newMessages.lastObject.aslMessage, ASL_KEY_TIME) ?: "null");
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.updateHandler(newMessages);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Log Message Fetching
|
||||
|
||||
- (NSArray<FLEXSystemLogMessage *> *)newLogMessagesForCurrentProcess {
|
||||
if (!self.logMessageIdentifiers.count) {
|
||||
return [self allLogMessagesForCurrentProcess];
|
||||
}
|
||||
|
||||
aslresponse response = [self ASLMessageListForCurrentProcess];
|
||||
aslmsg aslMessage = NULL;
|
||||
|
||||
NSMutableArray<FLEXSystemLogMessage *> *newMessages = [NSMutableArray new];
|
||||
|
||||
while ((aslMessage = asl_next(response))) {
|
||||
NSUInteger messageID = (NSUInteger)atoll(asl_get(aslMessage, ASL_KEY_MSG_ID));
|
||||
if (![self.logMessageIdentifiers containsIndex:messageID]) {
|
||||
[newMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
||||
}
|
||||
}
|
||||
|
||||
asl_release(response);
|
||||
return newMessages;
|
||||
}
|
||||
|
||||
- (aslresponse)ASLMessageListForCurrentProcess {
|
||||
static NSString *pidString = nil;
|
||||
if (!pidString) {
|
||||
pidString = @([NSProcessInfo.processInfo processIdentifier]).stringValue;
|
||||
}
|
||||
|
||||
// Create system log query object.
|
||||
asl_object_t query = asl_new(ASL_TYPE_QUERY);
|
||||
|
||||
// Filter for messages from the current process.
|
||||
// Note that this appears to happen by default on device, but is required in the simulator.
|
||||
asl_set_query(query, ASL_KEY_PID, pidString.UTF8String, ASL_QUERY_OP_EQUAL);
|
||||
// Filter for messages after the last retrieved message.
|
||||
if (self.lastTimestamp) {
|
||||
asl_set_query(query, ASL_KEY_TIME, self.lastTimestamp.UTF8String, ASL_QUERY_OP_GREATER);
|
||||
}
|
||||
|
||||
return asl_search(NULL, query);
|
||||
}
|
||||
|
||||
- (NSArray<FLEXSystemLogMessage *> *)allLogMessagesForCurrentProcess {
|
||||
aslresponse response = [self ASLMessageListForCurrentProcess];
|
||||
aslmsg aslMessage = NULL;
|
||||
|
||||
NSMutableArray<FLEXSystemLogMessage *> *logMessages = [NSMutableArray new];
|
||||
while ((aslMessage = asl_next(response))) {
|
||||
[logMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
||||
}
|
||||
asl_release(response);
|
||||
|
||||
return logMessages;
|
||||
}
|
||||
|
||||
@end
|
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// FLEXLogController.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 3/17/19.
|
||||
// Copyright © 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FLEXSystemLogMessage.h"
|
||||
|
||||
@protocol FLEXLogController <NSObject>
|
||||
|
||||
/// Guaranteed to call back on the main thread.
|
||||
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler;
|
||||
|
||||
- (BOOL)startMonitoring;
|
||||
|
||||
@end
|
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// FLEXOSLogController.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 12/19/18.
|
||||
// Copyright © 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXLogController.h"
|
||||
|
||||
#define FLEXOSLogAvailable() (NSProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 10)
|
||||
|
||||
/// The log controller used for iOS 10 and up.
|
||||
@interface FLEXOSLogController : NSObject <FLEXLogController>
|
||||
|
||||
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler;
|
||||
|
||||
- (BOOL)startMonitoring;
|
||||
|
||||
/// Whether log messages are to be recorded and kept in-memory in the background.
|
||||
/// You do not need to initialize this value, only change it.
|
||||
@property (nonatomic) BOOL persistent;
|
||||
/// Used mostly internally, but also used by the log VC to persist messages
|
||||
/// that were created prior to enabling persistence.
|
||||
@property (nonatomic) NSMutableArray<FLEXSystemLogMessage *> *messages;
|
||||
|
||||
@end
|
214
Tweaks/FLEX/GlobalStateExplorers/SystemLog/FLEXOSLogController.m
Normal file
214
Tweaks/FLEX/GlobalStateExplorers/SystemLog/FLEXOSLogController.m
Normal file
@@ -0,0 +1,214 @@
|
||||
//
|
||||
// FLEXOSLogController.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 12/19/18.
|
||||
// Copyright © 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXOSLogController.h"
|
||||
#import "NSUserDefaults+FLEX.h"
|
||||
#include <dlfcn.h>
|
||||
#include "ActivityStreamAPI.h"
|
||||
|
||||
static os_activity_stream_for_pid_t OSActivityStreamForPID;
|
||||
static os_activity_stream_resume_t OSActivityStreamResume;
|
||||
static os_activity_stream_cancel_t OSActivityStreamCancel;
|
||||
static os_log_copy_formatted_message_t OSLogCopyFormattedMessage;
|
||||
static os_activity_stream_set_event_handler_t OSActivityStreamSetEventHandler;
|
||||
static int (*proc_name)(int, char *, unsigned int);
|
||||
static int (*proc_listpids)(uint32_t, uint32_t, void*, int);
|
||||
static uint8_t (*OSLogGetType)(void *);
|
||||
|
||||
@interface FLEXOSLogController ()
|
||||
|
||||
+ (FLEXOSLogController *)sharedLogController;
|
||||
|
||||
@property (nonatomic) void (^updateHandler)(NSArray<FLEXSystemLogMessage *> *);
|
||||
|
||||
@property (nonatomic) BOOL canPrint;
|
||||
@property (nonatomic) int filterPid;
|
||||
@property (nonatomic) BOOL levelInfo;
|
||||
@property (nonatomic) BOOL subsystemInfo;
|
||||
|
||||
@property (nonatomic) os_activity_stream_t stream;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXOSLogController
|
||||
|
||||
+ (void)load {
|
||||
// Persist logs when the app launches on iOS 10 if we have persistent logs turned on
|
||||
if (FLEXOSLogAvailable()) {
|
||||
if (NSUserDefaults.standardUserDefaults.flex_cacheOSLogMessages) {
|
||||
[self sharedLogController].persistent = YES;
|
||||
[[self sharedLogController] startMonitoring];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (instancetype)sharedLogController {
|
||||
static FLEXOSLogController *shared = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
shared = [self new];
|
||||
});
|
||||
|
||||
return shared;
|
||||
}
|
||||
|
||||
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler {
|
||||
FLEXOSLogController *shared = [self sharedLogController];
|
||||
shared.updateHandler = newMessagesHandler;
|
||||
return shared;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
NSAssert(FLEXOSLogAvailable(), @"os_log is only available on iOS 10 and up");
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_filterPid = NSProcessInfo.processInfo.processIdentifier;
|
||||
_levelInfo = NO;
|
||||
_subsystemInfo = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
OSActivityStreamCancel(self.stream);
|
||||
_stream = nil;
|
||||
}
|
||||
|
||||
- (void)setPersistent:(BOOL)persistent {
|
||||
if (_persistent == persistent) return;
|
||||
|
||||
_persistent = persistent;
|
||||
self.messages = persistent ? [NSMutableArray new] : nil;
|
||||
}
|
||||
|
||||
- (BOOL)startMonitoring {
|
||||
if (![self lookupSPICalls]) {
|
||||
// >= iOS 10 is required
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Are we already monitoring?
|
||||
if (self.stream) {
|
||||
// Should we send out the "persisted" messages?
|
||||
if (self.updateHandler && self.messages.count) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.updateHandler(self.messages);
|
||||
});
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Stream entry handler
|
||||
os_activity_stream_block_t block = ^bool(os_activity_stream_entry_t entry, int error) {
|
||||
return [self handleStreamEntry:entry error:error];
|
||||
};
|
||||
|
||||
// Controls which types of messages we see
|
||||
// 'Historical' appears to just show NSLog stuff
|
||||
uint32_t activity_stream_flags = OS_ACTIVITY_STREAM_HISTORICAL;
|
||||
activity_stream_flags |= OS_ACTIVITY_STREAM_PROCESS_ONLY;
|
||||
// activity_stream_flags |= OS_ACTIVITY_STREAM_PROCESS_ONLY;
|
||||
|
||||
self.stream = OSActivityStreamForPID(self.filterPid, activity_stream_flags, block);
|
||||
|
||||
// Specify the stream-related event handler
|
||||
OSActivityStreamSetEventHandler(self.stream, [self streamEventHandlerBlock]);
|
||||
// Start the stream
|
||||
OSActivityStreamResume(self.stream);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)lookupSPICalls {
|
||||
static BOOL hasSPI = NO;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
void *handle = dlopen("/System/Library/PrivateFrameworks/LoggingSupport.framework/LoggingSupport", RTLD_NOW);
|
||||
|
||||
OSActivityStreamForPID = (os_activity_stream_for_pid_t)dlsym(handle, "os_activity_stream_for_pid");
|
||||
OSActivityStreamResume = (os_activity_stream_resume_t)dlsym(handle, "os_activity_stream_resume");
|
||||
OSActivityStreamCancel = (os_activity_stream_cancel_t)dlsym(handle, "os_activity_stream_cancel");
|
||||
OSLogCopyFormattedMessage = (os_log_copy_formatted_message_t)dlsym(handle, "os_log_copy_formatted_message");
|
||||
OSActivityStreamSetEventHandler = (os_activity_stream_set_event_handler_t)dlsym(handle, "os_activity_stream_set_event_handler");
|
||||
proc_name = (int(*)(int, char *, unsigned int))dlsym(handle, "proc_name");
|
||||
proc_listpids = (int(*)(uint32_t, uint32_t, void*, int))dlsym(handle, "proc_listpids");
|
||||
OSLogGetType = (uint8_t(*)(void *))dlsym(handle, "os_log_get_type");
|
||||
|
||||
hasSPI = (OSActivityStreamForPID != NULL) &&
|
||||
(OSActivityStreamResume != NULL) &&
|
||||
(OSActivityStreamCancel != NULL) &&
|
||||
(OSLogCopyFormattedMessage != NULL) &&
|
||||
(OSActivityStreamSetEventHandler != NULL) &&
|
||||
(OSLogGetType != NULL) &&
|
||||
(proc_name != NULL);
|
||||
});
|
||||
|
||||
return hasSPI;
|
||||
}
|
||||
|
||||
- (BOOL)handleStreamEntry:(os_activity_stream_entry_t)entry error:(int)error {
|
||||
if (!self.canPrint || (self.filterPid != -1 && entry->pid != self.filterPid)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (!error && entry) {
|
||||
if (entry->type == OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE ||
|
||||
entry->type == OS_ACTIVITY_STREAM_TYPE_LEGACY_LOG_MESSAGE) {
|
||||
os_log_message_t log_message = &entry->log_message;
|
||||
|
||||
// Get date
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:log_message->tv_gmt.tv_sec];
|
||||
|
||||
// Get log message text
|
||||
// https://github.com/limneos/oslog/issues/1
|
||||
// https://github.com/FLEXTool/FLEX/issues/564
|
||||
const char *messageText = OSLogCopyFormattedMessage(log_message) ?: "";
|
||||
|
||||
// move messageText from stack to heap
|
||||
NSString *msg = [NSString stringWithUTF8String:messageText];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
FLEXSystemLogMessage *message = [FLEXSystemLogMessage logMessageFromDate:date text:msg];
|
||||
if (self.persistent) {
|
||||
[self.messages addObject:message];
|
||||
}
|
||||
if (self.updateHandler) {
|
||||
self.updateHandler(@[message]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (os_activity_stream_event_block_t)streamEventHandlerBlock {
|
||||
return [^void(os_activity_stream_t stream, os_activity_stream_event_t event) {
|
||||
switch (event) {
|
||||
case OS_ACTIVITY_STREAM_EVENT_STARTED:
|
||||
self.canPrint = YES;
|
||||
break;
|
||||
case OS_ACTIVITY_STREAM_EVENT_STOPPED:
|
||||
break;
|
||||
case OS_ACTIVITY_STREAM_EVENT_FAILED:
|
||||
break;
|
||||
case OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED:
|
||||
break;
|
||||
case OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED:
|
||||
break;
|
||||
default:
|
||||
printf("=== Unhandled case ===\n");
|
||||
break;
|
||||
}
|
||||
} copy];
|
||||
}
|
||||
|
||||
@end
|
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// FLEXSystemLogCell.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/25/15.
|
||||
// Copyright (c) 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXTableViewCell.h"
|
||||
|
||||
@class FLEXSystemLogMessage;
|
||||
|
||||
extern NSString *const kFLEXSystemLogCellIdentifier;
|
||||
|
||||
@interface FLEXSystemLogCell : FLEXTableViewCell
|
||||
|
||||
@property (nonatomic) FLEXSystemLogMessage *logMessage;
|
||||
@property (nonatomic, copy) NSString *highlightedText;
|
||||
|
||||
+ (NSString *)displayedTextForLogMessage:(FLEXSystemLogMessage *)logMessage;
|
||||
+ (CGFloat)preferredHeightForLogMessage:(FLEXSystemLogMessage *)logMessage inWidth:(CGFloat)width;
|
||||
|
||||
@end
|
119
Tweaks/FLEX/GlobalStateExplorers/SystemLog/FLEXSystemLogCell.m
Normal file
119
Tweaks/FLEX/GlobalStateExplorers/SystemLog/FLEXSystemLogCell.m
Normal file
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// FLEXSystemLogCell.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/25/15.
|
||||
// Copyright (c) 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXSystemLogCell.h"
|
||||
#import "FLEXSystemLogMessage.h"
|
||||
#import "UIFont+FLEX.h"
|
||||
|
||||
NSString *const kFLEXSystemLogCellIdentifier = @"FLEXSystemLogCellIdentifier";
|
||||
|
||||
@interface FLEXSystemLogCell ()
|
||||
|
||||
@property (nonatomic) UILabel *logMessageLabel;
|
||||
@property (nonatomic) NSAttributedString *logMessageAttributedText;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXSystemLogCell
|
||||
|
||||
- (void)postInit {
|
||||
[super postInit];
|
||||
|
||||
self.logMessageLabel = [UILabel new];
|
||||
self.logMessageLabel.numberOfLines = 0;
|
||||
self.separatorInset = UIEdgeInsetsZero;
|
||||
self.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
[self.contentView addSubview:self.logMessageLabel];
|
||||
}
|
||||
|
||||
- (void)setLogMessage:(FLEXSystemLogMessage *)logMessage {
|
||||
if (![_logMessage isEqual:logMessage]) {
|
||||
_logMessage = logMessage;
|
||||
self.logMessageAttributedText = nil;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setHighlightedText:(NSString *)highlightedText {
|
||||
if (![_highlightedText isEqual:highlightedText]) {
|
||||
_highlightedText = highlightedText;
|
||||
self.logMessageAttributedText = nil;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSAttributedString *)logMessageAttributedText {
|
||||
if (!_logMessageAttributedText) {
|
||||
_logMessageAttributedText = [[self class] attributedTextForLogMessage:self.logMessage highlightedText:self.highlightedText];
|
||||
}
|
||||
return _logMessageAttributedText;
|
||||
}
|
||||
|
||||
static const UIEdgeInsets kFLEXLogMessageCellInsets = {10.0, 10.0, 10.0, 10.0};
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
self.logMessageLabel.attributedText = self.logMessageAttributedText;
|
||||
self.logMessageLabel.frame = UIEdgeInsetsInsetRect(self.contentView.bounds, kFLEXLogMessageCellInsets);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Stateless helpers
|
||||
|
||||
+ (NSAttributedString *)attributedTextForLogMessage:(FLEXSystemLogMessage *)logMessage highlightedText:(NSString *)highlightedText {
|
||||
NSString *text = [self displayedTextForLogMessage:logMessage];
|
||||
NSDictionary<NSString *, id> *attributes = @{ NSFontAttributeName : UIFont.flex_codeFont };
|
||||
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:attributes];
|
||||
|
||||
if (highlightedText.length > 0) {
|
||||
NSMutableAttributedString *mutableAttributedText = attributedText.mutableCopy;
|
||||
NSMutableDictionary<NSString *, id> *highlightAttributes = attributes.mutableCopy;
|
||||
highlightAttributes[NSBackgroundColorAttributeName] = UIColor.yellowColor;
|
||||
|
||||
NSRange remainingSearchRange = NSMakeRange(0, text.length);
|
||||
while (remainingSearchRange.location < text.length) {
|
||||
remainingSearchRange.length = text.length - remainingSearchRange.location;
|
||||
NSRange foundRange = [text rangeOfString:highlightedText options:NSCaseInsensitiveSearch range:remainingSearchRange];
|
||||
if (foundRange.location != NSNotFound) {
|
||||
remainingSearchRange.location = foundRange.location + foundRange.length;
|
||||
[mutableAttributedText setAttributes:highlightAttributes range:foundRange];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
attributedText = mutableAttributedText;
|
||||
}
|
||||
|
||||
return attributedText;
|
||||
}
|
||||
|
||||
+ (NSString *)displayedTextForLogMessage:(FLEXSystemLogMessage *)logMessage {
|
||||
return [NSString stringWithFormat:@"%@: %@", [self logTimeStringFromDate:logMessage.date], logMessage.messageText];
|
||||
}
|
||||
|
||||
+ (CGFloat)preferredHeightForLogMessage:(FLEXSystemLogMessage *)logMessage inWidth:(CGFloat)width {
|
||||
UIEdgeInsets insets = kFLEXLogMessageCellInsets;
|
||||
CGFloat availableWidth = width - insets.left - insets.right;
|
||||
NSAttributedString *attributedLogText = [self attributedTextForLogMessage:logMessage highlightedText:nil];
|
||||
CGSize labelSize = [attributedLogText boundingRectWithSize:CGSizeMake(availableWidth, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading context:nil].size;
|
||||
return labelSize.height + insets.top + insets.bottom;
|
||||
}
|
||||
|
||||
+ (NSString *)logTimeStringFromDate:(NSDate *)date {
|
||||
static NSDateFormatter *formatter = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
formatter = [NSDateFormatter new];
|
||||
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS";
|
||||
});
|
||||
|
||||
return [formatter stringFromDate:date];
|
||||
}
|
||||
|
||||
@end
|
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// FLEXSystemLogMessage.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/25/15.
|
||||
// Copyright (c) 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <asl.h>
|
||||
#import "ActivityStreamAPI.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FLEXSystemLogMessage : NSObject
|
||||
|
||||
+ (instancetype)logMessageFromASLMessage:(aslmsg)aslMessage;
|
||||
+ (instancetype)logMessageFromDate:(NSDate *)date text:(NSString *)text;
|
||||
|
||||
// ASL specific properties
|
||||
@property (nonatomic, readonly, nullable) NSString *sender;
|
||||
@property (nonatomic, readonly, nullable) aslmsg aslMessage;
|
||||
|
||||
@property (nonatomic, readonly) NSDate *date;
|
||||
@property (nonatomic, readonly) NSString *messageText;
|
||||
@property (nonatomic, readonly) long long messageID;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// FLEXSystemLogMessage.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/25/15.
|
||||
// Copyright (c) 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXSystemLogMessage.h"
|
||||
|
||||
@implementation FLEXSystemLogMessage
|
||||
|
||||
+ (instancetype)logMessageFromASLMessage:(aslmsg)aslMessage {
|
||||
NSDate *date = nil;
|
||||
NSString *sender = nil, *text = nil;
|
||||
long long identifier = 0;
|
||||
|
||||
const char *timestamp = asl_get(aslMessage, ASL_KEY_TIME);
|
||||
if (timestamp) {
|
||||
NSTimeInterval timeInterval = [@(timestamp) integerValue];
|
||||
const char *nanoseconds = asl_get(aslMessage, ASL_KEY_TIME_NSEC);
|
||||
if (nanoseconds) {
|
||||
timeInterval += [@(nanoseconds) doubleValue] / NSEC_PER_SEC;
|
||||
}
|
||||
date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
|
||||
}
|
||||
|
||||
const char *s = asl_get(aslMessage, ASL_KEY_SENDER);
|
||||
if (s) {
|
||||
sender = @(s);
|
||||
}
|
||||
|
||||
const char *messageText = asl_get(aslMessage, ASL_KEY_MSG);
|
||||
if (messageText) {
|
||||
text = @(messageText);
|
||||
}
|
||||
|
||||
const char *messageID = asl_get(aslMessage, ASL_KEY_MSG_ID);
|
||||
if (messageID) {
|
||||
identifier = [@(messageID) longLongValue];
|
||||
}
|
||||
|
||||
FLEXSystemLogMessage *message = [[self alloc] initWithDate:date sender:sender text:text messageID:identifier];
|
||||
message->_aslMessage = aslMessage;
|
||||
return message;
|
||||
}
|
||||
|
||||
+ (instancetype)logMessageFromDate:(NSDate *)date text:(NSString *)text {
|
||||
return [[self alloc] initWithDate:date sender:nil text:text messageID:0];
|
||||
}
|
||||
|
||||
- (id)initWithDate:(NSDate *)date sender:(NSString *)sender text:(NSString *)text messageID:(long long)identifier {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_date = date;
|
||||
_sender = sender;
|
||||
_messageText = text;
|
||||
_messageID = identifier;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if ([object isKindOfClass:[self class]]) {
|
||||
if (self.messageID) {
|
||||
// Only ASL uses messageID, otherwise it is 0
|
||||
return self.messageID == [object messageID];
|
||||
} else {
|
||||
// Test message texts and dates for OS Log
|
||||
return [self.messageText isEqual:[object messageText]] &&
|
||||
[self.date isEqualToDate:[object date]];
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return (NSUInteger)self.messageID;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
NSString *escaped = [self.messageText stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
|
||||
return [NSString stringWithFormat:@"(%@) %@", @(self.messageText.length), escaped];
|
||||
}
|
||||
|
||||
@end
|
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// FLEXSystemLogViewController.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/19/15.
|
||||
// Copyright (c) 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXFilteringTableViewController.h"
|
||||
#import "FLEXGlobalsEntry.h"
|
||||
|
||||
@interface FLEXSystemLogViewController : FLEXFilteringTableViewController <FLEXGlobalsEntry>
|
||||
|
||||
@end
|
@@ -0,0 +1,293 @@
|
||||
//
|
||||
// FLEXSystemLogViewController.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/19/15.
|
||||
// Copyright (c) 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXSystemLogViewController.h"
|
||||
#import "FLEXASLLogController.h"
|
||||
#import "FLEXOSLogController.h"
|
||||
#import "FLEXSystemLogCell.h"
|
||||
#import "FLEXMutableListSection.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXColor.h"
|
||||
#import "FLEXResources.h"
|
||||
#import "UIBarButtonItem+FLEX.h"
|
||||
#import "NSUserDefaults+FLEX.h"
|
||||
#import "flex_fishhook.h"
|
||||
#import <dlfcn.h>
|
||||
|
||||
@interface FLEXSystemLogViewController ()
|
||||
|
||||
@property (nonatomic, readonly) FLEXMutableListSection<FLEXSystemLogMessage *> *logMessages;
|
||||
@property (nonatomic, readonly) id<FLEXLogController> logController;
|
||||
|
||||
@end
|
||||
|
||||
static void (*MSHookFunction)(void *symbol, void *replace, void **result);
|
||||
|
||||
static BOOL FLEXDidHookNSLog = NO;
|
||||
static BOOL FLEXNSLogHookWorks = NO;
|
||||
|
||||
BOOL (*os_log_shim_enabled)(void *addr) = nil;
|
||||
BOOL (*orig_os_log_shim_enabled)(void *addr) = nil;
|
||||
static BOOL my_os_log_shim_enabled(void *addr) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
@implementation FLEXSystemLogViewController
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
+ (void)load {
|
||||
// User must opt-into disabling os_log
|
||||
if (!NSUserDefaults.standardUserDefaults.flex_disableOSLog) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Thanks to @Ram4096 on GitHub for telling me that
|
||||
// os_log is conditionally enabled by the SDK version
|
||||
void *addr = __builtin_return_address(0);
|
||||
void *libsystem_trace = dlopen("/usr/lib/system/libsystem_trace.dylib", RTLD_LAZY);
|
||||
os_log_shim_enabled = dlsym(libsystem_trace, "os_log_shim_enabled");
|
||||
if (!os_log_shim_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
FLEXDidHookNSLog = flex_rebind_symbols((struct rebinding[1]) {{
|
||||
"os_log_shim_enabled",
|
||||
(void *)my_os_log_shim_enabled,
|
||||
(void **)&orig_os_log_shim_enabled
|
||||
}}, 1) == 0;
|
||||
|
||||
if (FLEXDidHookNSLog && orig_os_log_shim_enabled != nil) {
|
||||
// Check if our rebinding worked
|
||||
FLEXNSLogHookWorks = my_os_log_shim_enabled(addr) == NO;
|
||||
}
|
||||
|
||||
// So, just because we rebind the lazily loaded symbol for
|
||||
// this function doesn't mean it's even going to be used.
|
||||
// While it seems to be sufficient for the simulator, for
|
||||
// whatever reason it is not sufficient on-device. We need
|
||||
// to actually hook the function with something like Substrate.
|
||||
|
||||
// Check if we have substrate, and if so use that instead
|
||||
void *handle = dlopen("/usr/lib/libsubstrate.dylib", RTLD_LAZY);
|
||||
if (handle) {
|
||||
MSHookFunction = dlsym(handle, "MSHookFunction");
|
||||
|
||||
if (MSHookFunction) {
|
||||
// Set the hook and check if it worked
|
||||
void *unused;
|
||||
MSHookFunction(os_log_shim_enabled, my_os_log_shim_enabled, &unused);
|
||||
FLEXNSLogHookWorks = os_log_shim_enabled(addr) == NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
return [super initWithStyle:UITableViewStylePlain];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Overrides
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.showsSearchBar = YES;
|
||||
self.pinSearchBar = YES;
|
||||
|
||||
weakify(self)
|
||||
id logHandler = ^(NSArray<FLEXSystemLogMessage *> *newMessages) { strongify(self)
|
||||
[self handleUpdateWithNewMessages:newMessages];
|
||||
};
|
||||
|
||||
if (FLEXOSLogAvailable() && !FLEXNSLogHookWorks) {
|
||||
_logController = [FLEXOSLogController withUpdateHandler:logHandler];
|
||||
} else {
|
||||
_logController = [FLEXASLLogController withUpdateHandler:logHandler];
|
||||
}
|
||||
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
self.title = @"Waiting for Logs...";
|
||||
|
||||
// Toolbar buttons //
|
||||
|
||||
UIBarButtonItem *scrollDown = [UIBarButtonItem
|
||||
flex_itemWithImage:FLEXResources.scrollToBottomIcon
|
||||
target:self
|
||||
action:@selector(scrollToLastRow)
|
||||
];
|
||||
UIBarButtonItem *settings = [UIBarButtonItem
|
||||
flex_itemWithImage:FLEXResources.gearIcon
|
||||
target:self
|
||||
action:@selector(showLogSettings)
|
||||
];
|
||||
|
||||
[self addToolbarItems:@[scrollDown, settings]];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
[self.logController startMonitoring];
|
||||
}
|
||||
|
||||
- (NSArray<FLEXTableViewSection *> *)makeSections { weakify(self)
|
||||
_logMessages = [FLEXMutableListSection list:@[]
|
||||
cellConfiguration:^(FLEXSystemLogCell *cell, FLEXSystemLogMessage *message, NSInteger row) {
|
||||
strongify(self)
|
||||
|
||||
cell.logMessage = message;
|
||||
cell.highlightedText = self.filterText;
|
||||
|
||||
if (row % 2 == 0) {
|
||||
cell.backgroundColor = FLEXColor.primaryBackgroundColor;
|
||||
} else {
|
||||
cell.backgroundColor = FLEXColor.secondaryBackgroundColor;
|
||||
}
|
||||
} filterMatcher:^BOOL(NSString *filterText, FLEXSystemLogMessage *message) {
|
||||
NSString *displayedText = [FLEXSystemLogCell displayedTextForLogMessage:message];
|
||||
return [displayedText localizedCaseInsensitiveContainsString:filterText];
|
||||
}
|
||||
];
|
||||
|
||||
self.logMessages.cellRegistrationMapping = @{
|
||||
kFLEXSystemLogCellIdentifier : [FLEXSystemLogCell class]
|
||||
};
|
||||
|
||||
return @[self.logMessages];
|
||||
}
|
||||
|
||||
- (NSArray<FLEXTableViewSection *> *)nonemptySections {
|
||||
return @[self.logMessages];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)handleUpdateWithNewMessages:(NSArray<FLEXSystemLogMessage *> *)newMessages {
|
||||
self.title = [self.class globalsEntryTitle:FLEXGlobalsRowSystemLog];
|
||||
|
||||
[self.logMessages mutate:^(NSMutableArray *list) {
|
||||
[list addObjectsFromArray:newMessages];
|
||||
}];
|
||||
|
||||
// Re-filter messages to filter against new messages
|
||||
if (self.filterText.length) {
|
||||
[self updateSearchResults:self.filterText];
|
||||
}
|
||||
|
||||
// "Follow" the log as new messages stream in if we were previously near the bottom.
|
||||
UITableView *tv = self.tableView;
|
||||
BOOL wasNearBottom = tv.contentOffset.y >= tv.contentSize.height - tv.frame.size.height - 100.0;
|
||||
[self reloadData];
|
||||
if (wasNearBottom) {
|
||||
[self scrollToLastRow];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollToLastRow {
|
||||
NSInteger numberOfRows = [self.tableView numberOfRowsInSection:0];
|
||||
if (numberOfRows > 0) {
|
||||
NSIndexPath *last = [NSIndexPath indexPathForRow:numberOfRows - 1 inSection:0];
|
||||
[self.tableView scrollToRowAtIndexPath:last atScrollPosition:UITableViewScrollPositionBottom animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showLogSettings {
|
||||
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
|
||||
BOOL disableOSLog = defaults.flex_disableOSLog;
|
||||
BOOL persistent = defaults.flex_cacheOSLogMessages;
|
||||
|
||||
NSString *aslToggle = disableOSLog ? @"Enable os_log (default)" : @"Disable os_log";
|
||||
NSString *persistence = persistent ? @"Disable persistent logging" : @"Enable persistent logging";
|
||||
|
||||
NSString *title = @"System Log Settings";
|
||||
NSString *body = @"In iOS 10 and up, ASL has been replaced by os_log. "
|
||||
"The os_log API is much more limited. Below, you can opt-into the old behavior "
|
||||
"if you want cleaner, more reliable logs within FLEX, but this will break "
|
||||
"anything that expects os_log to be working, such as Console.app. "
|
||||
"This setting requires the app to restart to take effect. \n\n"
|
||||
|
||||
"To get as close to the old behavior as possible with os_log enabled, logs must "
|
||||
"be collected manually at launch and stored. This setting has no effect "
|
||||
"on iOS 9 and below, or if os_log is disabled. "
|
||||
"You should only enable persistent logging when you need it.";
|
||||
|
||||
FLEXOSLogController *logController = (FLEXOSLogController *)self.logController;
|
||||
|
||||
[FLEXAlert makeAlert:^(FLEXAlert *make) {
|
||||
make.title(title).message(body);
|
||||
make.button(aslToggle).destructiveStyle().handler(^(NSArray<NSString *> *strings) {
|
||||
[defaults flex_toggleBoolForKey:kFLEXDefaultsDisableOSLogForceASLKey];
|
||||
});
|
||||
|
||||
make.button(persistence).handler(^(NSArray<NSString *> *strings) {
|
||||
[defaults flex_toggleBoolForKey:kFLEXDefaultsiOSPersistentOSLogKey];
|
||||
logController.persistent = !persistent;
|
||||
[logController.messages addObjectsFromArray:self.logMessages.list];
|
||||
});
|
||||
make.button(@"Dismiss").cancelStyle();
|
||||
} showFrom:self];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - FLEXGlobalsEntry
|
||||
|
||||
+ (NSString *)globalsEntryTitle:(FLEXGlobalsRow)row {
|
||||
return @"⚠️ System Log";
|
||||
}
|
||||
|
||||
+ (UIViewController *)globalsEntryViewController:(FLEXGlobalsRow)row {
|
||||
return [self new];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FLEXSystemLogMessage *logMessage = self.logMessages.filteredList[indexPath.row];
|
||||
return [FLEXSystemLogCell preferredHeightForLogMessage:logMessage inWidth:self.tableView.bounds.size.width];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Copy on long press
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
|
||||
return action == @selector(copy:);
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
|
||||
if (action == @selector(copy:)) {
|
||||
// We usually only want to copy the log message itself, not any metadata associated with it.
|
||||
UIPasteboard.generalPasteboard.string = self.logMessages.filteredList[indexPath.row].messageText ?: @"";
|
||||
}
|
||||
}
|
||||
|
||||
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView
|
||||
contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
point:(CGPoint)point __IOS_AVAILABLE(13.0) {
|
||||
weakify(self)
|
||||
return [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil
|
||||
actionProvider:^UIMenu *(NSArray<UIMenuElement *> *suggestedActions) {
|
||||
UIAction *copy = [UIAction actionWithTitle:@"Copy"
|
||||
image:nil
|
||||
identifier:@"Copy"
|
||||
handler:^(UIAction *action) { strongify(self)
|
||||
// We usually only want to copy the log message itself, not any metadata associated with it.
|
||||
UIPasteboard.generalPasteboard.string = self.logMessages.filteredList[indexPath.row].messageText ?: @"";
|
||||
}];
|
||||
return [UIMenu menuWithTitle:@"" image:nil identifier:nil options:UIMenuOptionsDisplayInline children:@[copy]];
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@end
|
276
Tweaks/FLEX/GlobalStateExplorers/SystemLog/LLVM_LICENSE.TXT
Normal file
276
Tweaks/FLEX/GlobalStateExplorers/SystemLog/LLVM_LICENSE.TXT
Normal file
@@ -0,0 +1,276 @@
|
||||
==============================================================================
|
||||
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
|
||||
==============================================================================
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
---- LLVM Exceptions to the Apache 2.0 License ----
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into an Object form of such source code, you
|
||||
may redistribute such embedded portions in such Object form without complying
|
||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||
|
||||
In addition, if you combine or link compiled forms of this Software with
|
||||
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||
court of competent jurisdiction determines that the patent provision (Section
|
||||
3), the indemnity provision (Section 9) or other Section of the License
|
||||
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||
the License, but only in their entirety and only with respect to the Combined
|
||||
Software.
|
||||
|
||||
==============================================================================
|
||||
Software from third parties included in the LLVM Project:
|
||||
==============================================================================
|
||||
The LLVM Project contains third party software which is under different license
|
||||
terms. All such code will be identified clearly using at least one of two
|
||||
mechanisms:
|
||||
1) It will be in a separate directory tree with its own `LICENSE.txt` or
|
||||
`LICENSE` file at the top containing the specific license and restrictions
|
||||
which apply to that software, or
|
||||
2) It will contain specific license and restriction terms at the top of every
|
||||
file.
|
||||
|
||||
==============================================================================
|
||||
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
|
||||
==============================================================================
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2010 Apple Inc.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLDB Team
|
||||
|
||||
http://lldb.llvm.org/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLDB Team, copyright holders, nor the names of
|
||||
its contributors may be used to endorse or promote products derived from
|
||||
this Software without specific prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
Reference in New Issue
Block a user