Send a crash report when a hung process is detected.
[chromium-blink-merge.git] / device / media_transfer_protocol / media_transfer_protocol_daemon_client.cc
blobdeecea6ba1cd2d398c0fef26a5ba244219b63ed3
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 // 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);
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));
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);
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));
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);
110 proxy_->CallMethod(
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,
118 uint32 file_id,
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);
126 proxy_->CallMethod(
127 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
128 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectoryIds,
129 weak_ptr_factory_.GetWeakPtr(),
130 callback,
131 error_callback));
134 void GetFileInfo(const std::string& handle,
135 const std::vector<uint32>& file_ids,
136 size_t offset,
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();
142 return;
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);
160 proxy_->CallMethod(
161 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
162 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo,
163 weak_ptr_factory_.GetWeakPtr(),
164 callback,
165 error_callback));
168 // MediaTransferProtocolDaemonClient override.
169 void ReadFileChunk(const std::string& handle,
170 uint32 file_id,
171 uint32 offset,
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);
182 proxy_->CallMethod(
183 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
184 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile,
185 weak_ptr_factory_.GetWeakPtr(),
186 callback,
187 error_callback));
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);
200 proxy_->CallMethod(
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);
222 proxy_->CallMethod(
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);
236 proxy_->CallMethod(
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(),
259 handler,
260 kSignalEventTuples[i].is_attach),
261 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnSignalConnected,
262 weak_ptr_factory_.GetWeakPtr()));
266 private:
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;
271 bool is_attach;
274 // Handles the result of EnumerateStorages and calls |callback| or
275 // |error_callback|.
276 void OnEnumerateStorages(const EnumerateStoragesCallback& callback,
277 const ErrorCallback& error_callback,
278 dbus::Response* response) {
279 if (!response) {
280 error_callback.Run();
281 return;
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();
288 return;
290 callback.Run(storage_names);
293 // Handles the result of GetStorageInfo and calls |callback| or
294 // |error_callback|.
295 void OnGetStorageInfo(const std::string& storage_name,
296 const GetStorageInfoCallback& callback,
297 const ErrorCallback& error_callback,
298 dbus::Response* response) {
299 if (!response) {
300 error_callback.Run();
301 return;
304 dbus::MessageReader reader(response);
305 MtpStorageInfo protobuf;
306 if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
307 LOG(ERROR) << kInvalidResponseMsg << response->ToString();
308 error_callback.Run();
309 return;
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) {
318 if (!response) {
319 error_callback.Run();
320 return;
322 dbus::MessageReader reader(response);
323 std::string handle;
324 if (!reader.PopString(&handle)) {
325 LOG(ERROR) << kInvalidResponseMsg << response->ToString();
326 error_callback.Run();
327 return;
329 callback.Run(handle);
332 // Handles the result of CloseStorage and calls |callback| or
333 // |error_callback|.
334 void OnCloseStorage(const CloseStorageCallback& callback,
335 const ErrorCallback& error_callback,
336 dbus::Response* response) {
337 if (!response) {
338 error_callback.Run();
339 return;
341 callback.Run();
344 void OnCreateDirectory(const CreateDirectoryCallback& callback,
345 const ErrorCallback& error_callback,
346 dbus::Response* response) {
347 if (!response) {
348 error_callback.Run();
349 return;
351 callback.Run();
354 // Handles the result of ReadDirectoryEntryIds and calls |callback| or
355 // |error_callback|.
356 void OnReadDirectoryIds(const ReadDirectoryEntryIdsCallback& callback,
357 const ErrorCallback& error_callback,
358 dbus::Response* response) {
359 if (!response) {
360 error_callback.Run();
361 return;
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();
370 return;
373 while (array_reader.HasMoreData()) {
374 uint32 file_id;
375 if (array_reader.PopUint32(&file_id)) {
376 file_ids.push_back(file_id);
377 } else {
378 LOG(ERROR) << kInvalidResponseMsg << response->ToString();
379 error_callback.Run();
380 return;
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) {
390 if (!response) {
391 error_callback.Run();
392 return;
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();
401 return;
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
410 // |error_callback|.
411 void OnReadFile(const ReadFileCallback& callback,
412 const ErrorCallback& error_callback,
413 dbus::Response* response) {
414 if (!response) {
415 error_callback.Run();
416 return;
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();
424 return;
426 std::string data(reinterpret_cast<const char*>(data_bytes), data_length);
427 callback.Run(data);
430 void OnRenameObject(const RenameObjectCallback& callback,
431 const ErrorCallback& error_callback,
432 dbus::Response* response) {
433 if (!response) {
434 error_callback.Run();
435 return;
438 callback.Run();
441 void OnCopyFileFromLocal(const CopyFileFromLocalCallback& callback,
442 const ErrorCallback& error_callback,
443 dbus::Response* response) {
444 if (!response) {
445 error_callback.Run();
446 return;
449 callback.Run();
452 void OnDeleteObject(const DeleteObjectCallback& callback,
453 const ErrorCallback& error_callback,
454 dbus::Response* response) {
455 if (!response) {
456 error_callback.Run();
457 return;
460 callback.Run();
463 // Handles MTPStorageAttached/Dettached signals and calls |handler|.
464 void OnMTPStorageSignal(MTPStorageEventHandler handler,
465 bool is_attach,
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();
471 return;
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,
481 bool succeeded) {
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);
497 } // namespace
499 ////////////////////////////////////////////////////////////////////////////////
500 // MediaTransferProtocolDaemonClient
502 MediaTransferProtocolDaemonClient::MediaTransferProtocolDaemonClient() {}
504 MediaTransferProtocolDaemonClient::~MediaTransferProtocolDaemonClient() {}
506 // static
507 MediaTransferProtocolDaemonClient* MediaTransferProtocolDaemonClient::Create(
508 dbus::Bus* bus) {
509 return new MediaTransferProtocolDaemonClientImpl(bus);
512 } // namespace device