blob: c84c8b0c12833b1c4660d5675500397b4e3f04fd [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/metrics/thread_watcher_android.h"
#include "base/android/application_status_listener.h"
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "chrome/browser/metrics/thread_watcher.h"
#include "content/public/browser/browser_thread.h"
namespace {
// For most of the activities, the C++ side is initialized asynchronously
// and the very first APPLICATION_STATE_HAS_RUNNING_ACTIVITIES is never received
// whilst the ThreadWatcherList is initiated higher up in the stack.
// However, some activities are initialized synchronously, and it'll receive
// an APPLICATION_STATE_HAS_RUNNING_ACTIVITIES here as well.
// Protect against this case, and only let
// APPLICATION_STATE_HAS_RUNNING_ACTIVITIES turn on the
// watchdog if it was previously handled by an
// APPLICATION_STATE_HAS_STOPPED_ACTIVITIES (which is always handled here).
bool g_application_has_stopped = false;
void OnApplicationStateChange(
base::android::ApplicationState application_state) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (application_state ==
base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES) {
g_application_has_stopped = true;
ThreadWatcherList::StopWatchingAll();
} else if (application_state ==
base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES &&
g_application_has_stopped) {
g_application_has_stopped = false;
ThreadWatcherList::StartWatchingAll(
*base::CommandLine::ForCurrentProcess());
}
}
// This wrapper is needed so we can call the ApplicationStatusListener::New
// method which returns a unique_ptr.
class ApplicationStatusListenerWrapper {
public:
ApplicationStatusListenerWrapper()
: listener_(base::android::ApplicationStatusListener::New(
base::BindRepeating(&OnApplicationStateChange))) {}
private:
std::unique_ptr<base::android::ApplicationStatusListener> listener_;
};
struct LeakyApplicationStatusListenerTraits {
static const bool kRegisterOnExit = false;
#if DCHECK_IS_ON()
static const bool kAllowedToAccessOnNonjoinableThread = true;
#endif
static ApplicationStatusListenerWrapper* New(void* instance) {
ANNOTATE_SCOPED_MEMORY_LEAK;
return new (instance) ApplicationStatusListenerWrapper();
}
static void Delete(ApplicationStatusListenerWrapper* instance) {}
};
base::LazyInstance<ApplicationStatusListenerWrapper,
LeakyApplicationStatusListenerTraits>
g_application_status_listener = LAZY_INSTANCE_INITIALIZER;
} // namespace
void ThreadWatcherAndroid::RegisterApplicationStatusListener() {
// Leaky.
g_application_status_listener.Get();
}