| OLD | NEW |
| 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 #include "chromecast/base/device_capabilities_impl.h" | 5 #include "chromecast/base/device_capabilities_impl.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 |
| 8 #include <utility> | 9 #include <utility> |
| 9 | 10 |
| 10 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/ptr_util.h" |
| 11 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
| 12 #include "base/thread_task_runner_handle.h" | 14 #include "base/thread_task_runner_handle.h" |
| 13 #include "base/values.h" | 15 #include "base/values.h" |
| 14 #include "chromecast/base/serializers.h" | 16 #include "chromecast/base/serializers.h" |
| 15 | 17 |
| 16 namespace chromecast { | 18 namespace chromecast { |
| 17 | 19 |
| 18 namespace { | 20 namespace { |
| 19 | 21 |
| 20 const char kPathSeparator = '.'; | 22 const char kPathSeparator = '.'; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 44 | 46 |
| 45 } // namespace | 47 } // namespace |
| 46 | 48 |
| 47 // static Default Capability Keys | 49 // static Default Capability Keys |
| 48 const char DeviceCapabilities::kKeyBluetoothSupported[] = "bluetooth_supported"; | 50 const char DeviceCapabilities::kKeyBluetoothSupported[] = "bluetooth_supported"; |
| 49 const char DeviceCapabilities::kKeyDisplaySupported[] = "display_supported"; | 51 const char DeviceCapabilities::kKeyDisplaySupported[] = "display_supported"; |
| 50 const char DeviceCapabilities::kKeyHiResAudioSupported[] = | 52 const char DeviceCapabilities::kKeyHiResAudioSupported[] = |
| 51 "hi_res_audio_supported"; | 53 "hi_res_audio_supported"; |
| 52 | 54 |
| 53 // static | 55 // static |
| 54 scoped_ptr<DeviceCapabilities> DeviceCapabilities::Create() { | 56 std::unique_ptr<DeviceCapabilities> DeviceCapabilities::Create() { |
| 55 return make_scoped_ptr(new DeviceCapabilitiesImpl); | 57 return base::WrapUnique(new DeviceCapabilitiesImpl); |
| 56 } | 58 } |
| 57 | 59 |
| 58 // static | 60 // static |
| 59 scoped_ptr<DeviceCapabilities> DeviceCapabilities::CreateForTesting() { | 61 std::unique_ptr<DeviceCapabilities> DeviceCapabilities::CreateForTesting() { |
| 60 DeviceCapabilities* capabilities = new DeviceCapabilitiesImpl; | 62 DeviceCapabilities* capabilities = new DeviceCapabilitiesImpl; |
| 61 capabilities->SetCapability( | 63 capabilities->SetCapability( |
| 62 kKeyBluetoothSupported, | 64 kKeyBluetoothSupported, |
| 63 make_scoped_ptr(new base::FundamentalValue(false))); | 65 base::WrapUnique(new base::FundamentalValue(false))); |
| 64 capabilities->SetCapability( | 66 capabilities->SetCapability( |
| 65 kKeyDisplaySupported, make_scoped_ptr(new base::FundamentalValue(true))); | 67 kKeyDisplaySupported, base::WrapUnique(new base::FundamentalValue(true))); |
| 66 capabilities->SetCapability( | 68 capabilities->SetCapability( |
| 67 kKeyHiResAudioSupported, | 69 kKeyHiResAudioSupported, |
| 68 make_scoped_ptr(new base::FundamentalValue(false))); | 70 base::WrapUnique(new base::FundamentalValue(false))); |
| 69 return make_scoped_ptr(capabilities); | 71 return base::WrapUnique(capabilities); |
| 70 } | 72 } |
| 71 | 73 |
| 72 scoped_refptr<DeviceCapabilities::Data> DeviceCapabilities::CreateData() { | 74 scoped_refptr<DeviceCapabilities::Data> DeviceCapabilities::CreateData() { |
| 73 return make_scoped_refptr(new Data); | 75 return make_scoped_refptr(new Data); |
| 74 } | 76 } |
| 75 | 77 |
| 76 scoped_refptr<DeviceCapabilities::Data> DeviceCapabilities::CreateData( | 78 scoped_refptr<DeviceCapabilities::Data> DeviceCapabilities::CreateData( |
| 77 scoped_ptr<const base::DictionaryValue> dictionary) { | 79 std::unique_ptr<const base::DictionaryValue> dictionary) { |
| 78 DCHECK(dictionary.get()); | 80 DCHECK(dictionary.get()); |
| 79 return make_scoped_refptr(new Data(std::move(dictionary))); | 81 return make_scoped_refptr(new Data(std::move(dictionary))); |
| 80 } | 82 } |
| 81 | 83 |
| 82 DeviceCapabilities::Validator::Validator(DeviceCapabilities* capabilities) | 84 DeviceCapabilities::Validator::Validator(DeviceCapabilities* capabilities) |
| 83 : capabilities_(capabilities) { | 85 : capabilities_(capabilities) { |
| 84 DCHECK(capabilities); | 86 DCHECK(capabilities); |
| 85 } | 87 } |
| 86 | 88 |
| 87 void DeviceCapabilities::Validator::SetValidatedValue( | 89 void DeviceCapabilities::Validator::SetValidatedValue( |
| 88 const std::string& path, | 90 const std::string& path, |
| 89 scoped_ptr<base::Value> new_value) const { | 91 std::unique_ptr<base::Value> new_value) const { |
| 90 capabilities_->SetValidatedValue(path, std::move(new_value)); | 92 capabilities_->SetValidatedValue(path, std::move(new_value)); |
| 91 } | 93 } |
| 92 | 94 |
| 93 DeviceCapabilities::Data::Data() | 95 DeviceCapabilities::Data::Data() |
| 94 : dictionary_(new base::DictionaryValue), | 96 : dictionary_(new base::DictionaryValue), |
| 95 json_string_(SerializeToJson(*dictionary_)) { | 97 json_string_(SerializeToJson(*dictionary_)) { |
| 96 DCHECK(json_string_.get()); | 98 DCHECK(json_string_.get()); |
| 97 } | 99 } |
| 98 | 100 |
| 99 DeviceCapabilities::Data::Data( | 101 DeviceCapabilities::Data::Data( |
| 100 scoped_ptr<const base::DictionaryValue> dictionary) | 102 std::unique_ptr<const base::DictionaryValue> dictionary) |
| 101 : dictionary_(std::move(dictionary)), | 103 : dictionary_(std::move(dictionary)), |
| 102 json_string_(SerializeToJson(*dictionary_)) { | 104 json_string_(SerializeToJson(*dictionary_)) { |
| 103 DCHECK(dictionary_.get()); | 105 DCHECK(dictionary_.get()); |
| 104 DCHECK(json_string_.get()); | 106 DCHECK(json_string_.get()); |
| 105 } | 107 } |
| 106 | 108 |
| 107 DeviceCapabilitiesImpl::Data::~Data() {} | 109 DeviceCapabilitiesImpl::Data::~Data() {} |
| 108 | 110 |
| 109 DeviceCapabilitiesImpl::ValidatorInfo::ValidatorInfo(Validator* validator) | 111 DeviceCapabilitiesImpl::ValidatorInfo::ValidatorInfo(Validator* validator) |
| 110 : validator_(validator), task_runner_(base::ThreadTaskRunnerHandle::Get()) { | 112 : validator_(validator), task_runner_(base::ThreadTaskRunnerHandle::Get()) { |
| 111 DCHECK(validator_); | 113 DCHECK(validator_); |
| 112 DCHECK(task_runner_.get()); | 114 DCHECK(task_runner_.get()); |
| 113 } | 115 } |
| 114 | 116 |
| 115 DeviceCapabilitiesImpl::ValidatorInfo::~ValidatorInfo() { | 117 DeviceCapabilitiesImpl::ValidatorInfo::~ValidatorInfo() { |
| 116 // Check that ValidatorInfo is being destroyed on the same thread that it was | 118 // Check that ValidatorInfo is being destroyed on the same thread that it was |
| 117 // constructed on. | 119 // constructed on. |
| 118 DCHECK(task_runner_->BelongsToCurrentThread()); | 120 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 119 } | 121 } |
| 120 | 122 |
| 121 void DeviceCapabilitiesImpl::ValidatorInfo::Validate( | 123 void DeviceCapabilitiesImpl::ValidatorInfo::Validate( |
| 122 const std::string& path, | 124 const std::string& path, |
| 123 scoped_ptr<base::Value> proposed_value) const { | 125 std::unique_ptr<base::Value> proposed_value) const { |
| 124 // Check that we are running Validate on the same thread that ValidatorInfo | 126 // Check that we are running Validate on the same thread that ValidatorInfo |
| 125 // was constructed on. | 127 // was constructed on. |
| 126 DCHECK(task_runner_->BelongsToCurrentThread()); | 128 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 127 validator_->Validate(path, std::move(proposed_value)); | 129 validator_->Validate(path, std::move(proposed_value)); |
| 128 } | 130 } |
| 129 | 131 |
| 130 DeviceCapabilitiesImpl::DeviceCapabilitiesImpl() | 132 DeviceCapabilitiesImpl::DeviceCapabilitiesImpl() |
| 131 : data_(CreateData()), | 133 : data_(CreateData()), |
| 132 task_runner_for_writes_(base::ThreadTaskRunnerHandle::Get()), | 134 task_runner_for_writes_(base::ThreadTaskRunnerHandle::Get()), |
| 133 observer_list_(new base::ObserverListThreadSafe<Observer>) { | 135 observer_list_(new base::ObserverListThreadSafe<Observer>) { |
| 134 DCHECK(task_runner_for_writes_.get()); | 136 DCHECK(task_runner_for_writes_.get()); |
| 135 } | 137 } |
| 136 | 138 |
| 137 DeviceCapabilitiesImpl::~DeviceCapabilitiesImpl() { | 139 DeviceCapabilitiesImpl::~DeviceCapabilitiesImpl() { |
| 138 // Make sure that any registered Validators have unregistered at this point | 140 // Make sure that any registered Validators have unregistered at this point |
| 139 DCHECK(validator_map_.empty()); | 141 DCHECK(validator_map_.empty()); |
| 140 // Make sure that all observers have been removed at this point | 142 // Make sure that all observers have been removed at this point |
| 141 observer_list_->AssertEmpty(); | 143 observer_list_->AssertEmpty(); |
| 142 } | 144 } |
| 143 | 145 |
| 144 void DeviceCapabilitiesImpl::Register(const std::string& key, | 146 void DeviceCapabilitiesImpl::Register(const std::string& key, |
| 145 Validator* validator) { | 147 Validator* validator) { |
| 146 DCHECK(IsValidRegisterKey(key)); | 148 DCHECK(IsValidRegisterKey(key)); |
| 147 DCHECK(validator); | 149 DCHECK(validator); |
| 148 | 150 |
| 149 base::AutoLock auto_lock(validation_lock_); | 151 base::AutoLock auto_lock(validation_lock_); |
| 150 bool added = | 152 bool added = |
| 151 validator_map_.add(key, make_scoped_ptr(new ValidatorInfo(validator))) | 153 validator_map_.add(key, base::WrapUnique(new ValidatorInfo(validator))) |
| 152 .second; | 154 .second; |
| 153 // Check that a validator has not already been registered for this key | 155 // Check that a validator has not already been registered for this key |
| 154 DCHECK(added); | 156 DCHECK(added); |
| 155 } | 157 } |
| 156 | 158 |
| 157 void DeviceCapabilitiesImpl::Unregister(const std::string& key, | 159 void DeviceCapabilitiesImpl::Unregister(const std::string& key, |
| 158 const Validator* validator) { | 160 const Validator* validator) { |
| 159 base::AutoLock auto_lock(validation_lock_); | 161 base::AutoLock auto_lock(validation_lock_); |
| 160 auto validator_it = validator_map_.find(key); | 162 auto validator_it = validator_map_.find(key); |
| 161 DCHECK(validator_it != validator_map_.end()); | 163 DCHECK(validator_it != validator_map_.end()); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 | 200 |
| 199 bool DeviceCapabilitiesImpl::HiResAudioSupported() const { | 201 bool DeviceCapabilitiesImpl::HiResAudioSupported() const { |
| 200 scoped_refptr<Data> data_ref = GetData(); | 202 scoped_refptr<Data> data_ref = GetData(); |
| 201 bool hi_res_audio_supported = false; | 203 bool hi_res_audio_supported = false; |
| 202 bool found_key = data_ref->dictionary().GetBoolean(kKeyHiResAudioSupported, | 204 bool found_key = data_ref->dictionary().GetBoolean(kKeyHiResAudioSupported, |
| 203 &hi_res_audio_supported); | 205 &hi_res_audio_supported); |
| 204 DCHECK(found_key); | 206 DCHECK(found_key); |
| 205 return hi_res_audio_supported; | 207 return hi_res_audio_supported; |
| 206 } | 208 } |
| 207 | 209 |
| 208 scoped_ptr<base::Value> DeviceCapabilitiesImpl::GetCapability( | 210 std::unique_ptr<base::Value> DeviceCapabilitiesImpl::GetCapability( |
| 209 const std::string& path) const { | 211 const std::string& path) const { |
| 210 scoped_refptr<Data> data_ref = GetData(); | 212 scoped_refptr<Data> data_ref = GetData(); |
| 211 const base::Value* value = nullptr; | 213 const base::Value* value = nullptr; |
| 212 bool found_path = data_ref->dictionary().Get(path, &value); | 214 bool found_path = data_ref->dictionary().Get(path, &value); |
| 213 return found_path ? value->CreateDeepCopy() : scoped_ptr<base::Value>(); | 215 return found_path ? value->CreateDeepCopy() : std::unique_ptr<base::Value>(); |
| 214 } | 216 } |
| 215 | 217 |
| 216 scoped_refptr<DeviceCapabilities::Data> | 218 scoped_refptr<DeviceCapabilities::Data> |
| 217 DeviceCapabilitiesImpl::GetData() const { | 219 DeviceCapabilitiesImpl::GetData() const { |
| 218 // Need to acquire lock here when copy constructing data_ otherwise we could | 220 // Need to acquire lock here when copy constructing data_ otherwise we could |
| 219 // be concurrently be writing to scoped_refptr in SetValidatedValue(), which | 221 // be concurrently be writing to scoped_refptr in SetValidatedValue(), which |
| 220 // could cause a bad scoped_refptr read. | 222 // could cause a bad scoped_refptr read. |
| 221 base::AutoLock auto_lock(data_lock_); | 223 base::AutoLock auto_lock(data_lock_); |
| 222 return data_; | 224 return data_; |
| 223 } | 225 } |
| 224 | 226 |
| 225 void DeviceCapabilitiesImpl::SetCapability( | 227 void DeviceCapabilitiesImpl::SetCapability( |
| 226 const std::string& path, | 228 const std::string& path, |
| 227 scoped_ptr<base::Value> proposed_value) { | 229 std::unique_ptr<base::Value> proposed_value) { |
| 228 DCHECK(proposed_value.get()); | 230 DCHECK(proposed_value.get()); |
| 229 if (!IsValidPath(path)) { | 231 if (!IsValidPath(path)) { |
| 230 LOG(DFATAL) << "Invalid capability path encountered for SetCapability()"; | 232 LOG(DFATAL) << "Invalid capability path encountered for SetCapability()"; |
| 231 return; | 233 return; |
| 232 } | 234 } |
| 233 | 235 |
| 234 { | 236 { |
| 235 base::AutoLock auto_lock(validation_lock_); | 237 base::AutoLock auto_lock(validation_lock_); |
| 236 // Check for Validator registered under first key per the Register() | 238 // Check for Validator registered under first key per the Register() |
| 237 // interface. | 239 // interface. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 observer_list_->AddObserver(observer); | 271 observer_list_->AddObserver(observer); |
| 270 } | 272 } |
| 271 | 273 |
| 272 void DeviceCapabilitiesImpl::RemoveCapabilitiesObserver(Observer* observer) { | 274 void DeviceCapabilitiesImpl::RemoveCapabilitiesObserver(Observer* observer) { |
| 273 DCHECK(observer); | 275 DCHECK(observer); |
| 274 observer_list_->RemoveObserver(observer); | 276 observer_list_->RemoveObserver(observer); |
| 275 } | 277 } |
| 276 | 278 |
| 277 void DeviceCapabilitiesImpl::SetValidatedValue( | 279 void DeviceCapabilitiesImpl::SetValidatedValue( |
| 278 const std::string& path, | 280 const std::string& path, |
| 279 scoped_ptr<base::Value> new_value) { | 281 std::unique_ptr<base::Value> new_value) { |
| 280 // All internal writes/modifications of capabilities must occur on same | 282 // All internal writes/modifications of capabilities must occur on same |
| 281 // thread to avoid race conditions. | 283 // thread to avoid race conditions. |
| 282 if (!task_runner_for_writes_->BelongsToCurrentThread()) { | 284 if (!task_runner_for_writes_->BelongsToCurrentThread()) { |
| 283 task_runner_for_writes_->PostTask( | 285 task_runner_for_writes_->PostTask( |
| 284 FROM_HERE, | 286 FROM_HERE, |
| 285 base::Bind(&DeviceCapabilitiesImpl::SetValidatedValue, | 287 base::Bind(&DeviceCapabilitiesImpl::SetValidatedValue, |
| 286 base::Unretained(this), path, base::Passed(&new_value))); | 288 base::Unretained(this), path, base::Passed(&new_value))); |
| 287 return; | 289 return; |
| 288 } | 290 } |
| 289 | 291 |
| 290 DCHECK(IsValidPath(path)); | 292 DCHECK(IsValidPath(path)); |
| 291 DCHECK(new_value.get()); | 293 DCHECK(new_value.get()); |
| 292 | 294 |
| 293 // We don't need to acquire lock here when reading data_ because we know that | 295 // We don't need to acquire lock here when reading data_ because we know that |
| 294 // all writes to data_ must occur serially on thread that we're on. | 296 // all writes to data_ must occur serially on thread that we're on. |
| 295 const base::Value* cur_value = nullptr; | 297 const base::Value* cur_value = nullptr; |
| 296 bool capability_unchanged = data_->dictionary().Get(path, &cur_value) && | 298 bool capability_unchanged = data_->dictionary().Get(path, &cur_value) && |
| 297 cur_value->Equals(new_value.get()); | 299 cur_value->Equals(new_value.get()); |
| 298 if (capability_unchanged) { | 300 if (capability_unchanged) { |
| 299 VLOG(1) << "Ignoring unchanged capability: " << path; | 301 VLOG(1) << "Ignoring unchanged capability: " << path; |
| 300 return; | 302 return; |
| 301 } | 303 } |
| 302 | 304 |
| 303 // In this sequence, we create a deep copy, modify the deep copy, and then | 305 // In this sequence, we create a deep copy, modify the deep copy, and then |
| 304 // do a pointer swap. We do this to have minimal time spent in the | 306 // do a pointer swap. We do this to have minimal time spent in the |
| 305 // data_lock_. If we were to lock and modify the capabilities | 307 // data_lock_. If we were to lock and modify the capabilities |
| 306 // dictionary directly, there may be expensive writes that block other | 308 // dictionary directly, there may be expensive writes that block other |
| 307 // threads. | 309 // threads. |
| 308 scoped_ptr<base::DictionaryValue> dictionary_deep_copy( | 310 std::unique_ptr<base::DictionaryValue> dictionary_deep_copy( |
| 309 data_->dictionary().CreateDeepCopy()); | 311 data_->dictionary().CreateDeepCopy()); |
| 310 dictionary_deep_copy->Set(path, std::move(new_value)); | 312 dictionary_deep_copy->Set(path, std::move(new_value)); |
| 311 scoped_refptr<Data> new_data(CreateData(std::move(dictionary_deep_copy))); | 313 scoped_refptr<Data> new_data(CreateData(std::move(dictionary_deep_copy))); |
| 312 | 314 |
| 313 { | 315 { |
| 314 base::AutoLock auto_lock(data_lock_); | 316 base::AutoLock auto_lock(data_lock_); |
| 315 // Using swap instead of assignment operator here because it's a little | 317 // Using swap instead of assignment operator here because it's a little |
| 316 // faster. Avoids an extra call to AddRef()/Release(). | 318 // faster. Avoids an extra call to AddRef()/Release(). |
| 317 data_.swap(new_data); | 319 data_.swap(new_data); |
| 318 } | 320 } |
| 319 | 321 |
| 320 // Even though ObserverListThreadSafe notifications are always asynchronous | 322 // Even though ObserverListThreadSafe notifications are always asynchronous |
| 321 // (posts task even if to same thread), no locks should be held at this point | 323 // (posts task even if to same thread), no locks should be held at this point |
| 322 // in the code. This is just to be safe that no deadlocks occur if Observers | 324 // in the code. This is just to be safe that no deadlocks occur if Observers |
| 323 // call DeviceCapabilities methods in OnCapabilitiesChanged(). | 325 // call DeviceCapabilities methods in OnCapabilitiesChanged(). |
| 324 observer_list_->Notify(FROM_HERE, &Observer::OnCapabilitiesChanged, path); | 326 observer_list_->Notify(FROM_HERE, &Observer::OnCapabilitiesChanged, path); |
| 325 } | 327 } |
| 326 | 328 |
| 327 } // namespace chromecast | 329 } // namespace chromecast |
| OLD | NEW |