sbIPDMarshall.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4 //=BEGIN SONGBIRD GPL
5 //
6 // This file is part of the Songbird web player.
7 //
8 // Copyright(c) 2005-2009 POTI, Inc.
9 // http://www.songbirdnest.com
10 //
11 // This file may be licensed under the terms of of the
12 // GNU General Public License Version 2 (the GPL).
13 //
14 // Software distributed under the License is distributed
15 // on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either
16 // express or implied. See the GPL for the specific language
17 // governing rights and limitations.
18 //
19 // You should have received a copy of the GPL along with this
20 // program. If not, go to http://www.gnu.org/licenses/gpl.html
21 // or write to the Free Software Foundation, Inc.,
22 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 //
24 //=END SONGBIRD GPL
25 */
26 
27 //------------------------------------------------------------------------------
28 //
29 // iPod device marshall services.
30 //
31 // The iPod device marshall services scan for iPod devices at startup and
32 // listen for added and removed devices. The marshall communicates these events
33 // to the other device services.
34 //
35 // Thread strategy:
36 //
37 // Most marshall interfaces are not typically called from more than one
38 // thread. The marshall device event handlers are always called from the main
39 // thread. A single lock is thus used to serialize thread access since multiple
40 // threads are not expected to be blocked.
41 // A few exceptions to this strategy will use alternate methods or no locking
42 // (e.g., GetId).
43 //
44 //------------------------------------------------------------------------------
45 
46 
52 //------------------------------------------------------------------------------
53 //
54 // iPod device marshall imported services.
55 //
56 //------------------------------------------------------------------------------
57 
58 // Local imports.
59 #include "sbIPDLog.h"
60 #include "sbIPDUtils.h"
61 #include "sbIPDMarshall.h"
62 
63 // Songbird imports.
64 #include <sbIDevice.h>
65 #include <sbIDeviceController.h>
66 #include <sbIDeviceControllerRegistrar.h>
67 #include <sbIDeviceEvent.h>
68 
69 // Mozilla imports.
70 #include <nsIClassInfoImpl.h>
71 #include <nsIProgrammingLanguage.h>
72 #include <nsIWritablePropertyBag.h>
73 #include <nsMemory.h>
74 #include <nsServiceManagerUtils.h>
75 #include <nsComponentManagerUtils.h>
76 
77 
78 //------------------------------------------------------------------------------
79 //
80 // iPod device marshall nsISupports and nsIClassInfo implementation.
81 //
82 //------------------------------------------------------------------------------
83 
84 // nsISupports implementation.
85 // NS_IMPL_THREADSAFE_ISUPPORTS1_CI(sbIPDMarshall, sbIDeviceMarshall)
88 NS_IMPL_QUERY_INTERFACE1_CI(sbIPDMarshall, sbIDeviceMarshall)
90 
91 // nsIClassInfo implementation.
92 NS_IMPL_THREADSAFE_CI(sbIPDMarshall)
93 
94 
95 //------------------------------------------------------------------------------
96 //
97 // iPod device marshall sbIDeviceMarshall implementation.
98 //
99 //------------------------------------------------------------------------------
100 
106 NS_IMETHODIMP
107 sbIPDMarshall::LoadControllers(sbIDeviceControllerRegistrar* aRegistrar)
108 {
109  // Validate parameters.
110  NS_ENSURE_ARG_POINTER(aRegistrar);
111 
112  // Register the controllers.
113  RegisterControllers(aRegistrar);
114 
115  return NS_OK;
116 }
117 
118 
124 NS_IMETHODIMP
125 sbIPDMarshall::BeginMonitoring()
126 {
127  // Serialize.
128  nsAutoMonitor mon(mMonitor);
129 
130  // Initialize event services.
131  EventInitialize();
132 
133  // Scan for connected devices.
134  ScanForConnectedDevices();
135 
136  return NS_OK;
137 }
138 
139 
145 NS_IMETHODIMP
146 sbIPDMarshall::StopMonitoring()
147 {
148  // Serialize.
149  nsAutoMonitor mon(mMonitor);
150 
151  // Finalize the event services.
152  EventFinalize();
153 
154  return NS_OK;
155 }
156 
157 
158 //
159 // Getters/setters.
160 //
161 
166 NS_IMETHODIMP
167 sbIPDMarshall::GetId(nsID** aId)
168 {
169  // Validate parameters.
170  NS_ENSURE_ARG_POINTER(aId);
171 
172  // Allocate an nsID.
173  nsID* pId = static_cast<nsID*>(NS_Alloc(sizeof(nsID)));
174  NS_ENSURE_TRUE(pId, NS_ERROR_OUT_OF_MEMORY);
175 
176  // Return the ID.
177  static nsID const id = SB_IPDMARSHALL_CID;
178  *pId = id;
179  *aId = pId;
180 
181  return NS_OK;
182 }
183 
184 
189 NS_IMETHODIMP
190 sbIPDMarshall::GetName(nsAString& aName)
191 {
192  aName.AssignLiteral(SB_IPDMARSHALL_CLASSNAME);
193  return NS_OK;
194 }
195 
196 
197 //------------------------------------------------------------------------------
198 //
199 // iPod device marshall public services.
200 //
201 //------------------------------------------------------------------------------
202 
209  mSBLibHalCtx(NULL)
210 {
211  // Initialize the logging services.
213 
214  // Initialize the device marshall services.
215  Initialize();
216 }
217 
218 
224 {
225  // Finalize the device marshall services.
226  Finalize();
227 }
228 
229 
230 //------------------------------------------------------------------------------
231 //
232 // iPod device marshall event services.
233 //
234 //------------------------------------------------------------------------------
235 
240 nsresult
241 sbIPDMarshall::EventInitialize()
242 {
243  nsresult rv;
244 
245  // Trace execution.
246  FIELD_LOG(("1: sbIPDMarshall::InitializeHal\n"));
247 
248  // Initialize the HAL library context.
249  mSBLibHalCtx = new sbLibHalCtx();
250  NS_ENSURE_TRUE(mSBLibHalCtx, NS_ERROR_OUT_OF_MEMORY);
251  rv = mSBLibHalCtx->Initialize();
252  NS_ENSURE_SUCCESS(rv, rv);
253 
254  // Set up HAL library callbacks. Listen for property modified events to
255  // detect added iPods. The neccessary properties are not yet available in the
256  // device added callback.
257  rv = mSBLibHalCtx->SetUserData(this);
258  NS_ENSURE_SUCCESS(rv, rv);
259  rv = mSBLibHalCtx->DevicePropertyWatchAll();
260  NS_ENSURE_SUCCESS(rv, rv);
261  rv = mSBLibHalCtx->SetDevicePropertyModified
262  (HandleLibHalDevicePropertyModified);
263  NS_ENSURE_SUCCESS(rv, rv);
264  rv = mSBLibHalCtx->SetDeviceRemoved(HandleLibHalDeviceRemoved);
265  NS_ENSURE_SUCCESS(rv, rv);
266 
267  return NS_OK;
268 }
269 
270 
275 void
276 sbIPDMarshall::EventFinalize()
277 {
278  // Dispose of the HAL library context.
279  if (mSBLibHalCtx)
280  delete mSBLibHalCtx;
281  mSBLibHalCtx = nsnull;
282 }
283 
284 
298 /* static */
299 void
300 sbIPDMarshall::HandleLibHalDevicePropertyModified(LibHalContext* aLibHalCtx,
301  const char* aDeviceUDI,
302  const char* aKey,
303  dbus_bool_t aIsRemoved,
304  dbus_bool_t aIsAdded)
305 {
306  // Validate arguments.
307  NS_ENSURE_TRUE(aLibHalCtx, /* void */);
308  NS_ENSURE_TRUE(aDeviceUDI, /* void */);
309  NS_ENSURE_TRUE(aKey, /* void */);
310 
311  // Get the iPod device system object.
312  sbIPDMarshall* marshall =
313  (sbIPDMarshall *) libhal_ctx_get_user_data(aLibHalCtx);
314 
315  // Dispatch processing to the object.
316  nsCAutoString deviceUDI;
317  deviceUDI = aDeviceUDI;
318  marshall->HandleLibHalDevicePropertyModified(deviceUDI,
319  aKey,
320  aIsRemoved,
321  aIsAdded);
322 }
323 
324 void sbIPDMarshall::HandleLibHalDevicePropertyModified(nsACString& aDeviceUDI,
325  const char* aKey,
326  dbus_bool_t aIsRemoved,
327  dbus_bool_t aIsAdded)
328 {
329  // Probe device.
330  if (!strcmp(aKey, "volume.is_mounted")) {
331  ProbeDev(aDeviceUDI);
332  }
333 }
334 
335 
344 /* static */
345 void
346 sbIPDMarshall::HandleLibHalDeviceRemoved(LibHalContext* aLibHalCtx,
347  const char* aDeviceUDI)
348 {
349  // Validate arguments.
350  NS_ENSURE_TRUE(aLibHalCtx, /* void */);
351  NS_ENSURE_TRUE(aDeviceUDI, /* void */);
352 
353  // Get the iPod device system object.
354  sbIPDMarshall* marshall =
355  (sbIPDMarshall *) libhal_ctx_get_user_data(aLibHalCtx);
356 
357  // Dispatch processing to the object.
358  nsCAutoString deviceUDI;
359  deviceUDI = aDeviceUDI;
360  marshall->HandleLibHalDeviceRemoved(deviceUDI);
361 }
362 
363 void
364 sbIPDMarshall::HandleLibHalDeviceRemoved(nsACString& aDeviceUDI)
365 {
366  // Trace execution.
367  FIELD_LOG(("1: sbIPDMarshall::HandleLibHalDeviceRemoved %s\n",
368  aDeviceUDI.BeginReading()));
369 
370  // If the removed device is the media partition of a device in the device
371  // list, remove the device.
372 
373  // Do nothing if the removed device is not in the device media partition
374  // table.
375  nsCString* iPodUDI;
376  if (!mDeviceMediaPartitionTable.Get(aDeviceUDI, &iPodUDI))
377  return;
378 
379  // Trace execution.
380  FIELD_LOG(("2: sbIPDMarshall::HandleLibHalDeviceRemoved %s\n",
381  iPodUDI->get()));
382 
383  // Handle the device removed event.
384  HandleRemovedEvent(*iPodUDI, aDeviceUDI);
385 }
386 
387 
396 void
397 sbIPDMarshall::HandleAddedEvent(const nsACString& aDeviceUDI,
398  const nsACString& aMediaPartitionUDI)
399 {
400  nsresult rv;
401 
402  // Serialize.
403  nsAutoMonitor mon(mMonitor);
404 
405  // Log progress.
406  FIELD_LOG(("Enter: HandleAddedEvent device=%s media partition=%s\n",
407  aDeviceUDI.BeginReading(),
408  aMediaPartitionUDI.BeginReading()));
409 
410  // Do nothing if device has already been added.
411  nsCOMPtr<sbIDevice> device;
412  if (mDeviceList.Get(aDeviceUDI, getter_AddRefs(device)))
413  return;
414 
415  // Set up the device properties.
416  nsCOMPtr<nsIWritablePropertyBag>
417  propBag = do_CreateInstance("@mozilla.org/hash-property-bag;1", &rv);
418  NS_ENSURE_SUCCESS(rv, /* void */);
419  rv = propBag->SetProperty(NS_LITERAL_STRING("DeviceType"),
420  sbIPDVariant("iPod").get());
421  NS_ENSURE_SUCCESS(rv, /* void */);
422  rv = propBag->SetProperty(NS_LITERAL_STRING("DeviceUDI"),
423  sbIPDVariant(aDeviceUDI).get());
424  NS_ENSURE_SUCCESS(rv, /* void */);
425  rv = propBag->SetProperty(NS_LITERAL_STRING("MediaPartitionUDI"),
426  sbIPDVariant(aMediaPartitionUDI).get());
427  NS_ENSURE_SUCCESS(rv, /* void */);
428 
429  // Find a controller for the device. Do nothing more if none found.
430  nsCOMPtr<sbIDeviceController> controller = FindCompatibleControllers(propBag);
431  if (!controller)
432  return;
433 
434  // Create a device.
435  rv = controller->CreateDevice(propBag, getter_AddRefs(device));
436  NS_ENSURE_SUCCESS(rv, /* void */);
437 
438  // Register the device.
439  rv = mDeviceRegistrar->RegisterDevice(device);
440  NS_ENSURE_SUCCESS(rv, /* void */);
441 
442  // Add device to device list and media partition to media partition list.
443  mDeviceList.Put(aDeviceUDI, device);
444  mDeviceMediaPartitionTable.Put(aMediaPartitionUDI, new nsCString(aDeviceUDI));
445 
446  // Send device added notification.
448  sbIPDVariant(device).get(),
449  (sbIDeviceMarshall *) this);
450 }
451 
452 
461 void
462 sbIPDMarshall::HandleRemovedEvent(const nsACString& aDeviceUDI,
463  const nsACString& aMediaPartitionUDI)
464 {
465  nsresult rv;
466 
467  // Serialize.
468  nsAutoMonitor mon(mMonitor);
469 
470  // Get removed device. Do nothing if device has not been added.
471  nsCOMPtr<sbIDevice> device;
472  if (!mDeviceList.Get(aDeviceUDI, getter_AddRefs(device)))
473  return;
474 
475  // Log progress.
476  FIELD_LOG(("Enter: HandleRemovedEvent %s\n", nsCString(aDeviceUDI).get()));
477 
478  // Get the device and device controller registrars.
479  nsCOMPtr<sbIDeviceRegistrar> deviceRegistrar =
480  do_GetService("@songbirdnest.com/Songbird/DeviceManager;2", &rv);
481  NS_ENSURE_SUCCESS(rv, /* void */);
482  nsCOMPtr<sbIDeviceControllerRegistrar> deviceControllerRegistrar =
483  do_GetService("@songbirdnest.com/Songbird/DeviceManager;2", &rv);
484  NS_ENSURE_SUCCESS(rv, /* void */);
485 
486  // Get the device controller ID and set it up for auto-disposal.
487  nsID *controllerID = nsnull;
488  rv = device->GetControllerId(&controllerID);
489  sbAutoNSMemPtr autoControllerID(controllerID);
490 
491  // Get the device controller.
492  nsCOMPtr<sbIDeviceController> deviceController;
493  if (NS_SUCCEEDED(rv)) {
494  rv = deviceControllerRegistrar->GetController
495  (controllerID,
496  getter_AddRefs(deviceController));
497  }
498  if (NS_FAILED(rv)) {
499  NS_WARNING("Failed to get device controller.");
500  deviceController = nsnull;
501  }
502 
503  // Release the device from the controller.
504  if (deviceController) {
505  rv = deviceController->ReleaseDevice(device);
506  if (NS_FAILED(rv))
507  NS_WARNING("Failed to release device.");
508  }
509 
510  // Unregister the device.
511  rv = deviceRegistrar->UnregisterDevice(device);
512  if (NS_FAILED(rv))
513  NS_WARNING("Failed to unregister device.");
514 
515  // Remove device from device list and media partition from media partition
516  // list.
517  mDeviceList.Remove(aDeviceUDI);
518  mDeviceMediaPartitionTable.Remove(aMediaPartitionUDI);
519 
520  // Send device added notification.
522  sbIPDVariant(device).get(),
523  (sbIDeviceMarshall *) this);
524 }
525 
526 
527 //------------------------------------------------------------------------------
528 //
529 // Internal iPod device marshall services.
530 //
531 //------------------------------------------------------------------------------
532 
537 nsresult
538 sbIPDMarshall::Initialize()
539 {
540  PRBool success;
541  nsresult rv;
542 
543  // Create the device marshall services monitor.
544  mMonitor = nsAutoMonitor::NewMonitor("sbIPDMarshall.mMonitor");
545  NS_ENSURE_TRUE(mMonitor, NS_ERROR_OUT_OF_MEMORY);
546 
547  // Get the device manager and registrar.
548  mDeviceManager = do_GetService("@songbirdnest.com/Songbird/DeviceManager;2",
549  &rv);
550  NS_ENSURE_SUCCESS(rv, rv);
551  mDeviceRegistrar = do_QueryInterface(mDeviceManager, &rv);
552  NS_ENSURE_SUCCESS(rv, rv);
553 
554  // Initialize the device list.
555  success = mDeviceList.Init();
556  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
557 
558  // Initialize the device media partition table.
559  success = mDeviceMediaPartitionTable.Init();
560  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
561 
562  return NS_OK;
563 }
564 
565 
570 void
571 sbIPDMarshall::Finalize()
572 {
573  // Dispose of the device marshall services monitor.
574  if (mMonitor)
575  {
576  nsAutoMonitor::DestroyMonitor(mMonitor);
577  mMonitor = nsnull;
578  }
579 
580  // Release object references.
581  mDeviceManager = nsnull;
582  mDeviceRegistrar = nsnull;
583 }
584 
585 
590 nsresult
591 sbIPDMarshall::ScanForConnectedDevices()
592 {
593  nsCStringArray deviceList;
594  nsCString deviceUDI;
595  nsCString iPodUDI;
596  PRInt32 i;
597  nsresult rv;
598 
599  // Probe all devices.
600  rv = mSBLibHalCtx->GetAllDevices(deviceList);
601  NS_ENSURE_SUCCESS(rv, rv);
602  for (i = 0; i < deviceList.Count(); i++)
603  {
604  // Get the device UDI.
605  deviceUDI = *(deviceList[i]);
606 
607  // Probe the device.
608  ProbeDev(deviceUDI);
609  }
610 
611  return NS_OK;
612 }
613 
614 
623 nsresult
624 sbIPDMarshall::ProbeDev(nsACString &aProbeUDI)
625 {
626  nsresult rv;
627 
628  // Trace execution.
629  FIELD_LOG(("ProbeDev aProbeUDI=%s\n", aProbeUDI.BeginReading()));
630 
631  // If probed device is not a media partition, do nothing more.
632  nsCAutoString mediaPartitionUDI;
633  if (!IsMediaPartition(aProbeUDI))
634  return NS_OK;
635  mediaPartitionUDI = aProbeUDI;
636 
637  // If the media partition is not mounted, do nothing more.
638  nsCAutoString mountPoint;
639  rv = mSBLibHalCtx->DeviceGetPropertyString(mediaPartitionUDI,
640  "volume.mount_point",
641  mountPoint);
642  if (NS_FAILED(rv) || mountPoint.IsEmpty()) {
643  return NS_OK;
644  }
645 
646  // Get the media partition's parent. This is the device UDI for iPods.
647  nsCAutoString parentUDI;
648  rv = mSBLibHalCtx->DeviceGetPropertyString(mediaPartitionUDI,
649  "info.parent",
650  parentUDI);
651  if (NS_FAILED(rv))
652  return NS_OK;
653  FIELD_LOG(("ProbeDev parentUDI=%s\n", parentUDI.get()));
654 
655  // If probed device parent is not an iPod, do nothing more.
656  nsCAutoString iPodUDI;
657  if (!IsIPod(parentUDI))
658  return NS_OK;
659  iPodUDI = parentUDI;
660 
661  // Send a device added event.
662  HandleAddedEvent(iPodUDI, mediaPartitionUDI);
663 
664  return NS_OK;
665 }
666 
667 
677 PRBool
678 sbIPDMarshall::IsIPod(nsACString& aDeviceUDI)
679 {
680  nsresult rv;
681 
682  // Trace execution.
683  FIELD_LOG(("1: sbIPDMarshall::IsIPod %s\n", aDeviceUDI.BeginReading()));
684 
685  // Get the device info vendor and product properties.
686  nsCAutoString vendor;
687  nsCAutoString product;
688  rv = mSBLibHalCtx->DeviceGetPropertyString(aDeviceUDI, "info.vendor", vendor);
689  if (NS_FAILED(rv))
690  return PR_FALSE;
691  rv = mSBLibHalCtx->DeviceGetPropertyString(aDeviceUDI,
692  "info.product",
693  product);
694  if (NS_FAILED(rv))
695  return PR_FALSE;
696 
697  // Trace execution.
698  FIELD_LOG(("2: sbIPDMarshall::IsIPod vendor=%s product=%s\n",
699  vendor.get(),
700  product.get()));
701 
702  // Check device vendor and product properties.
703  if (!vendor.Equals("Apple") || !product.Equals("iPod"))
704  return PR_FALSE;
705 
706  return PR_TRUE;
707 }
708 
709 
720 PRBool
721 sbIPDMarshall::IsMediaPartition(nsACString& aDeviceUDI)
722 {
723  nsresult rv;
724 
725  // Check if device has a volume interface.
726  PRBool hasInterface;
727  rv = mSBLibHalCtx->DeviceHasInterface(aDeviceUDI,
728  "org.freedesktop.Hal.Device.Volume",
729  &hasInterface);
730  NS_ENSURE_SUCCESS(rv, rv);
731  if (!hasInterface)
732  return PR_FALSE;
733 
734  return PR_TRUE;
735 }
736 
737 nsresult
738 sbIPDMarshall::RemoveDevice(sbIDevice* aDevice)
739 {
740  return NS_ERROR_NOT_IMPLEMENTED;
741 }
nsresult SetDevicePropertyModified(LibHalDevicePropertyModified aCallback)
Definition: sbLibHal.cpp:551
return NS_OK
nsresult CreateAndDispatchDeviceManagerEvent(PRUint32 aType, nsIVariant *aData, nsISupports *aOrigin, PRUint32 aDeviceState, PRBool aAsync)
Definition: sbIPDUtils.cpp:72
Songbird iPod Device Utility Definitions.
NS_DECL_ISUPPORTS NS_DECL_SBIDEVICEMARSHALL NS_DECL_NSICLASSINFO sbIPDMarshall()
nsresult GetAllDevices(nsCStringArray &aDeviceList)
Definition: sbLibHal.cpp:190
nsresult DeviceHasInterface(const nsACString &aUDI, const char *aInterface, PRBool *aHasInterface)
Definition: sbLibHal.cpp:623
static void Initialize()
Definition: sbIPDLog.cpp:73
NS_IMPL_THREADSAFE_CI(sbMediaListEnumeratorWrapper)
const unsigned long EVENT_DEVICE_ADDED
nsresult DevicePropertyWatchAll()
Definition: sbLibHal.cpp:575
NS_IMPL_THREADSAFE_RELEASE(sbRequestItem)
NS_IMPL_THREADSAFE_ADDREF(sbRequestItem)
nsresult SetDeviceRemoved(LibHalDeviceRemoved aCallback)
Definition: sbLibHal.cpp:526
sbIDeviceController * FindCompatibleControllers(nsIPropertyBag *deviceParams)
#define FIELD_LOG(args)
Definition: sbIPDLog.h:126
#define SB_IPDMARSHALL_CLASSNAME
Definition: sbIPDMarshall.h:74
Songbird iPod Device Logging Definitions.
const unsigned long EVENT_DEVICE_REMOVED
[UNIMPLEMENTED UNTIL AFTER 0.3]
_updateCookies aName
virtual ~sbIPDMarshall()
#define SB_IPDMARSHALL_CID
Definition: sbIPDMarshall.h:76
nsresult SetUserData(void *aUserData)
Definition: sbLibHal.cpp:168
nsresult Initialize()
Definition: sbLibHal.cpp:101
#define SB_DEVICE_CONTROLLER_CATEGORY
readonly attribute nsIDPtr id
_getSelectedPageStyle s i
nsresult DeviceGetPropertyString(const nsACString &aUDI, const char *aKey, nsCString &aProperty)
Definition: sbLibHal.cpp:306
NS_INTERFACE_MAP_END NS_IMPL_CI_INTERFACE_GETTER1(CDatabaseQuery, sbIDatabaseQuery) CDatabaseQuery