Evacuate early message cache after memory warning

This commit is contained in:
Nora Trapp 2020-06-07 10:05:07 -07:00
parent fb688abcb5
commit ad64727ecc
7 changed files with 96 additions and 51 deletions

View File

@ -116,6 +116,7 @@ NS_ASSUME_NONNULL_BEGIN
BulkProfileFetch *bulkProfileFetch = [BulkProfileFetch new];
BulkUUIDLookup *bulkUUIDLookup = [BulkUUIDLookup new];
id<VersionedProfiles> versionedProfiles = [VersionedProfilesImpl new];
EarlyMessageManager *earlyMessageManager = [EarlyMessageManager new];
[Environment setShared:[[Environment alloc] initWithAudioSession:audioSession
incomingContactSyncJobQueue:incomingContactSyncJobQueue
@ -173,7 +174,8 @@ NS_ASSUME_NONNULL_BEGIN
messageFetcherJob:messageFetcherJob
bulkProfileFetch:bulkProfileFetch
bulkUUIDLookup:bulkUUIDLookup
versionedProfiles:versionedProfiles]];
versionedProfiles:versionedProfiles
earlyMessageManager:earlyMessageManager]];
appSpecificSingletonBlock();

View File

@ -67,6 +67,11 @@ NS_ASSUME_NONNULL_BEGIN
return SSKEnvironment.shared.tsAccountManager;
}
+ (EarlyMessageManager *)earlyMessageManager
{
return SSKEnvironment.shared.earlyMessageManager;
}
#pragma mark -
+ (void)processIncomingSentMessageTranscript:(OWSIncomingSentMessageTranscript *)transcript
@ -234,7 +239,7 @@ NS_ASSUME_NONNULL_BEGIN
expirationStartedAt:transcript.expirationStartedAt
transaction:transaction];
[OWSEarlyMessageManager applyPendingMessagesFor:outgoingMessage transaction:transaction];
[self.earlyMessageManager applyPendingMessagesFor:outgoingMessage transaction:transaction];
if (outgoingMessage.isViewOnceMessage) {
// To be extra-conservative, always mark

View File

@ -4,7 +4,7 @@
import Foundation
@objc(OWSEarlyMessageManager)
@objc
public class EarlyMessageManager: NSObject {
private struct MessageIdentifier: Hashable {
let timestamp: UInt64
@ -34,19 +34,42 @@ public class EarlyMessageManager: NSObject {
private static let maxQueuedMessages = 100
private static let maxEarlyEnvelopeSize = 1024
private static let serialQueue = DispatchQueue(label: "EarlyMessageManager")
private static var pendingEnvelopes = OrderedDictionary<MessageIdentifier, [EarlyEnvelope]>()
private static var pendingReceipts = OrderedDictionary<MessageIdentifier, [EarlyReceipt]>()
private let serialQueue = DispatchQueue(label: "EarlyMessageManager")
private var pendingEnvelopes = OrderedDictionary<MessageIdentifier, [EarlyEnvelope]>()
private var pendingReceipts = OrderedDictionary<MessageIdentifier, [EarlyReceipt]>()
public override init() {
super.init()
SwiftSingletons.register(self)
// Listen for memory warnings to evacuate the caches
NotificationCenter.default.addObserver(
self,
selector: #selector(didReceiveMemoryWarning),
name: UIApplication.didReceiveMemoryWarningNotification,
object: nil
)
}
@objc
public static func recordEarlyEnvelope(
func didReceiveMemoryWarning() {
Logger.error("Dropping all early messages due to memory warning.")
serialQueue.sync {
pendingEnvelopes = OrderedDictionary()
pendingReceipts = OrderedDictionary()
}
}
@objc
public func recordEarlyEnvelope(
_ envelope: SSKProtoEnvelope,
plainTextData: Data?,
wasReceivedByUD: Bool,
associatedMessageTimestamp: UInt64,
associatedMessageAuthor: SignalServiceAddress
) {
guard plainTextData?.count ?? 0 <= maxEarlyEnvelopeSize else {
guard plainTextData?.count ?? 0 <= Self.maxEarlyEnvelopeSize else {
return owsFailDebug("unexpectedly tried to record an excessively large early envelope")
}
@ -54,7 +77,7 @@ public class EarlyMessageManager: NSObject {
serialQueue.sync {
var envelopes = pendingEnvelopes[identifier] ?? []
while envelopes.count >= maxQueuedPerMessage, let droppedEarlyEnvelope = envelopes.first {
while envelopes.count >= Self.maxQueuedPerMessage, let droppedEarlyEnvelope = envelopes.first {
envelopes.remove(at: 0)
owsFailDebug("Dropping early envelope \(droppedEarlyEnvelope.envelope.timestamp) for message \(identifier) due to excessive early envelopes.")
}
@ -62,7 +85,7 @@ public class EarlyMessageManager: NSObject {
envelopes.append(EarlyEnvelope(envelope: envelope, plainTextData: plainTextData, wasReceivedByUD: wasReceivedByUD))
pendingEnvelopes[identifier] = envelopes
while pendingEnvelopes.count >= maxQueuedMessages, let droppedEarlyIdentifier = pendingEnvelopes.orderedKeys.first {
while pendingEnvelopes.count >= Self.maxQueuedMessages, let droppedEarlyIdentifier = pendingEnvelopes.orderedKeys.first {
pendingEnvelopes.remove(key: droppedEarlyIdentifier)
owsFailDebug("Dropping all early envelopes for message \(droppedEarlyIdentifier) due to excessive early messages.")
}
@ -70,7 +93,7 @@ public class EarlyMessageManager: NSObject {
}
@objc
public static func recordEarlyReceiptForOutgoingMessage(
public func recordEarlyReceiptForOutgoingMessage(
type: SSKProtoReceiptMessageType,
sender: SignalServiceAddress,
timestamp: UInt64,
@ -88,7 +111,7 @@ public class EarlyMessageManager: NSObject {
}
@objc
public static func recordEarlyReadReceiptFromLinkedDevice(
public func recordEarlyReadReceiptFromLinkedDevice(
timestamp: UInt64,
associatedMessageTimestamp: UInt64,
associatedMessageAuthor: SignalServiceAddress
@ -100,7 +123,7 @@ public class EarlyMessageManager: NSObject {
)
}
private static func recordEarlyReceipt(
private func recordEarlyReceipt(
_ earlyReceipt: EarlyReceipt,
associatedMessageTimestamp: UInt64,
associatedMessageAuthor: SignalServiceAddress
@ -109,7 +132,7 @@ public class EarlyMessageManager: NSObject {
serialQueue.sync {
var receipts = pendingReceipts[identifier] ?? []
while receipts.count >= maxQueuedPerMessage, let droppedEarlyReceipt = receipts.first {
while receipts.count >= Self.maxQueuedPerMessage, let droppedEarlyReceipt = receipts.first {
receipts.remove(at: 0)
owsFailDebug("Dropping early receipt \(droppedEarlyReceipt) for message \(identifier) due to excessive early receipts.")
}
@ -117,7 +140,7 @@ public class EarlyMessageManager: NSObject {
receipts.append(earlyReceipt)
pendingReceipts[identifier] = receipts
while pendingReceipts.count >= maxQueuedMessages, let droppedEarlyIdentifier = pendingReceipts.orderedKeys.first {
while pendingReceipts.count >= Self.maxQueuedMessages, let droppedEarlyIdentifier = pendingReceipts.orderedKeys.first {
pendingReceipts.remove(key: droppedEarlyIdentifier)
owsFailDebug("Dropping all early envelopes for message \(droppedEarlyIdentifier) due to excessive early messages.")
}
@ -125,7 +148,7 @@ public class EarlyMessageManager: NSObject {
}
@objc
public static func applyPendingMessages(for message: TSMessage, transaction: SDSAnyWriteTransaction) {
public func applyPendingMessages(for message: TSMessage, transaction: SDSAnyWriteTransaction) {
var earlyReceipts: [EarlyReceipt]?
var earlyEnvelopes: [EarlyEnvelope]?

View File

@ -172,6 +172,11 @@ NS_ASSUME_NONNULL_BEGIN
return SSKEnvironment.shared.groupsV2;
}
- (EarlyMessageManager *)earlyMessageManager
{
return SSKEnvironment.shared.earlyMessageManager;
}
#pragma mark -
- (void)startObserving
@ -942,10 +947,10 @@ NS_ASSUME_NONNULL_BEGIN
for (NSNumber *nsEarlyTimestamp in earlyTimestamps) {
UInt64 earlyTimestamp = [nsEarlyTimestamp unsignedLongLongValue];
[OWSEarlyMessageManager recordEarlyReceiptForOutgoingMessageWithType:receiptMessage.unwrappedType
sender:envelope.sourceAddress
timestamp:envelope.timestamp
associatedMessageTimestamp:earlyTimestamp];
[self.earlyMessageManager recordEarlyReceiptForOutgoingMessageWithType:receiptMessage.unwrappedType
sender:envelope.sourceAddress
timestamp:envelope.timestamp
associatedMessageTimestamp:earlyTimestamp];
}
}
@ -1480,11 +1485,11 @@ NS_ASSUME_NONNULL_BEGIN
case OWSReactionProcessingResultInvalidReaction:
break;
case OWSReactionProcessingResultAssociatedMessageMissing:
[OWSEarlyMessageManager recordEarlyEnvelope:envelope
plainTextData:plaintextData
wasReceivedByUD:wasReceivedByUD
associatedMessageTimestamp:dataMessage.reaction.timestamp
associatedMessageAuthor:dataMessage.reaction.authorAddress];
[self.earlyMessageManager recordEarlyEnvelope:envelope
plainTextData:plaintextData
wasReceivedByUD:wasReceivedByUD
associatedMessageTimestamp:dataMessage.reaction.timestamp
associatedMessageAuthor:dataMessage.reaction.authorAddress];
break;
}
} else if (dataMessage.delete != nil) {
@ -1515,11 +1520,11 @@ NS_ASSUME_NONNULL_BEGIN
OWSLogError(@"Failed to remotely delete message: %llu", dataMessage.delete.targetSentTimestamp);
break;
case OWSRemoteDeleteProcessingResultDeletedMessageMissing:
[OWSEarlyMessageManager recordEarlyEnvelope:envelope
plainTextData:plaintextData
wasReceivedByUD:wasReceivedByUD
associatedMessageTimestamp:dataMessage.delete.targetSentTimestamp
associatedMessageAuthor:envelope.sourceAddress];
[self.earlyMessageManager recordEarlyEnvelope:envelope
plainTextData:plaintextData
wasReceivedByUD:wasReceivedByUD
associatedMessageTimestamp:dataMessage.delete.targetSentTimestamp
associatedMessageAuthor:envelope.sourceAddress];
break;
}
} else {
@ -1577,9 +1582,10 @@ NS_ASSUME_NONNULL_BEGIN
readTimestamp:envelope.timestamp
transaction:transaction];
for (SSKProtoSyncMessageRead *readReceiptProto in earlyReceipts) {
[OWSEarlyMessageManager recordEarlyReadReceiptFromLinkedDeviceWithTimestamp:envelope.timestamp
associatedMessageTimestamp:readReceiptProto.timestamp
associatedMessageAuthor:readReceiptProto.senderAddress];
[self.earlyMessageManager
recordEarlyReadReceiptFromLinkedDeviceWithTimestamp:envelope.timestamp
associatedMessageTimestamp:readReceiptProto.timestamp
associatedMessageAuthor:readReceiptProto.senderAddress];
}
} else if (syncMessage.verified) {
OWSLogInfo(@"Received verification state for %@", syncMessage.verified.destinationAddress);
@ -1603,11 +1609,11 @@ NS_ASSUME_NONNULL_BEGIN
case OWSViewOnceSyncMessageProcessingResultInvalidSyncMessage:
break;
case OWSViewOnceSyncMessageProcessingResultAssociatedMessageMissing:
[OWSEarlyMessageManager recordEarlyEnvelope:envelope
plainTextData:plaintextData
wasReceivedByUD:wasReceivedByUD
associatedMessageTimestamp:syncMessage.viewOnceOpen.timestamp
associatedMessageAuthor:syncMessage.viewOnceOpen.senderAddress];
[self.earlyMessageManager recordEarlyEnvelope:envelope
plainTextData:plaintextData
wasReceivedByUD:wasReceivedByUD
associatedMessageTimestamp:syncMessage.viewOnceOpen.timestamp
associatedMessageAuthor:syncMessage.viewOnceOpen.senderAddress];
break;
}
} else if (syncMessage.configuration) {
@ -1903,11 +1909,11 @@ NS_ASSUME_NONNULL_BEGIN
case OWSReactionProcessingResultInvalidReaction:
break;
case OWSReactionProcessingResultAssociatedMessageMissing:
[OWSEarlyMessageManager recordEarlyEnvelope:envelope
plainTextData:plaintextData
wasReceivedByUD:wasReceivedByUD
associatedMessageTimestamp:dataMessage.reaction.timestamp
associatedMessageAuthor:dataMessage.reaction.authorAddress];
[self.earlyMessageManager recordEarlyEnvelope:envelope
plainTextData:plaintextData
wasReceivedByUD:wasReceivedByUD
associatedMessageTimestamp:dataMessage.reaction.timestamp
associatedMessageAuthor:dataMessage.reaction.authorAddress];
break;
}
@ -1929,11 +1935,11 @@ NS_ASSUME_NONNULL_BEGIN
OWSLogError(@"Failed to remotely delete message: %llu", dataMessage.delete.targetSentTimestamp);
break;
case OWSRemoteDeleteProcessingResultDeletedMessageMissing:
[OWSEarlyMessageManager recordEarlyEnvelope:envelope
plainTextData:plaintextData
wasReceivedByUD:wasReceivedByUD
associatedMessageTimestamp:dataMessage.delete.targetSentTimestamp
associatedMessageAuthor:envelope.sourceAddress];
[self.earlyMessageManager recordEarlyEnvelope:envelope
plainTextData:plaintextData
wasReceivedByUD:wasReceivedByUD
associatedMessageTimestamp:dataMessage.delete.targetSentTimestamp
associatedMessageAuthor:envelope.sourceAddress];
break;
}
return nil;
@ -2021,7 +2027,7 @@ NS_ASSUME_NONNULL_BEGIN
[incomingMessage anyInsertWithTransaction:transaction];
[OWSEarlyMessageManager applyPendingMessagesFor:incomingMessage transaction:transaction];
[self.earlyMessageManager applyPendingMessagesFor:incomingMessage transaction:transaction];
// Any messages sent from the current user - from this device or another - should be automatically marked as read.
if (envelope.sourceAddress.isLocalAddress) {

View File

@ -8,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN
@class BulkProfileFetch;
@class BulkUUIDLookup;
@class ContactsUpdater;
@class EarlyMessageManager;
@class GroupsV2MessageProcessor;
@class MessageFetcherJob;
@class MessageProcessing;
@ -105,7 +106,8 @@ NS_ASSUME_NONNULL_BEGIN
messageFetcherJob:(MessageFetcherJob *)messageFetcherJob
bulkProfileFetch:(BulkProfileFetch *)bulkProfileFetch
bulkUUIDLookup:(BulkUUIDLookup *)bulkUUIDLookup
versionedProfiles:(id<VersionedProfiles>)versionedProfiles NS_DESIGNATED_INITIALIZER;
versionedProfiles:(id<VersionedProfiles>)versionedProfiles
earlyMessageManager:(EarlyMessageManager *)earlyMessageManager NS_DESIGNATED_INITIALIZER;
@property (nonatomic, readonly, class) SSKEnvironment *shared;
@ -163,6 +165,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) BulkProfileFetch *bulkProfileFetch;
@property (nonatomic, readonly) BulkUUIDLookup *bulkUUIDLookup;
@property (nonatomic, readonly) id<VersionedProfiles> versionedProfiles;
@property (nonatomic, readonly) EarlyMessageManager *earlyMessageManager;
@property (nonatomic, readonly, nullable) OWSPrimaryStorage *primaryStorage;

View File

@ -52,6 +52,7 @@ static SSKEnvironment *sharedSSKEnvironment;
@property (nonatomic) BulkProfileFetch *bulkProfileFetch;
@property (nonatomic) BulkUUIDLookup *bulkUUIDLookup;
@property (nonatomic) id<VersionedProfiles> versionedProfiles;
@property (nonatomic) EarlyMessageManager *earlyMessageManager;
@end
@ -109,6 +110,7 @@ static SSKEnvironment *sharedSSKEnvironment;
bulkProfileFetch:(BulkProfileFetch *)bulkProfileFetch
bulkUUIDLookup:(BulkUUIDLookup *)bulkUUIDLookup
versionedProfiles:(id<VersionedProfiles>)versionedProfiles
earlyMessageManager:(EarlyMessageManager *)earlyMessageManager
{
self = [super init];
if (!self) {
@ -160,6 +162,7 @@ static SSKEnvironment *sharedSSKEnvironment;
OWSAssertDebug(bulkProfileFetch);
OWSAssertDebug(versionedProfiles);
OWSAssertDebug(bulkUUIDLookup);
OWSAssertDebug(earlyMessageManager);
_contactsManager = contactsManager;
_linkPreviewManager = linkPreviewManager;
@ -207,6 +210,7 @@ static SSKEnvironment *sharedSSKEnvironment;
_bulkProfileFetch = bulkProfileFetch;
_versionedProfiles = versionedProfiles;
_bulkUUIDLookup = bulkUUIDLookup;
_earlyMessageManager = earlyMessageManager;
return self;
}

View File

@ -108,6 +108,7 @@ NS_ASSUME_NONNULL_BEGIN
BulkProfileFetch *bulkProfileFetch = [BulkProfileFetch new];
BulkUUIDLookup *bulkUUIDLookup = [BulkUUIDLookup new];
id<VersionedProfiles> versionedProfiles = [MockVersionedProfiles new];
EarlyMessageManager *earlyMessageManager = [EarlyMessageManager new];
self = [super initWithContactsManager:contactsManager
linkPreviewManager:linkPreviewManager
@ -154,7 +155,8 @@ NS_ASSUME_NONNULL_BEGIN
messageFetcherJob:messageFetcherJob
bulkProfileFetch:bulkProfileFetch
bulkUUIDLookup:bulkUUIDLookup
versionedProfiles:versionedProfiles];
versionedProfiles:versionedProfiles
earlyMessageManager:earlyMessageManager];
if (!self) {
return nil;