// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/app/application_delegate/memory_warning_helper.h"

#import "base/memory/memory_pressure_listener.h"
#import "base/metrics/histogram_macros.h"
#import "components/previous_session_info/previous_session_info.h"
#import "ios/chrome/browser/crash_report/model/crash_keys_helper.h"

namespace {
// The number of seconds to wait after a memory warning to clear the flag used
// to detect Out Of Memory crashes.
// NOTE: From local tests on various devices, this interval ranges between 1 and
// 3 seconds. It is set to 5 to ensure all out of memory crashes are identified,
// even if this may lead to overcounting them.
const CFTimeInterval kOutOfMemoryResetTimeInterval = 5;
}  // namespace

@interface MemoryWarningHelper () {
  // The time at which to reset the OOM crash flag in the user defaults. This
  // is used to handle receiving multiple memory warnings in short
  // succession.
  CFAbsoluteTime _outOfMemoryResetTime;
}
// Resets the OOM crash flag from the user defaults.
- (void)resetOutOfMemoryFlagIfNecessary;
@end

@implementation MemoryWarningHelper

@synthesize foregroundMemoryWarningCount = _foregroundMemoryWarningCount;

- (void)handleMemoryPressure {
  // Notify the system that the memory is critical and something should be done.
  base::MemoryPressureListener::NotifyMemoryPressure(
      base::MEMORY_PRESSURE_LEVEL_CRITICAL);

  ++_foregroundMemoryWarningCount;
  // Register that we might die because of memory. If we are still alive in
  // `kOutOfMemoryResetTimeInterval` seconds, reset the flag.
  [[PreviousSessionInfo sharedInstance] setMemoryWarningFlag];
  _outOfMemoryResetTime =
      CFAbsoluteTimeGetCurrent() + kOutOfMemoryResetTimeInterval;

  // Add information to crash keys.
  crash_keys::SetMemoryWarningCount(_foregroundMemoryWarningCount);
  crash_keys::SetMemoryWarningInProgress(true);

  dispatch_after(kOutOfMemoryResetTimeInterval, dispatch_get_main_queue(), ^{
    [self resetOutOfMemoryFlagIfNecessary];
  });
}

- (void)resetOutOfMemoryFlagIfNecessary {
  if (CFAbsoluteTimeGetCurrent() < _outOfMemoryResetTime) {
    return;
  }
  _outOfMemoryResetTime = 0;
  [[PreviousSessionInfo sharedInstance] resetMemoryWarningFlag];
  crash_keys::SetMemoryWarningInProgress(false);
}

- (void)resetForegroundMemoryWarningCount {
  _foregroundMemoryWarningCount = 0;
  crash_keys::SetMemoryWarningCount(0);
}

@end
