gcm_client_impl.cc 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481
  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. #include "components/gcm_driver/gcm_client_impl.h"
  5. #include <stddef.h>
  6. #include <memory>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/files/file_path.h"
  10. #include "base/location.h"
  11. #include "base/logging.h"
  12. #include "base/memory/ptr_util.h"
  13. #include "base/metrics/histogram_functions.h"
  14. #include "base/metrics/histogram_macros.h"
  15. #include "base/strings/string_number_conversions.h"
  16. #include "base/task/sequenced_task_runner.h"
  17. #include "base/task/single_thread_task_runner.h"
  18. #include "base/time/default_clock.h"
  19. #include "base/timer/timer.h"
  20. #include "components/crx_file/id_util.h"
  21. #include "components/gcm_driver/crypto/gcm_decryption_result.h"
  22. #include "components/gcm_driver/features.h"
  23. #include "components/gcm_driver/gcm_account_mapper.h"
  24. #include "components/gcm_driver/gcm_backoff_policy.h"
  25. #include "google_apis/gcm/base/encryptor.h"
  26. #include "google_apis/gcm/base/mcs_message.h"
  27. #include "google_apis/gcm/base/mcs_util.h"
  28. #include "google_apis/gcm/engine/checkin_request.h"
  29. #include "google_apis/gcm/engine/connection_factory_impl.h"
  30. #include "google_apis/gcm/engine/gcm_registration_request_handler.h"
  31. #include "google_apis/gcm/engine/gcm_store_impl.h"
  32. #include "google_apis/gcm/engine/gcm_unregistration_request_handler.h"
  33. #include "google_apis/gcm/engine/instance_id_delete_token_request_handler.h"
  34. #include "google_apis/gcm/engine/instance_id_get_token_request_handler.h"
  35. #include "google_apis/gcm/monitoring/gcm_stats_recorder.h"
  36. #include "google_apis/gcm/protocol/checkin.pb.h"
  37. #include "google_apis/gcm/protocol/mcs.pb.h"
  38. #include "services/network/public/cpp/shared_url_loader_factory.h"
  39. #include "url/gurl.h"
  40. namespace gcm {
  41. // It is okay to append to the enum if these states grow. DO NOT reorder,
  42. // renumber or otherwise reuse existing values.
  43. // Do not assign an explicit value to REGISTRATION_CACHE_STATUS_COUNT, as
  44. // this lets the compiler keep it up to date.
  45. enum class RegistrationCacheStatus {
  46. REGISTRATION_NOT_FOUND = 0,
  47. REGISTRATION_FOUND_AND_FRESH = 1,
  48. REGISTRATION_FOUND_BUT_STALE = 2,
  49. REGISTRATION_FOUND_BUT_SENDERS_DONT_MATCH = 3,
  50. // NOTE: always keep this entry at the end. Add new value only immediately
  51. // above this line. Make sure to update the corresponding histogram enum
  52. // accordingly.
  53. REGISTRATION_CACHE_STATUS_COUNT
  54. };
  55. namespace {
  56. // Indicates a message type of the received message.
  57. enum MessageType {
  58. UNKNOWN, // Undetermined type.
  59. DATA_MESSAGE, // Regular data message.
  60. DELETED_MESSAGES, // Messages were deleted on the server.
  61. SEND_ERROR, // Error sending a message.
  62. };
  63. enum ResetStoreError {
  64. DESTROYING_STORE_FAILED,
  65. INFINITE_STORE_RESET,
  66. // NOTE: always keep this entry at the end. Add new value only immediately
  67. // above this line. Make sure to update the corresponding histogram enum
  68. // accordingly.
  69. RESET_STORE_ERROR_COUNT
  70. };
  71. const int kMaxRegistrationRetries = 5;
  72. const int kMaxUnregistrationRetries = 5;
  73. const char kDeletedCountKey[] = "total_deleted";
  74. const char kMessageTypeDataMessage[] = "gcm";
  75. const char kMessageTypeDeletedMessagesKey[] = "deleted_messages";
  76. const char kMessageTypeKey[] = "message_type";
  77. const char kMessageTypeSendErrorKey[] = "send_error";
  78. const char kSubtypeKey[] = "subtype";
  79. const char kSendMessageFromValue[] = "gcm@chrome.com";
  80. const int64_t kDefaultUserSerialNumber = 0LL;
  81. const int kDestroyGCMStoreDelayMS = 5 * 60 * 1000; // 5 minutes.
  82. GCMClient::Result ToGCMClientResult(MCSClient::MessageSendStatus status) {
  83. switch (status) {
  84. case MCSClient::QUEUED:
  85. return GCMClient::SUCCESS;
  86. case MCSClient::MESSAGE_TOO_LARGE:
  87. return GCMClient::INVALID_PARAMETER;
  88. case MCSClient::QUEUE_SIZE_LIMIT_REACHED:
  89. case MCSClient::APP_QUEUE_SIZE_LIMIT_REACHED:
  90. case MCSClient::NO_CONNECTION_ON_ZERO_TTL:
  91. case MCSClient::TTL_EXCEEDED:
  92. return GCMClient::NETWORK_ERROR;
  93. case MCSClient::SENT:
  94. case MCSClient::SEND_STATUS_COUNT:
  95. NOTREACHED();
  96. break;
  97. }
  98. return GCMClientImpl::UNKNOWN_ERROR;
  99. }
  100. void ToCheckinProtoVersion(
  101. const GCMClient::ChromeBuildInfo& chrome_build_info,
  102. checkin_proto::ChromeBuildProto* android_build_info) {
  103. checkin_proto::ChromeBuildProto_Platform platform =
  104. checkin_proto::ChromeBuildProto_Platform_PLATFORM_LINUX;
  105. switch (chrome_build_info.platform) {
  106. case GCMClient::PLATFORM_WIN:
  107. platform = checkin_proto::ChromeBuildProto_Platform_PLATFORM_WIN;
  108. break;
  109. case GCMClient::PLATFORM_MAC:
  110. platform = checkin_proto::ChromeBuildProto_Platform_PLATFORM_MAC;
  111. break;
  112. case GCMClient::PLATFORM_LINUX:
  113. platform = checkin_proto::ChromeBuildProto_Platform_PLATFORM_LINUX;
  114. break;
  115. case GCMClient::PLATFORM_IOS:
  116. platform = checkin_proto::ChromeBuildProto_Platform_PLATFORM_IOS;
  117. break;
  118. case GCMClient::PLATFORM_ANDROID:
  119. platform = checkin_proto::ChromeBuildProto_Platform_PLATFORM_ANDROID;
  120. break;
  121. case GCMClient::PLATFORM_CROS:
  122. platform = checkin_proto::ChromeBuildProto_Platform_PLATFORM_CROS;
  123. break;
  124. case GCMClient::PLATFORM_UNSPECIFIED:
  125. // For unknown platform, return as LINUX.
  126. platform = checkin_proto::ChromeBuildProto_Platform_PLATFORM_LINUX;
  127. break;
  128. }
  129. android_build_info->set_platform(platform);
  130. checkin_proto::ChromeBuildProto_Channel channel =
  131. checkin_proto::ChromeBuildProto_Channel_CHANNEL_UNKNOWN;
  132. switch (chrome_build_info.channel) {
  133. case GCMClient::CHANNEL_STABLE:
  134. channel = checkin_proto::ChromeBuildProto_Channel_CHANNEL_STABLE;
  135. break;
  136. case GCMClient::CHANNEL_BETA:
  137. channel = checkin_proto::ChromeBuildProto_Channel_CHANNEL_BETA;
  138. break;
  139. case GCMClient::CHANNEL_DEV:
  140. channel = checkin_proto::ChromeBuildProto_Channel_CHANNEL_DEV;
  141. break;
  142. case GCMClient::CHANNEL_CANARY:
  143. channel = checkin_proto::ChromeBuildProto_Channel_CHANNEL_CANARY;
  144. break;
  145. case GCMClient::CHANNEL_UNKNOWN:
  146. channel = checkin_proto::ChromeBuildProto_Channel_CHANNEL_UNKNOWN;
  147. break;
  148. }
  149. android_build_info->set_channel(channel);
  150. android_build_info->set_chrome_version(chrome_build_info.version);
  151. }
  152. MessageType DecodeMessageType(const std::string& value) {
  153. if (kMessageTypeDeletedMessagesKey == value)
  154. return DELETED_MESSAGES;
  155. if (kMessageTypeSendErrorKey == value)
  156. return SEND_ERROR;
  157. if (kMessageTypeDataMessage == value)
  158. return DATA_MESSAGE;
  159. return UNKNOWN;
  160. }
  161. int ConstructGCMVersion(const std::string& chrome_version) {
  162. // Major Chrome version is passed as GCM version.
  163. size_t pos = chrome_version.find('.');
  164. if (pos == std::string::npos) {
  165. NOTREACHED();
  166. return 0;
  167. }
  168. int gcm_version = 0;
  169. base::StringToInt(
  170. base::StringPiece(chrome_version.c_str(), pos), &gcm_version);
  171. return gcm_version;
  172. }
  173. std::string SerializeInstanceIDData(const std::string& instance_id,
  174. const std::string& extra_data) {
  175. DCHECK(!instance_id.empty() && !extra_data.empty());
  176. DCHECK(instance_id.find(',') == std::string::npos);
  177. return instance_id + "," + extra_data;
  178. }
  179. bool DeserializeInstanceIDData(const std::string& serialized_data,
  180. std::string* instance_id,
  181. std::string* extra_data) {
  182. DCHECK(instance_id && extra_data);
  183. std::size_t pos = serialized_data.find(',');
  184. if (pos == std::string::npos)
  185. return false;
  186. *instance_id = serialized_data.substr(0, pos);
  187. *extra_data = serialized_data.substr(pos + 1);
  188. return !instance_id->empty() && !extra_data->empty();
  189. }
  190. bool InstanceIDUsesSubtypeForAppId(const std::string& app_id) {
  191. // Always use subtypes with Instance ID, except for Chrome Apps/Extensions.
  192. return !crx_file::id_util::IdIsValid(app_id);
  193. }
  194. void RecordResetStoreErrorToUMA(ResetStoreError error) {
  195. UMA_HISTOGRAM_ENUMERATION("GCM.ResetStore", error, RESET_STORE_ERROR_COUNT);
  196. }
  197. } // namespace
  198. void RecordRegistrationRequestToUMA(gcm::RegistrationCacheStatus status) {
  199. UMA_HISTOGRAM_ENUMERATION(
  200. "GCM.RegistrationCacheStatus", status,
  201. RegistrationCacheStatus::REGISTRATION_CACHE_STATUS_COUNT);
  202. }
  203. GCMInternalsBuilder::GCMInternalsBuilder() {}
  204. GCMInternalsBuilder::~GCMInternalsBuilder() {}
  205. base::Clock* GCMInternalsBuilder::GetClock() {
  206. return base::DefaultClock::GetInstance();
  207. }
  208. std::unique_ptr<MCSClient> GCMInternalsBuilder::BuildMCSClient(
  209. const std::string& version,
  210. base::Clock* clock,
  211. ConnectionFactory* connection_factory,
  212. GCMStore* gcm_store,
  213. scoped_refptr<base::SequencedTaskRunner> io_task_runner,
  214. GCMStatsRecorder* recorder) {
  215. return std::make_unique<MCSClient>(version, clock, connection_factory,
  216. gcm_store, std::move(io_task_runner),
  217. recorder);
  218. }
  219. std::unique_ptr<ConnectionFactory> GCMInternalsBuilder::BuildConnectionFactory(
  220. const std::vector<GURL>& endpoints,
  221. const net::BackoffEntry::Policy& backoff_policy,
  222. base::RepeatingCallback<void(
  223. mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>)>
  224. get_socket_factory_callback,
  225. scoped_refptr<base::SequencedTaskRunner> io_task_runner,
  226. GCMStatsRecorder* recorder,
  227. network::NetworkConnectionTracker* network_connection_tracker) {
  228. return std::make_unique<ConnectionFactoryImpl>(
  229. endpoints, backoff_policy, std::move(get_socket_factory_callback),
  230. std::move(io_task_runner), recorder, network_connection_tracker);
  231. }
  232. GCMClientImpl::CheckinInfo::CheckinInfo()
  233. : android_id(0), secret(0), accounts_set(false) {
  234. }
  235. GCMClientImpl::CheckinInfo::~CheckinInfo() {
  236. }
  237. void GCMClientImpl::CheckinInfo::SnapshotCheckinAccounts() {
  238. last_checkin_accounts.clear();
  239. for (auto iter = account_tokens.begin(); iter != account_tokens.end();
  240. ++iter) {
  241. last_checkin_accounts.insert(iter->first);
  242. }
  243. }
  244. void GCMClientImpl::CheckinInfo::Reset() {
  245. android_id = 0;
  246. secret = 0;
  247. accounts_set = false;
  248. account_tokens.clear();
  249. last_checkin_accounts.clear();
  250. }
  251. GCMClientImpl::GCMClientImpl(
  252. std::unique_ptr<GCMInternalsBuilder> internals_builder)
  253. : internals_builder_(std::move(internals_builder)),
  254. state_(UNINITIALIZED),
  255. delegate_(nullptr),
  256. start_mode_(DELAYED_START),
  257. clock_(internals_builder_->GetClock()),
  258. gcm_store_reset_(false),
  259. network_connection_tracker_(nullptr) {}
  260. GCMClientImpl::~GCMClientImpl() {
  261. }
  262. void GCMClientImpl::Initialize(
  263. const ChromeBuildInfo& chrome_build_info,
  264. const base::FilePath& path,
  265. bool remove_account_mappings_with_email_key,
  266. const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
  267. scoped_refptr<base::SequencedTaskRunner> io_task_runner,
  268. base::RepeatingCallback<void(
  269. mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>)>
  270. get_socket_factory_callback,
  271. const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
  272. network::NetworkConnectionTracker* network_connection_tracker,
  273. std::unique_ptr<Encryptor> encryptor,
  274. GCMClient::Delegate* delegate) {
  275. DCHECK_EQ(UNINITIALIZED, state_);
  276. DCHECK(delegate);
  277. DCHECK(io_task_runner);
  278. DCHECK(io_task_runner->RunsTasksInCurrentSequence());
  279. get_socket_factory_callback_ = std::move(get_socket_factory_callback);
  280. url_loader_factory_ = url_loader_factory;
  281. network_connection_tracker_ = network_connection_tracker;
  282. chrome_build_info_ = chrome_build_info;
  283. gcm_store_ = std::make_unique<GCMStoreImpl>(
  284. path, remove_account_mappings_with_email_key, blocking_task_runner,
  285. std::move(encryptor));
  286. delegate_ = delegate;
  287. io_task_runner_ = std::move(io_task_runner);
  288. recorder_.SetDelegate(this);
  289. state_ = INITIALIZED;
  290. }
  291. void GCMClientImpl::Start(StartMode start_mode) {
  292. DCHECK_NE(UNINITIALIZED, state_);
  293. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  294. if (state_ == LOADED) {
  295. // Start the GCM if not yet.
  296. if (start_mode == IMMEDIATE_START) {
  297. // Give up the scheduling to wipe out the store since now some one starts
  298. // to use GCM.
  299. destroying_gcm_store_ptr_factory_.InvalidateWeakPtrs();
  300. StartGCM();
  301. }
  302. return;
  303. }
  304. // The delay start behavior will be abandoned when Start has been called
  305. // once with IMMEDIATE_START behavior.
  306. if (start_mode == IMMEDIATE_START)
  307. start_mode_ = IMMEDIATE_START;
  308. // Bail out if the loading is not started or completed.
  309. if (state_ != INITIALIZED)
  310. return;
  311. // Once the loading is completed, the check-in will be initiated.
  312. // If we're in lazy start mode, don't create a new store since none is really
  313. // using GCM functionality yet.
  314. gcm_store_->Load((start_mode == IMMEDIATE_START) ? GCMStore::CREATE_IF_MISSING
  315. : GCMStore::DO_NOT_CREATE,
  316. base::BindOnce(&GCMClientImpl::OnLoadCompleted,
  317. weak_ptr_factory_.GetWeakPtr()));
  318. state_ = LOADING;
  319. }
  320. void GCMClientImpl::OnLoadCompleted(
  321. std::unique_ptr<GCMStore::LoadResult> result) {
  322. DCHECK_EQ(LOADING, state_);
  323. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  324. if (!result->success) {
  325. if (result->store_does_not_exist) {
  326. if (start_mode_ == IMMEDIATE_START) {
  327. // An immediate start was requested during the delayed start that just
  328. // completed. Perform it now.
  329. gcm_store_->Load(GCMStore::CREATE_IF_MISSING,
  330. base::BindOnce(&GCMClientImpl::OnLoadCompleted,
  331. weak_ptr_factory_.GetWeakPtr()));
  332. } else {
  333. // In the case that the store does not exist, set |state_| back to
  334. // INITIALIZED such that store loading could be triggered again when
  335. // Start() is called with IMMEDIATE_START.
  336. state_ = INITIALIZED;
  337. }
  338. } else {
  339. // Otherwise, destroy the store to try again.
  340. ResetStore();
  341. }
  342. return;
  343. }
  344. gcm_store_reset_ = false;
  345. device_checkin_info_.android_id = result->device_android_id;
  346. device_checkin_info_.secret = result->device_security_token;
  347. device_checkin_info_.last_checkin_accounts = result->last_checkin_accounts;
  348. // A case where there were previously no accounts reported with checkin is
  349. // considered to be the same as when the list of accounts is empty. It enables
  350. // scheduling a periodic checkin for devices with no signed in users
  351. // immediately after restart, while keeping |accounts_set == false| delays the
  352. // checkin until the list of accounts is set explicitly.
  353. if (result->last_checkin_accounts.size() == 0)
  354. device_checkin_info_.accounts_set = true;
  355. last_checkin_time_ = result->last_checkin_time;
  356. gservices_settings_.UpdateFromLoadResult(*result);
  357. for (auto iter = result->registrations.begin();
  358. iter != result->registrations.end();
  359. ++iter) {
  360. std::string registration_id;
  361. scoped_refptr<RegistrationInfo> registration =
  362. RegistrationInfo::BuildFromString(iter->first, iter->second,
  363. &registration_id);
  364. // TODO(jianli): Add UMA to track the error case.
  365. if (registration)
  366. registrations_.emplace(std::move(registration), registration_id);
  367. }
  368. for (auto iter = result->instance_id_data.begin();
  369. iter != result->instance_id_data.end();
  370. ++iter) {
  371. std::string instance_id;
  372. std::string extra_data;
  373. if (DeserializeInstanceIDData(iter->second, &instance_id, &extra_data))
  374. instance_id_data_[iter->first] = std::make_pair(instance_id, extra_data);
  375. }
  376. load_result_ = std::move(result);
  377. state_ = LOADED;
  378. // Don't initiate the GCM connection when GCM is in delayed start mode and
  379. // not any standalone app has registered GCM yet.
  380. if (start_mode_ == DELAYED_START && !HasStandaloneRegisteredApp()) {
  381. // If no standalone app is using GCM and the device ID is present, schedule
  382. // to have the store wiped out.
  383. if (device_checkin_info_.android_id) {
  384. io_task_runner_->PostDelayedTask(
  385. FROM_HERE,
  386. base::BindOnce(&GCMClientImpl::DestroyStoreWhenNotNeeded,
  387. destroying_gcm_store_ptr_factory_.GetWeakPtr()),
  388. base::Milliseconds(kDestroyGCMStoreDelayMS));
  389. }
  390. return;
  391. }
  392. StartGCM();
  393. }
  394. void GCMClientImpl::StartGCM() {
  395. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  396. // Taking over the value of account_mappings before passing the ownership of
  397. // load result to InitializeMCSClient.
  398. std::vector<AccountMapping> account_mappings;
  399. account_mappings.swap(load_result_->account_mappings);
  400. base::Time last_token_fetch_time = load_result_->last_token_fetch_time;
  401. InitializeMCSClient();
  402. if (device_checkin_info_.IsValid()) {
  403. SchedulePeriodicCheckin();
  404. OnReady(account_mappings, last_token_fetch_time);
  405. return;
  406. }
  407. state_ = INITIAL_DEVICE_CHECKIN;
  408. device_checkin_info_.Reset();
  409. StartCheckin();
  410. }
  411. void GCMClientImpl::InitializeMCSClient() {
  412. DCHECK(network_connection_tracker_);
  413. std::vector<GURL> endpoints;
  414. endpoints.push_back(gservices_settings_.GetMCSMainEndpoint());
  415. GURL fallback_endpoint = gservices_settings_.GetMCSFallbackEndpoint();
  416. if (fallback_endpoint.is_valid())
  417. endpoints.push_back(fallback_endpoint);
  418. connection_factory_ = internals_builder_->BuildConnectionFactory(
  419. endpoints, GetGCMBackoffPolicy(), get_socket_factory_callback_,
  420. io_task_runner_, &recorder_, network_connection_tracker_);
  421. connection_factory_->SetConnectionListener(this);
  422. mcs_client_ = internals_builder_->BuildMCSClient(
  423. chrome_build_info_.version, clock_, connection_factory_.get(),
  424. gcm_store_.get(), io_task_runner_, &recorder_);
  425. mcs_client_->Initialize(
  426. base::BindRepeating(&GCMClientImpl::OnMCSError,
  427. weak_ptr_factory_.GetWeakPtr()),
  428. base::BindRepeating(&GCMClientImpl::OnMessageReceivedFromMCS,
  429. weak_ptr_factory_.GetWeakPtr()),
  430. base::BindRepeating(&GCMClientImpl::OnMessageSentToMCS,
  431. weak_ptr_factory_.GetWeakPtr()),
  432. std::move(load_result_));
  433. }
  434. void GCMClientImpl::OnFirstTimeDeviceCheckinCompleted(
  435. const CheckinInfo& checkin_info) {
  436. DCHECK(!device_checkin_info_.IsValid());
  437. device_checkin_info_.android_id = checkin_info.android_id;
  438. device_checkin_info_.secret = checkin_info.secret;
  439. // If accounts were not set by now, we can consider them set (to empty list)
  440. // to make sure periodic checkins get scheduled after initial checkin.
  441. device_checkin_info_.accounts_set = true;
  442. gcm_store_->SetDeviceCredentials(
  443. checkin_info.android_id, checkin_info.secret,
  444. base::BindOnce(&GCMClientImpl::SetDeviceCredentialsCallback,
  445. weak_ptr_factory_.GetWeakPtr()));
  446. OnReady(std::vector<AccountMapping>(), base::Time());
  447. }
  448. void GCMClientImpl::OnReady(const std::vector<AccountMapping>& account_mappings,
  449. const base::Time& last_token_fetch_time) {
  450. state_ = READY;
  451. StartMCSLogin();
  452. delegate_->OnGCMReady(account_mappings, last_token_fetch_time);
  453. }
  454. void GCMClientImpl::StartMCSLogin() {
  455. DCHECK_EQ(READY, state_);
  456. DCHECK(device_checkin_info_.IsValid());
  457. mcs_client_->Login(device_checkin_info_.android_id,
  458. device_checkin_info_.secret);
  459. }
  460. void GCMClientImpl::DestroyStoreWhenNotNeeded() {
  461. if (state_ != LOADED || start_mode_ != DELAYED_START)
  462. return;
  463. gcm_store_->Destroy(base::BindOnce(&GCMClientImpl::DestroyStoreCallback,
  464. weak_ptr_factory_.GetWeakPtr()));
  465. }
  466. void GCMClientImpl::ResetStore() {
  467. // If already being reset, don't do it again. We want to prevent from
  468. // resetting and loading from the store again and again.
  469. if (gcm_store_reset_) {
  470. RecordResetStoreErrorToUMA(INFINITE_STORE_RESET);
  471. state_ = UNINITIALIZED;
  472. return;
  473. }
  474. gcm_store_reset_ = true;
  475. // Destroy the GCM store to start over.
  476. gcm_store_->Destroy(base::BindOnce(&GCMClientImpl::ResetStoreCallback,
  477. weak_ptr_factory_.GetWeakPtr()));
  478. }
  479. void GCMClientImpl::SetAccountTokens(
  480. const std::vector<AccountTokenInfo>& account_tokens) {
  481. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  482. device_checkin_info_.account_tokens.clear();
  483. for (auto iter = account_tokens.begin(); iter != account_tokens.end();
  484. ++iter) {
  485. device_checkin_info_.account_tokens[iter->email] = iter->access_token;
  486. }
  487. bool accounts_set_before = device_checkin_info_.accounts_set;
  488. device_checkin_info_.accounts_set = true;
  489. DVLOG(1) << "Set account called with: " << account_tokens.size()
  490. << " accounts.";
  491. if (state_ != READY && state_ != INITIAL_DEVICE_CHECKIN)
  492. return;
  493. bool account_removed = false;
  494. for (auto iter = device_checkin_info_.last_checkin_accounts.begin();
  495. iter != device_checkin_info_.last_checkin_accounts.end(); ++iter) {
  496. if (device_checkin_info_.account_tokens.find(*iter) ==
  497. device_checkin_info_.account_tokens.end()) {
  498. account_removed = true;
  499. }
  500. }
  501. // Checkin will be forced when any of the accounts was removed during the
  502. // current Chrome session or if there has been an account removed between the
  503. // restarts of Chrome. If there is a checkin in progress, it will be canceled.
  504. // We only force checkin when user signs out. When there is a new account
  505. // signed in, the periodic checkin will take care of adding the association in
  506. // reasonable time.
  507. if (account_removed) {
  508. DVLOG(1) << "Detected that account has been removed. Forcing checkin.";
  509. checkin_request_.reset();
  510. StartCheckin();
  511. } else if (!accounts_set_before) {
  512. SchedulePeriodicCheckin();
  513. DVLOG(1) << "Accounts set for the first time. Scheduled periodic checkin.";
  514. }
  515. }
  516. void GCMClientImpl::UpdateAccountMapping(
  517. const AccountMapping& account_mapping) {
  518. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  519. gcm_store_->AddAccountMapping(
  520. account_mapping, base::BindOnce(&GCMClientImpl::DefaultStoreCallback,
  521. weak_ptr_factory_.GetWeakPtr()));
  522. }
  523. void GCMClientImpl::RemoveAccountMapping(const CoreAccountId& account_id) {
  524. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  525. gcm_store_->RemoveAccountMapping(
  526. account_id, base::BindOnce(&GCMClientImpl::DefaultStoreCallback,
  527. weak_ptr_factory_.GetWeakPtr()));
  528. }
  529. void GCMClientImpl::SetLastTokenFetchTime(const base::Time& time) {
  530. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  531. gcm_store_->SetLastTokenFetchTime(
  532. time,
  533. base::BindOnce(&GCMClientImpl::IgnoreWriteResultCallback,
  534. weak_ptr_factory_.GetWeakPtr(),
  535. /*operation_suffix_for_uma=*/"SetLastTokenFetchTime"));
  536. }
  537. void GCMClientImpl::UpdateHeartbeatTimer(
  538. std::unique_ptr<base::RetainingOneShotTimer> timer) {
  539. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  540. DCHECK(mcs_client_);
  541. mcs_client_->UpdateHeartbeatTimer(std::move(timer));
  542. }
  543. void GCMClientImpl::AddInstanceIDData(const std::string& app_id,
  544. const std::string& instance_id,
  545. const std::string& extra_data) {
  546. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  547. instance_id_data_[app_id] = std::make_pair(instance_id, extra_data);
  548. // TODO(crbug/1028761): If this call fails, we likely leak a registration
  549. // (the one stored in instance_id_data_ would be used for a registration but
  550. // not persisted).
  551. gcm_store_->AddInstanceIDData(
  552. app_id, SerializeInstanceIDData(instance_id, extra_data),
  553. base::BindOnce(&GCMClientImpl::IgnoreWriteResultCallback,
  554. weak_ptr_factory_.GetWeakPtr(),
  555. /*operation_suffix_for_uma=*/"AddInstanceIDData"));
  556. }
  557. void GCMClientImpl::RemoveInstanceIDData(const std::string& app_id) {
  558. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  559. instance_id_data_.erase(app_id);
  560. gcm_store_->RemoveInstanceIDData(
  561. app_id,
  562. base::BindOnce(&GCMClientImpl::IgnoreWriteResultCallback,
  563. weak_ptr_factory_.GetWeakPtr(),
  564. /*operation_suffix_for_uma=*/"RemoveInstanceIDData"));
  565. }
  566. void GCMClientImpl::GetInstanceIDData(const std::string& app_id,
  567. std::string* instance_id,
  568. std::string* extra_data) {
  569. DCHECK(instance_id && extra_data);
  570. auto iter = instance_id_data_.find(app_id);
  571. if (iter == instance_id_data_.end())
  572. return;
  573. *instance_id = iter->second.first;
  574. *extra_data = iter->second.second;
  575. }
  576. void GCMClientImpl::AddHeartbeatInterval(const std::string& scope,
  577. int interval_ms) {
  578. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  579. DCHECK(mcs_client_);
  580. mcs_client_->AddHeartbeatInterval(scope, interval_ms);
  581. }
  582. void GCMClientImpl::RemoveHeartbeatInterval(const std::string& scope) {
  583. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  584. DCHECK(mcs_client_);
  585. mcs_client_->RemoveHeartbeatInterval(scope);
  586. }
  587. void GCMClientImpl::StartCheckin() {
  588. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  589. // Make sure no checkin is in progress.
  590. if (checkin_request_)
  591. return;
  592. checkin_proto::ChromeBuildProto chrome_build_proto;
  593. ToCheckinProtoVersion(chrome_build_info_, &chrome_build_proto);
  594. CheckinRequest::RequestInfo request_info(device_checkin_info_.android_id,
  595. device_checkin_info_.secret,
  596. device_checkin_info_.account_tokens,
  597. gservices_settings_.digest(),
  598. chrome_build_proto);
  599. checkin_request_ = std::make_unique<CheckinRequest>(
  600. gservices_settings_.GetCheckinURL(), request_info, GetGCMBackoffPolicy(),
  601. base::BindOnce(&GCMClientImpl::OnCheckinCompleted,
  602. weak_ptr_factory_.GetWeakPtr()),
  603. url_loader_factory_, io_task_runner_, &recorder_);
  604. // Taking a snapshot of the accounts count here, as there might be an asynch
  605. // update of the account tokens while checkin is in progress.
  606. device_checkin_info_.SnapshotCheckinAccounts();
  607. checkin_request_->Start();
  608. }
  609. void GCMClientImpl::OnCheckinCompleted(
  610. net::HttpStatusCode response_code,
  611. const checkin_proto::AndroidCheckinResponse& checkin_response) {
  612. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  613. checkin_request_.reset();
  614. if (response_code == net::HTTP_UNAUTHORIZED ||
  615. response_code == net::HTTP_BAD_REQUEST) {
  616. LOG(ERROR) << "Checkin rejected. Resetting GCM Store.";
  617. ResetStore();
  618. return;
  619. }
  620. DCHECK(checkin_response.has_android_id());
  621. DCHECK(checkin_response.has_security_token());
  622. CheckinInfo checkin_info;
  623. checkin_info.android_id = checkin_response.android_id();
  624. checkin_info.secret = checkin_response.security_token();
  625. if (state_ == INITIAL_DEVICE_CHECKIN) {
  626. OnFirstTimeDeviceCheckinCompleted(checkin_info);
  627. } else {
  628. // checkin_info is not expected to change after a periodic checkin as it
  629. // would invalidate the registration IDs.
  630. DCHECK_EQ(READY, state_);
  631. DCHECK_EQ(device_checkin_info_.android_id, checkin_info.android_id);
  632. DCHECK_EQ(device_checkin_info_.secret, checkin_info.secret);
  633. }
  634. if (device_checkin_info_.IsValid()) {
  635. // First update G-services settings, as something might have changed.
  636. if (gservices_settings_.UpdateFromCheckinResponse(checkin_response)) {
  637. gcm_store_->SetGServicesSettings(
  638. gservices_settings_.settings_map(), gservices_settings_.digest(),
  639. base::BindOnce(&GCMClientImpl::SetGServicesSettingsCallback,
  640. weak_ptr_factory_.GetWeakPtr()));
  641. }
  642. last_checkin_time_ = clock_->Now();
  643. gcm_store_->SetLastCheckinInfo(
  644. last_checkin_time_, device_checkin_info_.last_checkin_accounts,
  645. base::BindOnce(&GCMClientImpl::SetLastCheckinInfoCallback,
  646. weak_ptr_factory_.GetWeakPtr()));
  647. SchedulePeriodicCheckin();
  648. }
  649. }
  650. void GCMClientImpl::SetGServicesSettingsCallback(bool success) {
  651. DCHECK(success);
  652. }
  653. void GCMClientImpl::SchedulePeriodicCheckin() {
  654. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  655. // Make sure no checkin is in progress.
  656. if (checkin_request_.get() || !device_checkin_info_.accounts_set)
  657. return;
  658. // There should be only one periodic checkin pending at a time. Removing
  659. // pending periodic checkin to schedule a new one.
  660. periodic_checkin_ptr_factory_.InvalidateWeakPtrs();
  661. base::TimeDelta time_to_next_checkin = GetTimeToNextCheckin();
  662. if (time_to_next_checkin.is_negative())
  663. time_to_next_checkin = base::TimeDelta();
  664. io_task_runner_->PostDelayedTask(
  665. FROM_HERE,
  666. base::BindOnce(&GCMClientImpl::StartCheckin,
  667. periodic_checkin_ptr_factory_.GetWeakPtr()),
  668. time_to_next_checkin);
  669. }
  670. base::TimeDelta GCMClientImpl::GetTimeToNextCheckin() const {
  671. return last_checkin_time_ + gservices_settings_.GetCheckinInterval() -
  672. clock_->Now();
  673. }
  674. void GCMClientImpl::SetLastCheckinInfoCallback(bool success) {
  675. // TODO(fgorski): This is one of the signals that store needs a rebuild.
  676. DCHECK(success);
  677. }
  678. void GCMClientImpl::SetDeviceCredentialsCallback(bool success) {
  679. // TODO(fgorski): This is one of the signals that store needs a rebuild.
  680. DCHECK(success);
  681. }
  682. void GCMClientImpl::UpdateRegistrationCallback(bool success) {
  683. // TODO(fgorski): This is one of the signals that store needs a rebuild.
  684. DCHECK(success);
  685. }
  686. void GCMClientImpl::DefaultStoreCallback(bool success) {
  687. DCHECK(success);
  688. }
  689. void GCMClientImpl::IgnoreWriteResultCallback(
  690. const std::string& operation_suffix_for_uma,
  691. bool success) {
  692. // TODO(crbug.com/1081149): Implement proper error handling.
  693. // TODO(fgorski): Ignoring the write result for now to make sure
  694. // sync_intergration_tests are not broken.
  695. }
  696. void GCMClientImpl::DestroyStoreCallback(bool success) {
  697. ResetCache();
  698. if (!success) {
  699. LOG(ERROR) << "Failed to destroy GCM store";
  700. RecordResetStoreErrorToUMA(DESTROYING_STORE_FAILED);
  701. state_ = UNINITIALIZED;
  702. return;
  703. }
  704. state_ = INITIALIZED;
  705. }
  706. void GCMClientImpl::ResetStoreCallback(bool success) {
  707. // Even an incomplete reset may invalidate registrations, and this might be
  708. // the only opportunity to notify the delegate. For example a partial reset
  709. // that deletes the "CURRENT" file will cause GCMStoreImpl to consider the DB
  710. // to no longer exist, in which case the next load will simply create a new
  711. // store rather than resetting it.
  712. delegate_->OnStoreReset();
  713. if (!success) {
  714. LOG(ERROR) << "Failed to reset GCM store";
  715. RecordResetStoreErrorToUMA(DESTROYING_STORE_FAILED);
  716. state_ = UNINITIALIZED;
  717. return;
  718. }
  719. state_ = INITIALIZED;
  720. Start(start_mode_);
  721. }
  722. void GCMClientImpl::Stop() {
  723. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  724. // TODO(fgorski): Perhaps we should make a distinction between a Stop and a
  725. // Shutdown.
  726. DVLOG(1) << "Stopping the GCM Client";
  727. ResetCache();
  728. state_ = INITIALIZED;
  729. gcm_store_->Close();
  730. }
  731. void GCMClientImpl::ResetCache() {
  732. weak_ptr_factory_.InvalidateWeakPtrs();
  733. periodic_checkin_ptr_factory_.InvalidateWeakPtrs();
  734. device_checkin_info_.Reset();
  735. connection_factory_.reset();
  736. delegate_->OnDisconnected();
  737. mcs_client_.reset();
  738. checkin_request_.reset();
  739. // Delete all of the pending registration and unregistration requests.
  740. pending_registration_requests_.clear();
  741. pending_unregistration_requests_.clear();
  742. }
  743. void GCMClientImpl::Register(
  744. scoped_refptr<RegistrationInfo> registration_info) {
  745. DCHECK_EQ(state_, READY);
  746. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  747. // Registrations should never pass as an app_id the special category used
  748. // internally when registering with a subtype. See security note in
  749. // GCMClientImpl::HandleIncomingMessage.
  750. CHECK_NE(registration_info->app_id,
  751. chrome_build_info_.product_category_for_subtypes);
  752. // Find and use the cached registration ID.
  753. RegistrationInfoMap::const_iterator registrations_iter =
  754. registrations_.find(registration_info);
  755. if (registrations_iter != registrations_.end()) {
  756. bool matched = true;
  757. // For GCM registration, we also match the sender IDs since multiple
  758. // registrations are not supported.
  759. const GCMRegistrationInfo* gcm_registration_info =
  760. GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
  761. if (gcm_registration_info) {
  762. const GCMRegistrationInfo* cached_gcm_registration_info =
  763. GCMRegistrationInfo::FromRegistrationInfo(
  764. registrations_iter->first.get());
  765. DCHECK(cached_gcm_registration_info);
  766. if (gcm_registration_info->sender_ids !=
  767. cached_gcm_registration_info->sender_ids) {
  768. matched = false;
  769. // Senders IDs don't match existing registration.
  770. RecordRegistrationRequestToUMA(
  771. RegistrationCacheStatus::REGISTRATION_FOUND_BUT_SENDERS_DONT_MATCH);
  772. }
  773. }
  774. if (matched) {
  775. // Skip registration if token is fresh.
  776. base::TimeDelta token_invalidation_period =
  777. features::GetTokenInvalidationInterval();
  778. base::TimeDelta time_since_last_validation =
  779. clock_->Now() - registrations_iter->first->last_validated;
  780. if (token_invalidation_period.is_zero() ||
  781. time_since_last_validation < token_invalidation_period) {
  782. // Token is fresh, or token invalidation is disabled.
  783. // Use cached registration.
  784. delegate_->OnRegisterFinished(registration_info,
  785. registrations_iter->second, SUCCESS);
  786. RecordRegistrationRequestToUMA(
  787. RegistrationCacheStatus::REGISTRATION_FOUND_AND_FRESH);
  788. return;
  789. } else {
  790. // Token is stale.
  791. RecordRegistrationRequestToUMA(
  792. RegistrationCacheStatus::REGISTRATION_FOUND_BUT_STALE);
  793. }
  794. }
  795. } else {
  796. // New Registration request (no existing registration)
  797. RecordRegistrationRequestToUMA(
  798. RegistrationCacheStatus::REGISTRATION_NOT_FOUND);
  799. }
  800. std::unique_ptr<RegistrationRequest::CustomRequestHandler> request_handler;
  801. std::string source_to_record;
  802. const GCMRegistrationInfo* gcm_registration_info =
  803. GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
  804. if (gcm_registration_info) {
  805. std::string senders;
  806. for (auto iter = gcm_registration_info->sender_ids.begin();
  807. iter != gcm_registration_info->sender_ids.end();
  808. ++iter) {
  809. if (!senders.empty())
  810. senders.append(",");
  811. senders.append(*iter);
  812. }
  813. request_handler = std::make_unique<GCMRegistrationRequestHandler>(senders);
  814. source_to_record = senders;
  815. }
  816. const InstanceIDTokenInfo* instance_id_token_info =
  817. InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
  818. if (instance_id_token_info) {
  819. auto instance_id_iter = instance_id_data_.find(registration_info->app_id);
  820. DCHECK(instance_id_iter != instance_id_data_.end());
  821. request_handler = std::make_unique<InstanceIDGetTokenRequestHandler>(
  822. instance_id_iter->second.first,
  823. instance_id_token_info->authorized_entity,
  824. instance_id_token_info->scope,
  825. ConstructGCMVersion(chrome_build_info_.version),
  826. instance_id_token_info->time_to_live);
  827. source_to_record = instance_id_token_info->authorized_entity + "/" +
  828. instance_id_token_info->scope;
  829. }
  830. bool use_subtype = instance_id_token_info &&
  831. InstanceIDUsesSubtypeForAppId(registration_info->app_id);
  832. std::string category = use_subtype
  833. ? chrome_build_info_.product_category_for_subtypes
  834. : registration_info->app_id;
  835. std::string subtype = use_subtype ? registration_info->app_id : std::string();
  836. RegistrationRequest::RequestInfo request_info(device_checkin_info_.android_id,
  837. device_checkin_info_.secret,
  838. category, subtype);
  839. std::unique_ptr<RegistrationRequest> registration_request(
  840. new RegistrationRequest(
  841. gservices_settings_.GetRegistrationURL(), request_info,
  842. std::move(request_handler), GetGCMBackoffPolicy(),
  843. base::BindOnce(&GCMClientImpl::OnRegisterCompleted,
  844. weak_ptr_factory_.GetWeakPtr(), registration_info),
  845. kMaxRegistrationRetries, url_loader_factory_, io_task_runner_,
  846. &recorder_, source_to_record));
  847. registration_request->Start();
  848. pending_registration_requests_.insert(
  849. std::make_pair(registration_info, std::move(registration_request)));
  850. }
  851. void GCMClientImpl::OnRegisterCompleted(
  852. scoped_refptr<RegistrationInfo> registration_info,
  853. RegistrationRequest::Status status,
  854. const std::string& registration_id) {
  855. DCHECK(delegate_);
  856. Result result;
  857. PendingRegistrationRequests::const_iterator iter =
  858. pending_registration_requests_.find(registration_info);
  859. if (iter == pending_registration_requests_.end()) {
  860. result = UNKNOWN_ERROR;
  861. } else if (status == RegistrationRequest::INVALID_SENDER) {
  862. result = INVALID_PARAMETER;
  863. } else if (registration_id.empty()) {
  864. // All other errors are currently treated as SERVER_ERROR (including
  865. // REACHED_MAX_RETRIES due to the device being offline!).
  866. result = SERVER_ERROR;
  867. } else {
  868. result = SUCCESS;
  869. }
  870. if (result == SUCCESS) {
  871. // Cache it.
  872. // Note that the existing cached record has to be removed first because
  873. // otherwise the key value in registrations_ will not be updated. For GCM
  874. // registrations, the key consists of pair of app_id and sender_ids though
  875. // only app_id is used in the key comparison.
  876. registrations_.erase(registration_info);
  877. registration_info->last_validated = clock_->Now();
  878. registrations_[registration_info] = registration_id;
  879. // Save it in the persistent store.
  880. gcm_store_->AddRegistration(
  881. registration_info->GetSerializedKey(),
  882. registration_info->GetSerializedValue(registration_id),
  883. base::BindOnce(&GCMClientImpl::UpdateRegistrationCallback,
  884. weak_ptr_factory_.GetWeakPtr()));
  885. }
  886. delegate_->OnRegisterFinished(
  887. registration_info,
  888. result == SUCCESS ? registration_id : std::string(),
  889. result);
  890. if (iter != pending_registration_requests_.end())
  891. pending_registration_requests_.erase(iter);
  892. }
  893. bool GCMClientImpl::ValidateRegistration(
  894. scoped_refptr<RegistrationInfo> registration_info,
  895. const std::string& registration_id) {
  896. DCHECK_EQ(state_, READY);
  897. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  898. // Must have a cached registration.
  899. RegistrationInfoMap::const_iterator registrations_iter =
  900. registrations_.find(registration_info);
  901. if (registrations_iter == registrations_.end())
  902. return false;
  903. // Cached registration ID must match.
  904. const std::string& cached_registration_id = registrations_iter->second;
  905. if (registration_id != cached_registration_id)
  906. return false;
  907. // For GCM registration, we also match the sender IDs since multiple
  908. // registrations are not supported.
  909. const GCMRegistrationInfo* gcm_registration_info =
  910. GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
  911. if (gcm_registration_info) {
  912. const GCMRegistrationInfo* cached_gcm_registration_info =
  913. GCMRegistrationInfo::FromRegistrationInfo(
  914. registrations_iter->first.get());
  915. DCHECK(cached_gcm_registration_info);
  916. if (gcm_registration_info->sender_ids !=
  917. cached_gcm_registration_info->sender_ids) {
  918. return false;
  919. }
  920. }
  921. return true;
  922. }
  923. void GCMClientImpl::Unregister(
  924. scoped_refptr<RegistrationInfo> registration_info) {
  925. DCHECK_EQ(state_, READY);
  926. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  927. std::unique_ptr<UnregistrationRequest::CustomRequestHandler> request_handler;
  928. std::string source_to_record;
  929. const GCMRegistrationInfo* gcm_registration_info =
  930. GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
  931. if (gcm_registration_info) {
  932. request_handler = std::make_unique<GCMUnregistrationRequestHandler>(
  933. registration_info->app_id);
  934. }
  935. const InstanceIDTokenInfo* instance_id_token_info =
  936. InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
  937. if (instance_id_token_info) {
  938. auto instance_id_iter = instance_id_data_.find(registration_info->app_id);
  939. if (instance_id_iter == instance_id_data_.end()) {
  940. // This should not be reached since we should not delete tokens when
  941. // an InstanceID has not been created yet.
  942. NOTREACHED();
  943. return;
  944. }
  945. request_handler = std::make_unique<InstanceIDDeleteTokenRequestHandler>(
  946. instance_id_iter->second.first,
  947. instance_id_token_info->authorized_entity,
  948. instance_id_token_info->scope,
  949. ConstructGCMVersion(chrome_build_info_.version));
  950. source_to_record = instance_id_token_info->authorized_entity + "/" +
  951. instance_id_token_info->scope;
  952. }
  953. // Remove the registration/token(s) from the cache and the store.
  954. // TODO(jianli): Remove it only when the request is successful.
  955. if (instance_id_token_info &&
  956. instance_id_token_info->authorized_entity == "*" &&
  957. instance_id_token_info->scope == "*") {
  958. // If authorized_entity and scope are '*', find and remove all associated
  959. // tokens.
  960. bool token_found = false;
  961. for (auto iter = registrations_.begin();
  962. iter != registrations_.end();) {
  963. InstanceIDTokenInfo* cached_instance_id_token_info =
  964. InstanceIDTokenInfo::FromRegistrationInfo(iter->first.get());
  965. if (cached_instance_id_token_info &&
  966. cached_instance_id_token_info->app_id == registration_info->app_id) {
  967. token_found = true;
  968. gcm_store_->RemoveRegistration(
  969. cached_instance_id_token_info->GetSerializedKey(),
  970. base::BindOnce(&GCMClientImpl::UpdateRegistrationCallback,
  971. weak_ptr_factory_.GetWeakPtr()));
  972. registrations_.erase(iter++);
  973. } else {
  974. ++iter;
  975. }
  976. }
  977. // If no token is found for the Instance ID, don't need to unregister
  978. // since the Instance ID is not sent to the server yet.
  979. if (!token_found) {
  980. OnUnregisterCompleted(registration_info,
  981. UnregistrationRequest::SUCCESS);
  982. return;
  983. }
  984. } else {
  985. auto iter = registrations_.find(registration_info);
  986. if (iter == registrations_.end()) {
  987. delegate_->OnUnregisterFinished(registration_info, INVALID_PARAMETER);
  988. return;
  989. }
  990. registrations_.erase(iter);
  991. gcm_store_->RemoveRegistration(
  992. registration_info->GetSerializedKey(),
  993. base::BindOnce(&GCMClientImpl::UpdateRegistrationCallback,
  994. weak_ptr_factory_.GetWeakPtr()));
  995. }
  996. bool use_subtype = instance_id_token_info &&
  997. InstanceIDUsesSubtypeForAppId(registration_info->app_id);
  998. std::string category = use_subtype
  999. ? chrome_build_info_.product_category_for_subtypes
  1000. : registration_info->app_id;
  1001. std::string subtype = use_subtype ? registration_info->app_id : std::string();
  1002. UnregistrationRequest::RequestInfo request_info(
  1003. device_checkin_info_.android_id, device_checkin_info_.secret, category,
  1004. subtype);
  1005. std::unique_ptr<UnregistrationRequest> unregistration_request(
  1006. new UnregistrationRequest(
  1007. gservices_settings_.GetRegistrationURL(), request_info,
  1008. std::move(request_handler), GetGCMBackoffPolicy(),
  1009. base::BindOnce(&GCMClientImpl::OnUnregisterCompleted,
  1010. weak_ptr_factory_.GetWeakPtr(), registration_info),
  1011. kMaxUnregistrationRetries, url_loader_factory_, io_task_runner_,
  1012. &recorder_, source_to_record));
  1013. unregistration_request->Start();
  1014. pending_unregistration_requests_.insert(
  1015. std::make_pair(registration_info, std::move(unregistration_request)));
  1016. }
  1017. void GCMClientImpl::OnUnregisterCompleted(
  1018. scoped_refptr<RegistrationInfo> registration_info,
  1019. UnregistrationRequest::Status status) {
  1020. DVLOG(1) << "Unregister completed for app: " << registration_info->app_id
  1021. << " with " << (status ? "success." : "failure.");
  1022. Result result;
  1023. switch (status) {
  1024. case UnregistrationRequest::SUCCESS:
  1025. result = SUCCESS;
  1026. break;
  1027. case UnregistrationRequest::INVALID_PARAMETERS:
  1028. result = INVALID_PARAMETER;
  1029. break;
  1030. default:
  1031. // All other errors are currently treated as SERVER_ERROR (including
  1032. // REACHED_MAX_RETRIES due to the device being offline!).
  1033. result = SERVER_ERROR;
  1034. break;
  1035. }
  1036. delegate_->OnUnregisterFinished(registration_info, result);
  1037. pending_unregistration_requests_.erase(registration_info);
  1038. }
  1039. void GCMClientImpl::OnGCMStoreDestroyed(bool success) {
  1040. DLOG_IF(ERROR, !success) << "GCM store failed to be destroyed!";
  1041. UMA_HISTOGRAM_BOOLEAN("GCM.StoreDestroySucceeded", success);
  1042. }
  1043. void GCMClientImpl::Send(const std::string& app_id,
  1044. const std::string& receiver_id,
  1045. const OutgoingMessage& message) {
  1046. DCHECK_EQ(state_, READY);
  1047. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  1048. mcs_proto::DataMessageStanza stanza;
  1049. stanza.set_ttl(message.time_to_live);
  1050. stanza.set_sent(clock_->Now().ToInternalValue() /
  1051. base::Time::kMicrosecondsPerSecond);
  1052. stanza.set_id(message.id);
  1053. stanza.set_from(kSendMessageFromValue);
  1054. stanza.set_to(receiver_id);
  1055. stanza.set_category(app_id);
  1056. for (auto iter = message.data.begin(); iter != message.data.end(); ++iter) {
  1057. mcs_proto::AppData* app_data = stanza.add_app_data();
  1058. app_data->set_key(iter->first);
  1059. app_data->set_value(iter->second);
  1060. }
  1061. MCSMessage mcs_message(stanza);
  1062. DVLOG(1) << "MCS message size: " << mcs_message.size();
  1063. mcs_client_->SendMessage(mcs_message);
  1064. }
  1065. std::string GCMClientImpl::GetStateString() const {
  1066. switch(state_) {
  1067. case GCMClientImpl::UNINITIALIZED:
  1068. return "UNINITIALIZED";
  1069. case GCMClientImpl::INITIALIZED:
  1070. return "INITIALIZED";
  1071. case GCMClientImpl::LOADING:
  1072. return "LOADING";
  1073. case GCMClientImpl::LOADED:
  1074. return "LOADED";
  1075. case GCMClientImpl::INITIAL_DEVICE_CHECKIN:
  1076. return "INITIAL_DEVICE_CHECKIN";
  1077. case GCMClientImpl::READY:
  1078. return "READY";
  1079. }
  1080. NOTREACHED();
  1081. return std::string();
  1082. }
  1083. void GCMClientImpl::RecordDecryptionFailure(const std::string& app_id,
  1084. GCMDecryptionResult result) {
  1085. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  1086. recorder_.RecordDecryptionFailure(app_id, result);
  1087. }
  1088. void GCMClientImpl::SetRecording(bool recording) {
  1089. recorder_.set_is_recording(recording);
  1090. }
  1091. void GCMClientImpl::ClearActivityLogs() {
  1092. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  1093. recorder_.Clear();
  1094. }
  1095. GCMClient::GCMStatistics GCMClientImpl::GetStatistics() const {
  1096. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  1097. GCMClient::GCMStatistics stats;
  1098. stats.gcm_client_created = true;
  1099. stats.is_recording = recorder_.is_recording();
  1100. stats.gcm_client_state = GetStateString();
  1101. stats.connection_client_created = mcs_client_ != nullptr;
  1102. stats.last_checkin = last_checkin_time_;
  1103. stats.next_checkin =
  1104. last_checkin_time_ + gservices_settings_.GetCheckinInterval();
  1105. if (connection_factory_)
  1106. stats.connection_state = connection_factory_->GetConnectionStateString();
  1107. if (mcs_client_) {
  1108. stats.send_queue_size = mcs_client_->GetSendQueueSize();
  1109. stats.resend_queue_size = mcs_client_->GetResendQueueSize();
  1110. }
  1111. if (device_checkin_info_.android_id > 0)
  1112. stats.android_id = device_checkin_info_.android_id;
  1113. if (device_checkin_info_.secret > 0)
  1114. stats.android_secret = device_checkin_info_.secret;
  1115. recorder_.CollectActivities(&stats.recorded_activities);
  1116. for (auto it = registrations_.begin(); it != registrations_.end(); ++it) {
  1117. stats.registered_app_ids.push_back(it->first->app_id);
  1118. }
  1119. return stats;
  1120. }
  1121. void GCMClientImpl::OnActivityRecorded() {
  1122. delegate_->OnActivityRecorded();
  1123. }
  1124. void GCMClientImpl::OnConnected(const GURL& current_server,
  1125. const net::IPEndPoint& ip_endpoint) {
  1126. // TODO(gcm): expose current server in debug page.
  1127. delegate_->OnActivityRecorded();
  1128. delegate_->OnConnected(ip_endpoint);
  1129. }
  1130. void GCMClientImpl::OnDisconnected() {
  1131. delegate_->OnActivityRecorded();
  1132. delegate_->OnDisconnected();
  1133. }
  1134. void GCMClientImpl::OnMessageReceivedFromMCS(const gcm::MCSMessage& message) {
  1135. switch (message.tag()) {
  1136. case kLoginResponseTag:
  1137. DVLOG(1) << "Login response received by GCM Client. Ignoring.";
  1138. return;
  1139. case kDataMessageStanzaTag:
  1140. DVLOG(1) << "A downstream message received. Processing...";
  1141. HandleIncomingMessage(message);
  1142. return;
  1143. default:
  1144. NOTREACHED() << "Message with unexpected tag received by GCMClient";
  1145. return;
  1146. }
  1147. }
  1148. void GCMClientImpl::OnMessageSentToMCS(int64_t user_serial_number,
  1149. const std::string& app_id,
  1150. const std::string& message_id,
  1151. MCSClient::MessageSendStatus status) {
  1152. DCHECK_EQ(user_serial_number, kDefaultUserSerialNumber);
  1153. DCHECK(delegate_);
  1154. // TTL_EXCEEDED is singled out here, because it can happen long time after the
  1155. // message was sent. That is why it comes as |OnMessageSendError| event rather
  1156. // than |OnSendFinished|. SendErrorDetails.additional_data is left empty.
  1157. // All other errors will be raised immediately, through asynchronous callback.
  1158. // It is expected that TTL_EXCEEDED will be issued for a message that was
  1159. // previously issued |OnSendFinished| with status SUCCESS.
  1160. // TODO(jianli): Consider adding UMA for this status.
  1161. if (status == MCSClient::TTL_EXCEEDED) {
  1162. SendErrorDetails send_error_details;
  1163. send_error_details.message_id = message_id;
  1164. send_error_details.result = GCMClient::TTL_EXCEEDED;
  1165. delegate_->OnMessageSendError(app_id, send_error_details);
  1166. } else if (status == MCSClient::SENT) {
  1167. delegate_->OnSendAcknowledged(app_id, message_id);
  1168. } else {
  1169. delegate_->OnSendFinished(app_id, message_id, ToGCMClientResult(status));
  1170. }
  1171. }
  1172. void GCMClientImpl::OnMCSError() {
  1173. // TODO(fgorski): For now it replaces the initialization method. Long term it
  1174. // should have an error or status passed in.
  1175. }
  1176. void GCMClientImpl::HandleIncomingMessage(const gcm::MCSMessage& message) {
  1177. DCHECK(delegate_);
  1178. const mcs_proto::DataMessageStanza& data_message_stanza =
  1179. reinterpret_cast<const mcs_proto::DataMessageStanza&>(
  1180. message.GetProtobuf());
  1181. DCHECK_EQ(data_message_stanza.device_user_id(), kDefaultUserSerialNumber);
  1182. // Copy all the data from the stanza to a MessageData object. When present,
  1183. // keys like kSubtypeKey or kMessageTypeKey will be filtered out later.
  1184. MessageData message_data;
  1185. for (int i = 0; i < data_message_stanza.app_data_size(); ++i) {
  1186. std::string key = data_message_stanza.app_data(i).key();
  1187. message_data[key] = data_message_stanza.app_data(i).value();
  1188. }
  1189. std::string subtype;
  1190. auto subtype_iter = message_data.find(kSubtypeKey);
  1191. if (subtype_iter != message_data.end()) {
  1192. subtype = subtype_iter->second;
  1193. message_data.erase(subtype_iter);
  1194. }
  1195. // SECURITY NOTE: Subtypes received from GCM *cannot* be trusted for
  1196. // registrations without a subtype (as the sender can pass any subtype they
  1197. // want). They can however be trusted for registrations that are known to have
  1198. // a subtype (as GCM overwrites anything passed by the sender).
  1199. //
  1200. // So a given Chrome profile always passes a fixed string called
  1201. // |product_category_for_subtypes| (of the form "com.chrome.macosx") as the
  1202. // category when registering with a subtype, and incoming subtypes are only
  1203. // trusted for that category.
  1204. //
  1205. // TODO(johnme): Remove this check if GCM starts sending the subtype in a
  1206. // field that's guaranteed to be trusted (b/18198485).
  1207. //
  1208. // (On Android, all registrations made by Chrome on behalf of third-party
  1209. // apps/extensions/websites have always had a subtype, so such a check is not
  1210. // necessary - or possible, since category is fixed to the true package name).
  1211. bool subtype_is_trusted = data_message_stanza.category() ==
  1212. chrome_build_info_.product_category_for_subtypes;
  1213. bool use_subtype = subtype_is_trusted && !subtype.empty();
  1214. std::string app_id = use_subtype ? subtype : data_message_stanza.category();
  1215. MessageType message_type = DATA_MESSAGE;
  1216. auto type_iter = message_data.find(kMessageTypeKey);
  1217. if (type_iter != message_data.end()) {
  1218. message_type = DecodeMessageType(type_iter->second);
  1219. message_data.erase(type_iter);
  1220. }
  1221. switch (message_type) {
  1222. case DATA_MESSAGE:
  1223. HandleIncomingDataMessage(app_id, use_subtype, data_message_stanza,
  1224. message_data);
  1225. break;
  1226. case DELETED_MESSAGES:
  1227. HandleIncomingDeletedMessages(app_id, data_message_stanza, message_data);
  1228. break;
  1229. case SEND_ERROR:
  1230. HandleIncomingSendError(app_id, data_message_stanza, message_data);
  1231. break;
  1232. case UNKNOWN:
  1233. DVLOG(1) << "Unknown message_type received. Message ignored. "
  1234. << "App ID: " << app_id << ".";
  1235. break;
  1236. }
  1237. }
  1238. void GCMClientImpl::HandleIncomingDataMessage(
  1239. const std::string& app_id,
  1240. bool was_subtype,
  1241. const mcs_proto::DataMessageStanza& data_message_stanza,
  1242. MessageData& message_data) {
  1243. UMA_HISTOGRAM_BOOLEAN("GCM.DataMessageReceived", true);
  1244. bool has_collapse_key =
  1245. data_message_stanza.has_token() && !data_message_stanza.token().empty();
  1246. UMA_HISTOGRAM_BOOLEAN("GCM.DataMessageReceivedHasCollapseKey",
  1247. has_collapse_key);
  1248. recorder_.RecordDataMessageReceived(app_id, data_message_stanza.from(),
  1249. data_message_stanza.ByteSize(),
  1250. GCMStatsRecorder::DATA_MESSAGE);
  1251. IncomingMessage incoming_message;
  1252. incoming_message.sender_id = data_message_stanza.from();
  1253. incoming_message.message_id = data_message_stanza.persistent_id();
  1254. if (data_message_stanza.has_token())
  1255. incoming_message.collapse_key = data_message_stanza.token();
  1256. incoming_message.data = message_data;
  1257. incoming_message.raw_data = data_message_stanza.raw_data();
  1258. delegate_->OnMessageReceived(app_id, incoming_message);
  1259. }
  1260. void GCMClientImpl::HandleIncomingDeletedMessages(
  1261. const std::string& app_id,
  1262. const mcs_proto::DataMessageStanza& data_message_stanza,
  1263. MessageData& message_data) {
  1264. int deleted_count = 0;
  1265. auto count_iter = message_data.find(kDeletedCountKey);
  1266. if (count_iter != message_data.end()) {
  1267. if (!base::StringToInt(count_iter->second, &deleted_count))
  1268. deleted_count = 0;
  1269. }
  1270. UMA_HISTOGRAM_COUNTS_1000("GCM.DeletedMessagesReceived", deleted_count);
  1271. recorder_.RecordDataMessageReceived(app_id, data_message_stanza.from(),
  1272. data_message_stanza.ByteSize(),
  1273. GCMStatsRecorder::DELETED_MESSAGES);
  1274. delegate_->OnMessagesDeleted(app_id);
  1275. }
  1276. void GCMClientImpl::HandleIncomingSendError(
  1277. const std::string& app_id,
  1278. const mcs_proto::DataMessageStanza& data_message_stanza,
  1279. MessageData& message_data) {
  1280. SendErrorDetails send_error_details;
  1281. send_error_details.additional_data = message_data;
  1282. send_error_details.result = SERVER_ERROR;
  1283. send_error_details.message_id = data_message_stanza.persistent_id();
  1284. recorder_.RecordIncomingSendError(app_id, data_message_stanza.to(),
  1285. data_message_stanza.id());
  1286. delegate_->OnMessageSendError(app_id, send_error_details);
  1287. }
  1288. bool GCMClientImpl::HasStandaloneRegisteredApp() const {
  1289. if (registrations_.empty())
  1290. return false;
  1291. // Note that account mapper is not counted as a standalone app since it is
  1292. // automatically started when other app uses GCM.
  1293. return registrations_.size() > 1 ||
  1294. !ExistsGCMRegistrationInMap(registrations_, kGCMAccountMapperAppId);
  1295. }
  1296. } // namespace gcm