summaryrefslogtreecommitdiffstats
path: root/ceee/ie/broker/broker_module.cc
blob: 252e6a4d8b9c3c3d85eb6f48e12805c0ca60c088 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
// Copyright (c) 2010 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.
//
// Declaration of ATL module object for EXE module.

#include <atlbase.h>
#include <atlhost.h>

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/logging_win.h"
#include "ceee/ie/broker/broker.h"
#include "ceee/ie/broker/broker_rpc_server.h"
#include "ceee/ie/broker/chrome_postman.h"
#include "ceee/ie/broker/executors_manager.h"
#include "ceee/ie/broker/resource.h"
#include "ceee/ie/broker/window_events_funnel.h"
#include "ceee/ie/plugin/toolband/toolband_proxy.h"
#include "ceee/ie/common/crash_reporter.h"
#include "ceee/common/com_utils.h"
#include "chrome/common/url_constants.h"
#include "chrome_frame/metrics_service.h"

namespace {

const wchar_t kLogFileName[] = L"CeeeBroker.log";

// {6E3D6168-1DD2-4edb-A183-584C2C66E96D}
const GUID kCeeeBrokerLogProviderName =
    { 0x6e3d6168, 0x1dd2, 0x4edb,
        { 0xa1, 0x83, 0x58, 0x4c, 0x2c, 0x66, 0xe9, 0x6d } };

}  // namespace

// Object entries go here instead of with each object, so that we can keep
// the objects in a lib, and also to decrease the amount of magic.
OBJECT_ENTRY_AUTO(__uuidof(CeeeBroker), CeeeBroker)

class CeeeBrokerModule : public CAtlExeModuleT<CeeeBrokerModule> {
 public:
  CeeeBrokerModule();
  ~CeeeBrokerModule();

  DECLARE_LIBID(LIBID_CeeeBrokerLib)
  static HRESULT WINAPI UpdateRegistryAppId(BOOL register) throw();

  // We have our own version so that we can explicitly specify
  // that we want to be in a multi threaded apartment.
  static HRESULT InitializeCom();

  // Prevent COM objects we don't own to control our lock count.
  // To properly manage our lifespan, yet still be able to control the
  // lifespan of the ChromePostman's thread, we must only rely on the
  // CeeeBroker implementation of the IExternalConnection interface
  // as well as the ExecutorsManager map content to decide when to die.
  virtual LONG Lock() {
    return 1;
  }
  virtual LONG Unlock() {
    return 1;
  }

  // We prevent access to the module lock count from objects we don't
  // own by overriding the Un/Lock methods above. But when we want to
  // access the module lock count, we do it from here, and bypass our
  // override. These are the entry points that only our code accesses.
  LONG LockModule() {
    return CAtlExeModuleT<CeeeBrokerModule>::Lock();
  }
  LONG UnlockModule() {
    return CAtlExeModuleT<CeeeBrokerModule>::Unlock();
  }

  HRESULT PostMessageLoop();
  HRESULT PreMessageLoop(int show);
 private:
  void TearDown();

  // We maintain a postman COM object on the stack so that we can
  // properly initialize and terminate it at the right time.
  CComObjectStackEx<ChromePostman> chrome_postman_;
  CrashReporter crash_reporter_;
  base::AtExitManager at_exit_;
  BrokerRpcServer rpc_server_;
};

CeeeBrokerModule module;

extern "C" int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int nShowCmd) {
  return module.WinMain(nShowCmd);
}

CeeeBrokerModule::CeeeBrokerModule()
    : crash_reporter_(L"ceee_broker") {
  TRACE_EVENT_BEGIN("ceee.broker", this, "");

  wchar_t logfile_path[MAX_PATH];
  DWORD len = ::GetTempPath(arraysize(logfile_path), logfile_path);
  ::PathAppend(logfile_path, kLogFileName);

  // It seems we're obliged to initialize the current command line
  // before initializing logging.
  CommandLine::Init(0, NULL);

  logging::InitLogging(
      logfile_path,
      logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
      logging::LOCK_LOG_FILE,
      logging::APPEND_TO_OLD_LOG_FILE);

  // Initialize ETW logging.
  logging::LogEventProvider::Initialize(kCeeeBrokerLogProviderName);

  // Initialize control hosting.
  BOOL initialized = AtlAxWinInit();
  DCHECK(initialized);

  // Needs to be called before we can use GURL.
  chrome::RegisterChromeSchemes();

  crash_reporter_.InitializeCrashReporting(false);
}

HRESULT CeeeBrokerModule::InitializeCom() {
  HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
  if (FAILED(hr))
    return hr;

  // We need to initialize security before setting global options.
  hr = ::CoInitializeSecurity(NULL,
                              -1,
                              NULL,
                              NULL,
                              // Clients must identify.
                              RPC_C_IMP_LEVEL_IDENTIFY,
                              // And we identify.
                              RPC_C_IMP_LEVEL_IDENTIFY,
                              NULL,
                              // We don't want low integrity to be able to
                              // instantiate arbitrary objects in our process.
                              EOAC_NO_CUSTOM_MARSHAL,
                              NULL);
  DCHECK(SUCCEEDED(hr));

  // Ensure the marshaling machinery doesn't eat our crashes.
  CComPtr<IGlobalOptions> options;
  hr = options.CoCreateInstance(CLSID_GlobalOptions);
  if (SUCCEEDED(hr)) {
    hr = options->Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE);
  }
  DLOG_IF(WARNING, FAILED(hr)) << "IGlobalOptions::Set failed "
                               << com::LogHr(hr);

  // Register the executor proxy/stubs.
  // Note that this registers the proxy/stub class objects for all threads
  // in the multithreaded apartment.
  if (!RegisterProxyStubs(NULL)) {
    LOG(ERROR) << "Failed to register executor proxy/stubs";
    return E_UNEXPECTED;
  }

  // The above is best-effort, don't bail on error.
  return S_OK;
}

HRESULT CeeeBrokerModule::PreMessageLoop(int show) {
  // It's important to initialize the postman BEFORE we make the Broker
  // and the event funnel available, since we may get requests to execute
  // API invocation or Fire events before the postman is ready to handle them.
  chrome_postman_.Init();
  WindowEventsFunnel::Initialize();

  // Another instance of broker may be shutting down right now. Do several
  // attempts in hope the process exits and releases endpoint.
  for (int i = 0; i < 10 && !rpc_server_.Start(); ++i)
    Sleep(500);

  // Initialize metrics. We need the rpc_server_ above to be available.
  MetricsService::Start();

  HRESULT hr = rpc_server_.is_started() ? S_OK : RPC_E_FAULT;
  if (SUCCEEDED(hr))
    hr = CAtlExeModuleT<CeeeBrokerModule>::PreMessageLoop(show);
  if (FAILED(hr))
    TearDown();
  return hr;
}

HRESULT CeeeBrokerModule::PostMessageLoop() {
  HRESULT hr = CAtlExeModuleT<CeeeBrokerModule>::PostMessageLoop();
  TearDown();
  return hr;
}

void CeeeBrokerModule::TearDown() {
  rpc_server_.Stop();
  Singleton<ExecutorsManager,
            ExecutorsManager::SingletonTraits>()->Terminate();
  WindowEventsFunnel::Terminate();

  // Upload data if necessary.
  MetricsService::Stop();

  chrome_postman_.Term();
}

CeeeBrokerModule::~CeeeBrokerModule() {
  crash_reporter_.ShutdownCrashReporting();
  logging::CloseLogFile();
  TRACE_EVENT_END("ceee.broker", this, "");
}

HRESULT WINAPI CeeeBrokerModule::UpdateRegistryAppId(BOOL reg) throw() {
  return com::ModuleRegistrationWithoutAppid(IDR_BROKER_MODULE, reg);
}

namespace ceee_module_util {

LONG LockModule() {
  return module.LockModule();
}

LONG UnlockModule() {
  return module.UnlockModule();
}

}  // namespace