Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(351)

Side by Side Diff: chrome/browser/metrics/metrics_service.h

Issue 256143006: Refactor MetricsStateManager class out of MetricsService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // This file defines a service that collects information about the user 5 // This file defines a service that collects information about the user
6 // experience in order to help improve future versions of the app. 6 // experience in order to help improve future versions of the app.
7 7
8 #ifndef CHROME_BROWSER_METRICS_METRICS_SERVICE_H_ 8 #ifndef CHROME_BROWSER_METRICS_METRICS_SERVICE_H_
9 #define CHROME_BROWSER_METRICS_METRICS_SERVICE_H_ 9 #define CHROME_BROWSER_METRICS_METRICS_SERVICE_H_
10 10
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 struct WebPluginInfo; 62 struct WebPluginInfo;
63 } 63 }
64 64
65 namespace extensions { 65 namespace extensions {
66 class ExtensionDownloader; 66 class ExtensionDownloader;
67 class ManifestFetchData; 67 class ManifestFetchData;
68 class MetricsPrivateGetIsCrashReportingEnabledFunction; 68 class MetricsPrivateGetIsCrashReportingEnabledFunction;
69 } 69 }
70 70
71 namespace metrics { 71 namespace metrics {
72 class ClonedInstallDetector; 72 class MetricsStateManager;
73 } 73 }
74 74
75 namespace net { 75 namespace net {
76 class URLFetcher; 76 class URLFetcher;
77 } 77 }
78 78
79 namespace prerender { 79 namespace prerender {
80 bool IsOmniboxEnabled(Profile* profile); 80 bool IsOmniboxEnabled(Profile* profile);
81 } 81 }
82 82
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 UNINITIALIZED_PHASE = 0, 120 UNINITIALIZED_PHASE = 0,
121 START_METRICS_RECORDING = 100, 121 START_METRICS_RECORDING = 100,
122 CREATE_PROFILE = 200, 122 CREATE_PROFILE = 200,
123 STARTUP_TIMEBOMB_ARM = 300, 123 STARTUP_TIMEBOMB_ARM = 300,
124 THREAD_WATCHER_START = 400, 124 THREAD_WATCHER_START = 400,
125 MAIN_MESSAGE_LOOP_RUN = 500, 125 MAIN_MESSAGE_LOOP_RUN = 500,
126 SHUTDOWN_TIMEBOMB_ARM = 600, 126 SHUTDOWN_TIMEBOMB_ARM = 600,
127 SHUTDOWN_COMPLETE = 700, 127 SHUTDOWN_COMPLETE = 700,
128 }; 128 };
129 129
130 enum ReportingState {
131 REPORTING_ENABLED,
132 REPORTING_DISABLED,
133 };
134
135 MetricsService(); 130 MetricsService();
136 virtual ~MetricsService(); 131 virtual ~MetricsService();
137 132
138 // Initializes metrics recording state. Updates various bookkeeping values in 133 // Initializes metrics recording state. Updates various bookkeeping values in
139 // prefs and sets up the scheduler. This is a separate function rather than 134 // prefs and sets up the scheduler. This is a separate function rather than
140 // being done by the constructor so that field trials could be created before 135 // being done by the constructor so that field trials could be created before
141 // this is run. Takes |reporting_state| parameter which specifies whether UMA 136 // this is run.
142 // is enabled. 137 void InitializeMetricsRecordingState();
143 void InitializeMetricsRecordingState(ReportingState reporting_state);
144 138
145 // Starts the metrics system, turning on recording and uploading of metrics. 139 // Starts the metrics system, turning on recording and uploading of metrics.
146 // Should be called when starting up with metrics enabled, or when metrics 140 // Should be called when starting up with metrics enabled, or when metrics
147 // are turned on. 141 // are turned on.
148 void Start(); 142 void Start();
149 143
144 // If metrics reporting is enabled, starts the metrics service. Returns
145 // whether the metrics service was started.
146 bool StartIfMetricsReportingEnabled();
147
150 // Starts the metrics system in a special test-only mode. Metrics won't ever 148 // Starts the metrics system in a special test-only mode. Metrics won't ever
151 // be uploaded or persisted in this mode, but metrics will be recorded in 149 // be uploaded or persisted in this mode, but metrics will be recorded in
152 // memory. 150 // memory.
153 void StartRecordingForTests(); 151 void StartRecordingForTests();
154 152
155 // Shuts down the metrics system. Should be called at shutdown, or if metrics 153 // Shuts down the metrics system. Should be called at shutdown, or if metrics
156 // are turned off. 154 // are turned off.
157 void Stop(); 155 void Stop();
158 156
159 // Enable/disable transmission of accumulated logs and crash reports (dumps). 157 // Enable/disable transmission of accumulated logs and crash reports (dumps).
160 // Calling Start() automatically enables reporting, but sending is 158 // Calling Start() automatically enables reporting, but sending is
161 // asyncronous so this can be called immediately after Start() to prevent 159 // asyncronous so this can be called immediately after Start() to prevent
162 // any uploading. 160 // any uploading.
163 void EnableReporting(); 161 void EnableReporting();
164 void DisableReporting(); 162 void DisableReporting();
165 163
166 // Returns the client ID for this client, or the empty string if metrics 164 // Returns the client ID for this client, or the empty string if metrics
167 // recording is not currently running. 165 // recording is not currently running.
168 std::string GetClientId(); 166 std::string GetClientId();
169 167
170 // Returns the preferred entropy provider used to seed persistent activities 168 // Returns the preferred entropy provider used to seed persistent activities
171 // based on whether or not metrics reporting will be permitted on this client. 169 // based on whether or not metrics reporting will be permitted on this client.
172 // The caller must determine if metrics reporting will be enabled for this
173 // client and pass that state in as |reporting_will_be_enabled|.
174 // 170 //
175 // If |reporting_will_be_enabled| is true, this method returns an entropy 171 // If metrics reporting is enabled, this method returns an entropy provider
176 // provider that has a high source of entropy, partially based on the client 172 // that has a high source of entropy, partially based on the client ID.
177 // ID. Otherwise, an entropy provider that is based on a low entropy source 173 // Otherwise, it returns an entropy provider that is based on a low entropy
178 // is returned. 174 // source.
179 // 175 scoped_ptr<const base::FieldTrial::EntropyProvider> CreateEntropyProvider();
180 // Note that this reporting state can not be checked by reporting_active()
181 // because this method may need to be called before the MetricsService needs
182 // to be started.
183 scoped_ptr<const base::FieldTrial::EntropyProvider> CreateEntropyProvider(
184 ReportingState reporting_state);
185
186 // Force the client ID to be generated. This is useful in case it's needed
187 // before recording.
188 void ForceClientIdCreation();
189 176
190 // At startup, prefs needs to be called with a list of all the pref names and 177 // At startup, prefs needs to be called with a list of all the pref names and
191 // types we'll be using. 178 // types we'll be using.
192 static void RegisterPrefs(PrefRegistrySimple* registry); 179 static void RegisterPrefs(PrefRegistrySimple* registry);
193 #if defined(OS_ANDROID) 180 #if defined(OS_ANDROID)
194 static void RegisterPrefsAndroid(PrefRegistrySimple* registry); 181 static void RegisterPrefsAndroid(PrefRegistrySimple* registry);
195 #endif // defined(OS_ANDROID) 182 #endif // defined(OS_ANDROID)
196 183
197 // Set up notifications which indicate that a user is performing work. This is 184 // Set up notifications which indicate that a user is performing work. This is
198 // useful to allow some features to sleep, until the machine becomes active, 185 // useful to allow some features to sleep, until the machine becomes active,
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 SENDING_INITIAL_METRICS_LOG, // Initial metrics log being sent. 292 SENDING_INITIAL_METRICS_LOG, // Initial metrics log being sent.
306 SENDING_OLD_LOGS, // Sending unsent logs from last session. 293 SENDING_OLD_LOGS, // Sending unsent logs from last session.
307 SENDING_CURRENT_LOGS, // Sending ongoing logs as they accrue. 294 SENDING_CURRENT_LOGS, // Sending ongoing logs as they accrue.
308 }; 295 };
309 296
310 enum ShutdownCleanliness { 297 enum ShutdownCleanliness {
311 CLEANLY_SHUTDOWN = 0xdeadbeef, 298 CLEANLY_SHUTDOWN = 0xdeadbeef,
312 NEED_TO_SHUTDOWN = ~CLEANLY_SHUTDOWN 299 NEED_TO_SHUTDOWN = ~CLEANLY_SHUTDOWN
313 }; 300 };
314 301
315 // Designates which entropy source was returned from this MetricsService.
316 // This is used for testing to validate that we return the correct source
317 // depending on the state of the service.
318 enum EntropySourceReturned {
319 LAST_ENTROPY_NONE,
320 LAST_ENTROPY_LOW,
321 LAST_ENTROPY_HIGH,
322 };
323
324 struct ChildProcessStats; 302 struct ChildProcessStats;
325 303
326 typedef std::vector<SyntheticTrialGroup> SyntheticTrialGroups; 304 typedef std::vector<SyntheticTrialGroup> SyntheticTrialGroups;
327 305
328 // First part of the init task. Called on the FILE thread to load hardware 306 // First part of the init task. Called on the FILE thread to load hardware
329 // class information. 307 // class information.
330 static void InitTaskGetHardwareClass(base::WeakPtr<MetricsService> self, 308 static void InitTaskGetHardwareClass(base::WeakPtr<MetricsService> self,
331 base::MessageLoopProxy* target_loop); 309 base::MessageLoopProxy* target_loop);
332 310
333 // Callback from InitTaskGetHardwareClass() that continues the init task by 311 // Callback from InitTaskGetHardwareClass() that continues the init task by
(...skipping 27 matching lines...) Expand all
361 // Get the amount of uptime since this process started and since the last 339 // Get the amount of uptime since this process started and since the last
362 // call to this function. Also updates the cumulative uptime metric (stored 340 // call to this function. Also updates the cumulative uptime metric (stored
363 // as a pref) for uninstall. Uptimes are measured using TimeTicks, which 341 // as a pref) for uninstall. Uptimes are measured using TimeTicks, which
364 // guarantees that it is monotonic and does not jump if the user changes 342 // guarantees that it is monotonic and does not jump if the user changes
365 // his/her clock. The TimeTicks implementation also makes the clock not 343 // his/her clock. The TimeTicks implementation also makes the clock not
366 // count time the computer is suspended. 344 // count time the computer is suspended.
367 void GetUptimes(PrefService* pref, 345 void GetUptimes(PrefService* pref,
368 base::TimeDelta* incremental_uptime, 346 base::TimeDelta* incremental_uptime,
369 base::TimeDelta* uptime); 347 base::TimeDelta* uptime);
370 348
371 // Reset the client id and low entropy source if the kMetricsResetMetricIDs
372 // pref is true.
373 void ResetMetricsIDsIfNecessary();
374
375 // Returns the low entropy source for this client. This is a random value
376 // that is non-identifying amongst browser clients. This method will
377 // generate the entropy source value if it has not been called before.
378 int GetLowEntropySource();
379
380 // Returns the first entropy source that was returned by this service since
381 // start up, or NONE if neither was returned yet. This is exposed for testing
382 // only.
383 EntropySourceReturned entropy_source_returned() const {
384 return entropy_source_returned_;
385 }
386
387 // Turns recording on or off. 349 // Turns recording on or off.
388 // DisableRecording() also forces a persistent save of logging state (if 350 // DisableRecording() also forces a persistent save of logging state (if
389 // anything has been recorded, or transmitted). 351 // anything has been recorded, or transmitted).
390 void EnableRecording(); 352 void EnableRecording();
391 void DisableRecording(); 353 void DisableRecording();
392 354
393 // If in_idle is true, sets idle_since_last_transmission to true. 355 // If in_idle is true, sets idle_since_last_transmission to true.
394 // If in_idle is false and idle_since_last_transmission_ is true, sets 356 // If in_idle is false and idle_since_last_transmission_ is true, sets
395 // idle_since_last_transmission to false and starts the timer (provided 357 // idle_since_last_transmission to false and starts the timer (provided
396 // starting the timer is permitted). 358 // starting the timer is permitted).
397 void HandleIdleSinceLastTransmission(bool in_idle); 359 void HandleIdleSinceLastTransmission(bool in_idle);
398 360
399 // Set up client ID, session ID, etc. 361 // Set up client ID, session ID, etc.
400 void InitializeMetricsState(ReportingState reporting_state); 362 void InitializeMetricsState();
401
402 // Generates a new client ID to use to identify self to metrics server.
403 static std::string GenerateClientID();
404 363
405 // Schedule the next save of LocalState information. This is called 364 // Schedule the next save of LocalState information. This is called
406 // automatically by the task that performs each save to schedule the next one. 365 // automatically by the task that performs each save to schedule the next one.
407 void ScheduleNextStateSave(); 366 void ScheduleNextStateSave();
408 367
409 // Save the LocalState information immediately. This should not be called by 368 // Save the LocalState information immediately. This should not be called by
410 // anybody other than the scheduler to avoid doing too many writes. When you 369 // anybody other than the scheduler to avoid doing too many writes. When you
411 // make a change, call ScheduleNextStateSave() instead. 370 // make a change, call ScheduleNextStateSave() instead.
412 void SaveLocalState(); 371 void SaveLocalState();
413 372
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 464
506 // Returns true if process of type |type| should be counted as a plugin 465 // Returns true if process of type |type| should be counted as a plugin
507 // process, and false otherwise. 466 // process, and false otherwise.
508 static bool IsPluginProcess(int process_type); 467 static bool IsPluginProcess(int process_type);
509 468
510 // Returns a list of synthetic field trials that were active for the entire 469 // Returns a list of synthetic field trials that were active for the entire
511 // duration of the current log. 470 // duration of the current log.
512 void GetCurrentSyntheticFieldTrials( 471 void GetCurrentSyntheticFieldTrials(
513 std::vector<chrome_variations::ActiveGroupId>* synthetic_trials); 472 std::vector<chrome_variations::ActiveGroupId>* synthetic_trials);
514 473
474 // Used to manage various metrics reporting state prefs, such as client id,
475 // low entropy source and whether metrics reporting is enabled.
476 scoped_ptr<metrics::MetricsStateManager> state_manager_;
477
515 base::ActionCallback action_callback_; 478 base::ActionCallback action_callback_;
516 479
517 content::NotificationRegistrar registrar_; 480 content::NotificationRegistrar registrar_;
518 481
519 // Set to true when |ResetMetricsIDsIfNecessary| is called for the first time. 482 // Set to true when |ResetMetricsIDsIfNecessary| is called for the first time.
520 // This prevents multiple resets within the same Chrome session. 483 // This prevents multiple resets within the same Chrome session.
521 bool metrics_ids_reset_check_performed_; 484 bool metrics_ids_reset_check_performed_;
522 485
523 // Indicate whether recording and reporting are currently happening. 486 // Indicate whether recording and reporting are currently happening.
524 // These should not be set directly, but by calling SetRecording and 487 // These should not be set directly, but by calling SetRecording and
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
556 519
557 // The outstanding transmission appears as a URL Fetch operation. 520 // The outstanding transmission appears as a URL Fetch operation.
558 scoped_ptr<net::URLFetcher> current_fetch_; 521 scoped_ptr<net::URLFetcher> current_fetch_;
559 522
560 // The TCP/UDP echo server to collect network connectivity stats. 523 // The TCP/UDP echo server to collect network connectivity stats.
561 std::string network_stats_server_; 524 std::string network_stats_server_;
562 525
563 // The HTTP pipelining test server. 526 // The HTTP pipelining test server.
564 std::string http_pipelining_test_server_; 527 std::string http_pipelining_test_server_;
565 528
566 // The identifier that's sent to the server with the log reports.
567 std::string client_id_;
568
569 // The non-identifying low entropy source value.
570 int low_entropy_source_;
571
572 // Whether the MetricsService object has received any notifications since 529 // Whether the MetricsService object has received any notifications since
573 // the last time a transmission was sent. 530 // the last time a transmission was sent.
574 bool idle_since_last_transmission_; 531 bool idle_since_last_transmission_;
575 532
576 // A number that identifies the how many times the app has been launched. 533 // A number that identifies the how many times the app has been launched.
577 int session_id_; 534 int session_id_;
578 535
579 // Maps WebContentses (corresponding to tabs) or Browsers (corresponding to 536 // Maps WebContentses (corresponding to tabs) or Browsers (corresponding to
580 // Windows) to a unique integer that we will use to identify them. 537 // Windows) to a unique integer that we will use to identify them.
581 // |next_window_id_| is used to track which IDs we have used so far. 538 // |next_window_id_| is used to track which IDs we have used so far.
(...skipping 20 matching lines...) Expand all
602 bool waiting_for_asynchronous_reporting_step_; 559 bool waiting_for_asynchronous_reporting_step_;
603 560
604 // Number of async histogram fetch requests in progress. 561 // Number of async histogram fetch requests in progress.
605 int num_async_histogram_fetches_in_progress_; 562 int num_async_histogram_fetches_in_progress_;
606 563
607 #if defined(OS_CHROMEOS) 564 #if defined(OS_CHROMEOS)
608 // The external metric service is used to log ChromeOS UMA events. 565 // The external metric service is used to log ChromeOS UMA events.
609 scoped_refptr<chromeos::ExternalMetrics> external_metrics_; 566 scoped_refptr<chromeos::ExternalMetrics> external_metrics_;
610 #endif 567 #endif
611 568
612 // The last entropy source returned by this service, used for testing.
613 EntropySourceReturned entropy_source_returned_;
614
615 // Stores the time of the first call to |GetUptimes()|. 569 // Stores the time of the first call to |GetUptimes()|.
616 base::TimeTicks first_updated_time_; 570 base::TimeTicks first_updated_time_;
617 571
618 // Stores the time of the last call to |GetUptimes()|. 572 // Stores the time of the last call to |GetUptimes()|.
619 base::TimeTicks last_updated_time_; 573 base::TimeTicks last_updated_time_;
620 574
621 // Execution phase the browser is in. 575 // Execution phase the browser is in.
622 static ExecutionPhase execution_phase_; 576 static ExecutionPhase execution_phase_;
623 577
624 // Reduntant marker to check that we completed our shutdown, and set the 578 // Reduntant marker to check that we completed our shutdown, and set the
625 // exited-cleanly bit in the prefs. 579 // exited-cleanly bit in the prefs.
626 static ShutdownCleanliness clean_shutdown_status_; 580 static ShutdownCleanliness clean_shutdown_status_;
627 581
628 // Field trial groups that map to Chrome configuration states. 582 // Field trial groups that map to Chrome configuration states.
629 SyntheticTrialGroups synthetic_trial_groups_; 583 SyntheticTrialGroups synthetic_trial_groups_;
630 584
631 scoped_ptr<metrics::ClonedInstallDetector> cloned_install_detector_;
632
633 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, ClientIdCorrectlyFormatted);
634 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, IsPluginProcess); 585 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, IsPluginProcess);
635 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, LowEntropySource0NotReset);
636 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, 586 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest,
637 PermutedEntropyCacheClearedWhenLowEntropyReset); 587 PermutedEntropyCacheClearedWhenLowEntropyReset);
638 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RegisterSyntheticTrial); 588 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RegisterSyntheticTrial);
639 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, ResetMetricsIDs);
640 FRIEND_TEST_ALL_PREFIXES(MetricsServiceBrowserTest,
641 CheckLowEntropySourceUsed);
642 FRIEND_TEST_ALL_PREFIXES(MetricsServiceReportingTest,
643 CheckHighEntropySourceUsed);
644 589
645 DISALLOW_COPY_AND_ASSIGN(MetricsService); 590 DISALLOW_COPY_AND_ASSIGN(MetricsService);
646 }; 591 };
647 592
648 // This class limits and documents access to the IsMetricsReportingEnabled() and 593 // This class limits and documents access to the IsMetricsReportingEnabled() and
649 // IsCrashReportingEnabled() methods. Since these methods are private, each user 594 // IsCrashReportingEnabled() methods. Since these methods are private, each user
650 // has to be explicitly declared as a 'friend' below. 595 // has to be explicitly declared as a 'friend' below.
651 class MetricsServiceHelper { 596 class MetricsServiceHelper {
652 private: 597 private:
653 friend bool prerender::IsOmniboxEnabled(Profile* profile); 598 friend bool prerender::IsOmniboxEnabled(Profile* profile);
654 friend class ChromeRenderMessageFilter; 599 friend class ChromeRenderMessageFilter;
655 friend class ::CrashesDOMHandler; 600 friend class ::CrashesDOMHandler;
656 friend class extensions::ExtensionDownloader; 601 friend class extensions::ExtensionDownloader;
657 friend class extensions::ManifestFetchData; 602 friend class extensions::ManifestFetchData;
658 friend class extensions::MetricsPrivateGetIsCrashReportingEnabledFunction; 603 friend class extensions::MetricsPrivateGetIsCrashReportingEnabledFunction;
659 friend class ::FlashDOMHandler; 604 friend class ::FlashDOMHandler;
660 friend class system_logs::ChromeInternalLogSource; 605 friend class system_logs::ChromeInternalLogSource;
661 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, MetricsReportingEnabled); 606 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, MetricsReportingEnabled);
662 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, CrashReportingEnabled); 607 FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, CrashReportingEnabled);
663 608
664 // Returns true if prefs::kMetricsReportingEnabled is set. 609 // Returns true if prefs::kMetricsReportingEnabled is set.
610 // TODO(asvitkine): Consolidate the method in MetricsStateManager.
611 // TODO(asvitkine): This function does not report the correct value on
612 // Android and ChromeOS, see http://crbug.com/362192.
665 static bool IsMetricsReportingEnabled(); 613 static bool IsMetricsReportingEnabled();
666 614
667 // Returns true if crash reporting is enabled. This is set at the platform 615 // Returns true if crash reporting is enabled. This is set at the platform
668 // level for Android and ChromeOS, and otherwise is the same as 616 // level for Android and ChromeOS, and otherwise is the same as
669 // IsMetricsReportingEnabled for desktop Chrome. 617 // IsMetricsReportingEnabled for desktop Chrome.
670 static bool IsCrashReportingEnabled(); 618 static bool IsCrashReportingEnabled();
671 619
672 DISALLOW_IMPLICIT_CONSTRUCTORS(MetricsServiceHelper); 620 DISALLOW_IMPLICIT_CONSTRUCTORS(MetricsServiceHelper);
673 }; 621 };
674 622
675 #endif // CHROME_BROWSER_METRICS_METRICS_SERVICE_H_ 623 #endif // CHROME_BROWSER_METRICS_METRICS_SERVICE_H_
OLDNEW
« no previous file with comments | « chrome/browser/metrics/cloned_install_detector_unittest.cc ('k') | chrome/browser/metrics/metrics_service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698