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

Side by Side Diff: ios/chrome/browser/omaha/omaha_service.mm

Issue 2568003005: [ios] Adds code for Omaha and the upgrade center. (Closed)
Patch Set: Review. Created 4 years 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
OLDNEW
(Empty)
1 // Copyright 2012 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 #include "ios/chrome/browser/omaha/omaha_service.h"
6
7 #include <Foundation/Foundation.h>
8
9 #include <memory>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/i18n/time_formatting.h"
14 #include "base/ios/device_util.h"
15 #include "base/logging.h"
16 #include "base/mac/scoped_nsobject.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/metrics/field_trial.h"
19 #include "base/rand_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/sys_string_conversions.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/sys_info.h"
24 #include "base/time/time.h"
25 #include "base/values.h"
26 #include "components/metrics/metrics_pref_names.h"
27 #include "components/prefs/pref_service.h"
28 #include "components/version_info/version_info.h"
29 #include "ios/chrome/browser/application_context.h"
30 #include "ios/chrome/browser/arch_util.h"
31 #include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h"
32 #include "ios/chrome/browser/browser_state_metrics/browser_state_metrics.h"
33 #include "ios/chrome/browser/install_time_util.h"
34 #include "ios/chrome/browser/ui/ui_util.h"
35 #include "ios/chrome/browser/upgrade/upgrade_recommended_details.h"
36 #include "ios/chrome/common/channel_info.h"
37 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
38 #include "ios/public/provider/chrome/browser/omaha/omaha_service_provider.h"
39 #include "ios/public/provider/chrome/browser/omaha/omaha_xml_writer.h"
40 #include "ios/web/public/web_thread.h"
41 #include "libxml/xmlwriter.h"
42 #include "net/base/backoff_entry.h"
43 #include "net/base/load_flags.h"
44 #include "net/url_request/url_fetcher.h"
45 #include "url/gurl.h"
46
47 namespace {
48 // Number of hours to wait between successful requests.
49 const int kHoursBetweenRequests = 5;
50 // Minimal time to wait between retry requests.
51 const CFTimeInterval kPostRetryBaseSeconds = 3600;
52 // Maximal time to wait between retry requests.
53 const CFTimeInterval kPostRetryMaxSeconds = 6 * kPostRetryBaseSeconds;
54
55 // Default last sent application version when none has been sent yet.
56 const char kDefaultLastSentVersion[] = "0.0.0.0";
57
58 // Key for saving states in the UserDefaults.
59 NSString* const kNextTriesTimesKey = @"ChromeOmahaServiceNextTries";
60 NSString* const kCurrentPingKey = @"ChromeOmahaServiceCurrentPing";
61 NSString* const kNumberTriesKey = @"ChromeOmahaServiceNumberTries";
62 NSString* const kLastSentVersionKey = @"ChromeOmahaServiceLastSentVersion";
63 NSString* const kLastSentTimeKey = @"ChromeOmahaServiceLastSentTime";
64 NSString* const kRetryRequestIdKey = @"ChromeOmahaServiceRetryRequestId";
65
66 class XmlWrapper : public OmahaXmlWriter {
67 public:
68 XmlWrapper()
69 : buffer_(xmlBufferCreate()),
70 writer_(xmlNewTextWriterMemory(buffer_, /* compression */ 0)) {
71 DCHECK(buffer_);
72 DCHECK(writer_);
73 }
74
75 ~XmlWrapper() override {
76 xmlFreeTextWriter(writer_);
77 xmlBufferFree(buffer_);
78 }
79
80 void StartElement(const char* name) override {
81 DCHECK(name);
82 int result = xmlTextWriterStartElement(
83 writer_, reinterpret_cast<const xmlChar*>(name));
84 DCHECK_GE(result, 0);
85 }
86
87 void EndElement() override {
88 int result = xmlTextWriterEndElement(writer_);
89 DCHECK_GE(result, 0);
90 }
91
92 void WriteAttribute(const char* name, const char* value) override {
93 DCHECK(name);
94 int result = xmlTextWriterWriteAttribute(
95 writer_, reinterpret_cast<const xmlChar*>(name),
96 reinterpret_cast<const xmlChar*>(value));
97 DCHECK_GE(result, 0);
98 }
99
100 void Finalize() override {
101 int result = xmlTextWriterEndDocument(writer_);
102 DCHECK_GE(result, 0);
103 }
104
105 std::string GetContentAsString() override {
106 return std::string(reinterpret_cast<char*>(buffer_->content));
107 }
108
109 private:
110 xmlBufferPtr buffer_;
111 xmlTextWriterPtr writer_;
112
113 DISALLOW_COPY_AND_ASSIGN(XmlWrapper);
114 };
115
116 } // namespace
117
118 #pragma mark -
119
120 // XML parser for the server response.
121 @interface ResponseParser : NSObject<NSXMLParserDelegate> {
122 BOOL hasError_;
123 BOOL responseIsParsed_;
124 BOOL appIsParsed_;
125 BOOL updateCheckIsParsed_;
126 BOOL urlIsParsed_;
127 BOOL manifestIsParsed_;
128 BOOL pingIsParsed_;
129 BOOL eventIsParsed_;
130 base::scoped_nsobject<NSString> appId_;
131 std::unique_ptr<UpgradeRecommendedDetails> updateInformation_;
132 }
133
134 // Initialization method. |appId| is the application id one expects to find in
135 // the response message.
136 - (instancetype)initWithAppId:(NSString*)appId;
137
138 // Returns YES if the message has been correctly parsed.
139 - (BOOL)isCorrect;
140
141 // If an upgrade is possible, returns the details of the notification to send.
142 // Otherwise, return NULL.
143 - (UpgradeRecommendedDetails*)upgradeRecommendedDetails;
144
145 @end
146
147 @implementation ResponseParser
148
149 - (instancetype)initWithAppId:(NSString*)appId {
150 if (self = [super init]) {
151 appId_.reset([appId retain]);
152 }
153 return self;
154 }
155
156 - (BOOL)isCorrect {
157 // A response should have either a ping ACK or an event ACK, depending on the
158 // contents of the request.
159 return !hasError_ && (pingIsParsed_ || eventIsParsed_);
160 }
161
162 - (UpgradeRecommendedDetails*)upgradeRecommendedDetails {
163 return updateInformation_.get();
164 }
165
166 // This method is parsing a message with the following type:
167 // <response...>
168 // <daystart.../>
169 // <app...>
170 // <updatecheck status="ok">
171 // <urls>
172 // <url codebase="???"/>
173 // </urls>
174 // <manifest version="???">
175 // <packages>
176 // <package hash="0" name="Chrome" required="true" size="0"/>
177 // </packages>
178 // <actions>
179 // <action event="update" run="Chrome"/>
180 // <action event="postinstall"/>
181 // </actions>
182 // </manifest>
183 // </updatecheck>
184 // <ping.../>
185 // </app>
186 // </response>
187 // --- OR ---
188 // <response...>
189 // <daystart.../>
190 // <app...>
191 // <event.../>
192 // </app>
193 // </response>
194 // See http://code.google.com/p/omaha/wiki/ServerProtocol for details.
195 - (void)parser:(NSXMLParser*)parser
196 didStartElement:(NSString*)elementName
197 namespaceURI:(NSString*)namespaceURI
198 qualifiedName:(NSString*)qualifiedName
199 attributes:(NSDictionary*)attributeDict {
200 if (hasError_)
201 return;
202
203 // Array of uninteresting tags in the Omaha xml response.
204 NSArray* ignoredTagNames =
205 @[ @"action", @"actions", @"daystart", @"package", @"packages", @"urls" ];
206 if ([ignoredTagNames containsObject:elementName])
207 return;
208
209 if (!responseIsParsed_) {
210 if ([elementName isEqualToString:@"response"] &&
211 [[attributeDict valueForKey:@"protocol"] isEqualToString:@"3.0"] &&
212 [[attributeDict valueForKey:@"server"] isEqualToString:@"prod"]) {
213 responseIsParsed_ = YES;
214 } else {
215 hasError_ = YES;
216 }
217 } else if (!appIsParsed_) {
218 if ([elementName isEqualToString:@"app"] &&
219 [[attributeDict valueForKey:@"status"] isEqualToString:@"ok"] &&
220 [[attributeDict valueForKey:@"appid"] isEqualToString:appId_]) {
221 appIsParsed_ = YES;
222 } else {
223 hasError_ = YES;
224 }
225 } else if (!eventIsParsed_ && !updateCheckIsParsed_) {
226 if ([elementName isEqualToString:@"updatecheck"]) {
227 updateCheckIsParsed_ = YES;
228 NSString* status = [attributeDict valueForKey:@"status"];
229 if ([status isEqualToString:@"noupdate"]) {
230 // No update is available on the Market, so we won't get a <url> or
231 // <manifest> tag.
232 urlIsParsed_ = YES;
233 manifestIsParsed_ = YES;
234 } else if ([status isEqualToString:@"ok"]) {
235 updateInformation_ = base::MakeUnique<UpgradeRecommendedDetails>();
236 } else {
237 hasError_ = YES;
238 }
239 } else if ([elementName isEqualToString:@"event"]) {
240 if ([[attributeDict valueForKey:@"status"] isEqualToString:@"ok"]) {
241 eventIsParsed_ = YES;
242 } else {
243 hasError_ = YES;
244 }
245 } else {
246 hasError_ = YES;
247 }
248 } else if (!urlIsParsed_) {
249 if ([elementName isEqualToString:@"url"] &&
250 [[attributeDict valueForKey:@"codebase"] length] > 0) {
251 urlIsParsed_ = YES;
252 DCHECK(updateInformation_);
253 NSString* url = [attributeDict valueForKey:@"codebase"];
254 if ([[url substringFromIndex:([url length] - 1)] isEqualToString:@"/"])
255 url = [url substringToIndex:([url length] - 1)];
256 updateInformation_.get()->upgrade_url =
257 GURL(base::SysNSStringToUTF8(url));
258 if (!updateInformation_.get()->upgrade_url.is_valid())
259 hasError_ = YES;
260 } else {
261 hasError_ = YES;
262 }
263 } else if (!manifestIsParsed_) {
264 if ([elementName isEqualToString:@"manifest"] &&
265 [attributeDict valueForKey:@"version"]) {
266 manifestIsParsed_ = YES;
267 DCHECK(updateInformation_);
268 updateInformation_.get()->next_version =
269 base::SysNSStringToUTF8([attributeDict valueForKey:@"version"]);
270 } else {
271 hasError_ = YES;
272 }
273 } else if (!pingIsParsed_) {
274 if ([elementName isEqualToString:@"ping"] &&
275 [[attributeDict valueForKey:@"status"] isEqualToString:@"ok"]) {
276 pingIsParsed_ = YES;
277 } else {
278 hasError_ = YES;
279 }
280 } else {
281 hasError_ = YES;
282 }
283 }
284
285 @end
286
287 // static
288 OmahaService* OmahaService::GetInstance() {
289 return base::Singleton<OmahaService>::get();
290 }
291
292 // static
293 void OmahaService::Start(net::URLRequestContextGetter* request_context_getter,
294 const UpgradeRecommendedCallback& callback) {
295 DCHECK(request_context_getter);
296 DCHECK(!callback.is_null());
297 OmahaService* result = GetInstance();
298 result->set_upgrade_recommended_callback(callback);
299 // This should only be called once.
300 DCHECK(!result->request_context_getter_);
301 result->request_context_getter_ = request_context_getter;
302 result->locale_lang_ = GetApplicationContext()->GetApplicationLocale();
303 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE,
304 base::Bind(&OmahaService::SendOrScheduleNextPing,
305 base::Unretained(result)));
306 }
307
308 OmahaService::OmahaService()
309 : request_context_getter_(NULL),
310 schedule_(true),
311 application_install_date_(0),
312 sending_install_event_(false) {
313 Initialize();
314 }
315
316 OmahaService::OmahaService(bool schedule)
317 : request_context_getter_(NULL),
318 schedule_(schedule),
319 application_install_date_(0),
320 sending_install_event_(false) {
321 Initialize();
322 }
323
324 OmahaService::~OmahaService() {}
325
326 void OmahaService::Initialize() {
327 // Initialize the provider at the same time as the rest of the service.
328 ios::GetChromeBrowserProvider()->GetOmahaServiceProvider()->Initialize();
329
330 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
331 next_tries_time_ = base::Time::FromCFAbsoluteTime(
332 [defaults doubleForKey:kNextTriesTimesKey]);
333 current_ping_time_ =
334 base::Time::FromCFAbsoluteTime([defaults doubleForKey:kCurrentPingKey]);
335 number_of_tries_ = [defaults integerForKey:kNumberTriesKey];
336 last_sent_time_ =
337 base::Time::FromCFAbsoluteTime([defaults doubleForKey:kLastSentTimeKey]);
338 NSString* lastSentVersion = [defaults stringForKey:kLastSentVersionKey];
339 if (lastSentVersion) {
340 last_sent_version_ =
341 base::Version(base::SysNSStringToUTF8(lastSentVersion));
342 } else {
343 last_sent_version_ = base::Version(kDefaultLastSentVersion);
344 }
345
346 application_install_date_ =
347 GetApplicationContext()->GetLocalState()->GetInt64(
348 metrics::prefs::kInstallDate);
349 DCHECK(application_install_date_);
350
351 // Whether data should be persisted again to the user preferences.
352 bool persist_again = false;
353
354 base::Time now = base::Time::Now();
355 // If |last_sent_time_| is in the future, the clock has been tampered with.
356 // Reset |last_sent_time_| to now.
357 if (last_sent_time_ > now) {
358 last_sent_time_ = now;
359 persist_again = true;
360 }
361
362 // If the |next_tries_time_| is more than kHoursBetweenRequests hours away,
363 // there is a possibility that the clock has been tampered with. Reschedule
364 // the ping to be the usual interval after the last successful one.
365 if (next_tries_time_ - now >
366 base::TimeDelta::FromHours(kHoursBetweenRequests)) {
367 next_tries_time_ =
368 last_sent_time_ + base::TimeDelta::FromHours(kHoursBetweenRequests);
369 persist_again = true;
370 }
371
372 // Fire a ping as early as possible if the version changed.
373 base::Version current_version(version_info::GetVersionNumber());
374 if (last_sent_version_ < current_version) {
375 next_tries_time_ = base::Time::Now() - base::TimeDelta::FromSeconds(1);
376 number_of_tries_ = 0;
377 persist_again = true;
378 }
379
380 if (persist_again)
381 PersistStates();
382 }
383
384 // static
385 void OmahaService::GetDebugInformation(
386 const base::Callback<void(base::DictionaryValue*)> callback) {
387 web::WebThread::PostTask(
388 web::WebThread::IO, FROM_HERE,
389 base::Bind(&OmahaService::GetDebugInformationOnIOThread,
390 base::Unretained(GetInstance()), callback));
391 }
392
393 // static
394 base::TimeDelta OmahaService::GetBackOff(uint8_t number_of_tries) {
395 // Configuration for the service exponential backoff
396 static net::BackoffEntry::Policy kBackoffPolicy = {
397 0, // num_errors_to_ignore
398 kPostRetryBaseSeconds * 1000, // initial_delay_ms
399 2.0, // multiply_factor
400 0.1, // jitter_factor
401 kPostRetryMaxSeconds * 1000, // maximum_backoff_ms
402 -1, // entry_lifetime_ms
403 false // always_use_initial_delay
404 };
405
406 net::BackoffEntry backoff_entry(&kBackoffPolicy);
407 for (int i = 0; i < number_of_tries; ++i) {
408 backoff_entry.InformOfRequest(false);
409 }
410
411 return backoff_entry.GetTimeUntilRelease();
412 }
413
414 std::string OmahaService::GetPingContent(const std::string& requestId,
415 const std::string& sessionId,
416 const std::string& versionName,
417 const std::string& channelName,
418 const base::Time& installationTime,
419 PingContent pingContent) {
420 OmahaServiceProvider* provider =
421 ios::GetChromeBrowserProvider()->GetOmahaServiceProvider();
422
423 XmlWrapper xml_wrapper;
424 xml_wrapper.StartElement("request");
425 xml_wrapper.WriteAttribute("protocol", "3.0");
426 xml_wrapper.WriteAttribute("version", "iOS-1.0.0.0");
427 xml_wrapper.WriteAttribute("ismachine", "1");
428 xml_wrapper.WriteAttribute("requestid", requestId.c_str());
429 xml_wrapper.WriteAttribute("sessionid", sessionId.c_str());
430 provider->AppendExtraAttributes("request", &xml_wrapper);
431 xml_wrapper.WriteAttribute("hardware_class",
432 ios::device_util::GetPlatform().c_str());
433 // Set up <os platform="ios"... />
434 xml_wrapper.StartElement("os");
435 xml_wrapper.WriteAttribute("platform", "ios");
436 xml_wrapper.WriteAttribute("version",
437 base::SysInfo::OperatingSystemVersion().c_str());
438 xml_wrapper.WriteAttribute("arch", arch_util::kCurrentArch);
439 xml_wrapper.EndElement();
440
441 bool is_first_install =
442 pingContent == INSTALL_EVENT &&
443 last_sent_version_ == base::Version(kDefaultLastSentVersion);
444
445 // Set up <app version="" ...>
446 xml_wrapper.StartElement("app");
447 if (pingContent == INSTALL_EVENT) {
448 std::string previous_version =
449 is_first_install ? "" : last_sent_version_.GetString();
450 xml_wrapper.WriteAttribute("version", previous_version.c_str());
451 xml_wrapper.WriteAttribute("nextversion", versionName.c_str());
452 } else {
453 xml_wrapper.WriteAttribute("version", versionName.c_str());
454 xml_wrapper.WriteAttribute("nextversion", "");
455 }
456 xml_wrapper.WriteAttribute("lang", locale_lang_.c_str());
457 xml_wrapper.WriteAttribute("brand", provider->GetBrandCode().c_str());
458 xml_wrapper.WriteAttribute("client", "");
459 std::string application_id = provider->GetApplicationID();
460 xml_wrapper.WriteAttribute("appid", application_id.c_str());
461 std::string install_age;
462 if (is_first_install) {
463 install_age = "-1";
464 } else if (!installationTime.is_null() &&
465 installationTime.ToTimeT() !=
466 install_time_util::kUnknownInstallDate) {
467 install_age = base::StringPrintf(
468 "%d", (base::Time::Now() - installationTime).InDays());
469 }
470 provider->AppendExtraAttributes("app", &xml_wrapper);
471 // If the install date is unknown, send nothing.
472 if (!install_age.empty())
473 xml_wrapper.WriteAttribute("installage", install_age.c_str());
474
475 if (pingContent == INSTALL_EVENT) {
476 // Add an install complete event.
477 xml_wrapper.StartElement("event");
478 if (is_first_install) {
479 xml_wrapper.WriteAttribute("eventtype", "2"); // install
480 } else {
481 xml_wrapper.WriteAttribute("eventtype", "3"); // update
482 }
483 xml_wrapper.WriteAttribute("eventresult", "1"); // succeeded
484 xml_wrapper.EndElement();
485 } else {
486 // Set up <updatecheck/>
487 xml_wrapper.StartElement("updatecheck");
488 xml_wrapper.WriteAttribute("tag", channelName.c_str());
489 xml_wrapper.EndElement();
490
491 // Set up <ping active=1/>
492 xml_wrapper.StartElement("ping");
493 xml_wrapper.WriteAttribute("active", "1");
494 xml_wrapper.EndElement();
495 }
496
497 // End app.
498 xml_wrapper.EndElement();
499 // End request.
500 xml_wrapper.EndElement();
501
502 xml_wrapper.Finalize();
503 return xml_wrapper.GetContentAsString();
504 }
505
506 std::string OmahaService::GetCurrentPingContent() {
507 base::Version current_version(version_info::GetVersionNumber());
508 sending_install_event_ = last_sent_version_ < current_version;
509 PingContent ping_content =
510 sending_install_event_ ? INSTALL_EVENT : USAGE_PING;
511
512 // An install retry ping only makes sense if an install event must be send.
513 DCHECK(sending_install_event_ || !IsNextPingInstallRetry());
514 std::string request_id = GetNextPingRequestId(ping_content);
515 return GetPingContent(request_id, ios::device_util::GetRandomId(),
516 version_info::GetVersionNumber(), GetChannelString(),
517 base::Time::FromTimeT(application_install_date_),
518 ping_content);
519 }
520
521 void OmahaService::SendPing() {
522 // Check that no request is in progress.
523 DCHECK(!fetcher_);
524
525 GURL url(ios::GetChromeBrowserProvider()
526 ->GetOmahaServiceProvider()
527 ->GetUpdateServerURL());
528 if (!url.is_valid()) {
529 return;
530 }
531
532 fetcher_ = net::URLFetcher::Create(0, url, net::URLFetcher::POST, this);
533 fetcher_->SetRequestContext(request_context_getter_);
534 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
535 net::LOAD_DO_NOT_SAVE_COOKIES);
536 fetcher_->SetUploadData("text/xml", GetCurrentPingContent());
537
538 // If this is not the first try, notify the omaha server.
539 if (number_of_tries_ && IsNextPingInstallRetry()) {
540 fetcher_->SetExtraRequestHeaders(base::StringPrintf(
541 "X-RequestAge: %lld",
542 (base::Time::Now() - current_ping_time_).InSeconds()));
543 }
544
545 // Update last fail time and number of tries, so that if anything fails
546 // catastrophically, the fail is taken into account.
547 if (number_of_tries_ < 30)
548 ++number_of_tries_;
549 next_tries_time_ = base::Time::Now() + GetBackOff(number_of_tries_);
550 PersistStates();
551
552 fetcher_->Start();
553 }
554
555 void OmahaService::SendOrScheduleNextPing() {
556 base::Time now = base::Time::Now();
557 if (next_tries_time_ <= now) {
558 SendPing();
559 return;
560 }
561 if (schedule_) {
562 timer_.Start(FROM_HERE, next_tries_time_ - now, this,
563 &OmahaService::SendPing);
564 }
565 }
566
567 void OmahaService::PersistStates() {
568 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
569
570 [defaults setDouble:next_tries_time_.ToCFAbsoluteTime()
571 forKey:kNextTriesTimesKey];
572 [defaults setDouble:current_ping_time_.ToCFAbsoluteTime()
573 forKey:kCurrentPingKey];
574 [defaults setDouble:last_sent_time_.ToCFAbsoluteTime()
575 forKey:kLastSentTimeKey];
576 [defaults setInteger:number_of_tries_ forKey:kNumberTriesKey];
577 [defaults setObject:base::SysUTF8ToNSString(last_sent_version_.GetString())
578 forKey:kLastSentVersionKey];
579
580 // Save critical state information for usage reporting.
581 [defaults synchronize];
582 }
583
584 void OmahaService::OnURLFetchComplete(const net::URLFetcher* fetcher) {
585 DCHECK(fetcher_.get() == fetcher);
586 // Transfer the ownership of fetcher_ to this method.
587 std::unique_ptr<net::URLFetcher> local_fetcher = std::move(fetcher_);
588
589 if (fetcher->GetResponseCode() != 200) {
590 DLOG(WARNING) << "Error contacting the Omaha server";
591 SendOrScheduleNextPing();
592 return;
593 }
594
595 std::string response;
596 bool result = fetcher->GetResponseAsString(&response);
597 DCHECK(result);
598 NSData* xml = [NSData dataWithBytes:response.data() length:response.length()];
599 base::scoped_nsobject<NSXMLParser> parser(
600 [[NSXMLParser alloc] initWithData:xml]);
601 const std::string application_id = ios::GetChromeBrowserProvider()
602 ->GetOmahaServiceProvider()
603 ->GetApplicationID();
604 base::scoped_nsobject<ResponseParser> delegate([[ResponseParser alloc]
605 initWithAppId:base::SysUTF8ToNSString(application_id)]);
606 parser.get().delegate = delegate.get();
607
608 if (![parser parse] || ![delegate isCorrect]) {
609 DLOG(ERROR) << "Unable to parse XML response from Omaha server.";
610 SendOrScheduleNextPing();
611 return;
612 }
613 // Handle success.
614 number_of_tries_ = 0;
615 // Schedule the next request. If requset that just finished was an install
616 // notification, send an active ping immediately.
617 next_tries_time_ = sending_install_event_
618 ? base::Time::Now()
619 : base::Time::Now() + base::TimeDelta::FromHours(
620 kHoursBetweenRequests);
621 current_ping_time_ = next_tries_time_;
622 last_sent_time_ = base::Time::Now();
623 last_sent_version_ = base::Version(version_info::GetVersionNumber());
624 sending_install_event_ = false;
625 ClearInstallRetryRequestId();
626 PersistStates();
627 SendOrScheduleNextPing();
628
629 // Send notification for updates if needed.
630 UpgradeRecommendedDetails* details =
631 [delegate.get() upgradeRecommendedDetails];
632 if (details) {
633 web::WebThread::PostTask(
634 web::WebThread::UI, FROM_HERE,
635 base::Bind(upgrade_recommended_callback_, *details));
636 }
637 }
638
639 void OmahaService::GetDebugInformationOnIOThread(
640 const base::Callback<void(base::DictionaryValue*)> callback) {
641 auto result = base::MakeUnique<base::DictionaryValue>();
642
643 result->SetString("message", GetCurrentPingContent());
644 result->SetString("last_sent_time",
645 base::TimeFormatShortDateAndTime(last_sent_time_));
646 result->SetString("next_tries_time",
647 base::TimeFormatShortDateAndTime(next_tries_time_));
648 result->SetString("current_ping_time",
649 base::TimeFormatShortDateAndTime(current_ping_time_));
650 result->SetString("last_sent_version", last_sent_version_.GetString());
651 result->SetString("number_of_tries",
652 base::StringPrintf("%d", number_of_tries_));
653 result->SetString("timer_running",
654 base::StringPrintf("%d", timer_.IsRunning()));
655 result->SetString(
656 "timer_current_delay",
657 base::StringPrintf("%llds", timer_.GetCurrentDelay().InSeconds()));
658 result->SetString("timer_desired_run_time",
659 base::TimeFormatShortDateAndTime(
660 base::Time::Now() +
661 (timer_.desired_run_time() - base::TimeTicks::Now())));
662
663 // Sending the value to the callback.
664 web::WebThread::PostTask(web::WebThread::UI, FROM_HERE,
665 base::Bind(callback, base::Owned(result.release())));
666 }
667
668 bool OmahaService::IsNextPingInstallRetry() {
669 return [[NSUserDefaults standardUserDefaults]
670 stringForKey:kRetryRequestIdKey] != nil;
671 }
672
673 std::string OmahaService::GetNextPingRequestId(PingContent ping_content) {
674 NSString* stored_id =
675 [[NSUserDefaults standardUserDefaults] stringForKey:kRetryRequestIdKey];
676 if (stored_id) {
677 DCHECK(ping_content == INSTALL_EVENT);
678 return base::SysNSStringToUTF8(stored_id);
679 } else {
680 std::string identifier = ios::device_util::GetRandomId();
681 if (ping_content == INSTALL_EVENT)
682 OmahaService::SetInstallRetryRequestId(identifier);
683 return identifier;
684 }
685 }
686
687 void OmahaService::SetInstallRetryRequestId(const std::string& request_id) {
688 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
689 [defaults setObject:base::SysUTF8ToNSString(request_id)
690 forKey:kRetryRequestIdKey];
691 // Save critical state information for usage reporting.
692 [defaults synchronize];
693 }
694
695 void OmahaService::ClearInstallRetryRequestId() {
696 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
697 [defaults removeObjectForKey:kRetryRequestIdKey];
698 // Clear critical state information for usage reporting.
699 [defaults synchronize];
700 }
701
702 void OmahaService::ClearPersistentStateForTests() {
703 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
704 [defaults removeObjectForKey:kNextTriesTimesKey];
705 [defaults removeObjectForKey:kCurrentPingKey];
706 [defaults removeObjectForKey:kNumberTriesKey];
707 [defaults removeObjectForKey:kLastSentVersionKey];
708 [defaults removeObjectForKey:kLastSentTimeKey];
709 [defaults removeObjectForKey:kRetryRequestIdKey];
710 }
OLDNEW
« no previous file with comments | « ios/chrome/browser/omaha/omaha_service.h ('k') | ios/chrome/browser/omaha/omaha_service_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698