Page MenuHomePhorge

D8795.1767121913.diff
No OneTemporary

Size
8 KB
Referenced Files
None
Subscribers
None

D8795.1767121913.diff

diff --git a/native/ios/NotificationService/NotificationService.mm b/native/ios/NotificationService/NotificationService.mm
--- a/native/ios/NotificationService/NotificationService.mm
+++ b/native/ios/NotificationService/NotificationService.mm
@@ -1,7 +1,9 @@
#import "NotificationService.h"
#import "Logger.h"
#import "NotificationsCryptoModule.h"
+#import "PlatformSpecificTools.h"
#import "TemporaryMessageStorage.h"
+#import <mach/mach.h>
NSString *const backgroundNotificationTypeKey = @"backgroundNotifType";
NSString *const messageInfosKey = @"messageInfos";
@@ -14,11 +16,31 @@
CFStringRef newMessageInfosDarwinNotification =
CFSTR("app.comm.darwin_new_message_infos");
+// Implementation below was inspired by the
+// following discussion with Apple staff member:
+// https://developer.apple.com/forums/thread/105088
+size_t getMemoryUsage() {
+ task_vm_info_data_t vmInfo;
+ mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
+
+ kern_return_t result =
+ task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vmInfo, &count);
+
+ if (result != KERN_SUCCESS) {
+ return -1;
+ }
+
+ size_t memory_usage = static_cast<size_t>(vmInfo.phys_footprint);
+ // We divide to get the result in MB's
+ return memory_usage / (1024 * 1024);
+}
+
@interface NotificationService ()
@property(nonatomic, strong) void (^contentHandler)
(UNNotificationContent *contentToDeliver);
@property(nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
+@property BOOL contentHandlerCalled;
@end
@@ -30,16 +52,30 @@
contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
+ self.contentHandlerCalled = NO;
+ dispatch_source_t memorySource = [self registerForMemoryEvents];
+
+ // Step 1: notification decryption.
if ([self shouldBeDecrypted:self.bestAttemptContent.userInfo]) {
- @try {
- [self decryptBestAttemptContent];
- } @catch (NSException *e) {
- comm::Logger::log(
- "NSE: Received exception: " + std::string([e.name UTF8String]) +
- " with reason: " + std::string([e.reason UTF8String]) +
- " during notification decryption");
- self.contentHandler([[UNNotificationContent alloc] init]);
+ std::string decryptErrorMessage;
+ try {
+ @try {
+ [self decryptBestAttemptContent];
+ } @catch (NSException *e) {
+ decryptErrorMessage = "NSE: Received Obj-C exception: " +
+ std::string([e.name UTF8String]) +
+ " during notification decryption.";
+ }
+ } catch (const std::exception &e) {
+ decryptErrorMessage =
+ "NSE: Received C++ exception: " + std::string(e.what()) +
+ " during notification decryption.";
+ }
+
+ if (decryptErrorMessage.size()) {
+ [self callContentHandlerOnErrorMessage:
+ [NSString stringWithUTF8String:decryptErrorMessage.c_str()]];
return;
}
} else if ([self shouldAlertUnencryptedNotification:self.bestAttemptContent
@@ -49,28 +85,73 @@
comm::Logger::log("NSE: Received erroneously unencrypted notitication.");
}
- [self persistMessagePayload:self.bestAttemptContent.userInfo];
+ // Step 2: notification persistence in a temporary storage
+ std::string persistErrorMessage;
+ try {
+ @try {
+ [self persistMessagePayload:self.bestAttemptContent.userInfo];
+ } @catch (NSException *e) {
+ persistErrorMessage =
+ "NSE: Received Obj-C exception: " + std::string([e.name UTF8String]) +
+ " during notification persistence.";
+ }
+ } catch (const std::exception &e) {
+ persistErrorMessage =
+ "NSE: Received C++ exception: " + std::string(e.what()) +
+ " during notification persistence.";
+ }
+
+ if (persistErrorMessage.size()) {
+ [self callContentHandlerOnErrorMessage:
+ [NSString stringWithUTF8String:persistErrorMessage.c_str()]];
+ return;
+ }
+
+ // Step 3: (optional) rescind read notifications
+
// Message payload persistence is a higher priority task, so it has
// to happen prior to potential notification center clearing.
if ([self isRescind:self.bestAttemptContent.userInfo]) {
- [self removeNotificationWithIdentifier:self.bestAttemptContent
- .userInfo[@"notificationId"]];
- self.contentHandler([[UNNotificationContent alloc] init]);
+ std::string rescindErrorMessage;
+ try {
+ @try {
+ [self
+ removeNotificationWithIdentifier:self.bestAttemptContent
+ .userInfo[@"notificationId"]];
+ } @catch (NSException *e) {
+ rescindErrorMessage = "NSE: Received Obj-C exception: " +
+ std::string([e.name UTF8String]) + " during notification rescind.";
+ }
+ } catch (const std::exception &e) {
+ rescindErrorMessage =
+ "NSE: Received C++ exception: " + std::string(e.what()) +
+ " during notification rescind.";
+ }
+
+ if (rescindErrorMessage.size()) {
+ [self callContentHandlerOnErrorMessage:
+ [NSString stringWithUTF8String:rescindErrorMessage.c_str()]];
+ return;
+ }
+ [self threadSafeContentHandlerCall:[[UNNotificationContent alloc] init]];
return;
}
+ // Step 4: (optional) update badge count for badge only notif
if ([self isBadgeOnly:self.bestAttemptContent.userInfo]) {
UNMutableNotificationContent *badgeOnlyContent =
[[UNMutableNotificationContent alloc] init];
badgeOnlyContent.badge = self.bestAttemptContent.badge;
- self.contentHandler(badgeOnlyContent);
+ [self threadSafeContentHandlerCall:badgeOnlyContent];
return;
}
+ // Step 5: notify main app that there is data
+ // to transfer to SQLite and redux.
[self sendNewMessageInfosNotification];
// TODO modify self.bestAttemptContent here
-
- self.contentHandler(self.bestAttemptContent);
+ [self unregisterForMemoryEventsFrom:memorySource];
+ [self threadSafeContentHandlerCall:self.bestAttemptContent];
}
- (void)serviceExtensionTimeWillExpire {
@@ -82,8 +163,9 @@
// remove relevant notification from notification center in
// in time given to NSE to process notification.
// It is an extremely unlikely to happen.
- comm::Logger::log("NSE: Exceeded time limit to rescind a notification.");
- self.contentHandler([[UNNotificationContent alloc] init]);
+ NSString *errorMessage =
+ @"NSE: Exceeded time limit to rescind a notification.";
+ [self callContentHandlerOnErrorMessage:errorMessage];
return;
}
if ([self shouldBeDecrypted:self.bestAttemptContent.userInfo] &&
@@ -91,8 +173,9 @@
// If we get to this place it means we were unable to
// decrypt encrypted notification content in time
// given to NSE to process notification.
- comm::Logger::log("NSE: Exceeded time limit to decrypt a notification.");
- self.contentHandler([[UNNotificationContent alloc] init]);
+ NSString *errorMessage =
+ @"NSE: Exceeded time limit to decrypt a notification.";
+ [self callContentHandlerOnErrorMessage:errorMessage];
return;
}
self.contentHandler(self.bestAttemptContent);
@@ -260,4 +343,60 @@
self.bestAttemptContent.userInfo = mutableUserInfo;
}
+- (void)callContentHandlerOnErrorMessage:(NSString *)errorMessage {
+ comm::Logger::log(std::string([errorMessage UTF8String]));
+
+ if (!comm::PlatformSpecificTools::isStaffRelease()) {
+ [self threadSafeContentHandlerCall:[[UNNotificationContent alloc] init]];
+ return;
+ }
+
+ UNMutableNotificationContent *content =
+ [[UNMutableNotificationContent alloc] init];
+ content.body = errorMessage;
+ [self threadSafeContentHandlerCall:content];
+}
+
+- (void)threadSafeContentHandlerCall:(UNNotificationContent *)content {
+ @synchronized(self) {
+ if (self.contentHandlerCalled) {
+ return;
+ }
+ self.contentHandlerCalled = YES;
+ self.contentHandler(content);
+ }
+}
+
+// Monitor memory usage
+- (dispatch_source_t)registerForMemoryEvents {
+ dispatch_source_t memorySource = dispatch_source_create(
+ DISPATCH_SOURCE_TYPE_MEMORYPRESSURE,
+ 0L,
+ DISPATCH_MEMORYPRESSURE_CRITICAL,
+ dispatch_get_main_queue());
+
+ __weak __typeof(self) weakSelf = self;
+ dispatch_block_t eventHandler = ^{
+ __typeof(weakSelf) strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+
+ NSString *criticalMemoryEventMessage =
+ [NSString stringWithFormat:
+ @"NSE: Received CRITICAL memory event. Memory usage: %ld",
+ getMemoryUsage()];
+
+ [strongSelf callContentHandlerOnErrorMessage:criticalMemoryEventMessage];
+ };
+
+ dispatch_source_set_event_handler(memorySource, eventHandler);
+ dispatch_activate(memorySource);
+ return memorySource;
+}
+
+- (void)unregisterForMemoryEventsFrom:(dispatch_source_t)source {
+ dispatch_source_cancel(source);
+}
+
@end

File Metadata

Mime Type
text/plain
Expires
Tue, Dec 30, 7:11 PM (8 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5869364
Default Alt Text
D8795.1767121913.diff (8 KB)

Event Timeline