Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/chromeos/settings/device_settings_service.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/file_util.h" | |
| 9 #include "base/lazy_instance.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/message_loop.h" | |
| 12 #include "base/stl_util.h" | |
| 13 #include "chrome/browser/chromeos/settings/owner_key_util.h" | |
| 14 #include "chrome/browser/chromeos/settings/session_manager_operation.h" | |
| 15 #include "chrome/browser/policy/proto/chrome_device_policy.pb.h" | |
| 16 #include "chrome/browser/policy/proto/device_management_backend.pb.h" | |
| 17 #include "chrome/common/chrome_notification_types.h" | |
| 18 #include "content/public/browser/browser_thread.h" | |
| 19 #include "content/public/browser/notification_service.h" | |
| 20 #include "content/public/browser/notification_source.h" | |
| 21 #include "crypto/rsa_private_key.h" | |
| 22 | |
| 23 namespace em = enterprise_management; | |
| 24 | |
| 25 namespace chromeos { | |
| 26 | |
| 27 static base::LazyInstance<DeviceSettingsService> g_device_settings_service = | |
|
Chris Masone
2012/08/03 16:28:25
There was recently a thread about making all these
Mattias Nissler (ping if slow)
2012/08/06 21:28:14
I think you're referring to this thread: https://g
| |
| 28 LAZY_INSTANCE_INITIALIZER; | |
| 29 | |
| 30 OwnerKey::OwnerKey(scoped_ptr<std::vector<uint8> > public_key, | |
| 31 scoped_ptr<crypto::RSAPrivateKey> private_key) | |
| 32 : public_key_(public_key.Pass()), | |
| 33 private_key_(private_key.Pass()) {} | |
| 34 | |
| 35 OwnerKey::~OwnerKey() {} | |
| 36 | |
| 37 DeviceSettingsService::Observer::~Observer() {} | |
| 38 | |
| 39 DeviceSettingsService::DeviceSettingsService() | |
| 40 : session_manager_client_(NULL), | |
| 41 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | |
| 42 store_status_(STORE_SUCCESS), | |
| 43 ownership_status_(OWNERSHIP_UNKNOWN) {} | |
| 44 | |
| 45 DeviceSettingsService::~DeviceSettingsService() { | |
| 46 DCHECK(pending_operations_.empty()); | |
| 47 } | |
| 48 | |
| 49 // static | |
| 50 DeviceSettingsService* DeviceSettingsService::Get() { | |
| 51 return g_device_settings_service.Pointer(); | |
| 52 } | |
| 53 | |
| 54 void DeviceSettingsService::Initialize( | |
| 55 SessionManagerClient* session_manager_client, | |
| 56 scoped_refptr<OwnerKeyUtil> owner_key_util) { | |
| 57 DCHECK(session_manager_client); | |
| 58 DCHECK(owner_key_util.get()); | |
| 59 DCHECK(!session_manager_client_); | |
| 60 DCHECK(!owner_key_util_.get()); | |
| 61 | |
| 62 session_manager_client_ = session_manager_client; | |
| 63 owner_key_util_ = owner_key_util; | |
| 64 | |
| 65 session_manager_client_->AddObserver(this); | |
| 66 | |
| 67 StartNextOperation(); | |
| 68 } | |
| 69 | |
| 70 void DeviceSettingsService::Shutdown() { | |
| 71 STLDeleteContainerPointers(pending_operations_.begin(), | |
| 72 pending_operations_.end()); | |
| 73 pending_operations_.clear(); | |
| 74 | |
| 75 session_manager_client_->RemoveObserver(this); | |
| 76 session_manager_client_ = NULL; | |
| 77 owner_key_util_ = NULL; | |
| 78 } | |
| 79 | |
| 80 scoped_refptr<OwnerKey> DeviceSettingsService::GetOwnerKey() { | |
| 81 return owner_key_; | |
| 82 } | |
| 83 | |
| 84 void DeviceSettingsService::Load() { | |
| 85 EnqueueLoad(false); | |
| 86 } | |
| 87 | |
| 88 void DeviceSettingsService::SignAndStore( | |
| 89 scoped_ptr<em::ChromeDeviceSettingsProto> settings, | |
|
Chris Masone
2012/08/03 16:28:25
IF this class is holding this settings proto, why
Mattias Nissler (ping if slow)
2012/08/06 21:28:14
It holds the current settings proto. The one passe
| |
| 90 const base::Closure& callback) { | |
| 91 Enqueue( | |
| 92 new SignAndStoreSettingsOperation( | |
| 93 base::Bind(&DeviceSettingsService::HandleCompletedOperation, | |
| 94 weak_factory_.GetWeakPtr(), | |
| 95 callback), | |
| 96 settings.Pass(), | |
| 97 username_)); | |
| 98 } | |
| 99 | |
| 100 void DeviceSettingsService::Store(const std::string& policy_blob, | |
| 101 const base::Closure& callback) { | |
| 102 Enqueue( | |
| 103 new StoreSettingsOperation( | |
| 104 base::Bind(&DeviceSettingsService::HandleCompletedOperation, | |
| 105 weak_factory_.GetWeakPtr(), | |
| 106 callback), | |
| 107 policy_blob)); | |
| 108 } | |
| 109 | |
| 110 DeviceSettingsService::OwnershipStatus | |
| 111 DeviceSettingsService::GetOwnershipStatus(bool blocking) { | |
| 112 OwnershipStatus status = OWNERSHIP_UNKNOWN; | |
| 113 bool is_owned = false; | |
| 114 if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { | |
| 115 ownership_status_lock_.Acquire(); | |
|
Chris Masone
2012/08/03 16:28:25
I always liked AutoLock() for this stuff.
{
Aut
Mattias Nissler (ping if slow)
2012/08/06 21:28:14
Done. This function is actually copied legacy code
| |
| 116 status = ownership_status_; | |
| 117 ownership_status_lock_.Release(); | |
| 118 if (status != OWNERSHIP_UNKNOWN || !blocking) | |
| 119 return status; | |
| 120 // Under common usage there is very short lapse of time when ownership | |
| 121 // status is still unknown after constructing DeviceSettingsService. | |
| 122 LOG(ERROR) << "Blocking on UI thread in DeviceSettingsService::GetStatus"; | |
| 123 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 124 is_owned = owner_key_util_->IsPublicKeyPresent(); | |
| 125 } else { | |
| 126 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
| 127 is_owned = owner_key_util_->IsPublicKeyPresent(); | |
| 128 } | |
| 129 status = is_owned ? OWNERSHIP_TAKEN : OWNERSHIP_NONE; | |
| 130 SetOwnershipStatus(status); | |
| 131 return status; | |
| 132 } | |
| 133 | |
| 134 void DeviceSettingsService::GetOwnershipStatusAsync( | |
|
Chris Masone
2012/08/03 16:28:25
it seems like the semantics of this and the above
Mattias Nissler (ping if slow)
2012/08/06 21:28:14
True. As commented above, the blocking and locking
| |
| 135 const OwnershipStatusCallback& callback) { | |
| 136 if (owner_key_.get()) { | |
| 137 // If there is a key, report status immediately. | |
| 138 MessageLoop::current()->PostTask( | |
| 139 FROM_HERE, | |
| 140 base::Bind(callback, | |
| 141 owner_key_->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE, | |
| 142 owner_key_->private_key())); | |
|
Chris Masone
2012/08/03 16:28:25
Hm. The level of abstraction between this point o
Mattias Nissler (ping if slow)
2012/08/06 21:28:14
Totally agree. Done.
| |
| 143 } else { | |
| 144 // If the key hasn't been loaded yet, trigger a policy load operation or | |
| 145 // wait for an existing operation to finish. | |
|
Chris Masone
2012/08/03 16:28:25
Well...you don't wait for an existing operation to
Mattias Nissler (ping if slow)
2012/08/06 21:28:14
Every operation returns the current key status. So
| |
| 146 pending_ownership_status_callbacks_.push_back(callback); | |
| 147 if (pending_operations_.empty()) | |
| 148 EnqueueLoad(false); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 bool DeviceSettingsService::HasPrivateOwnerKey() { | |
| 153 return owner_key_.get() && owner_key_->private_key(); | |
| 154 } | |
| 155 | |
| 156 void DeviceSettingsService::SetUsername(const std::string& username) { | |
| 157 username_ = username; | |
| 158 | |
| 159 // The private key may have become available, so force a key reload. | |
|
Chris Masone
2012/08/03 16:28:25
How does this follow?
Mattias Nissler (ping if slow)
2012/08/06 21:28:14
We throw away the old key, so the next operation t
| |
| 160 OwnerKeySet(true); | |
| 161 } | |
| 162 | |
| 163 const std::string& DeviceSettingsService::GetUsername() const { | |
| 164 return username_; | |
| 165 } | |
| 166 | |
| 167 void DeviceSettingsService::AddObserver(Observer* observer) { | |
| 168 observers_.AddObserver(observer); | |
| 169 } | |
| 170 | |
| 171 void DeviceSettingsService::RemoveObserver(Observer* observer) { | |
| 172 observers_.RemoveObserver(observer); | |
| 173 } | |
| 174 | |
| 175 void DeviceSettingsService::OwnerKeySet(bool success) { | |
| 176 if (!success) { | |
| 177 LOG(ERROR) << "Owner key change failed."; | |
| 178 return; | |
| 179 } | |
| 180 | |
| 181 owner_key_ = NULL; | |
| 182 EnsureReload(true); | |
| 183 } | |
| 184 | |
| 185 void DeviceSettingsService::PropertyChangeComplete(bool success) { | |
| 186 if (!success) { | |
| 187 LOG(ERROR) << "Policy update failed."; | |
| 188 return; | |
| 189 } | |
| 190 | |
| 191 EnsureReload(false); | |
| 192 } | |
| 193 | |
| 194 void DeviceSettingsService::Enqueue(SessionManagerOperation* operation) { | |
| 195 pending_operations_.push_back(operation); | |
| 196 if (pending_operations_.front() == operation) | |
| 197 StartNextOperation(); | |
| 198 } | |
| 199 | |
| 200 void DeviceSettingsService::EnqueueLoad(bool force_key_load) { | |
| 201 SessionManagerOperation* operation = | |
| 202 new LoadSettingsOperation( | |
| 203 base::Bind(&DeviceSettingsService::HandleCompletedOperation, | |
| 204 weak_factory_.GetWeakPtr(), | |
| 205 base::Closure())); | |
| 206 operation->set_force_key_load(force_key_load); | |
| 207 Enqueue(operation); | |
| 208 } | |
| 209 | |
| 210 void DeviceSettingsService::EnsureReload(bool force_key_load) { | |
| 211 if (!pending_operations_.empty()) | |
| 212 pending_operations_.front()->RestartLoad(force_key_load); | |
| 213 else | |
| 214 EnqueueLoad(force_key_load); | |
| 215 } | |
| 216 | |
| 217 void DeviceSettingsService::StartNextOperation() { | |
| 218 if (!pending_operations_.empty() && | |
| 219 session_manager_client_ && | |
| 220 owner_key_util_.get()) { | |
| 221 pending_operations_.front()->Start(session_manager_client_, | |
| 222 owner_key_util_, owner_key_); | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 void DeviceSettingsService::HandleCompletedOperation( | |
| 227 const base::Closure& callback, | |
| 228 SessionManagerOperation* operation, | |
| 229 Status status) { | |
| 230 DCHECK_EQ(operation, pending_operations_.front()); | |
| 231 store_status_ = status; | |
| 232 | |
| 233 OwnershipStatus ownership_status = OWNERSHIP_UNKNOWN; | |
| 234 bool is_owner = false; | |
| 235 scoped_refptr<OwnerKey> new_key(operation->owner_key()); | |
| 236 if (new_key.get()) { | |
| 237 ownership_status = | |
| 238 new_key->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE; | |
| 239 is_owner = (new_key->private_key() != NULL); | |
| 240 } else { | |
| 241 NOTREACHED() << "Failed to determine key status."; | |
| 242 } | |
| 243 SetOwnershipStatus(ownership_status); | |
| 244 | |
| 245 if (owner_key_.get() != new_key.get()) { | |
| 246 owner_key_ = new_key; | |
| 247 FOR_EACH_OBSERVER(Observer, observers_, OwnershipStatusChanged()); | |
| 248 content::NotificationService::current()->Notify( | |
| 249 chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED, | |
| 250 content::Source<DeviceSettingsService>(this), | |
| 251 content::NotificationService::NoDetails()); | |
| 252 } | |
| 253 | |
| 254 if (status == STORE_SUCCESS) { | |
| 255 policy_data_ = operation->policy_data().Pass(); | |
| 256 device_settings_ = operation->device_settings().Pass(); | |
| 257 } else if (status != STORE_KEY_UNAVAILABLE) { | |
| 258 LOG(ERROR) << "Session manager operation failed: " << status; | |
| 259 } | |
| 260 | |
| 261 FOR_EACH_OBSERVER(Observer, observers_, DeviceSettingsUpdated()); | |
| 262 | |
| 263 std::vector<OwnershipStatusCallback> callbacks; | |
| 264 callbacks.swap(pending_ownership_status_callbacks_); | |
| 265 for (std::vector<OwnershipStatusCallback>::iterator iter(callbacks.begin()); | |
| 266 iter != callbacks.end(); ++iter) { | |
| 267 iter->Run(ownership_status, is_owner); | |
| 268 } | |
| 269 | |
| 270 // The completion callback happens after the notification so clients can | |
| 271 // filter self-triggered updates. | |
| 272 if (!callback.is_null()) | |
| 273 callback.Run(); | |
| 274 | |
| 275 // Only remove the pending operation here, so new operations triggered by any | |
| 276 // of the callbacks above are queued up properly. | |
| 277 pending_operations_.pop_front(); | |
| 278 delete operation; | |
| 279 | |
| 280 StartNextOperation(); | |
| 281 } | |
| 282 | |
| 283 void DeviceSettingsService::SetOwnershipStatus(OwnershipStatus new_status) { | |
| 284 DCHECK(new_status == OWNERSHIP_TAKEN || new_status == OWNERSHIP_NONE); | |
| 285 base::AutoLock lk(ownership_status_lock_); | |
| 286 ownership_status_ = new_status; | |
| 287 } | |
| 288 | |
| 289 } // namespace chromeos | |
| OLD | NEW |