summaryrefslogtreecommitdiffstats
path: root/content/browser/service_worker/embedded_worker_instance.h
blob: e3e977162d56d5c9e4f3f13db135e55fbb9ce98a (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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// Copyright 2013 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.

#ifndef CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_INSTANCE_H_
#define CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_INSTANCE_H_

#include <map>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "url/gurl.h"

// Windows headers will redefine SendMessage.
#ifdef SendMessage
#undef SendMessage
#endif

struct EmbeddedWorkerMsg_StartWorker_Params;

namespace IPC {
class Message;
}

namespace content {

class EmbeddedWorkerRegistry;
class MessagePortMessageFilter;
class ServiceRegistry;
class ServiceRegistryImpl;
class ServiceWorkerContextCore;
struct ServiceWorkerFetchRequest;

// This gives an interface to control one EmbeddedWorker instance, which
// may be 'in-waiting' or running in one of the child processes added by
// AddProcessReference().
class CONTENT_EXPORT EmbeddedWorkerInstance {
 public:
  typedef base::Callback<void(ServiceWorkerStatusCode)> StatusCallback;
  enum Status {
    STOPPED,
    STARTING,
    RUNNING,
    STOPPING,
  };

  // This enum is used in UMA histograms, so don't change the order or remove
  // entries.
  enum StartingPhase {
    NOT_STARTING,
    ALLOCATING_PROCESS,
    REGISTERING_TO_DEVTOOLS,
    SENT_START_WORKER,
    SCRIPT_DOWNLOADING,
    SCRIPT_LOADED,
    SCRIPT_EVALUATED,
    STARTING_PHASE_MAX_VALUE,
  };

  class Listener {
   public:
    virtual ~Listener() {}
    virtual void OnScriptLoaded() {}
    virtual void OnStarting() {}
    virtual void OnStarted() {}
    virtual void OnStopping() {}
    // Received ACK from renderer that the worker context terminated.
    virtual void OnStopped(Status old_status) {}
    // The browser-side IPC endpoint for communication with the worker died.
    virtual void OnDetached(Status old_status) {}
    virtual void OnReportException(const base::string16& error_message,
                                   int line_number,
                                   int column_number,
                                   const GURL& source_url) {}
    virtual void OnReportConsoleMessage(int source_identifier,
                                        int message_level,
                                        const base::string16& message,
                                        int line_number,
                                        const GURL& source_url) {}
    // Returns false if the message is not handled by this listener.
    virtual bool OnMessageReceived(const IPC::Message& message) = 0;
  };

  ~EmbeddedWorkerInstance();

  // Starts the worker. It is invalid to call this when the worker is not in
  // STOPPED status. |callback| is invoked after the worker script has been
  // started and evaluated, or when an error occurs.
  void Start(int64 service_worker_version_id,
             const GURL& scope,
             const GURL& script_url,
             const StatusCallback& callback);

  // Stops the worker. It is invalid to call this when the worker is
  // not in STARTING or RUNNING status.
  // This returns false if stopping a worker fails immediately, e.g. when
  // IPC couldn't be sent to the worker.
  ServiceWorkerStatusCode Stop();

  // Stops the worker if the worker is not being debugged (i.e. devtools is
  // not attached). This method is called by a stop-worker timer to kill
  // idle workers.
  void StopIfIdle();

  // Sends |message| to the embedded worker running in the child process.
  // It is invalid to call this while the worker is not in STARTING or RUNNING
  // status.
  ServiceWorkerStatusCode SendMessage(const IPC::Message& message);

  // Returns the ServiceRegistry for this worker. It is invalid to call this
  // when the worker is not in STARTING or RUNNING status.
  ServiceRegistry* GetServiceRegistry();

  int embedded_worker_id() const { return embedded_worker_id_; }
  Status status() const { return status_; }
  StartingPhase starting_phase() const {
    DCHECK_EQ(STARTING, status());
    return starting_phase_;
  }
  int process_id() const { return process_id_; }
  int thread_id() const { return thread_id_; }
  int worker_devtools_agent_route_id() const;
  MessagePortMessageFilter* message_port_message_filter() const;

  void AddListener(Listener* listener);
  void RemoveListener(Listener* listener);

  void set_devtools_attached(bool attached) { devtools_attached_ = attached; }
  bool devtools_attached() const { return devtools_attached_; }

  // Called when the script load request accessed the network.
  void OnNetworkAccessedForScriptLoad();

  static std::string StatusToString(Status status);
  static std::string StartingPhaseToString(StartingPhase phase);

 private:
  typedef base::ObserverList<Listener> ListenerList;
  class DevToolsProxy;
  friend class EmbeddedWorkerRegistry;
  FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, StartAndStop);
  FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, DetachDuringStart);
  FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, StopDuringStart);

  // Constructor is called via EmbeddedWorkerRegistry::CreateWorker().
  // This instance holds a ref of |registry|.
  EmbeddedWorkerInstance(base::WeakPtr<ServiceWorkerContextCore> context,
                         int embedded_worker_id);

  // Called back from ServiceWorkerProcessManager after Start() passes control
  // to the UI thread to acquire a reference to the process.
  static void RunProcessAllocated(
      base::WeakPtr<EmbeddedWorkerInstance> instance,
      base::WeakPtr<ServiceWorkerContextCore> context,
      scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
      const EmbeddedWorkerInstance::StatusCallback& callback,
      ServiceWorkerStatusCode status,
      int process_id,
      bool is_new_process);
  void ProcessAllocated(scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
                        const StatusCallback& callback,
                        int process_id,
                        bool is_new_process,
                        ServiceWorkerStatusCode status);
  // Called back after ProcessAllocated() passes control to the UI thread to
  // register to WorkerDevToolsManager.
  void SendStartWorker(scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
                       const StatusCallback& callback,
                       bool is_new_process,
                       int worker_devtools_agent_route_id,
                       bool wait_for_debugger);

  // Called back from Registry when the worker instance has ack'ed that
  // it is ready for inspection.
  void OnReadyForInspection();

  // Called back from Registry when the worker instance has ack'ed that
  // it finished loading the script and has started a worker thread.
  void OnScriptLoaded(int thread_id);

  // Called back from Registry when the worker instance has ack'ed that
  // it failed to load the script.
  void OnScriptLoadFailed();

  // Called back from Registry when the worker instance has ack'ed that
  // it finished evaluating the script. This is called before OnStarted.
  void OnScriptEvaluated(bool success);

  // Called back from Registry when the worker instance has ack'ed that its
  // WorkerGlobalScope has actually started and evaluated the script. This is
  // called after OnScriptEvaluated.
  // This will change the internal status from STARTING to RUNNING.
  void OnStarted();

  // Called back from Registry when the worker instance has ack'ed that
  // its WorkerGlobalScope is actually stopped in the child process.
  // This will change the internal status from STARTING or RUNNING to
  // STOPPED.
  void OnStopped();
  // Called when ServiceWorkerDispatcherHost for the worker died while it was
  // running.
  void OnDetached();

  // Called back from Registry when the worker instance sends message
  // to the browser (i.e. EmbeddedWorker observers).
  // Returns false if the message is not handled.
  bool OnMessageReceived(const IPC::Message& message);

  // Called back from Registry when the worker instance reports the exception.
  void OnReportException(const base::string16& error_message,
                         int line_number,
                         int column_number,
                         const GURL& source_url);

  // Called back from Registry when the worker instance reports to the console.
  void OnReportConsoleMessage(int source_identifier,
                              int message_level,
                              const base::string16& message,
                              int line_number,
                              const GURL& source_url);

  // Resets all running state. After this function is called, |status_| is
  // STOPPED.
  void ReleaseProcess();
  // Called when the startup sequence failed. Calls ReleaseProcess() and invokes
  // |callback| with |status|. May destroy |this|.
  void OnStartFailed(const StatusCallback& callback,
                     ServiceWorkerStatusCode status);

  base::WeakPtr<ServiceWorkerContextCore> context_;
  scoped_refptr<EmbeddedWorkerRegistry> registry_;
  const int embedded_worker_id_;
  Status status_;
  StartingPhase starting_phase_;

  // Current running information. -1 indicates the worker is not running.
  int process_id_;
  int thread_id_;
  scoped_ptr<ServiceRegistryImpl> service_registry_;

  // Whether devtools is attached or not.
  bool devtools_attached_;

  // True if the script load request accessed the network. If the script was
  // served from HTTPCache or ServiceWorkerDatabase this value is false.
  bool network_accessed_for_script_;

  StatusCallback start_callback_;
  ListenerList listener_list_;
  scoped_ptr<DevToolsProxy> devtools_proxy_;

  base::TimeTicks start_timing_;

  base::WeakPtrFactory<EmbeddedWorkerInstance> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstance);
};

}  // namespace content

#endif  // CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_INSTANCE_H_