1effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// found in the LICENSE file.
4effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
5effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include <mach/mach.h>
6effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include <vector>
8effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
9effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/memory/ref_counted.h"
10effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/strings/string_util.h"
11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/strings/stringprintf.h"
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/ui/browser.h"
13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/ui/browser_window.h"
14effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/ui/tabs/tab_strip_model.h"
15effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/test/base/in_process_browser_test.h"
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "net/test/spawned_test_server/spawned_test_server.h"
17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "testing/perf/perf_test.h"
18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
19effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace {
20effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
21effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// This test spawns a new browser and counts the number of open Mach ports in
22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// the browser process. It navigates tabs and closes them, repeatedly measuring
23effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// the number of open ports. This is used to protect against leaking Mach ports,
24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// which was the source of <http://crbug.com/105513>.
25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochclass MachPortsTest : public InProcessBrowserTest {
26effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch public:
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  MachPortsTest()
28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      : server_(net::SpawnedTestServer::TYPE_HTTP,
29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                net::SpawnedTestServer::kLocalhost,
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                base::FilePath(FILE_PATH_LITERAL("data/mach_ports/moz"))) {
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
33effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  virtual void SetUp() OVERRIDE {
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    InProcessBrowserTest::SetUp();
35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
36effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ASSERT_TRUE(server_.Start());
37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  virtual void TearDown() OVERRIDE {
40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string ports;
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for (std::vector<int>::iterator it = port_counts_.begin();
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         it != port_counts_.end(); ++it) {
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::StringAppendF(&ports, "%d,", *it);
44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    perf_test::PrintResultList("mach_ports", "", "", ports, "ports", true);
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
47effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    InProcessBrowserTest::TearDown();
48effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
49effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Gets the browser's current number of Mach ports and records it.
51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void RecordPortCount() {
52effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    mach_port_name_array_t names;
53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    mach_msg_type_number_t names_count = 0;
54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    mach_port_type_array_t types;
55effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    mach_msg_type_number_t types_count = 0;
56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    mach_port_t self = mach_task_self();
58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // A friendlier interface would allow NULL buffers to only get the counts.
60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    kern_return_t kr = mach_port_names(self,
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                       &names, &names_count,
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                       &types, &types_count);
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ASSERT_EQ(KERN_SUCCESS, kr) << "Failed to get mach_port_names(): "
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                << mach_error_string(kr);
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ASSERT_EQ(names_count, types_count);  // Documented kernel invariant.
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    port_counts_.push_back(names_count);
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    vm_deallocate(self, reinterpret_cast<vm_address_t>(names),
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        names_count * sizeof(mach_port_name_array_t));
71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    vm_deallocate(self, reinterpret_cast<vm_address_t>(types),
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        types_count * sizeof(mach_port_type_array_t));
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Adds a tab from the page cycler data at the specified domain.
76effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void AddTab(const std::string& domain) {
77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    GURL url = server_.GetURL("files/" + domain + "/").Resolve("?skip");
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    AddTabAtIndex(0, url, content::PageTransition::PAGE_TRANSITION_TYPED);
79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch private:
82effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  net::SpawnedTestServer server_;
83effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::vector<int> port_counts_;
84effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
86effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochIN_PROC_BROWSER_TEST_F(MachPortsTest, GetCounts) {
87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  browser()->window()->Show();
88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Record startup number.
90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  RecordPortCount();
91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Create a browser and open a few tabs.
93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  AddTab("www.google.com");
94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  RecordPortCount();
95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  AddTab("www.cnn.com");
97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  RecordPortCount();
98effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
99effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  AddTab("www.nytimes.com");
100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  RecordPortCount();
101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
102effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  TabStripModel* tab_strip_model = browser()->tab_strip_model();
103effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  int tab_count = tab_strip_model->count();
104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ASSERT_EQ(4, tab_count);  // Also count about:blank.
105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Close each tab, recording the number of ports after each. Do not close the
107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // last tab, which is about:blank.
108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (int i = 0; i < tab_count - 1; ++i) {
109effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    EXPECT_TRUE(
110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        tab_strip_model->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE));
111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    RecordPortCount();
112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}  // namespace
116