| // 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 "base/metrics/user_metrics.h" | 
 |  | 
 | #include <stddef.h> | 
 |  | 
 | #include <vector> | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/lazy_instance.h" | 
 | #include "base/location.h" | 
 | #include "base/macros.h" | 
 | #include "base/threading/thread_checker.h" | 
 |  | 
 | namespace base { | 
 | namespace { | 
 |  | 
 | LazyInstance<std::vector<ActionCallback>>::DestructorAtExit g_callbacks = | 
 |     LAZY_INSTANCE_INITIALIZER; | 
 | LazyInstance<scoped_refptr<SingleThreadTaskRunner>>::DestructorAtExit | 
 |     g_task_runner = LAZY_INSTANCE_INITIALIZER; | 
 |  | 
 | }  // namespace | 
 |  | 
 | void RecordAction(const UserMetricsAction& action) { | 
 |   RecordComputedAction(action.str_); | 
 | } | 
 |  | 
 | void RecordComputedAction(const std::string& action) { | 
 |   if (!g_task_runner.Get()) { | 
 |     DCHECK(g_callbacks.Get().empty()); | 
 |     return; | 
 |   } | 
 |  | 
 |   if (!g_task_runner.Get()->BelongsToCurrentThread()) { | 
 |     g_task_runner.Get()->PostTask(FROM_HERE, | 
 |                                   BindOnce(&RecordComputedAction, action)); | 
 |     return; | 
 |   } | 
 |  | 
 |   for (const ActionCallback& callback : g_callbacks.Get()) { | 
 |     callback.Run(action); | 
 |   } | 
 | } | 
 |  | 
 | void AddActionCallback(const ActionCallback& callback) { | 
 |   // Only allow adding a callback if the task runner is set. | 
 |   DCHECK(g_task_runner.Get()); | 
 |   DCHECK(g_task_runner.Get()->BelongsToCurrentThread()); | 
 |   g_callbacks.Get().push_back(callback); | 
 | } | 
 |  | 
 | void RemoveActionCallback(const ActionCallback& callback) { | 
 |   DCHECK(g_task_runner.Get()); | 
 |   DCHECK(g_task_runner.Get()->BelongsToCurrentThread()); | 
 |   std::vector<ActionCallback>* callbacks = g_callbacks.Pointer(); | 
 |   for (size_t i = 0; i < callbacks->size(); ++i) { | 
 |     if ((*callbacks)[i].Equals(callback)) { | 
 |       callbacks->erase(callbacks->begin() + i); | 
 |       return; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void SetRecordActionTaskRunner( | 
 |     scoped_refptr<SingleThreadTaskRunner> task_runner) { | 
 |   DCHECK(task_runner->BelongsToCurrentThread()); | 
 |   DCHECK(!g_task_runner.Get() || g_task_runner.Get()->BelongsToCurrentThread()); | 
 |   g_task_runner.Get() = task_runner; | 
 | } | 
 |  | 
 | }  // namespace base |