Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 "device/bluetooth/bluetooth_adapter_mac.h" | 5 #include "device/bluetooth/bluetooth_adapter_mac.h" |
| 6 | 6 |
| 7 #import <IOBluetooth/objc/IOBluetoothDevice.h> | 7 #import <IOBluetooth/objc/IOBluetoothDevice.h> |
| 8 #import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h> | |
| 9 #import <IOBluetooth/objc/IOBluetoothHostController.h> | 8 #import <IOBluetooth/objc/IOBluetoothHostController.h> |
| 10 | 9 |
| 11 #include <string> | 10 #include <string> |
| 12 | 11 |
| 13 #include "base/bind.h" | 12 #include "base/bind.h" |
| 14 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 15 #include "base/containers/hash_tables.h" | 14 #include "base/containers/hash_tables.h" |
| 16 #include "base/location.h" | 15 #include "base/location.h" |
| 17 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
| 18 #include "base/sequenced_task_runner.h" | 17 #include "base/sequenced_task_runner.h" |
| 19 #include "base/single_thread_task_runner.h" | 18 #include "base/single_thread_task_runner.h" |
| 20 #include "base/strings/sys_string_conversions.h" | 19 #include "base/strings/sys_string_conversions.h" |
| 21 #include "base/thread_task_runner_handle.h" | 20 #include "base/thread_task_runner_handle.h" |
| 22 #include "base/time/time.h" | 21 #include "base/time/time.h" |
| 23 #include "device/bluetooth/bluetooth_device_mac.h" | 22 #include "device/bluetooth/bluetooth_device_mac.h" |
| 24 #include "device/bluetooth/bluetooth_socket_mac.h" | 23 #include "device/bluetooth/bluetooth_socket_mac.h" |
| 25 #include "device/bluetooth/bluetooth_uuid.h" | 24 #include "device/bluetooth/bluetooth_uuid.h" |
| 26 | 25 |
| 27 // Replicate specific 10.7 SDK declarations for building with prior SDKs. | 26 // Replicate specific 10.7 SDK declarations for building with prior SDKs. |
| 28 #if !defined(MAC_OS_X_VERSION_10_7) || \ | 27 #if !defined(MAC_OS_X_VERSION_10_7) || \ |
| 29 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 | 28 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 |
| 30 | 29 |
| 31 @interface IOBluetoothHostController (LionSDKDeclarations) | 30 @interface IOBluetoothHostController (LionSDKDeclarations) |
| 32 - (NSString*)nameAsString; | 31 - (NSString*)nameAsString; |
| 33 - (BluetoothHCIPowerState)powerState; | 32 - (BluetoothHCIPowerState)powerState; |
| 34 @end | 33 @end |
| 35 | 34 |
| 36 @protocol IOBluetoothDeviceInquiryDelegate | |
| 37 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender; | |
| 38 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender | |
| 39 device:(IOBluetoothDevice*)device; | |
| 40 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender | |
| 41 error:(IOReturn)error | |
| 42 aborted:(BOOL)aborted; | |
| 43 @end | |
| 44 | |
| 45 #endif // MAC_OS_X_VERSION_10_7 | 35 #endif // MAC_OS_X_VERSION_10_7 |
| 46 | 36 |
| 47 @interface BluetoothAdapterMacDelegate | |
| 48 : NSObject <IOBluetoothDeviceInquiryDelegate> { | |
| 49 @private | |
| 50 device::BluetoothAdapterMac* adapter_; // weak | |
| 51 } | |
| 52 | |
| 53 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter; | |
| 54 | |
| 55 @end | |
| 56 | |
| 57 @implementation BluetoothAdapterMacDelegate | |
| 58 | |
| 59 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter { | |
| 60 if ((self = [super init])) | |
| 61 adapter_ = adapter; | |
| 62 | |
| 63 return self; | |
| 64 } | |
| 65 | |
| 66 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender { | |
| 67 adapter_->DeviceInquiryStarted(sender); | |
| 68 } | |
| 69 | |
| 70 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender | |
| 71 device:(IOBluetoothDevice*)device { | |
| 72 adapter_->DeviceFound(sender, device); | |
| 73 } | |
| 74 | |
| 75 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender | |
| 76 error:(IOReturn)error | |
| 77 aborted:(BOOL)aborted { | |
| 78 adapter_->DeviceInquiryComplete(sender, error, aborted); | |
| 79 } | |
| 80 | |
| 81 @end | |
| 82 | |
| 83 namespace { | 37 namespace { |
| 84 | 38 |
| 85 const int kPollIntervalMs = 500; | 39 const int kPollIntervalMs = 500; |
| 86 | 40 |
| 87 } // namespace | 41 } // namespace |
| 88 | 42 |
| 89 namespace device { | 43 namespace device { |
| 90 | 44 |
| 91 // static | 45 // static |
| 92 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter( | 46 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter( |
| 93 const InitCallback& init_callback) { | 47 const InitCallback& init_callback) { |
| 94 return BluetoothAdapterMac::CreateAdapter(); | 48 return BluetoothAdapterMac::CreateAdapter(); |
| 95 } | 49 } |
| 96 | 50 |
| 97 // static | 51 // static |
| 98 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() { | 52 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() { |
| 99 BluetoothAdapterMac* adapter = new BluetoothAdapterMac(); | 53 BluetoothAdapterMac* adapter = new BluetoothAdapterMac(); |
| 100 adapter->Init(); | 54 adapter->Init(); |
| 101 return adapter->weak_ptr_factory_.GetWeakPtr(); | 55 return adapter->weak_ptr_factory_.GetWeakPtr(); |
| 102 } | 56 } |
| 103 | 57 |
| 104 BluetoothAdapterMac::BluetoothAdapterMac() | 58 BluetoothAdapterMac::BluetoothAdapterMac() |
| 105 : BluetoothAdapter(), | 59 : BluetoothAdapter(), |
| 106 powered_(false), | 60 powered_(false), |
| 107 discovery_status_(NOT_DISCOVERING), | 61 num_discovery_sessions_(0), |
| 108 adapter_delegate_( | 62 classic_discovery_manager_(BluetoothMacDiscoveryManager::CreateClassic()), |
| 109 [[BluetoothAdapterMacDelegate alloc] initWithAdapter:this]), | |
| 110 device_inquiry_( | |
| 111 [[IOBluetoothDeviceInquiry | |
| 112 inquiryWithDelegate:adapter_delegate_] retain]), | |
| 113 weak_ptr_factory_(this) { | 63 weak_ptr_factory_(this) { |
| 64 DCHECK(classic_discovery_manager_.get()); | |
| 65 classic_discovery_manager_->AddObserver(this); | |
| 114 } | 66 } |
| 115 | 67 |
| 116 BluetoothAdapterMac::~BluetoothAdapterMac() { | 68 BluetoothAdapterMac::~BluetoothAdapterMac() { |
| 69 classic_discovery_manager_->RemoveObserver(this); | |
| 117 } | 70 } |
| 118 | 71 |
| 119 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) { | 72 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) { |
| 120 DCHECK(observer); | 73 DCHECK(observer); |
| 121 observers_.AddObserver(observer); | 74 observers_.AddObserver(observer); |
| 122 } | 75 } |
| 123 | 76 |
| 124 void BluetoothAdapterMac::RemoveObserver(BluetoothAdapter::Observer* observer) { | 77 void BluetoothAdapterMac::RemoveObserver(BluetoothAdapter::Observer* observer) { |
| 125 DCHECK(observer); | 78 DCHECK(observer); |
| 126 observers_.RemoveObserver(observer); | 79 observers_.RemoveObserver(observer); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 164 } | 117 } |
| 165 | 118 |
| 166 void BluetoothAdapterMac::SetDiscoverable( | 119 void BluetoothAdapterMac::SetDiscoverable( |
| 167 bool discoverable, | 120 bool discoverable, |
| 168 const base::Closure& callback, | 121 const base::Closure& callback, |
| 169 const ErrorCallback& error_callback) { | 122 const ErrorCallback& error_callback) { |
| 170 NOTIMPLEMENTED(); | 123 NOTIMPLEMENTED(); |
| 171 } | 124 } |
| 172 | 125 |
| 173 bool BluetoothAdapterMac::IsDiscovering() const { | 126 bool BluetoothAdapterMac::IsDiscovering() const { |
| 174 return discovery_status_ == DISCOVERING || | 127 return classic_discovery_manager_->IsDiscovering(); |
| 175 discovery_status_ == DISCOVERY_STOPPING; | |
| 176 } | 128 } |
| 177 | 129 |
| 178 void BluetoothAdapterMac::CreateRfcommService( | 130 void BluetoothAdapterMac::CreateRfcommService( |
| 179 const BluetoothUUID& uuid, | 131 const BluetoothUUID& uuid, |
| 180 int channel, | 132 int channel, |
| 181 bool insecure, | 133 bool insecure, |
| 182 const CreateServiceCallback& callback, | 134 const CreateServiceCallback& callback, |
| 183 const CreateServiceErrorCallback& error_callback) { | 135 const CreateServiceErrorCallback& error_callback) { |
| 184 // TODO(keybuk): implement. | 136 // TODO(keybuk): implement. |
| 185 NOTIMPLEMENTED(); | 137 NOTIMPLEMENTED(); |
| 186 } | 138 } |
| 187 | 139 |
| 188 void BluetoothAdapterMac::CreateL2capService( | 140 void BluetoothAdapterMac::CreateL2capService( |
| 189 const BluetoothUUID& uuid, | 141 const BluetoothUUID& uuid, |
| 190 int psm, | 142 int psm, |
| 191 const CreateServiceCallback& callback, | 143 const CreateServiceCallback& callback, |
| 192 const CreateServiceErrorCallback& error_callback) { | 144 const CreateServiceErrorCallback& error_callback) { |
| 193 // TODO(keybuk): implement. | 145 // TODO(keybuk): implement. |
| 194 NOTIMPLEMENTED(); | 146 NOTIMPLEMENTED(); |
| 195 } | 147 } |
| 196 | 148 |
| 149 void BluetoothAdapterMac::DeviceFound(BluetoothMacDiscoveryManager* manager, | |
| 150 IOBluetoothDevice* device) { | |
| 151 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | |
| 152 if (discovered_devices_.find(device_address) == discovered_devices_.end()) { | |
| 153 BluetoothDeviceMac device_mac(device); | |
| 154 FOR_EACH_OBSERVER( | |
| 155 BluetoothAdapter::Observer, observers_, DeviceAdded(this, &device_mac)); | |
| 156 discovered_devices_.insert(device_address); | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 void BluetoothAdapterMac::DiscoveryStopped( | |
| 161 BluetoothMacDiscoveryManager* manager, | |
| 162 bool unexpected) { | |
| 163 if (manager != classic_discovery_manager_.get()) { | |
| 164 VLOG(1) << "Received \"DiscoveryStopped\" from unknown discovery manager."; | |
| 165 return; | |
| 166 } | |
|
Ilya Sherman
2014/06/10 01:10:59
Can this be a DCHECK rather than a VLOG?
armansito
2014/06/10 21:56:50
Done.
| |
| 167 if (unexpected) { | |
| 168 VLOG(1) << "Discovery stopped unexpectedly"; | |
|
Ilya Sherman
2014/06/10 01:10:59
Out of curiousity, why do we use VLOG rather than
keybuk
2014/06/10 01:13:12
CHROME OS debug builds haven't worked for somethin
Ilya Sherman
2014/06/10 01:14:04
Ok, good to know -- thanks :)
keybuk
2014/06/10 01:21:03
but this is _mac, so doesn't really apply, I was j
armansito
2014/06/10 21:56:50
Done.
| |
| 169 num_discovery_sessions_ = 0; | |
| 170 MarkDiscoverySessionsAsInactive(); | |
| 171 } | |
| 172 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, | |
| 173 observers_, | |
| 174 AdapterDiscoveringChanged(this, false)); | |
| 175 } | |
| 176 | |
| 197 void BluetoothAdapterMac::AddDiscoverySession( | 177 void BluetoothAdapterMac::AddDiscoverySession( |
| 198 const base::Closure& callback, | 178 const base::Closure& callback, |
| 199 const ErrorCallback& error_callback) { | 179 const ErrorCallback& error_callback) { |
| 200 if (discovery_status_ == DISCOVERING) { | 180 VLOG(1) << __func__; |
| 201 num_discovery_listeners_++; | 181 if (num_discovery_sessions_ > 0) { |
| 182 DCHECK(IsDiscovering()); | |
| 183 num_discovery_sessions_++; | |
| 202 callback.Run(); | 184 callback.Run(); |
| 203 return; | 185 return; |
| 204 } | 186 } |
| 205 on_start_discovery_callbacks_.push_back( | 187 |
| 206 std::make_pair(callback, error_callback)); | 188 DCHECK(num_discovery_sessions_ == 0); |
|
Ilya Sherman
2014/06/10 01:10:59
nit: DCHECK_EQ
armansito
2014/06/10 21:56:50
Done.
| |
| 207 MaybeStartDeviceInquiry(); | 189 |
| 190 if (!classic_discovery_manager_->StartDiscovery()) { | |
| 191 VLOG(1) << "Failed to add a discovery session"; | |
| 192 error_callback.Run(); | |
| 193 return; | |
| 194 } | |
| 195 | |
| 196 VLOG(1) << "Added a discovery session"; | |
| 197 num_discovery_sessions_++; | |
| 198 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, | |
| 199 observers_, | |
| 200 AdapterDiscoveringChanged(this, true)); | |
| 201 callback.Run(); | |
| 208 } | 202 } |
| 209 | 203 |
| 210 void BluetoothAdapterMac::RemoveDiscoverySession( | 204 void BluetoothAdapterMac::RemoveDiscoverySession( |
| 211 const base::Closure& callback, | 205 const base::Closure& callback, |
| 212 const ErrorCallback& error_callback) { | 206 const ErrorCallback& error_callback) { |
| 213 if (discovery_status_ == NOT_DISCOVERING) { | 207 VLOG(1) << __func__; |
| 208 | |
| 209 // There are active sessions other than the one currently being removed. | |
|
Ilya Sherman
2014/06/10 01:10:59
nit: Please move this into the if-stmt. Typically
armansito
2014/06/10 21:56:50
Done.
| |
| 210 if (num_discovery_sessions_ > 1) { | |
| 211 DCHECK(IsDiscovering()); | |
| 212 num_discovery_sessions_--; | |
| 213 callback.Run(); | |
| 214 return; | |
| 215 } | |
| 216 | |
| 217 if (num_discovery_sessions_ == 0) { | |
| 218 VLOG(1) << "No active discovery sessions. Returning error."; | |
| 214 error_callback.Run(); | 219 error_callback.Run(); |
| 215 return; | 220 return; |
| 216 } | 221 } |
| 217 on_stop_discovery_callbacks_.push_back( | 222 |
| 218 std::make_pair(callback, error_callback)); | 223 if (!classic_discovery_manager_->StopDiscovery()) { |
| 219 MaybeStopDeviceInquiry(); | 224 VLOG(1) << "Failed to stop discovery"; |
| 225 error_callback.Run(); | |
| 226 return; | |
| 227 } | |
| 228 | |
| 229 VLOG(1) << "Discovery stopped"; | |
| 230 num_discovery_sessions_--; | |
| 231 callback.Run(); | |
| 220 } | 232 } |
| 221 | 233 |
| 222 void BluetoothAdapterMac::RemovePairingDelegateInternal( | 234 void BluetoothAdapterMac::RemovePairingDelegateInternal( |
| 223 BluetoothDevice::PairingDelegate* pairing_delegate) { | 235 BluetoothDevice::PairingDelegate* pairing_delegate) { |
| 224 } | 236 } |
| 225 | 237 |
| 226 void BluetoothAdapterMac::Init() { | 238 void BluetoothAdapterMac::Init() { |
| 227 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | 239 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| 228 PollAdapter(); | 240 PollAdapter(); |
| 229 } | 241 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 275 } | 287 } |
| 276 | 288 |
| 277 ui_task_runner_->PostDelayedTask( | 289 ui_task_runner_->PostDelayedTask( |
| 278 FROM_HERE, | 290 FROM_HERE, |
| 279 base::Bind(&BluetoothAdapterMac::PollAdapter, | 291 base::Bind(&BluetoothAdapterMac::PollAdapter, |
| 280 weak_ptr_factory_.GetWeakPtr()), | 292 weak_ptr_factory_.GetWeakPtr()), |
| 281 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); | 293 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); |
| 282 } | 294 } |
| 283 | 295 |
| 284 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) { | 296 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) { |
| 297 // TODO(armansito): This code never calls | |
| 298 // BluetoothAdapter::Observer::DeviceRemoved. It should, if a device | |
| 299 // no longer exists. | |
| 285 STLDeleteValues(&devices_); | 300 STLDeleteValues(&devices_); |
| 286 for (IOBluetoothDevice* device in devices) { | 301 for (IOBluetoothDevice* device in devices) { |
| 287 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | 302 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); |
| 288 devices_[device_address] = new BluetoothDeviceMac(device); | 303 devices_[device_address] = new BluetoothDeviceMac(device); |
| 289 } | 304 } |
| 290 } | 305 } |
| 291 | 306 |
| 292 void BluetoothAdapterMac::DeviceInquiryStarted( | |
| 293 IOBluetoothDeviceInquiry* inquiry) { | |
| 294 DCHECK_EQ(device_inquiry_, inquiry); | |
| 295 if (discovery_status_ == DISCOVERING) | |
| 296 return; | |
| 297 | |
| 298 discovery_status_ = DISCOVERING; | |
| 299 RunCallbacks(on_start_discovery_callbacks_, true); | |
| 300 num_discovery_listeners_ = on_start_discovery_callbacks_.size(); | |
| 301 on_start_discovery_callbacks_.clear(); | |
| 302 | |
| 303 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
| 304 AdapterDiscoveringChanged(this, true)); | |
| 305 MaybeStopDeviceInquiry(); | |
| 306 } | |
| 307 | |
| 308 void BluetoothAdapterMac::DeviceFound(IOBluetoothDeviceInquiry* inquiry, | |
| 309 IOBluetoothDevice* device) { | |
| 310 DCHECK_EQ(device_inquiry_, inquiry); | |
| 311 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | |
| 312 if (discovered_devices_.find(device_address) == discovered_devices_.end()) { | |
| 313 BluetoothDeviceMac device_mac(device); | |
| 314 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
| 315 DeviceAdded(this, &device_mac)); | |
| 316 discovered_devices_.insert(device_address); | |
| 317 } | |
| 318 } | |
| 319 | |
| 320 void BluetoothAdapterMac::DeviceInquiryComplete( | |
| 321 IOBluetoothDeviceInquiry* inquiry, | |
| 322 IOReturn error, | |
| 323 bool aborted) { | |
| 324 DCHECK_EQ(device_inquiry_, inquiry); | |
| 325 if (discovery_status_ == DISCOVERING && | |
| 326 [device_inquiry_ start] == kIOReturnSuccess) { | |
| 327 return; | |
| 328 } | |
| 329 | |
| 330 // Device discovery is done. | |
| 331 discovered_devices_.clear(); | |
| 332 discovery_status_ = NOT_DISCOVERING; | |
| 333 RunCallbacks(on_stop_discovery_callbacks_, error == kIOReturnSuccess); | |
| 334 num_discovery_listeners_ = 0; | |
| 335 on_stop_discovery_callbacks_.clear(); | |
| 336 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
| 337 AdapterDiscoveringChanged(this, false)); | |
| 338 MaybeStartDeviceInquiry(); | |
| 339 } | |
| 340 | |
| 341 void BluetoothAdapterMac::MaybeStartDeviceInquiry() { | |
| 342 if (discovery_status_ == NOT_DISCOVERING && | |
| 343 !on_start_discovery_callbacks_.empty()) { | |
| 344 discovery_status_ = DISCOVERY_STARTING; | |
| 345 if ([device_inquiry_ start] != kIOReturnSuccess) { | |
| 346 discovery_status_ = NOT_DISCOVERING; | |
| 347 RunCallbacks(on_start_discovery_callbacks_, false); | |
| 348 on_start_discovery_callbacks_.clear(); | |
| 349 } | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 void BluetoothAdapterMac::MaybeStopDeviceInquiry() { | |
| 354 if (discovery_status_ != DISCOVERING) | |
| 355 return; | |
| 356 | |
| 357 if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) { | |
| 358 RunCallbacks(on_stop_discovery_callbacks_, true); | |
| 359 num_discovery_listeners_ -= on_stop_discovery_callbacks_.size(); | |
| 360 on_stop_discovery_callbacks_.clear(); | |
| 361 return; | |
| 362 } | |
| 363 | |
| 364 discovery_status_ = DISCOVERY_STOPPING; | |
| 365 if ([device_inquiry_ stop] != kIOReturnSuccess) { | |
| 366 RunCallbacks(on_stop_discovery_callbacks_, false); | |
| 367 on_stop_discovery_callbacks_.clear(); | |
| 368 } | |
| 369 } | |
| 370 | |
| 371 void BluetoothAdapterMac::RunCallbacks( | |
| 372 const DiscoveryCallbackList& callback_list, bool success) const { | |
| 373 for (DiscoveryCallbackList::const_iterator iter = callback_list.begin(); | |
| 374 iter != callback_list.end(); | |
| 375 ++iter) { | |
| 376 if (success) | |
| 377 ui_task_runner_->PostTask(FROM_HERE, iter->first); | |
| 378 else | |
| 379 ui_task_runner_->PostTask(FROM_HERE, iter->second); | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 } // namespace device | 307 } // namespace device |
| OLD | NEW |