roll libyuv from 1483 to 1487
[chromium-blink-merge.git] / ios / chrome / browser / updatable_config / updatable_config_base.mm
blob0fa087301c26bb7e13a56ff3466afc305e970b0f
1 // Copyright 2013 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.
5 #import "ios/chrome/browser/updatable_config/updatable_config_base.h"
7 #include "base/logging.h"
8 #import "base/mac/bind_objc_block.h"
9 #include "base/mac/scoped_nsobject.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
13 #import "ios/public/provider/chrome/browser/updatable_resource_provider.h"
14 #include "ios/web/public/web_thread.h"
15 #import "net/base/mac/url_conversions.h"
16 #include "net/http/http_status_code.h"
17 #include "net/url_request/url_fetcher.h"
18 #include "net/url_request/url_fetcher_delegate.h"
19 #include "net/url_request/url_request_context.h"
20 #include "net/url_request/url_request_context_getter.h"
21 #include "url/gurl.h"
23 @interface UpdatableConfigBase ()
24 // Returns the application ID to use for fetching updatable configuration.
25 + (NSString*)defaultAppId;
26 // Fetches server-side updatable configuration plist.
27 - (void)checkUpdate;
28 #if !defined(NDEBUG)
29 // A method that will be executed on a delay if -startUpdate: was NOT called.
30 - (void)startUpdateNotCalled:(id)config;
31 // Schedules a call to -startUpdateNotCalled: for later to make sure that
32 // -startUpdate: will be called.
33 - (void)scheduleConsistencyCheck;
34 // Cancels the delayed call to -startUpdateNotCalled:.
35 - (void)cancelConsistencyCheck;
36 #endif  // !defined(NDEBUG)
37 @end
39 namespace {
41 #if !defined(NDEBUG)
42 // Global flag to enable or disable debug check that -startUpdate:
43 // has been called.
44 BOOL g_consistency_check_enabled = NO;
45 #endif
47 // Periodically fetch configuration updates from server.
48 const int64_t kPeriodicCheckInNanoseconds = 60 * 60 * 24 * NSEC_PER_SEC;
50 // Class to fetch config update |url| and also act as the delegate to
51 // handle callbacks from URLFetcher.
52 class ConfigFetcher : public net::URLFetcherDelegate {
53  public:
54   ConfigFetcher(UpdatableConfigBase* owner,
55                 id<UpdatableResourceDescriptorBridge> descriptor)
56       : owner_(owner), descriptor_(descriptor) {}
58   // Starts fetching |url| for updated configuration.
59   void Fetch(const GURL& url, net::URLRequestContextGetter* context) {
60     fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
61     fetcher_->SetRequestContext(context);
62     fetcher_->Start();
63   }
65   void OnURLFetchComplete(const net::URLFetcher* fetcher) override {
66     DCHECK_EQ(fetcher_, fetcher);
67     NSData* responseData = nil;
68     if (fetcher_->GetResponseCode() == net::HTTP_OK) {
69       std::string response;
70       fetcher_->GetResponseAsString(&response);
71       responseData =
72           [NSData dataWithBytes:response.c_str() length:response.length()];
73     }
74     fetcher_.reset();
75     // If data was fetched, write the fetched data to local store in a
76     // separate thread. Then update the resource descriptor that configuration
77     // update is completed. Finally, schedule the next update check.
78     web::WebThread::PostBlockingPoolTask(FROM_HERE, base::BindBlock(^{
79       BOOL updateSuccess = NO;
80       if (responseData) {
81         NSString* path = [descriptor_ updateResourcePath];
82         updateSuccess = [responseData writeToFile:path atomically:YES];
83       }
84       dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^() {
85         [descriptor_ updateCheckDidFinishWithSuccess:updateSuccess];
86       });
87       dispatch_after(
88           dispatch_time(DISPATCH_TIME_NOW, kPeriodicCheckInNanoseconds),
89           dispatch_get_main_queue(), ^{
90             [owner_ checkUpdate];
91           });
92     }));
93   };
95  private:
96   UpdatableConfigBase* owner_;
97   id<UpdatableResourceDescriptorBridge> descriptor_;
98   scoped_ptr<net::URLFetcher> fetcher_;
101 }  // namespace
103 @implementation UpdatableConfigBase {
104   base::scoped_nsprotocol<id<UpdatableResourceBridge>> _updatableResource;
105   scoped_ptr<ConfigFetcher> _configFetcher;
106   scoped_refptr<net::URLRequestContextGetter> _requestContextGetter;
109 + (void)enableConsistencyCheck {
110 #if !defined(NDEBUG)
111   g_consistency_check_enabled = YES;
112 #endif
115 // Overrides default designated initializer.
116 - (instancetype)initWithAppId:(NSString*)appId
117                       version:(NSString*)appVersion
118                         plist:(NSString*)plistName {
119   self = [super init];
120   if (self) {
121     _updatableResource.reset([self newResource:plistName]);
122     // UpdatableResourceBridge initializes the appId to what is in the
123     // application bundle. The following overrides that with either the |appId|
124     // passed in or a default based on experimental settings if |appId| is nil.
125     if (!appId)
126       appId = [UpdatableConfigBase defaultAppId];
127     [[_updatableResource descriptor] setApplicationIdentifier:appId];
128     // Overrides the default application version if necessary.
129     if (appVersion)
130       [[_updatableResource descriptor] setApplicationVersion:appVersion];
131     // [UpdatableResourceBridge -loadDefaults] updates the resource in
132     // two phases and is probably not MT safe. However,
133     // initWithAppId:version:plist: is called from a singleton's
134     // initialization loop and thus will not be called more than once.
135     // TODO(pkl): -loadDefaults accesses the file system to load in the
136     // plist. This should be done via PostBlockingPoolTask.
137     [_updatableResource loadDefaults];
139     NSString* notificationName = ios::GetChromeBrowserProvider()
140                                      ->GetUpdatableResourceProvider()
141                                      ->GetUpdateNotificationName();
142     [[NSNotificationCenter defaultCenter]
143         addObserver:self
144            selector:@selector(resourceDidUpdate:)
145                name:notificationName
146              object:[_updatableResource descriptor]];
148 #if !defined(NDEBUG)
149     [self scheduleConsistencyCheck];
150 #endif
151   }
152   return self;
155 - (instancetype)init {
156   NOTREACHED();
157   return nil;
160 - (void)dealloc {
161   [[NSNotificationCenter defaultCenter] removeObserver:self];
162 #if !defined(NDEBUG)
163   [self cancelConsistencyCheck];
164 #endif
165   [super dealloc];
168 - (void)startUpdate:(net::URLRequestContextGetter*)requestContextGetter {
169 #if !defined(NDEBUG)
170   [self cancelConsistencyCheck];
171 #endif
172   _requestContextGetter = requestContextGetter;
173   [self checkUpdate];
176 - (void)stopUpdateChecks {
177   _requestContextGetter = nullptr;
180 - (void)resourceDidUpdate:(NSNotification*)notification {
181   id sender = [notification object];
182   DCHECK([_updatableResource descriptor] == sender);
185 #pragma mark -
186 #pragma mark For Subclasses
188 - (id<UpdatableResourceBridge>)newResource:(NSString*)resourceName {
189   // Subclasses must override this factory method.
190   NOTREACHED();
191   return nil;
194 - (id<UpdatableResourceBridge>)updatableResource {
195   return _updatableResource.get();
198 #pragma mark -
199 #pragma mark For Debug Compilations
201 #if !defined(NDEBUG)
202 - (void)scheduleConsistencyCheck {
203   if (!g_consistency_check_enabled)
204     return;
205   // Sets a delayed call that will cause a DCHECK if -startUpdate:
206   // was not called.
207   [self performSelector:@selector(startUpdateNotCalled:)
208              withObject:self
209              afterDelay:60.0];
212 - (void)cancelConsistencyCheck {
213   if (!g_consistency_check_enabled)
214     return;
215   // Cancels the delayed error check since -startUpdate: has been called.
216   // Added for completeness since singletons should never be deallocated.
217   [NSObject
218       cancelPreviousPerformRequestsWithTarget:self
219                                      selector:@selector(startUpdateNotCalled:)
220                                        object:self];
223 - (void)startUpdateNotCalled:(id)config {
224   DCHECK(self == config);
225   DCHECK(g_consistency_check_enabled);
226   // Make sure that |startUpdate:| was called for this config.
227   NOTREACHED() << "startUpdate: was not called for "
228                << [[self description] UTF8String];
230 #endif  // !defined(NDEBUG)
232 #pragma mark -
233 #pragma mark For Unit Testing
235 - (void)setUpdatableResource:(id<UpdatableResourceBridge>)resource {
236   _updatableResource.reset([resource retain]);
239 #pragma mark -
240 #pragma mark Private
242 + (NSString*)defaultAppId {
243   // During development and dogfooding, allow a different configuration
244   // update file to be used for testing.
245   NSString* flag = [[NSUserDefaults standardUserDefaults]
246       stringForKey:@"UpdatableConfigLocation"];
247   if ([flag length]) {
248     if ([flag isEqualToString:@"Stable"])
249       return @"com.google.chrome.ios";
250     else if ([flag isEqualToString:@"Dogfood"])
251       return @"com.google.chrome.ios.beta";
252     else if ([flag isEqualToString:@"None"])
253       return @"this.does.not.update";
254   }
255   return [[NSBundle mainBundle] bundleIdentifier];
258 - (void)checkUpdate {
259   if (!_requestContextGetter.get())
260     return;
261   if (!_configFetcher) {
262     _configFetcher.reset(
263         new ConfigFetcher(self, [_updatableResource descriptor]));
264   }
265   GURL url = net::GURLWithNSURL([[_updatableResource descriptor] updateURL]);
266   _configFetcher->Fetch(url, _requestContextGetter.get());
269 @end