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

Side by Side Diff: remoting/host/policy_watcher.cc

Issue 891053003: Reporting a policy error after detecting mistyped policies. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 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
« no previous file with comments | « remoting/host/policy_watcher.h ('k') | remoting/host/policy_watcher_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 // Most of this code is copied from: 5 // Most of this code is copied from:
6 // src/chrome/browser/policy/asynchronous_policy_loader.{h,cc} 6 // src/chrome/browser/policy/asynchronous_policy_loader.{h,cc}
7 7
8 #include "remoting/host/policy_watcher.h" 8 #include "remoting/host/policy_watcher.h"
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 24 matching lines...) Expand all
35 #include "components/policy/core/common/config_dir_policy_loader.h" 35 #include "components/policy/core/common/config_dir_policy_loader.h"
36 #endif 36 #endif
37 37
38 namespace remoting { 38 namespace remoting {
39 39
40 namespace key = ::policy::key; 40 namespace key = ::policy::key;
41 41
42 namespace { 42 namespace {
43 43
44 // Copies all policy values from one dictionary to another, using values from 44 // Copies all policy values from one dictionary to another, using values from
45 // |default| if they are not set in |from|, or values from |bad_type_values| if 45 // |default_values| if they are not set in |from|.
46 // the value in |from| has the wrong type. 46 scoped_ptr<base::DictionaryValue> CopyValuesAndAddDefaults(
47 scoped_ptr<base::DictionaryValue> CopyGoodValuesAndAddDefaults(
48 const base::DictionaryValue* from, 47 const base::DictionaryValue* from,
49 const base::DictionaryValue* default_values, 48 const base::DictionaryValue* default_values) {
50 const base::DictionaryValue* bad_type_values) {
51 scoped_ptr<base::DictionaryValue> to(default_values->DeepCopy()); 49 scoped_ptr<base::DictionaryValue> to(default_values->DeepCopy());
52 for (base::DictionaryValue::Iterator i(*default_values); !i.IsAtEnd(); 50 for (base::DictionaryValue::Iterator i(*default_values); !i.IsAtEnd();
53 i.Advance()) { 51 i.Advance()) {
54 const base::Value* value = nullptr; 52 const base::Value* value = nullptr;
55 53
56 // If the policy isn't in |from|, use the default. 54 // If the policy isn't in |from|, use the default.
57 if (!from->Get(i.key(), &value)) { 55 if (!from->Get(i.key(), &value)) {
58 continue; 56 continue;
59 } 57 }
60 58
61 // If the policy is the wrong type, use the value from |bad_type_values|. 59 CHECK(value->IsType(i.value().GetType()));
Sergey Ulanov 2015/02/12 19:22:58 Does this need to be a CHECK() instead of DCHECK()
Łukasz Anforowicz 2015/02/12 20:34:13 Good question. I was wondering about it myself.
62 if (!value->IsType(i.value().GetType())) {
63 CHECK(bad_type_values->Get(i.key(), &value));
64 }
65
66 to->Set(i.key(), value->DeepCopy()); 60 to->Set(i.key(), value->DeepCopy());
67 } 61 }
68 62
69 #if !defined(NDEBUG) 63 #if !defined(NDEBUG)
70 // Replace values with those specified in DebugOverridePolicies, if present. 64 // Replace values with those specified in DebugOverridePolicies, if present.
71 std::string policy_overrides; 65 std::string policy_overrides;
72 if (from->GetString(key::kRemoteAccessHostDebugOverridePolicies, 66 if (from->GetString(key::kRemoteAccessHostDebugOverridePolicies,
73 &policy_overrides)) { 67 &policy_overrides)) {
74 scoped_ptr<base::Value> value(base::JSONReader::Read(policy_overrides)); 68 scoped_ptr<base::Value> value(base::JSONReader::Read(policy_overrides));
75 const base::DictionaryValue* override_values; 69 const base::DictionaryValue* override_values;
76 if (value && value->GetAsDictionary(&override_values)) { 70 if (value && value->GetAsDictionary(&override_values)) {
77 to->MergeDictionary(override_values); 71 to->MergeDictionary(override_values);
78 } 72 }
79 } 73 }
80 #endif // defined(NDEBUG) 74 #endif // defined(NDEBUG)
81 75
82 return to.Pass(); 76 return to.Pass();
83 } 77 }
84 78
85 policy::PolicyNamespace GetPolicyNamespace() { 79 policy::PolicyNamespace GetPolicyNamespace() {
86 return policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()); 80 return policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string());
87 } 81 }
88 82
83 scoped_ptr<policy::SchemaRegistry> CreateSchemaRegistry() {
84 // TODO(lukasza): Schema below should ideally only cover Chromoting-specific
85 // policies (expecting perf and maintanability improvement, but no functional
86 // impact).
87 policy::Schema schema = policy::Schema::Wrap(policy::GetChromeSchemaData());
88
89 scoped_ptr<policy::SchemaRegistry> schema_registry(
90 new policy::SchemaRegistry());
91 schema_registry->RegisterComponent(GetPolicyNamespace(), schema);
92 return schema_registry.Pass();
93 }
94
89 } // namespace 95 } // namespace
90 96
91 void PolicyWatcher::StartWatching( 97 void PolicyWatcher::StartWatching(
92 const PolicyUpdatedCallback& policy_updated_callback, 98 const PolicyUpdatedCallback& policy_updated_callback,
93 const PolicyErrorCallback& policy_error_callback) { 99 const PolicyErrorCallback& policy_error_callback) {
94 DCHECK(CalledOnValidThread()); 100 DCHECK(CalledOnValidThread());
95 DCHECK(!policy_updated_callback.is_null()); 101 DCHECK(!policy_updated_callback.is_null());
96 DCHECK(!policy_error_callback.is_null()); 102 DCHECK(!policy_error_callback.is_null());
97 DCHECK(policy_updated_callback_.is_null()); 103 DCHECK(policy_updated_callback_.is_null());
98 104
99 policy_updated_callback_ = policy_updated_callback; 105 policy_updated_callback_ = policy_updated_callback;
100 policy_error_callback_ = policy_error_callback; 106 policy_error_callback_ = policy_error_callback;
101 107
102 // Listen for future policy changes. 108 // Listen for future policy changes.
103 policy_service_->AddObserver(policy::POLICY_DOMAIN_CHROME, this); 109 policy_service_->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
104 110
105 // Process current policy state. 111 // Process current policy state.
106 if (policy_service_->IsInitializationComplete(policy::POLICY_DOMAIN_CHROME)) { 112 if (policy_service_->IsInitializationComplete(policy::POLICY_DOMAIN_CHROME)) {
107 OnPolicyServiceInitialized(policy::POLICY_DOMAIN_CHROME); 113 OnPolicyServiceInitialized(policy::POLICY_DOMAIN_CHROME);
108 } 114 }
109 } 115 }
110 116
111 void PolicyWatcher::UpdatePolicies( 117 void PolicyWatcher::UpdatePolicies(
112 const base::DictionaryValue* new_policies_raw) { 118 const base::DictionaryValue* new_policies_raw) {
113 DCHECK(CalledOnValidThread()); 119 DCHECK(CalledOnValidThread());
114 120
115 transient_policy_error_retry_counter_ = 0;
116
117 // Use default values for any missing policies. 121 // Use default values for any missing policies.
118 scoped_ptr<base::DictionaryValue> new_policies = CopyGoodValuesAndAddDefaults( 122 scoped_ptr<base::DictionaryValue> new_policies =
119 new_policies_raw, default_values_.get(), bad_type_values_.get()); 123 CopyValuesAndAddDefaults(new_policies_raw, default_values_.get());
120 124
121 // Find the changed policies. 125 // Find the changed policies.
122 scoped_ptr<base::DictionaryValue> changed_policies( 126 scoped_ptr<base::DictionaryValue> changed_policies(
123 new base::DictionaryValue()); 127 new base::DictionaryValue());
124 base::DictionaryValue::Iterator iter(*new_policies); 128 base::DictionaryValue::Iterator iter(*new_policies);
125 while (!iter.IsAtEnd()) { 129 while (!iter.IsAtEnd()) {
126 base::Value* old_policy; 130 base::Value* old_policy;
127 if (!(old_policies_->Get(iter.key(), &old_policy) && 131 if (!(old_policies_->Get(iter.key(), &old_policy) &&
128 old_policy->Equals(&iter.value()))) { 132 old_policy->Equals(&iter.value()))) {
129 changed_policies->Set(iter.key(), iter.value().DeepCopy()); 133 changed_policies->Set(iter.key(), iter.value().DeepCopy());
130 } 134 }
131 iter.Advance(); 135 iter.Advance();
132 } 136 }
133 137
134 // Save the new policies. 138 // Save the new policies.
135 old_policies_.swap(new_policies); 139 old_policies_.swap(new_policies);
136 140
137 // Notify our client of the changed policies. 141 // Notify our client of the changed policies.
138 if (!changed_policies->empty()) { 142 if (!changed_policies->empty()) {
139 policy_updated_callback_.Run(changed_policies.Pass()); 143 policy_updated_callback_.Run(changed_policies.Pass());
140 } 144 }
141 } 145 }
142 146
143 void PolicyWatcher::SignalPolicyError() { 147 void PolicyWatcher::SignalPolicyError() {
144 transient_policy_error_retry_counter_ = 0;
145 policy_error_callback_.Run(); 148 policy_error_callback_.Run();
146 } 149 }
147 150
148 void PolicyWatcher::SignalTransientPolicyError() {
149 const int kMaxRetryCount = 5;
150 transient_policy_error_retry_counter_ += 1;
151 if (transient_policy_error_retry_counter_ >= kMaxRetryCount) {
152 SignalPolicyError();
153 }
154 }
155
156 PolicyWatcher::PolicyWatcher( 151 PolicyWatcher::PolicyWatcher(
157 policy::PolicyService* policy_service, 152 policy::PolicyService* policy_service,
158 scoped_ptr<policy::PolicyService> owned_policy_service, 153 scoped_ptr<policy::PolicyService> owned_policy_service,
159 scoped_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider, 154 scoped_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider,
160 scoped_ptr<policy::SchemaRegistry> owned_schema_registry) 155 scoped_ptr<policy::SchemaRegistry> owned_schema_registry)
161 : transient_policy_error_retry_counter_(0), 156 : old_policies_(new base::DictionaryValue()),
162 old_policies_(new base::DictionaryValue()),
163 default_values_(new base::DictionaryValue()), 157 default_values_(new base::DictionaryValue()),
164 policy_service_(policy_service), 158 policy_service_(policy_service),
165 owned_schema_registry_(owned_schema_registry.Pass()), 159 owned_schema_registry_(owned_schema_registry.Pass()),
166 owned_policy_provider_(owned_policy_provider.Pass()), 160 owned_policy_provider_(owned_policy_provider.Pass()),
167 owned_policy_service_(owned_policy_service.Pass()) { 161 owned_policy_service_(owned_policy_service.Pass()) {
162 DCHECK(policy_service_);
163 DCHECK(owned_schema_registry_);
164
168 // Initialize the default values for each policy. 165 // Initialize the default values for each policy.
169 default_values_->SetBoolean(key::kRemoteAccessHostFirewallTraversal, true); 166 default_values_->SetBoolean(key::kRemoteAccessHostFirewallTraversal, true);
170 default_values_->SetBoolean(key::kRemoteAccessHostRequireCurtain, false); 167 default_values_->SetBoolean(key::kRemoteAccessHostRequireCurtain, false);
171 default_values_->SetBoolean(key::kRemoteAccessHostMatchUsername, false); 168 default_values_->SetBoolean(key::kRemoteAccessHostMatchUsername, false);
172 default_values_->SetString(key::kRemoteAccessHostDomain, std::string()); 169 default_values_->SetString(key::kRemoteAccessHostDomain, std::string());
173 default_values_->SetString(key::kRemoteAccessHostTalkGadgetPrefix, 170 default_values_->SetString(key::kRemoteAccessHostTalkGadgetPrefix,
174 kDefaultHostTalkGadgetPrefix); 171 kDefaultHostTalkGadgetPrefix);
175 default_values_->SetString(key::kRemoteAccessHostTokenUrl, std::string()); 172 default_values_->SetString(key::kRemoteAccessHostTokenUrl, std::string());
176 default_values_->SetString(key::kRemoteAccessHostTokenValidationUrl, 173 default_values_->SetString(key::kRemoteAccessHostTokenValidationUrl,
177 std::string()); 174 std::string());
178 default_values_->SetString( 175 default_values_->SetString(
179 key::kRemoteAccessHostTokenValidationCertificateIssuer, std::string()); 176 key::kRemoteAccessHostTokenValidationCertificateIssuer, std::string());
180 default_values_->SetBoolean(key::kRemoteAccessHostAllowClientPairing, true); 177 default_values_->SetBoolean(key::kRemoteAccessHostAllowClientPairing, true);
181 default_values_->SetBoolean(key::kRemoteAccessHostAllowGnubbyAuth, true); 178 default_values_->SetBoolean(key::kRemoteAccessHostAllowGnubbyAuth, true);
182 default_values_->SetBoolean(key::kRemoteAccessHostAllowRelayedConnection, 179 default_values_->SetBoolean(key::kRemoteAccessHostAllowRelayedConnection,
183 true); 180 true);
184 default_values_->SetString(key::kRemoteAccessHostUdpPortRange, ""); 181 default_values_->SetString(key::kRemoteAccessHostUdpPortRange, "");
185 #if !defined(NDEBUG) 182 #if !defined(NDEBUG)
186 default_values_->SetString(key::kRemoteAccessHostDebugOverridePolicies, 183 default_values_->SetString(key::kRemoteAccessHostDebugOverridePolicies,
187 std::string()); 184 std::string());
188 #endif 185 #endif
189
190 // Initialize the fall-back values to use for unreadable policies.
191 // For most policies these match the defaults.
192 bad_type_values_.reset(default_values_->DeepCopy());
193 bad_type_values_->SetBoolean(key::kRemoteAccessHostFirewallTraversal, false);
194 bad_type_values_->SetBoolean(key::kRemoteAccessHostAllowRelayedConnection,
195 false);
196 } 186 }
197 187
198 PolicyWatcher::~PolicyWatcher() { 188 PolicyWatcher::~PolicyWatcher() {
199 // Stop observing |policy_service_| if StartWatching() has been called. 189 // Stop observing |policy_service_| if StartWatching() has been called.
200 if (!policy_updated_callback_.is_null()) { 190 if (!policy_updated_callback_.is_null()) {
201 policy_service_->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this); 191 policy_service_->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
202 } 192 }
203 193
204 if (owned_policy_provider_) { 194 if (owned_policy_provider_) {
205 owned_policy_provider_->Shutdown(); 195 owned_policy_provider_->Shutdown();
206 } 196 }
207 } 197 }
208 198
199 const policy::Schema* PolicyWatcher::GetPolicySchema() const {
200 policy::PolicyNamespace ns = GetPolicyNamespace();
201
202 const scoped_refptr<policy::SchemaMap>& schema_map =
203 owned_schema_registry_->schema_map();
204 const policy::Schema* schema = schema_map->GetSchema(ns);
Sergey Ulanov 2015/02/12 19:22:59 nit: You can write this whole function in one line
Łukasz Anforowicz 2015/02/12 20:34:13 Thanks. I don't know why I did it this way...
205
206 return schema;
207 }
208
209 void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns, 209 void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns,
210 const policy::PolicyMap& previous, 210 const policy::PolicyMap& previous,
211 const policy::PolicyMap& current) { 211 const policy::PolicyMap& current) {
212 const std::string policy_name_prefix = "RemoteAccessHost";
Sergey Ulanov 2015/02/12 19:22:59 This doesn't need to be std::string. Style guide a
Łukasz Anforowicz 2015/02/12 20:34:13 Done. BTW: I initially started replying that your
212 scoped_ptr<base::DictionaryValue> policy_dict(new base::DictionaryValue()); 213 scoped_ptr<base::DictionaryValue> policy_dict(new base::DictionaryValue());
213 for (auto it = current.begin(); it != current.end(); ++it) { 214 for (auto it = current.begin(); it != current.end(); ++it) {
214 // TODO(lukasza): Use policy::Schema::Normalize() for schema verification. 215 const std::string& key = it->first;
215 policy_dict->Set(it->first, it->second.value->DeepCopy()); 216 const base::Value* value = it->second.value;
217
218 // Copying only Chromoting-specific policies helps avoid false alarms
219 // raised by Schema::Normalize below (such alarms shutdown the host).
220 // TODO(lukasza): Removing this somewhat brittle filtering will be possible
221 // after having separate, Chromoting-specific schema.
222 if (key.find(policy_name_prefix) != std::string::npos) {
223 policy_dict->Set(key, value->DeepCopy());
224 }
216 } 225 }
217 UpdatePolicies(policy_dict.get()); 226
227 // Allowing unrecognized policy names allows presence of
228 // 1) comments,
Sergey Ulanov 2015/02/12 19:22:58 Comments should be dropped by the parser, no?
Łukasz Anforowicz 2015/02/12 20:34:13 By "comments" I meant JSON entries like these: {
229 // 2) policies intended for future/newer versions of the host,
230 // 3) policies not supported on all OS-s (i.e. RemoteAccessHostMatchUsername
231 // is not supported on Windows and therefore policy_templates.json omits
232 // schema for this policy on this particular platform).
233 auto strategy = policy::SCHEMA_ALLOW_UNKNOWN_TOPLEVEL;
234
235 std::string path;
236 std::string error;
237 bool changed;
238 const policy::Schema* schema = GetPolicySchema();
239 if (schema->Normalize(policy_dict.get(), strategy, &path, &error, &changed)) {
240 if (changed) {
241 LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path
242 << ": " << error;
243 }
244 UpdatePolicies(policy_dict.get());
245 } else {
246 LOG(ERROR) << "Invalid policy contents: " << path << ": " << error;
247 SignalPolicyError();
248 }
218 } 249 }
219 250
220 void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) { 251 void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) {
221 policy::PolicyNamespace ns = GetPolicyNamespace(); 252 policy::PolicyNamespace ns = GetPolicyNamespace();
222 const policy::PolicyMap& current = policy_service_->GetPolicies(ns); 253 const policy::PolicyMap& current = policy_service_->GetPolicies(ns);
223 OnPolicyUpdated(ns, current, current); 254 OnPolicyUpdated(ns, current, current);
224 } 255 }
225 256
226 scoped_ptr<PolicyWatcher> PolicyWatcher::CreateFromPolicyLoader( 257 scoped_ptr<PolicyWatcher> PolicyWatcher::CreateFromPolicyLoader(
227 scoped_ptr<policy::AsyncPolicyLoader> async_policy_loader) { 258 scoped_ptr<policy::AsyncPolicyLoader> async_policy_loader) {
228 // TODO(lukasza): Schema below should ideally only cover Chromoting-specific 259 scoped_ptr<policy::SchemaRegistry> schema_registry = CreateSchemaRegistry();
229 // policies (expecting perf and maintanability improvement, but no functional
230 // impact).
231 policy::Schema schema = policy::Schema::Wrap(policy::GetChromeSchemaData());
232
233 scoped_ptr<policy::SchemaRegistry> schema_registry(
234 new policy::SchemaRegistry());
235 schema_registry->RegisterComponent(GetPolicyNamespace(), schema);
236
237 scoped_ptr<policy::AsyncPolicyProvider> policy_provider( 260 scoped_ptr<policy::AsyncPolicyProvider> policy_provider(
238 new policy::AsyncPolicyProvider(schema_registry.get(), 261 new policy::AsyncPolicyProvider(schema_registry.get(),
239 async_policy_loader.Pass())); 262 async_policy_loader.Pass()));
240 policy_provider->Init(schema_registry.get()); 263 policy_provider->Init(schema_registry.get());
241 264
242 policy::PolicyServiceImpl::Providers providers; 265 policy::PolicyServiceImpl::Providers providers;
243 providers.push_back(policy_provider.get()); 266 providers.push_back(policy_provider.get());
244 scoped_ptr<policy::PolicyService> policy_service( 267 scoped_ptr<policy::PolicyService> policy_service(
245 new policy::PolicyServiceImpl(providers)); 268 new policy::PolicyServiceImpl(providers));
246 269
247 policy::PolicyService* borrowed_policy_service = policy_service.get(); 270 policy::PolicyService* borrowed_policy_service = policy_service.get();
248 return make_scoped_ptr( 271 return make_scoped_ptr(
249 new PolicyWatcher(borrowed_policy_service, policy_service.Pass(), 272 new PolicyWatcher(borrowed_policy_service, policy_service.Pass(),
250 policy_provider.Pass(), schema_registry.Pass())); 273 policy_provider.Pass(), schema_registry.Pass()));
251 } 274 }
252 275
253 scoped_ptr<PolicyWatcher> PolicyWatcher::Create( 276 scoped_ptr<PolicyWatcher> PolicyWatcher::Create(
254 policy::PolicyService* policy_service, 277 policy::PolicyService* policy_service,
255 const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner) { 278 const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner) {
256 #if defined(OS_CHROMEOS) 279 #if defined(OS_CHROMEOS)
257 // On Chrome OS the PolicyService is owned by the browser. 280 // On Chrome OS the PolicyService is owned by the browser.
258 DCHECK(policy_service); 281 DCHECK(policy_service);
259 return make_scoped_ptr( 282 return make_scoped_ptr(new PolicyWatcher(policy_service, nullptr, nullptr,
260 new PolicyWatcher(policy_service, nullptr, nullptr, nullptr)); 283 CreateSchemaRegistry()));
261 #else // !defined(OS_CHROMEOS) 284 #else // !defined(OS_CHROMEOS)
262 DCHECK(!policy_service); 285 DCHECK(!policy_service);
263 286
264 // Create platform-specific PolicyLoader. Always read the Chrome policies 287 // Create platform-specific PolicyLoader. Always read the Chrome policies
265 // (even on Chromium) so that policy enforcement can't be bypassed by running 288 // (even on Chromium) so that policy enforcement can't be bypassed by running
266 // Chromium. 289 // Chromium.
267 scoped_ptr<policy::AsyncPolicyLoader> policy_loader; 290 scoped_ptr<policy::AsyncPolicyLoader> policy_loader;
268 #if defined(OS_WIN) 291 #if defined(OS_WIN)
269 policy_loader = policy::PolicyLoaderWin::Create( 292 policy_loader = policy::PolicyLoaderWin::Create(
270 file_task_runner, L"SOFTWARE\\Policies\\Google\\Chrome"); 293 file_task_runner, L"SOFTWARE\\Policies\\Google\\Chrome");
(...skipping 10 matching lines...) Expand all
281 policy::POLICY_SCOPE_MACHINE)); 304 policy::POLICY_SCOPE_MACHINE));
282 #else 305 #else
283 #error OS that is not yet supported by PolicyWatcher code. 306 #error OS that is not yet supported by PolicyWatcher code.
284 #endif 307 #endif
285 308
286 return PolicyWatcher::CreateFromPolicyLoader(policy_loader.Pass()); 309 return PolicyWatcher::CreateFromPolicyLoader(policy_loader.Pass());
287 #endif // !(OS_CHROMEOS) 310 #endif // !(OS_CHROMEOS)
288 } 311 }
289 312
290 } // namespace remoting 313 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/policy_watcher.h ('k') | remoting/host/policy_watcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698