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"
10 #include "base/memory/weak_ptr.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"
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
{
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
);
44 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
45 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnEnumerateStorages
,
46 weak_ptr_factory_
.GetWeakPtr(),
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
);
59 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
60 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetStorageInfo
,
61 weak_ptr_factory_
.GetWeakPtr(),
67 // MediaTransferProtocolDaemonClient override.
68 void OpenStorage(const std::string
& storage_name
,
69 const std::string
& mode
,
70 const OpenStorageCallback
& callback
,
71 const ErrorCallback
& error_callback
) override
{
72 dbus::MethodCall
method_call(mtpd::kMtpdInterface
, mtpd::kOpenStorage
);
73 dbus::MessageWriter
writer(&method_call
);
74 writer
.AppendString(storage_name
);
75 DCHECK(mode
== mtpd::kReadOnlyMode
|| mode
== mtpd::kReadWriteMode
);
76 writer
.AppendString(mode
);
78 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
79 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage
,
80 weak_ptr_factory_
.GetWeakPtr(),
85 // MediaTransferProtocolDaemonClient override.
86 void CloseStorage(const std::string
& handle
,
87 const CloseStorageCallback
& callback
,
88 const ErrorCallback
& error_callback
) override
{
89 dbus::MethodCall
method_call(mtpd::kMtpdInterface
, mtpd::kCloseStorage
);
90 dbus::MessageWriter
writer(&method_call
);
91 writer
.AppendString(handle
);
93 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
94 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCloseStorage
,
95 weak_ptr_factory_
.GetWeakPtr(),
100 void CreateDirectory(const std::string
& handle
,
101 const uint32 parent_id
,
102 const std::string
& directory_name
,
103 const CreateDirectoryCallback
& callback
,
104 const ErrorCallback
& error_callback
) override
{
105 dbus::MethodCall
method_call(mtpd::kMtpdInterface
, mtpd::kCreateDirectory
);
106 dbus::MessageWriter
writer(&method_call
);
107 writer
.AppendString(handle
);
108 writer
.AppendUint32(parent_id
);
109 writer
.AppendString(directory_name
);
111 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
112 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCreateDirectory
,
113 weak_ptr_factory_
.GetWeakPtr(), callback
, error_callback
));
116 // MediaTransferProtocolDaemonClient override.
117 void ReadDirectoryEntryIds(const std::string
& handle
,
119 const ReadDirectoryEntryIdsCallback
& callback
,
120 const ErrorCallback
& error_callback
) override
{
121 dbus::MethodCall
method_call(mtpd::kMtpdInterface
,
122 mtpd::kReadDirectoryEntryIds
);
123 dbus::MessageWriter
writer(&method_call
);
124 writer
.AppendString(handle
);
125 writer
.AppendUint32(file_id
);
127 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
128 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectoryIds
,
129 weak_ptr_factory_
.GetWeakPtr(),
134 void GetFileInfo(const std::string
& handle
,
135 const std::vector
<uint32
>& file_ids
,
137 size_t entries_to_read
,
138 const GetFileInfoCallback
& callback
,
139 const ErrorCallback
& error_callback
) override
{
140 if (offset
>= file_ids
.size()) {
141 error_callback
.Run();
145 dbus::MethodCall
method_call(mtpd::kMtpdInterface
, mtpd::kGetFileInfo
);
146 dbus::MessageWriter
writer(&method_call
);
147 writer
.AppendString(handle
);
149 dbus::MessageWriter
array_writer(NULL
);
150 writer
.OpenArray("u", &array_writer
);
152 size_t end_offset
= file_ids
.size();
153 if (offset
<= SIZE_MAX
- entries_to_read
)
154 end_offset
= std::min(end_offset
, offset
+ entries_to_read
);
155 for (size_t i
= offset
; i
< end_offset
; ++i
)
156 array_writer
.AppendUint32(file_ids
[i
]);
158 writer
.CloseContainer(&array_writer
);
161 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
162 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo
,
163 weak_ptr_factory_
.GetWeakPtr(),
168 // MediaTransferProtocolDaemonClient override.
169 void ReadFileChunk(const std::string
& handle
,
172 uint32 bytes_to_read
,
173 const ReadFileCallback
& callback
,
174 const ErrorCallback
& error_callback
) override
{
175 DCHECK_LE(bytes_to_read
, kMaxChunkSize
);
176 dbus::MethodCall
method_call(mtpd::kMtpdInterface
, mtpd::kReadFileChunk
);
177 dbus::MessageWriter
writer(&method_call
);
178 writer
.AppendString(handle
);
179 writer
.AppendUint32(file_id
);
180 writer
.AppendUint32(offset
);
181 writer
.AppendUint32(bytes_to_read
);
183 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
184 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile
,
185 weak_ptr_factory_
.GetWeakPtr(),
190 void RenameObject(const std::string
& handle
,
191 const uint32 object_id
,
192 const std::string
& new_name
,
193 const RenameObjectCallback
& callback
,
194 const ErrorCallback
& error_callback
) override
{
195 dbus::MethodCall
method_call(mtpd::kMtpdInterface
, mtpd::kRenameObject
);
196 dbus::MessageWriter
writer(&method_call
);
197 writer
.AppendString(handle
);
198 writer
.AppendUint32(object_id
);
199 writer
.AppendString(new_name
);
201 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
202 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnRenameObject
,
203 weak_ptr_factory_
.GetWeakPtr(), callback
, error_callback
));
206 void CopyFileFromLocal(const std::string
& handle
,
207 const int source_file_descriptor
,
208 const uint32 parent_id
,
209 const std::string
& file_name
,
210 const CopyFileFromLocalCallback
& callback
,
211 const ErrorCallback
& error_callback
) override
{
212 dbus::FileDescriptor
file_descriptor(source_file_descriptor
);
213 file_descriptor
.CheckValidity();
215 dbus::MethodCall
method_call(mtpd::kMtpdInterface
,
216 mtpd::kCopyFileFromLocal
);
217 dbus::MessageWriter
writer(&method_call
);
218 writer
.AppendString(handle
);
219 writer
.AppendFileDescriptor(file_descriptor
);
220 writer
.AppendUint32(parent_id
);
221 writer
.AppendString(file_name
);
223 &method_call
, dbus::ObjectProxy::TIMEOUT_INFINITE
,
224 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCopyFileFromLocal
,
225 weak_ptr_factory_
.GetWeakPtr(), callback
, error_callback
));
228 void DeleteObject(const std::string
& handle
,
229 const uint32 object_id
,
230 const DeleteObjectCallback
& callback
,
231 const ErrorCallback
& error_callback
) override
{
232 dbus::MethodCall
method_call(mtpd::kMtpdInterface
, mtpd::kDeleteObject
);
233 dbus::MessageWriter
writer(&method_call
);
234 writer
.AppendString(handle
);
235 writer
.AppendUint32(object_id
);
237 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
238 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnDeleteObject
,
239 weak_ptr_factory_
.GetWeakPtr(), callback
, error_callback
));
242 // MediaTransferProtocolDaemonClient override.
243 void ListenForChanges(const MTPStorageEventHandler
& handler
) override
{
244 DCHECK(!listen_for_changes_called_
);
245 listen_for_changes_called_
= true;
247 static const SignalEventTuple kSignalEventTuples
[] = {
248 { mtpd::kMTPStorageAttached
, true },
249 { mtpd::kMTPStorageDetached
, false },
251 const size_t kNumSignalEventTuples
= arraysize(kSignalEventTuples
);
253 for (size_t i
= 0; i
< kNumSignalEventTuples
; ++i
) {
254 proxy_
->ConnectToSignal(
255 mtpd::kMtpdInterface
,
256 kSignalEventTuples
[i
].signal_name
,
257 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnMTPStorageSignal
,
258 weak_ptr_factory_
.GetWeakPtr(),
260 kSignalEventTuples
[i
].is_attach
),
261 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnSignalConnected
,
262 weak_ptr_factory_
.GetWeakPtr()));
267 // A struct to contain a pair of signal name and attachment event type.
268 // Used by SetUpConnections.
269 struct SignalEventTuple
{
270 const char* signal_name
;
274 // Handles the result of EnumerateStorages and calls |callback| or
276 void OnEnumerateStorages(const EnumerateStoragesCallback
& callback
,
277 const ErrorCallback
& error_callback
,
278 dbus::Response
* response
) {
280 error_callback
.Run();
283 dbus::MessageReader
reader(response
);
284 std::vector
<std::string
> storage_names
;
285 if (!reader
.PopArrayOfStrings(&storage_names
)) {
286 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
287 error_callback
.Run();
290 callback
.Run(storage_names
);
293 // Handles the result of GetStorageInfo and calls |callback| or
295 void OnGetStorageInfo(const std::string
& storage_name
,
296 const GetStorageInfoCallback
& callback
,
297 const ErrorCallback
& error_callback
,
298 dbus::Response
* response
) {
300 error_callback
.Run();
304 dbus::MessageReader
reader(response
);
305 MtpStorageInfo protobuf
;
306 if (!reader
.PopArrayOfBytesAsProto(&protobuf
)) {
307 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
308 error_callback
.Run();
311 callback
.Run(protobuf
);
314 // Handles the result of OpenStorage and calls |callback| or |error_callback|.
315 void OnOpenStorage(const OpenStorageCallback
& callback
,
316 const ErrorCallback
& error_callback
,
317 dbus::Response
* response
) {
319 error_callback
.Run();
322 dbus::MessageReader
reader(response
);
324 if (!reader
.PopString(&handle
)) {
325 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
326 error_callback
.Run();
329 callback
.Run(handle
);
332 // Handles the result of CloseStorage and calls |callback| or
334 void OnCloseStorage(const CloseStorageCallback
& callback
,
335 const ErrorCallback
& error_callback
,
336 dbus::Response
* response
) {
338 error_callback
.Run();
344 void OnCreateDirectory(const CreateDirectoryCallback
& callback
,
345 const ErrorCallback
& error_callback
,
346 dbus::Response
* response
) {
348 error_callback
.Run();
354 // Handles the result of ReadDirectoryEntryIds and calls |callback| or
356 void OnReadDirectoryIds(const ReadDirectoryEntryIdsCallback
& callback
,
357 const ErrorCallback
& error_callback
,
358 dbus::Response
* response
) {
360 error_callback
.Run();
364 std::vector
<uint32
> file_ids
;
365 dbus::MessageReader
reader(response
);
366 dbus::MessageReader
array_reader(NULL
);
367 if (!reader
.PopArray(&array_reader
) || reader
.HasMoreData()) {
368 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
369 error_callback
.Run();
373 while (array_reader
.HasMoreData()) {
375 if (array_reader
.PopUint32(&file_id
)) {
376 file_ids
.push_back(file_id
);
378 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
379 error_callback
.Run();
383 callback
.Run(file_ids
);
386 // Handles the result of GetFileInfo and calls |callback| or |error_callback|.
387 void OnGetFileInfo(const GetFileInfoCallback
& callback
,
388 const ErrorCallback
& error_callback
,
389 dbus::Response
* response
) {
391 error_callback
.Run();
395 std::vector
<MtpFileEntry
> file_entries
;
396 dbus::MessageReader
reader(response
);
397 MtpFileEntries entries_protobuf
;
398 if (!reader
.PopArrayOfBytesAsProto(&entries_protobuf
)) {
399 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
400 error_callback
.Run();
404 for (int i
= 0; i
< entries_protobuf
.file_entries_size(); ++i
)
405 file_entries
.push_back(entries_protobuf
.file_entries(i
));
406 callback
.Run(file_entries
);
409 // Handles the result of ReadFileChunk and calls |callback| or
411 void OnReadFile(const ReadFileCallback
& callback
,
412 const ErrorCallback
& error_callback
,
413 dbus::Response
* response
) {
415 error_callback
.Run();
419 const uint8
* data_bytes
= NULL
;
420 size_t data_length
= 0;
421 dbus::MessageReader
reader(response
);
422 if (!reader
.PopArrayOfBytes(&data_bytes
, &data_length
)) {
423 error_callback
.Run();
426 std::string
data(reinterpret_cast<const char*>(data_bytes
), data_length
);
430 void OnRenameObject(const RenameObjectCallback
& callback
,
431 const ErrorCallback
& error_callback
,
432 dbus::Response
* response
) {
434 error_callback
.Run();
441 void OnCopyFileFromLocal(const CopyFileFromLocalCallback
& callback
,
442 const ErrorCallback
& error_callback
,
443 dbus::Response
* response
) {
445 error_callback
.Run();
452 void OnDeleteObject(const DeleteObjectCallback
& callback
,
453 const ErrorCallback
& error_callback
,
454 dbus::Response
* response
) {
456 error_callback
.Run();
463 // Handles MTPStorageAttached/Dettached signals and calls |handler|.
464 void OnMTPStorageSignal(MTPStorageEventHandler handler
,
466 dbus::Signal
* signal
) {
467 dbus::MessageReader
reader(signal
);
468 std::string storage_name
;
469 if (!reader
.PopString(&storage_name
)) {
470 LOG(ERROR
) << "Invalid signal: " << signal
->ToString();
473 DCHECK(!storage_name
.empty());
474 handler
.Run(is_attach
, storage_name
);
478 // Handles the result of signal connection setup.
479 void OnSignalConnected(const std::string
& interface
,
480 const std::string
& signal
,
482 LOG_IF(ERROR
, !succeeded
) << "Connect to " << interface
<< " "
483 << signal
<< " failed.";
486 dbus::ObjectProxy
* proxy_
;
488 bool listen_for_changes_called_
;
490 // Note: This should remain the last member so it'll be destroyed and
491 // invalidate its weak pointers before any other members are destroyed.
492 base::WeakPtrFactory
<MediaTransferProtocolDaemonClientImpl
> weak_ptr_factory_
;
494 DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientImpl
);
499 ////////////////////////////////////////////////////////////////////////////////
500 // MediaTransferProtocolDaemonClient
502 MediaTransferProtocolDaemonClient::MediaTransferProtocolDaemonClient() {}
504 MediaTransferProtocolDaemonClient::~MediaTransferProtocolDaemonClient() {}
507 MediaTransferProtocolDaemonClient
* MediaTransferProtocolDaemonClient::Create(
509 return new MediaTransferProtocolDaemonClientImpl(bus
);
512 } // namespace device