mac: Let IPhotoDataProvider::GetAlbumNames() return albums in a deterministic order.
[chromium-blink-merge.git] / device / media_transfer_protocol / media_transfer_protocol_daemon_client.cc
blob1d2ca8cde0d3229ecd9478c165775959a1ba4544
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.
5 #include "device/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/memory/weak_ptr.h"
11 #include "dbus/bus.h"
12 #include "dbus/message.h"
13 #include "dbus/object_path.h"
14 #include "dbus/object_proxy.h"
15 #include "device/media_transfer_protocol/mtp_file_entry.pb.h"
16 #include "device/media_transfer_protocol/mtp_storage_info.pb.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
19 namespace device {
21 namespace {
23 const char kInvalidResponseMsg[] = "Invalid Response: ";
24 uint32 kMaxChunkSize = 1024*1024; // D-Bus has message size limits.
26 // The MediaTransferProtocolDaemonClient implementation.
27 class MediaTransferProtocolDaemonClientImpl
28 : public MediaTransferProtocolDaemonClient {
29 public:
30 explicit MediaTransferProtocolDaemonClientImpl(dbus::Bus* bus)
31 : proxy_(bus->GetObjectProxy(
32 mtpd::kMtpdServiceName,
33 dbus::ObjectPath(mtpd::kMtpdServicePath))),
34 listen_for_changes_called_(false),
35 weak_ptr_factory_(this) {
38 // MediaTransferProtocolDaemonClient override.
39 void EnumerateStorages(const EnumerateStoragesCallback& callback,
40 const ErrorCallback& error_callback) override {
41 dbus::MethodCall method_call(mtpd::kMtpdInterface,
42 mtpd::kEnumerateStorages);
43 proxy_->CallMethod(
44 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
45 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnEnumerateStorages,
46 weak_ptr_factory_.GetWeakPtr(),
47 callback,
48 error_callback));
51 // MediaTransferProtocolDaemonClient override.
52 void GetStorageInfo(const std::string& storage_name,
53 const GetStorageInfoCallback& callback,
54 const ErrorCallback& error_callback) override {
55 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetStorageInfo);
56 dbus::MessageWriter writer(&method_call);
57 writer.AppendString(storage_name);
58 proxy_->CallMethod(
59 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
60 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetStorageInfo,
61 weak_ptr_factory_.GetWeakPtr(),
62 storage_name,
63 callback,
64 error_callback));
67 void GetStorageInfoFromDevice(const std::string& storage_name,
68 const GetStorageInfoCallback& callback,
69 const ErrorCallback& error_callback) override {
70 dbus::MethodCall method_call(mtpd::kMtpdInterface,
71 mtpd::kGetStorageInfoFromDevice);
72 dbus::MessageWriter writer(&method_call);
73 writer.AppendString(storage_name);
74 proxy_->CallMethod(
75 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
76 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetStorageInfo,
77 weak_ptr_factory_.GetWeakPtr(), storage_name, callback,
78 error_callback));
81 // MediaTransferProtocolDaemonClient override.
82 void OpenStorage(const std::string& storage_name,
83 const std::string& mode,
84 const OpenStorageCallback& callback,
85 const ErrorCallback& error_callback) override {
86 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kOpenStorage);
87 dbus::MessageWriter writer(&method_call);
88 writer.AppendString(storage_name);
89 DCHECK(mode == mtpd::kReadOnlyMode || mode == mtpd::kReadWriteMode);
90 writer.AppendString(mode);
91 proxy_->CallMethod(
92 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
93 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage,
94 weak_ptr_factory_.GetWeakPtr(),
95 callback,
96 error_callback));
99 // MediaTransferProtocolDaemonClient override.
100 void CloseStorage(const std::string& handle,
101 const CloseStorageCallback& callback,
102 const ErrorCallback& error_callback) override {
103 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kCloseStorage);
104 dbus::MessageWriter writer(&method_call);
105 writer.AppendString(handle);
106 proxy_->CallMethod(
107 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
108 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCloseStorage,
109 weak_ptr_factory_.GetWeakPtr(),
110 callback,
111 error_callback));
114 void CreateDirectory(const std::string& handle,
115 const uint32 parent_id,
116 const std::string& directory_name,
117 const CreateDirectoryCallback& callback,
118 const ErrorCallback& error_callback) override {
119 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kCreateDirectory);
120 dbus::MessageWriter writer(&method_call);
121 writer.AppendString(handle);
122 writer.AppendUint32(parent_id);
123 writer.AppendString(directory_name);
124 proxy_->CallMethod(
125 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
126 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCreateDirectory,
127 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
130 // MediaTransferProtocolDaemonClient override.
131 void ReadDirectoryEntryIds(const std::string& handle,
132 uint32 file_id,
133 const ReadDirectoryEntryIdsCallback& callback,
134 const ErrorCallback& error_callback) override {
135 dbus::MethodCall method_call(mtpd::kMtpdInterface,
136 mtpd::kReadDirectoryEntryIds);
137 dbus::MessageWriter writer(&method_call);
138 writer.AppendString(handle);
139 writer.AppendUint32(file_id);
140 proxy_->CallMethod(
141 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
142 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectoryIds,
143 weak_ptr_factory_.GetWeakPtr(),
144 callback,
145 error_callback));
148 void GetFileInfo(const std::string& handle,
149 const std::vector<uint32>& file_ids,
150 size_t offset,
151 size_t entries_to_read,
152 const GetFileInfoCallback& callback,
153 const ErrorCallback& error_callback) override {
154 if (offset >= file_ids.size()) {
155 error_callback.Run();
156 return;
159 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetFileInfo);
160 dbus::MessageWriter writer(&method_call);
161 writer.AppendString(handle);
163 dbus::MessageWriter array_writer(NULL);
164 writer.OpenArray("u", &array_writer);
166 size_t end_offset = file_ids.size();
167 if (offset <= SIZE_MAX - entries_to_read)
168 end_offset = std::min(end_offset, offset + entries_to_read);
169 for (size_t i = offset; i < end_offset; ++i)
170 array_writer.AppendUint32(file_ids[i]);
172 writer.CloseContainer(&array_writer);
174 proxy_->CallMethod(
175 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
176 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo,
177 weak_ptr_factory_.GetWeakPtr(),
178 callback,
179 error_callback));
182 // MediaTransferProtocolDaemonClient override.
183 void ReadFileChunk(const std::string& handle,
184 uint32 file_id,
185 uint32 offset,
186 uint32 bytes_to_read,
187 const ReadFileCallback& callback,
188 const ErrorCallback& error_callback) override {
189 DCHECK_LE(bytes_to_read, kMaxChunkSize);
190 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kReadFileChunk);
191 dbus::MessageWriter writer(&method_call);
192 writer.AppendString(handle);
193 writer.AppendUint32(file_id);
194 writer.AppendUint32(offset);
195 writer.AppendUint32(bytes_to_read);
196 proxy_->CallMethod(
197 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
198 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile,
199 weak_ptr_factory_.GetWeakPtr(),
200 callback,
201 error_callback));
204 void RenameObject(const std::string& handle,
205 const uint32 object_id,
206 const std::string& new_name,
207 const RenameObjectCallback& callback,
208 const ErrorCallback& error_callback) override {
209 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kRenameObject);
210 dbus::MessageWriter writer(&method_call);
211 writer.AppendString(handle);
212 writer.AppendUint32(object_id);
213 writer.AppendString(new_name);
214 proxy_->CallMethod(
215 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
216 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnRenameObject,
217 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
220 void CopyFileFromLocal(const std::string& handle,
221 const int source_file_descriptor,
222 const uint32 parent_id,
223 const std::string& file_name,
224 const CopyFileFromLocalCallback& callback,
225 const ErrorCallback& error_callback) override {
226 dbus::FileDescriptor file_descriptor(source_file_descriptor);
227 file_descriptor.CheckValidity();
229 dbus::MethodCall method_call(mtpd::kMtpdInterface,
230 mtpd::kCopyFileFromLocal);
231 dbus::MessageWriter writer(&method_call);
232 writer.AppendString(handle);
233 writer.AppendFileDescriptor(file_descriptor);
234 writer.AppendUint32(parent_id);
235 writer.AppendString(file_name);
236 proxy_->CallMethod(
237 &method_call, dbus::ObjectProxy::TIMEOUT_INFINITE,
238 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCopyFileFromLocal,
239 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
242 void DeleteObject(const std::string& handle,
243 const uint32 object_id,
244 const DeleteObjectCallback& callback,
245 const ErrorCallback& error_callback) override {
246 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kDeleteObject);
247 dbus::MessageWriter writer(&method_call);
248 writer.AppendString(handle);
249 writer.AppendUint32(object_id);
250 proxy_->CallMethod(
251 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
252 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnDeleteObject,
253 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
256 // MediaTransferProtocolDaemonClient override.
257 void ListenForChanges(const MTPStorageEventHandler& handler) override {
258 DCHECK(!listen_for_changes_called_);
259 listen_for_changes_called_ = true;
261 static const SignalEventTuple kSignalEventTuples[] = {
262 { mtpd::kMTPStorageAttached, true },
263 { mtpd::kMTPStorageDetached, false },
265 const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples);
267 for (size_t i = 0; i < kNumSignalEventTuples; ++i) {
268 proxy_->ConnectToSignal(
269 mtpd::kMtpdInterface,
270 kSignalEventTuples[i].signal_name,
271 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnMTPStorageSignal,
272 weak_ptr_factory_.GetWeakPtr(),
273 handler,
274 kSignalEventTuples[i].is_attach),
275 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnSignalConnected,
276 weak_ptr_factory_.GetWeakPtr()));
280 private:
281 // A struct to contain a pair of signal name and attachment event type.
282 // Used by SetUpConnections.
283 struct SignalEventTuple {
284 const char* signal_name;
285 bool is_attach;
288 // Handles the result of EnumerateStorages and calls |callback| or
289 // |error_callback|.
290 void OnEnumerateStorages(const EnumerateStoragesCallback& callback,
291 const ErrorCallback& error_callback,
292 dbus::Response* response) {
293 if (!response) {
294 error_callback.Run();
295 return;
297 dbus::MessageReader reader(response);
298 std::vector<std::string> storage_names;
299 if (!reader.PopArrayOfStrings(&storage_names)) {
300 LOG(ERROR) << kInvalidResponseMsg << response->ToString();
301 error_callback.Run();
302 return;
304 callback.Run(storage_names);
307 // Handles the result of GetStorageInfo and calls |callback| or
308 // |error_callback|.
309 void OnGetStorageInfo(const std::string& storage_name,
310 const GetStorageInfoCallback& callback,
311 const ErrorCallback& error_callback,
312 dbus::Response* response) {
313 if (!response) {
314 error_callback.Run();
315 return;
318 dbus::MessageReader reader(response);
319 MtpStorageInfo protobuf;
320 if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
321 LOG(ERROR) << kInvalidResponseMsg << response->ToString();
322 error_callback.Run();
323 return;
325 callback.Run(protobuf);
328 // Handles the result of OpenStorage and calls |callback| or |error_callback|.
329 void OnOpenStorage(const OpenStorageCallback& callback,
330 const ErrorCallback& error_callback,
331 dbus::Response* response) {
332 if (!response) {
333 error_callback.Run();
334 return;
336 dbus::MessageReader reader(response);
337 std::string handle;
338 if (!reader.PopString(&handle)) {
339 LOG(ERROR) << kInvalidResponseMsg << response->ToString();
340 error_callback.Run();
341 return;
343 callback.Run(handle);
346 // Handles the result of CloseStorage and calls |callback| or
347 // |error_callback|.
348 void OnCloseStorage(const CloseStorageCallback& callback,
349 const ErrorCallback& error_callback,
350 dbus::Response* response) {
351 if (!response) {
352 error_callback.Run();
353 return;
355 callback.Run();
358 void OnCreateDirectory(const CreateDirectoryCallback& callback,
359 const ErrorCallback& error_callback,
360 dbus::Response* response) {
361 if (!response) {
362 error_callback.Run();
363 return;
365 callback.Run();
368 // Handles the result of ReadDirectoryEntryIds and calls |callback| or
369 // |error_callback|.
370 void OnReadDirectoryIds(const ReadDirectoryEntryIdsCallback& callback,
371 const ErrorCallback& error_callback,
372 dbus::Response* response) {
373 if (!response) {
374 error_callback.Run();
375 return;
378 std::vector<uint32> file_ids;
379 dbus::MessageReader reader(response);
380 dbus::MessageReader array_reader(NULL);
381 if (!reader.PopArray(&array_reader) || reader.HasMoreData()) {
382 LOG(ERROR) << kInvalidResponseMsg << response->ToString();
383 error_callback.Run();
384 return;
387 while (array_reader.HasMoreData()) {
388 uint32 file_id;
389 if (array_reader.PopUint32(&file_id)) {
390 file_ids.push_back(file_id);
391 } else {
392 LOG(ERROR) << kInvalidResponseMsg << response->ToString();
393 error_callback.Run();
394 return;
397 callback.Run(file_ids);
400 // Handles the result of GetFileInfo and calls |callback| or |error_callback|.
401 void OnGetFileInfo(const GetFileInfoCallback& callback,
402 const ErrorCallback& error_callback,
403 dbus::Response* response) {
404 if (!response) {
405 error_callback.Run();
406 return;
409 std::vector<MtpFileEntry> file_entries;
410 dbus::MessageReader reader(response);
411 MtpFileEntries entries_protobuf;
412 if (!reader.PopArrayOfBytesAsProto(&entries_protobuf)) {
413 LOG(ERROR) << kInvalidResponseMsg << response->ToString();
414 error_callback.Run();
415 return;
418 for (int i = 0; i < entries_protobuf.file_entries_size(); ++i)
419 file_entries.push_back(entries_protobuf.file_entries(i));
420 callback.Run(file_entries);
423 // Handles the result of ReadFileChunk and calls |callback| or
424 // |error_callback|.
425 void OnReadFile(const ReadFileCallback& callback,
426 const ErrorCallback& error_callback,
427 dbus::Response* response) {
428 if (!response) {
429 error_callback.Run();
430 return;
433 const uint8* data_bytes = NULL;
434 size_t data_length = 0;
435 dbus::MessageReader reader(response);
436 if (!reader.PopArrayOfBytes(&data_bytes, &data_length)) {
437 error_callback.Run();
438 return;
440 std::string data(reinterpret_cast<const char*>(data_bytes), data_length);
441 callback.Run(data);
444 void OnRenameObject(const RenameObjectCallback& callback,
445 const ErrorCallback& error_callback,
446 dbus::Response* response) {
447 if (!response) {
448 error_callback.Run();
449 return;
452 callback.Run();
455 void OnCopyFileFromLocal(const CopyFileFromLocalCallback& callback,
456 const ErrorCallback& error_callback,
457 dbus::Response* response) {
458 if (!response) {
459 error_callback.Run();
460 return;
463 callback.Run();
466 void OnDeleteObject(const DeleteObjectCallback& callback,
467 const ErrorCallback& error_callback,
468 dbus::Response* response) {
469 if (!response) {
470 error_callback.Run();
471 return;
474 callback.Run();
477 // Handles MTPStorageAttached/Dettached signals and calls |handler|.
478 void OnMTPStorageSignal(MTPStorageEventHandler handler,
479 bool is_attach,
480 dbus::Signal* signal) {
481 dbus::MessageReader reader(signal);
482 std::string storage_name;
483 if (!reader.PopString(&storage_name)) {
484 LOG(ERROR) << "Invalid signal: " << signal->ToString();
485 return;
487 DCHECK(!storage_name.empty());
488 handler.Run(is_attach, storage_name);
492 // Handles the result of signal connection setup.
493 void OnSignalConnected(const std::string& interface,
494 const std::string& signal,
495 bool succeeded) {
496 LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " "
497 << signal << " failed.";
500 dbus::ObjectProxy* proxy_;
502 bool listen_for_changes_called_;
504 // Note: This should remain the last member so it'll be destroyed and
505 // invalidate its weak pointers before any other members are destroyed.
506 base::WeakPtrFactory<MediaTransferProtocolDaemonClientImpl> weak_ptr_factory_;
508 DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientImpl);
511 } // namespace
513 ////////////////////////////////////////////////////////////////////////////////
514 // MediaTransferProtocolDaemonClient
516 MediaTransferProtocolDaemonClient::MediaTransferProtocolDaemonClient() {}
518 MediaTransferProtocolDaemonClient::~MediaTransferProtocolDaemonClient() {}
520 // static
521 MediaTransferProtocolDaemonClient* MediaTransferProtocolDaemonClient::Create(
522 dbus::Bus* bus) {
523 return new MediaTransferProtocolDaemonClientImpl(bus);
526 } // namespace device