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 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
);
75 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
76 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetStorageInfo
,
77 weak_ptr_factory_
.GetWeakPtr(), storage_name
, 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
);
92 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
93 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage
,
94 weak_ptr_factory_
.GetWeakPtr(),
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
);
107 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
108 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCloseStorage
,
109 weak_ptr_factory_
.GetWeakPtr(),
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
);
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
,
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
);
141 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
142 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectoryIds
,
143 weak_ptr_factory_
.GetWeakPtr(),
148 void GetFileInfo(const std::string
& handle
,
149 const std::vector
<uint32
>& file_ids
,
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();
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
);
175 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
176 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo
,
177 weak_ptr_factory_
.GetWeakPtr(),
182 // MediaTransferProtocolDaemonClient override.
183 void ReadFileChunk(const std::string
& handle
,
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
);
197 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
198 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile
,
199 weak_ptr_factory_
.GetWeakPtr(),
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
);
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
);
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
);
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(),
274 kSignalEventTuples
[i
].is_attach
),
275 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnSignalConnected
,
276 weak_ptr_factory_
.GetWeakPtr()));
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
;
288 // Handles the result of EnumerateStorages and calls |callback| or
290 void OnEnumerateStorages(const EnumerateStoragesCallback
& callback
,
291 const ErrorCallback
& error_callback
,
292 dbus::Response
* response
) {
294 error_callback
.Run();
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();
304 callback
.Run(storage_names
);
307 // Handles the result of GetStorageInfo and calls |callback| or
309 void OnGetStorageInfo(const std::string
& storage_name
,
310 const GetStorageInfoCallback
& callback
,
311 const ErrorCallback
& error_callback
,
312 dbus::Response
* response
) {
314 error_callback
.Run();
318 dbus::MessageReader
reader(response
);
319 MtpStorageInfo protobuf
;
320 if (!reader
.PopArrayOfBytesAsProto(&protobuf
)) {
321 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
322 error_callback
.Run();
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
) {
333 error_callback
.Run();
336 dbus::MessageReader
reader(response
);
338 if (!reader
.PopString(&handle
)) {
339 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
340 error_callback
.Run();
343 callback
.Run(handle
);
346 // Handles the result of CloseStorage and calls |callback| or
348 void OnCloseStorage(const CloseStorageCallback
& callback
,
349 const ErrorCallback
& error_callback
,
350 dbus::Response
* response
) {
352 error_callback
.Run();
358 void OnCreateDirectory(const CreateDirectoryCallback
& callback
,
359 const ErrorCallback
& error_callback
,
360 dbus::Response
* response
) {
362 error_callback
.Run();
368 // Handles the result of ReadDirectoryEntryIds and calls |callback| or
370 void OnReadDirectoryIds(const ReadDirectoryEntryIdsCallback
& callback
,
371 const ErrorCallback
& error_callback
,
372 dbus::Response
* response
) {
374 error_callback
.Run();
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();
387 while (array_reader
.HasMoreData()) {
389 if (array_reader
.PopUint32(&file_id
)) {
390 file_ids
.push_back(file_id
);
392 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
393 error_callback
.Run();
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
) {
405 error_callback
.Run();
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();
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
425 void OnReadFile(const ReadFileCallback
& callback
,
426 const ErrorCallback
& error_callback
,
427 dbus::Response
* response
) {
429 error_callback
.Run();
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();
440 std::string
data(reinterpret_cast<const char*>(data_bytes
), data_length
);
444 void OnRenameObject(const RenameObjectCallback
& callback
,
445 const ErrorCallback
& error_callback
,
446 dbus::Response
* response
) {
448 error_callback
.Run();
455 void OnCopyFileFromLocal(const CopyFileFromLocalCallback
& callback
,
456 const ErrorCallback
& error_callback
,
457 dbus::Response
* response
) {
459 error_callback
.Run();
466 void OnDeleteObject(const DeleteObjectCallback
& callback
,
467 const ErrorCallback
& error_callback
,
468 dbus::Response
* response
) {
470 error_callback
.Run();
477 // Handles MTPStorageAttached/Dettached signals and calls |handler|.
478 void OnMTPStorageSignal(MTPStorageEventHandler handler
,
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();
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
,
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
);
513 ////////////////////////////////////////////////////////////////////////////////
514 // MediaTransferProtocolDaemonClient
516 MediaTransferProtocolDaemonClient::MediaTransferProtocolDaemonClient() {}
518 MediaTransferProtocolDaemonClient::~MediaTransferProtocolDaemonClient() {}
521 MediaTransferProtocolDaemonClient
* MediaTransferProtocolDaemonClient::Create(
523 return new MediaTransferProtocolDaemonClientImpl(bus
);
526 } // namespace device