| // 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/bind.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(); |
| } |