1 // Copyright 2014 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 "chromeos/dbus/lorgnette_manager_client.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/callback.h" 12 #include "base/location.h" 13 #include "base/memory/ref_counted_memory.h" 14 #include "base/threading/worker_pool.h" 15 #include "dbus/bus.h" 16 #include "dbus/message.h" 17 #include "dbus/object_path.h" 18 #include "dbus/object_proxy.h" 19 #include "net/base/file_stream.h" 20 #include "third_party/cros_system_api/dbus/service_constants.h" 21 22 namespace chromeos { 23 24 // The LorgnetteManagerClient implementation used in production. 25 class LorgnetteManagerClientImpl : public LorgnetteManagerClient { 26 public: 27 LorgnetteManagerClientImpl() : 28 lorgnette_daemon_proxy_(NULL), weak_ptr_factory_(this) {} 29 30 virtual ~LorgnetteManagerClientImpl() {} 31 32 virtual void ListScanners(const ListScannersCallback& callback) OVERRIDE { 33 dbus::MethodCall method_call(lorgnette::kManagerServiceInterface, 34 lorgnette::kListScannersMethod); 35 lorgnette_daemon_proxy_->CallMethod( 36 &method_call, 37 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 38 base::Bind(&LorgnetteManagerClientImpl::OnListScanners, 39 weak_ptr_factory_.GetWeakPtr(), 40 callback)); 41 } 42 43 // LorgnetteManagerClient override. 44 virtual void ScanImage(std::string device_name, 45 base::PlatformFile file, 46 const ScanProperties& properties, 47 const ScanImageCallback& callback) OVERRIDE { 48 dbus::FileDescriptor* file_descriptor = new dbus::FileDescriptor(); 49 file_descriptor->PutValue(file); 50 // Punt descriptor validity check to a worker thread; on return we'll 51 // issue the D-Bus request to stop tracing and collect results. 52 base::WorkerPool::PostTaskAndReply( 53 FROM_HERE, 54 base::Bind(&LorgnetteManagerClientImpl::CheckValidity, 55 file_descriptor), 56 base::Bind(&LorgnetteManagerClientImpl::OnCheckValidityScanImage, 57 weak_ptr_factory_.GetWeakPtr(), 58 base::Owned(file_descriptor), 59 device_name, 60 properties, 61 callback), 62 false); 63 } 64 65 protected: 66 virtual void Init(dbus::Bus* bus) OVERRIDE { 67 lorgnette_daemon_proxy_ = 68 bus->GetObjectProxy(lorgnette::kManagerServiceName, 69 dbus::ObjectPath(lorgnette::kManagerServicePath)); 70 } 71 72 private: 73 // Called when ListScanners completes. 74 void OnListScanners(const ListScannersCallback& callback, 75 dbus::Response* response) { 76 ScannerTable scanners; 77 dbus::MessageReader table_reader(NULL); 78 if (!response || !dbus::MessageReader(response).PopArray(&table_reader)) { 79 callback.Run(false, scanners); 80 return; 81 } 82 83 bool decode_failure = false; 84 while (table_reader.HasMoreData()) { 85 std::string device_name; 86 dbus::MessageReader device_entry_reader(NULL); 87 dbus::MessageReader device_element_reader(NULL); 88 if (!table_reader.PopDictEntry(&device_entry_reader) || 89 !device_entry_reader.PopString(&device_name) || 90 !device_entry_reader.PopArray(&device_element_reader)) { 91 decode_failure = true; 92 break; 93 } 94 95 ScannerTableEntry scanner_entry; 96 while (device_element_reader.HasMoreData()) { 97 dbus::MessageReader device_attribute_reader(NULL); 98 std::string attribute; 99 std::string value; 100 if (!device_element_reader.PopDictEntry(&device_attribute_reader) || 101 !device_attribute_reader.PopString(&attribute) || 102 !device_attribute_reader.PopString(&value)) { 103 decode_failure = true; 104 break; 105 } 106 scanner_entry[attribute] = value; 107 } 108 109 if (decode_failure) 110 break; 111 112 scanners[device_name] = scanner_entry; 113 } 114 115 if (decode_failure) { 116 LOG(ERROR) << "Failed to decode response from ListScanners"; 117 callback.Run(false, scanners); 118 } else { 119 callback.Run(true, scanners); 120 } 121 } 122 123 // Called to check descriptor validity on a thread where i/o is permitted. 124 static void CheckValidity(dbus::FileDescriptor* file_descriptor) { 125 file_descriptor->CheckValidity(); 126 } 127 128 // Called when a CheckValidity response is received. 129 void OnCheckValidityScanImage( 130 dbus::FileDescriptor* file_descriptor, 131 std::string device_name, 132 const ScanProperties& properties, 133 const ScanImageCallback& callback) { 134 if (!file_descriptor->is_valid()) { 135 LOG(ERROR) << "Failed to scan image: file descriptor is invalid"; 136 callback.Run(false); 137 return; 138 } 139 // Issue the dbus request to scan an image. 140 dbus::MethodCall method_call( 141 lorgnette::kManagerServiceInterface, 142 lorgnette::kScanImageMethod); 143 dbus::MessageWriter writer(&method_call); 144 writer.AppendString(device_name); 145 writer.AppendFileDescriptor(*file_descriptor); 146 147 dbus::MessageWriter option_writer(NULL); 148 dbus::MessageWriter element_writer(NULL); 149 writer.OpenArray("{sv}", &option_writer); 150 if (!properties.mode.empty()) { 151 option_writer.OpenDictEntry(&element_writer); 152 element_writer.AppendString(lorgnette::kScanPropertyMode); 153 element_writer.AppendVariantOfString(properties.mode); 154 option_writer.CloseContainer(&element_writer); 155 } 156 if (properties.resolution_dpi) { 157 option_writer.OpenDictEntry(&element_writer); 158 element_writer.AppendString(lorgnette::kScanPropertyResolution); 159 element_writer.AppendVariantOfUint32(properties.resolution_dpi); 160 option_writer.CloseContainer(&element_writer); 161 } 162 writer.CloseContainer(&option_writer); 163 164 lorgnette_daemon_proxy_->CallMethod( 165 &method_call, 166 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 167 base::Bind(&LorgnetteManagerClientImpl::OnScanImageComplete, 168 weak_ptr_factory_.GetWeakPtr(), 169 callback)); 170 } 171 172 // Called when a response for ScanImage() is received. 173 void OnScanImageComplete(const ScanImageCallback& callback, 174 dbus::Response* response) { 175 if (!response) { 176 LOG(ERROR) << "Failed to scan image"; 177 callback.Run(false); 178 return; 179 } 180 callback.Run(true); 181 } 182 183 dbus::ObjectProxy* lorgnette_daemon_proxy_; 184 base::WeakPtrFactory<LorgnetteManagerClientImpl> weak_ptr_factory_; 185 186 DISALLOW_COPY_AND_ASSIGN(LorgnetteManagerClientImpl); 187 }; 188 189 LorgnetteManagerClient::LorgnetteManagerClient() { 190 } 191 192 LorgnetteManagerClient::~LorgnetteManagerClient() { 193 } 194 195 // static 196 LorgnetteManagerClient* LorgnetteManagerClient::Create() { 197 return new LorgnetteManagerClientImpl(); 198 } 199 200 } // namespace chromeos 201