1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef COMPONENTS_GCM_DRIVER_GCM_CLIENT_IMPL_H_
6#define COMPONENTS_GCM_DRIVER_GCM_CLIENT_IMPL_H_
7
8#include <map>
9#include <string>
10#include <vector>
11
12#include "base/compiler_specific.h"
13#include "base/memory/ref_counted.h"
14#include "base/memory/weak_ptr.h"
15#include "base/stl_util.h"
16#include "components/gcm_driver/gcm_client.h"
17#include "components/gcm_driver/gcm_stats_recorder_impl.h"
18#include "google_apis/gcm/base/mcs_message.h"
19#include "google_apis/gcm/engine/gcm_store.h"
20#include "google_apis/gcm/engine/gservices_settings.h"
21#include "google_apis/gcm/engine/mcs_client.h"
22#include "google_apis/gcm/engine/registration_request.h"
23#include "google_apis/gcm/engine/unregistration_request.h"
24#include "google_apis/gcm/protocol/android_checkin.pb.h"
25#include "google_apis/gcm/protocol/checkin.pb.h"
26#include "net/base/net_log.h"
27#include "net/url_request/url_request_context_getter.h"
28
29class GURL;
30
31namespace base {
32class Clock;
33class Time;
34}  // namespace base
35
36namespace mcs_proto {
37class DataMessageStanza;
38}  // namespace mcs_proto
39
40namespace net {
41class HttpNetworkSession;
42}  // namespace net
43
44namespace gcm {
45
46class CheckinRequest;
47class ConnectionFactory;
48class GCMClientImplTest;
49
50// Helper class for building GCM internals. Allows tests to inject fake versions
51// as necessary.
52class GCMInternalsBuilder {
53 public:
54  GCMInternalsBuilder();
55  virtual ~GCMInternalsBuilder();
56
57  virtual scoped_ptr<base::Clock> BuildClock();
58  virtual scoped_ptr<MCSClient> BuildMCSClient(
59      const std::string& version,
60      base::Clock* clock,
61      ConnectionFactory* connection_factory,
62      GCMStore* gcm_store,
63      GCMStatsRecorder* recorder);
64  virtual scoped_ptr<ConnectionFactory> BuildConnectionFactory(
65      const std::vector<GURL>& endpoints,
66      const net::BackoffEntry::Policy& backoff_policy,
67      scoped_refptr<net::HttpNetworkSession> network_session,
68      net::NetLog* net_log,
69      GCMStatsRecorder* recorder);
70};
71
72// Implements the GCM Client. It is used to coordinate MCS Client (communication
73// with MCS) and other pieces of GCM infrastructure like Registration and
74// Checkins. It also allows for registering user delegates that host
75// applications that send and receive messages.
76class GCMClientImpl
77    : public GCMClient, public GCMStatsRecorder::Delegate,
78      public ConnectionFactory::ConnectionListener {
79 public:
80  explicit GCMClientImpl(scoped_ptr<GCMInternalsBuilder> internals_builder);
81  virtual ~GCMClientImpl();
82
83  // GCMClient implementation.
84  virtual void Initialize(
85      const ChromeBuildInfo& chrome_build_info,
86      const base::FilePath& store_path,
87      const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
88      const scoped_refptr<net::URLRequestContextGetter>&
89          url_request_context_getter,
90      scoped_ptr<Encryptor> encryptor,
91      GCMClient::Delegate* delegate) OVERRIDE;
92  virtual void Start() OVERRIDE;
93  virtual void Stop() OVERRIDE;
94  virtual void CheckOut() OVERRIDE;
95  virtual void Register(const std::string& app_id,
96                        const std::vector<std::string>& sender_ids) OVERRIDE;
97  virtual void Unregister(const std::string& app_id) OVERRIDE;
98  virtual void Send(const std::string& app_id,
99                    const std::string& receiver_id,
100                    const OutgoingMessage& message) OVERRIDE;
101  virtual void SetRecording(bool recording) OVERRIDE;
102  virtual void ClearActivityLogs() OVERRIDE;
103  virtual GCMStatistics GetStatistics() const OVERRIDE;
104
105  // GCMStatsRecorder::Delegate implemenation.
106  virtual void OnActivityRecorded() OVERRIDE;
107
108  // ConnectionFactory::ConnectionListener implementation.
109  virtual void OnConnected(const GURL& current_server,
110                           const net::IPEndPoint& ip_endpoint) OVERRIDE;
111  virtual void OnDisconnected() OVERRIDE;
112
113 private:
114  // State representation of the GCMClient.
115  // Any change made to this enum should have corresponding change in the
116  // GetStateString(...) function.
117  enum State {
118    // Uninitialized.
119    UNINITIALIZED,
120    // Initialized,
121    INITIALIZED,
122    // GCM store loading is in progress.
123    LOADING,
124    // Initial device checkin is in progress.
125    INITIAL_DEVICE_CHECKIN,
126    // Ready to accept requests.
127    READY,
128  };
129
130  // The check-in info for the user. Returned by the server.
131  struct CheckinInfo {
132    CheckinInfo() : android_id(0), secret(0) {}
133    bool IsValid() const { return android_id != 0 && secret != 0; }
134    void Reset() {
135      android_id = 0;
136      secret = 0;
137    }
138
139    uint64 android_id;
140    uint64 secret;
141  };
142
143  // Collection of pending registration requests. Keys are app IDs, while values
144  // are pending registration requests to obtain a registration ID for
145  // requesting application.
146  typedef std::map<std::string, RegistrationRequest*>
147      PendingRegistrationRequests;
148
149  // Collection of pending unregistration requests. Keys are app IDs, while
150  // values are pending unregistration requests to disable the registration ID
151  // currently assigned to the application.
152  typedef std::map<std::string, UnregistrationRequest*>
153      PendingUnregistrationRequests;
154
155  friend class GCMClientImplTest;
156
157  // Returns text representation of the enum State.
158  std::string GetStateString() const;
159
160  // Callbacks for the MCSClient.
161  // Receives messages and dispatches them to relevant user delegates.
162  void OnMessageReceivedFromMCS(const gcm::MCSMessage& message);
163  // Receives confirmation of sent messages or information about errors.
164  void OnMessageSentToMCS(int64 user_serial_number,
165                          const std::string& app_id,
166                          const std::string& message_id,
167                          MCSClient::MessageSendStatus status);
168  // Receives information about mcs_client_ errors.
169  void OnMCSError();
170
171  // Runs after GCM Store load is done to trigger continuation of the
172  // initialization.
173  void OnLoadCompleted(scoped_ptr<GCMStore::LoadResult> result);
174  // Initializes mcs_client_, which handles the connection to MCS.
175  void InitializeMCSClient(scoped_ptr<GCMStore::LoadResult> result);
176  // Complets the first time device checkin.
177  void OnFirstTimeDeviceCheckinCompleted(const CheckinInfo& checkin_info);
178  // Starts a login on mcs_client_.
179  void StartMCSLogin();
180  // Resets state to before initialization.
181  void ResetState();
182  // Sets state to ready. This will initiate the MCS login and notify the
183  // delegates.
184  void OnReady();
185
186  // Starts a first time device checkin.
187  void StartCheckin();
188  // Completes the device checkin request by parsing the |checkin_response|.
189  // Function also cleans up the pending checkin.
190  void OnCheckinCompleted(
191      const checkin_proto::AndroidCheckinResponse& checkin_response);
192
193  // Callback passed to GCMStore::SetGServicesSettings.
194  void SetGServicesSettingsCallback(bool success);
195
196  // Schedules next periodic device checkin and makes sure there is at most one
197  // pending checkin at a time. This function is meant to be called after a
198  // successful checkin.
199  void SchedulePeriodicCheckin();
200  // Gets the time until next checkin.
201  base::TimeDelta GetTimeToNextCheckin() const;
202  // Callback for setting last checkin time in the |gcm_store_|.
203  void SetLastCheckinTimeCallback(bool success);
204
205  // Callback for persisting device credentials in the |gcm_store_|.
206  void SetDeviceCredentialsCallback(bool success);
207
208  // Callback for persisting registration info in the |gcm_store_|.
209  void UpdateRegistrationCallback(bool success);
210
211  // Completes the registration request.
212  void OnRegisterCompleted(const std::string& app_id,
213                           const std::vector<std::string>& sender_ids,
214                           RegistrationRequest::Status status,
215                           const std::string& registration_id);
216
217  // Completes the unregistration request.
218  void OnUnregisterCompleted(const std::string& app_id,
219                             UnregistrationRequest::Status status);
220
221  // Completes the GCM store destroy request.
222  void OnGCMStoreDestroyed(bool success);
223
224  // Handles incoming data message and dispatches it the delegate of this class.
225  void HandleIncomingMessage(const gcm::MCSMessage& message);
226
227  // Fires OnMessageReceived event on the delegate of this class, based on the
228  // details in |data_message_stanza| and |message_data|.
229  void HandleIncomingDataMessage(
230      const mcs_proto::DataMessageStanza& data_message_stanza,
231      MessageData& message_data);
232
233  // Fires OnMessageSendError event on the delegate of this calss, based on the
234  // details in |data_message_stanza| and |message_data|.
235  void HandleIncomingSendError(
236      const mcs_proto::DataMessageStanza& data_message_stanza,
237      MessageData& message_data);
238
239  // Builder for the GCM internals (mcs client, etc.).
240  scoped_ptr<GCMInternalsBuilder> internals_builder_;
241
242  // Recorder that logs GCM activities.
243  GCMStatsRecorderImpl recorder_;
244
245  // State of the GCM Client Implementation.
246  State state_;
247
248  GCMClient::Delegate* delegate_;
249
250  // Device checkin info (android ID and security token used by device).
251  CheckinInfo device_checkin_info_;
252
253  // Clock used for timing of retry logic. Passed in for testing. Owned by
254  // GCMClientImpl.
255  scoped_ptr<base::Clock> clock_;
256
257  // Information about the chrome build.
258  // TODO(fgorski): Check if it can be passed in constructor and made const.
259  ChromeBuildInfo chrome_build_info_;
260
261  // Persistent data store for keeping device credentials, messages and user to
262  // serial number mappings.
263  scoped_ptr<GCMStore> gcm_store_;
264
265  scoped_refptr<net::HttpNetworkSession> network_session_;
266  net::BoundNetLog net_log_;
267  scoped_ptr<ConnectionFactory> connection_factory_;
268  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
269
270  // Controls receiving and sending of packets and reliable message queueing.
271  scoped_ptr<MCSClient> mcs_client_;
272
273  scoped_ptr<CheckinRequest> checkin_request_;
274
275  // Cached registration info.
276  RegistrationInfoMap registrations_;
277
278  // Currently pending registration requests. GCMClientImpl owns the
279  // RegistrationRequests.
280  PendingRegistrationRequests pending_registration_requests_;
281  STLValueDeleter<PendingRegistrationRequests>
282      pending_registration_requests_deleter_;
283
284  // Currently pending unregistration requests. GCMClientImpl owns the
285  // UnregistrationRequests.
286  PendingUnregistrationRequests pending_unregistration_requests_;
287  STLValueDeleter<PendingUnregistrationRequests>
288      pending_unregistration_requests_deleter_;
289
290  // G-services settings that were provided by MCS.
291  GServicesSettings gservices_settings_;
292
293  // Time of the last successful checkin.
294  base::Time last_checkin_time_;
295
296  // Factory for creating references when scheduling periodic checkin.
297  base::WeakPtrFactory<GCMClientImpl> periodic_checkin_ptr_factory_;
298
299  // Factory for creating references in callbacks.
300  base::WeakPtrFactory<GCMClientImpl> weak_ptr_factory_;
301
302  DISALLOW_COPY_AND_ASSIGN(GCMClientImpl);
303};
304
305}  // namespace gcm
306
307#endif  // COMPONENTS_GCM_DRIVER_GCM_CLIENT_IMPL_H_
308