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