Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / device / media_transfer_protocol / media_transfer_protocol_daemon_client.cc
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.
4
5 #include "device/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
6
7 #include <algorithm>
8
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"
18
19 namespace device {
20
21 namespace {
22
23 const char kInvalidResponseMsg[] = "Invalid Response: ";
24 uint32 kMaxChunkSize = 1024*1024;  // D-Bus has message size limits.
25
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) {
36   }
37
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);
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));
49   }
50
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);
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));
65   }
66
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);
77     proxy_->CallMethod(
78         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
79         base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage,
80                    weak_ptr_factory_.GetWeakPtr(),
81                    callback,
82                    error_callback));
83   }
84
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);
92     proxy_->CallMethod(
93         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
94         base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCloseStorage,
95                    weak_ptr_factory_.GetWeakPtr(),
96                    callback,
97                    error_callback));
98   }
99
100   // MediaTransferProtocolDaemonClient override.
101   virtual void ReadDirectoryEntryIds(
102       const std::string& handle,
103       uint32 file_id,
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);
111     proxy_->CallMethod(
112         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
113         base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectoryIds,
114                    weak_ptr_factory_.GetWeakPtr(),
115                    callback,
116                    error_callback));
117   }
118
119   virtual void GetFileInfo(const std::string& handle,
120                            const std::vector<uint32>& file_ids,
121                            size_t offset,
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();
127       return;
128     }
129
130     dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetFileInfo);
131     dbus::MessageWriter writer(&method_call);
132     writer.AppendString(handle);
133     {
134       dbus::MessageWriter array_writer(NULL);
135       writer.OpenArray("u", &array_writer);
136
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]);
142
143       writer.CloseContainer(&array_writer);
144     }
145     proxy_->CallMethod(
146         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
147         base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo,
148                    weak_ptr_factory_.GetWeakPtr(),
149                    callback,
150                    error_callback));
151   }
152
153   // MediaTransferProtocolDaemonClient override.
154   virtual void ReadFileChunk(const std::string& handle,
155                              uint32 file_id,
156                              uint32 offset,
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);
167     proxy_->CallMethod(
168         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
169         base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile,
170                    weak_ptr_factory_.GetWeakPtr(),
171                    callback,
172                    error_callback));
173   }
174
175   // MediaTransferProtocolDaemonClient override.
176   virtual void ListenForChanges(
177       const MTPStorageEventHandler& handler) OVERRIDE {
178     DCHECK(!listen_for_changes_called_);
179     listen_for_changes_called_ = true;
180
181     static const SignalEventTuple kSignalEventTuples[] = {
182       { mtpd::kMTPStorageAttached, true },
183       { mtpd::kMTPStorageDetached, false },
184     };
185     const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples);
186
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(),
193                      handler,
194                      kSignalEventTuples[i].is_attach),
195           base::Bind(&MediaTransferProtocolDaemonClientImpl::OnSignalConnected,
196                      weak_ptr_factory_.GetWeakPtr()));
197     }
198   }
199
200  private:
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;
205     bool is_attach;
206   };
207
208   // Handles the result of EnumerateStorages and calls |callback| or
209   // |error_callback|.
210   void OnEnumerateStorages(const EnumerateStoragesCallback& callback,
211                            const ErrorCallback& error_callback,
212                            dbus::Response* response) {
213     if (!response) {
214       error_callback.Run();
215       return;
216     }
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();
222       return;
223     }
224     callback.Run(storage_names);
225   }
226
227   // Handles the result of GetStorageInfo and calls |callback| or
228   // |error_callback|.
229   void OnGetStorageInfo(const std::string& storage_name,
230                         const GetStorageInfoCallback& callback,
231                         const ErrorCallback& error_callback,
232                         dbus::Response* response) {
233     if (!response) {
234       error_callback.Run();
235       return;
236     }
237
238     dbus::MessageReader reader(response);
239     MtpStorageInfo protobuf;
240     if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
241       LOG(ERROR) << kInvalidResponseMsg << response->ToString();
242       error_callback.Run();
243       return;
244     }
245     callback.Run(protobuf);
246   }
247
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) {
252     if (!response) {
253       error_callback.Run();
254       return;
255     }
256     dbus::MessageReader reader(response);
257     std::string handle;
258     if (!reader.PopString(&handle)) {
259       LOG(ERROR) << kInvalidResponseMsg << response->ToString();
260       error_callback.Run();
261       return;
262     }
263     callback.Run(handle);
264   }
265
266   // Handles the result of CloseStorage and calls |callback| or
267   // |error_callback|.
268   void OnCloseStorage(const CloseStorageCallback& callback,
269                       const ErrorCallback& error_callback,
270                       dbus::Response* response) {
271     if (!response) {
272       error_callback.Run();
273       return;
274     }
275     callback.Run();
276   }
277
278   // Handles the result of ReadDirectoryEntryIds and calls |callback| or
279   // |error_callback|.
280   void OnReadDirectoryIds(const ReadDirectoryEntryIdsCallback& callback,
281                           const ErrorCallback& error_callback,
282                           dbus::Response* response) {
283     if (!response) {
284       error_callback.Run();
285       return;
286     }
287
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();
294       return;
295     }
296
297     while (array_reader.HasMoreData()) {
298       uint32 file_id;
299       if (array_reader.PopUint32(&file_id)) {
300         file_ids.push_back(file_id);
301       } else {
302         LOG(ERROR) << kInvalidResponseMsg << response->ToString();
303         error_callback.Run();
304         return;
305       }
306     }
307     callback.Run(file_ids);
308   }
309
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) {
314     if (!response) {
315       error_callback.Run();
316       return;
317     }
318
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();
325       return;
326     }
327
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);
331   }
332
333   // Handles the result of ReadFileChunk and calls |callback| or
334   // |error_callback|.
335   void OnReadFile(const ReadFileCallback& callback,
336                   const ErrorCallback& error_callback,
337                   dbus::Response* response) {
338     if (!response) {
339       error_callback.Run();
340       return;
341     }
342
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();
348       return;
349     }
350     std::string data(reinterpret_cast<const char*>(data_bytes), data_length);
351     callback.Run(data);
352   }
353
354   // Handles MTPStorageAttached/Dettached signals and calls |handler|.
355   void OnMTPStorageSignal(MTPStorageEventHandler handler,
356                           bool is_attach,
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();
362       return;
363     }
364     DCHECK(!storage_name.empty());
365     handler.Run(is_attach, storage_name);
366   }
367
368
369   // Handles the result of signal connection setup.
370   void OnSignalConnected(const std::string& interface,
371                          const std::string& signal,
372                          bool succeeded) {
373     LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " "
374                               << signal << " failed.";
375   }
376
377   dbus::ObjectProxy* proxy_;
378
379   bool listen_for_changes_called_;
380
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_;
384
385   DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientImpl);
386 };
387
388 }  // namespace
389
390 ////////////////////////////////////////////////////////////////////////////////
391 // MediaTransferProtocolDaemonClient
392
393 MediaTransferProtocolDaemonClient::MediaTransferProtocolDaemonClient() {}
394
395 MediaTransferProtocolDaemonClient::~MediaTransferProtocolDaemonClient() {}
396
397 // static
398 MediaTransferProtocolDaemonClient* MediaTransferProtocolDaemonClient::Create(
399     dbus::Bus* bus) {
400   return new MediaTransferProtocolDaemonClientImpl(bus);
401 }
402
403 }  // namespace device