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 virtual 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 virtual 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 virtual 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_EQ(mtpd::kReadOnlyMode
, mode
);
76 writer
.AppendString(mtpd::kReadOnlyMode
);
78 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
79 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage
,
80 weak_ptr_factory_
.GetWeakPtr(),
85 // MediaTransferProtocolDaemonClient override.
86 virtual 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 // MediaTransferProtocolDaemonClient override.
101 virtual void ReadDirectoryEntryIds(
102 const std::string
& handle
,
104 const ReadDirectoryEntryIdsCallback
& callback
,
105 const ErrorCallback
& error_callback
) OVERRIDE
{
106 dbus::MethodCall
method_call(mtpd::kMtpdInterface
,
107 mtpd::kReadDirectoryEntryIds
);
108 dbus::MessageWriter
writer(&method_call
);
109 writer
.AppendString(handle
);
110 writer
.AppendUint32(file_id
);
112 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
113 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectoryIds
,
114 weak_ptr_factory_
.GetWeakPtr(),
119 virtual void GetFileInfo(const std::string
& handle
,
120 const std::vector
<uint32
>& file_ids
,
122 size_t entries_to_read
,
123 const GetFileInfoCallback
& callback
,
124 const ErrorCallback
& error_callback
) OVERRIDE
{
125 if (offset
>= file_ids
.size()) {
126 error_callback
.Run();
130 dbus::MethodCall
method_call(mtpd::kMtpdInterface
, mtpd::kGetFileInfo
);
131 dbus::MessageWriter
writer(&method_call
);
132 writer
.AppendString(handle
);
134 dbus::MessageWriter
array_writer(NULL
);
135 writer
.OpenArray("u", &array_writer
);
137 size_t end_offset
= file_ids
.size();
138 if (offset
<= SIZE_MAX
- entries_to_read
)
139 end_offset
= std::min(end_offset
, offset
+ entries_to_read
);
140 for (size_t i
= offset
; i
< end_offset
; ++i
)
141 array_writer
.AppendUint32(file_ids
[i
]);
143 writer
.CloseContainer(&array_writer
);
146 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
147 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo
,
148 weak_ptr_factory_
.GetWeakPtr(),
153 // MediaTransferProtocolDaemonClient override.
154 virtual void ReadFileChunk(const std::string
& handle
,
157 uint32 bytes_to_read
,
158 const ReadFileCallback
& callback
,
159 const ErrorCallback
& error_callback
) OVERRIDE
{
160 DCHECK_LE(bytes_to_read
, kMaxChunkSize
);
161 dbus::MethodCall
method_call(mtpd::kMtpdInterface
, mtpd::kReadFileChunk
);
162 dbus::MessageWriter
writer(&method_call
);
163 writer
.AppendString(handle
);
164 writer
.AppendUint32(file_id
);
165 writer
.AppendUint32(offset
);
166 writer
.AppendUint32(bytes_to_read
);
168 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
169 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile
,
170 weak_ptr_factory_
.GetWeakPtr(),
175 // MediaTransferProtocolDaemonClient override.
176 virtual void ListenForChanges(
177 const MTPStorageEventHandler
& handler
) OVERRIDE
{
178 DCHECK(!listen_for_changes_called_
);
179 listen_for_changes_called_
= true;
181 static const SignalEventTuple kSignalEventTuples
[] = {
182 { mtpd::kMTPStorageAttached
, true },
183 { mtpd::kMTPStorageDetached
, false },
185 const size_t kNumSignalEventTuples
= arraysize(kSignalEventTuples
);
187 for (size_t i
= 0; i
< kNumSignalEventTuples
; ++i
) {
188 proxy_
->ConnectToSignal(
189 mtpd::kMtpdInterface
,
190 kSignalEventTuples
[i
].signal_name
,
191 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnMTPStorageSignal
,
192 weak_ptr_factory_
.GetWeakPtr(),
194 kSignalEventTuples
[i
].is_attach
),
195 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnSignalConnected
,
196 weak_ptr_factory_
.GetWeakPtr()));
201 // A struct to contain a pair of signal name and attachment event type.
202 // Used by SetUpConnections.
203 struct SignalEventTuple
{
204 const char* signal_name
;
208 // Handles the result of EnumerateStorages and calls |callback| or
210 void OnEnumerateStorages(const EnumerateStoragesCallback
& callback
,
211 const ErrorCallback
& error_callback
,
212 dbus::Response
* response
) {
214 error_callback
.Run();
217 dbus::MessageReader
reader(response
);
218 std::vector
<std::string
> storage_names
;
219 if (!reader
.PopArrayOfStrings(&storage_names
)) {
220 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
221 error_callback
.Run();
224 callback
.Run(storage_names
);
227 // Handles the result of GetStorageInfo and calls |callback| or
229 void OnGetStorageInfo(const std::string
& storage_name
,
230 const GetStorageInfoCallback
& callback
,
231 const ErrorCallback
& error_callback
,
232 dbus::Response
* response
) {
234 error_callback
.Run();
238 dbus::MessageReader
reader(response
);
239 MtpStorageInfo protobuf
;
240 if (!reader
.PopArrayOfBytesAsProto(&protobuf
)) {
241 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
242 error_callback
.Run();
245 callback
.Run(protobuf
);
248 // Handles the result of OpenStorage and calls |callback| or |error_callback|.
249 void OnOpenStorage(const OpenStorageCallback
& callback
,
250 const ErrorCallback
& error_callback
,
251 dbus::Response
* response
) {
253 error_callback
.Run();
256 dbus::MessageReader
reader(response
);
258 if (!reader
.PopString(&handle
)) {
259 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
260 error_callback
.Run();
263 callback
.Run(handle
);
266 // Handles the result of CloseStorage and calls |callback| or
268 void OnCloseStorage(const CloseStorageCallback
& callback
,
269 const ErrorCallback
& error_callback
,
270 dbus::Response
* response
) {
272 error_callback
.Run();
278 // Handles the result of ReadDirectoryEntryIds and calls |callback| or
280 void OnReadDirectoryIds(const ReadDirectoryEntryIdsCallback
& callback
,
281 const ErrorCallback
& error_callback
,
282 dbus::Response
* response
) {
284 error_callback
.Run();
288 std::vector
<uint32
> file_ids
;
289 dbus::MessageReader
reader(response
);
290 dbus::MessageReader
array_reader(NULL
);
291 if (!reader
.PopArray(&array_reader
) || reader
.HasMoreData()) {
292 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
293 error_callback
.Run();
297 while (array_reader
.HasMoreData()) {
299 if (array_reader
.PopUint32(&file_id
)) {
300 file_ids
.push_back(file_id
);
302 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
303 error_callback
.Run();
307 callback
.Run(file_ids
);
310 // Handles the result of GetFileInfo and calls |callback| or |error_callback|.
311 void OnGetFileInfo(const GetFileInfoCallback
& callback
,
312 const ErrorCallback
& error_callback
,
313 dbus::Response
* response
) {
315 error_callback
.Run();
319 std::vector
<MtpFileEntry
> file_entries
;
320 dbus::MessageReader
reader(response
);
321 MtpFileEntries entries_protobuf
;
322 if (!reader
.PopArrayOfBytesAsProto(&entries_protobuf
)) {
323 LOG(ERROR
) << kInvalidResponseMsg
<< response
->ToString();
324 error_callback
.Run();
328 for (int i
= 0; i
< entries_protobuf
.file_entries_size(); ++i
)
329 file_entries
.push_back(entries_protobuf
.file_entries(i
));
330 callback
.Run(file_entries
);
333 // Handles the result of ReadFileChunk and calls |callback| or
335 void OnReadFile(const ReadFileCallback
& callback
,
336 const ErrorCallback
& error_callback
,
337 dbus::Response
* response
) {
339 error_callback
.Run();
343 const uint8
* data_bytes
= NULL
;
344 size_t data_length
= 0;
345 dbus::MessageReader
reader(response
);
346 if (!reader
.PopArrayOfBytes(&data_bytes
, &data_length
)) {
347 error_callback
.Run();
350 std::string
data(reinterpret_cast<const char*>(data_bytes
), data_length
);
354 // Handles MTPStorageAttached/Dettached signals and calls |handler|.
355 void OnMTPStorageSignal(MTPStorageEventHandler handler
,
357 dbus::Signal
* signal
) {
358 dbus::MessageReader
reader(signal
);
359 std::string storage_name
;
360 if (!reader
.PopString(&storage_name
)) {
361 LOG(ERROR
) << "Invalid signal: " << signal
->ToString();
364 DCHECK(!storage_name
.empty());
365 handler
.Run(is_attach
, storage_name
);
369 // Handles the result of signal connection setup.
370 void OnSignalConnected(const std::string
& interface
,
371 const std::string
& signal
,
373 LOG_IF(ERROR
, !succeeded
) << "Connect to " << interface
<< " "
374 << signal
<< " failed.";
377 dbus::ObjectProxy
* proxy_
;
379 bool listen_for_changes_called_
;
381 // Note: This should remain the last member so it'll be destroyed and
382 // invalidate its weak pointers before any other members are destroyed.
383 base::WeakPtrFactory
<MediaTransferProtocolDaemonClientImpl
> weak_ptr_factory_
;
385 DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientImpl
);
390 ////////////////////////////////////////////////////////////////////////////////
391 // MediaTransferProtocolDaemonClient
393 MediaTransferProtocolDaemonClient::MediaTransferProtocolDaemonClient() {}
395 MediaTransferProtocolDaemonClient::~MediaTransferProtocolDaemonClient() {}
398 MediaTransferProtocolDaemonClient
* MediaTransferProtocolDaemonClient::Create(
400 return new MediaTransferProtocolDaemonClientImpl(bus
);
403 } // namespace device