15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/base/tracing.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/debug/trace_event.h"
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/files/file_path.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/strings/string_util.h"
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/timer/timer.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/public/browser/tracing_controller.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/test/test_utils.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass StringTraceSink : public content::TracingController::TraceDataSink {
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public:
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  StringTraceSink(std::string* result, const base::Closure& callback)
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      : result_(result), completion_callback_(callback) {}
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual void AddTraceChunk(const std::string& chunk) OVERRIDE {
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    *result_ += result_->empty() ? "[" : ",";
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    *result_ += chunk;
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual void Close() OVERRIDE {
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!result_->empty())
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      *result_ += "]";
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    completion_callback_.Run();
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private:
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual ~StringTraceSink() {}
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string* result_;
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::Closure completion_callback_;
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DISALLOW_COPY_AND_ASSIGN(StringTraceSink);
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class InProcessTraceController {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static InProcessTraceController* GetInstance() {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Singleton<InProcessTraceController>::get();
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InProcessTraceController()
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : is_waiting_on_watch_(false),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        watch_notification_count_(0) {}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~InProcessTraceController() {}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool BeginTracing(const std::string& category_patterns) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return content::TracingController::GetInstance()->EnableRecording(
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::debug::CategoryFilter(category_patterns),
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::debug::TraceOptions(),
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        content::TracingController::EnableRecordingDoneCallback());
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool BeginTracingWithWatch(const std::string& category_patterns,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const std::string& category_name,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const std::string& event_name,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int num_occurrences) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(num_occurrences > 0);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    watch_notification_count_ = num_occurrences;
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!content::TracingController::GetInstance()->SetWatchEvent(
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            category_name, event_name,
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            base::Bind(&InProcessTraceController::OnWatchEventMatched,
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       base::Unretained(this)))) {
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!content::TracingController::GetInstance()->EnableRecording(
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            base::debug::CategoryFilter(category_patterns),
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            base::debug::TraceOptions(),
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            base::Bind(&InProcessTraceController::OnEnableTracingComplete,
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       base::Unretained(this)))) {
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    message_loop_runner_ = new content::MessageLoopRunner;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    message_loop_runner_->Run();
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool WaitForWatchEvent(base::TimeDelta timeout) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (watch_notification_count_ == 0)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (timeout != base::TimeDelta()) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_.Start(FROM_HERE, timeout, this,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   &InProcessTraceController::Timeout);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_waiting_on_watch_ = true;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_ = new content::MessageLoopRunner;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_->Run();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_waiting_on_watch_ = false;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return watch_notification_count_ == 0;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool EndTracing(std::string* json_trace_output) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    using namespace base::debug;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!content::TracingController::GetInstance()->DisableRecording(
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            new StringTraceSink(
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                json_trace_output,
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                base::Bind(&InProcessTraceController::OnTracingComplete,
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           base::Unretained(this))))) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait for OnEndTracingComplete() to quit the message loop.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_ = new content::MessageLoopRunner;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_->Run();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Watch notifications can occur during this method's message loop run, but
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // not after, so clear them here.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    watch_notification_count_ = 0;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct DefaultSingletonTraits<InProcessTraceController>;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnEnableTracingComplete() {
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    message_loop_runner_->Quit();
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void OnTracingComplete() { message_loop_runner_->Quit(); }
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void OnWatchEventMatched() {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (watch_notification_count_ == 0)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (--watch_notification_count_ == 0) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_.Stop();
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (is_waiting_on_watch_)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        message_loop_runner_->Quit();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Timeout() {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(is_waiting_on_watch_);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_runner_->Quit();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::OneShotTimer<InProcessTraceController> timer_;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_waiting_on_watch_;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int watch_notification_count_;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(InProcessTraceController);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace tracing {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool BeginTracing(const std::string& category_patterns) {
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return InProcessTraceController::GetInstance()->BeginTracing(
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      category_patterns);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool BeginTracingWithWatch(const std::string& category_patterns,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const std::string& category_name,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const std::string& event_name,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           int num_occurrences) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return InProcessTraceController::GetInstance()->BeginTracingWithWatch(
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      category_patterns, category_name, event_name, num_occurrences);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WaitForWatchEvent(base::TimeDelta timeout) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return InProcessTraceController::GetInstance()->WaitForWatchEvent(timeout);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EndTracing(std::string* json_trace_output) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return InProcessTraceController::GetInstance()->EndTracing(json_trace_output);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace tracing
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
191