DeviceManager.cpp
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2008 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25  */
26 
31 #include "DeviceManager.h"
32 #include "DeviceBase.h"
33 
34 #include <nsAutoLock.h>
35 #include <nsComponentManagerUtils.h>
36 #include <nsIComponentRegistrar.h>
37 #include <nsIObserverService.h>
38 #include <nsISimpleEnumerator.h>
39 #include <nsServiceManagerUtils.h>
40 #include <nsISupportsPrimitives.h>
41 #include <nsXPCOM.h>
42 #include <prlog.h>
43 
44 #include <sbILibraryManager.h>
45 
46 /*
47  * To log this module, set the following environment variable:
48  * NSPR_LOG_MODULES=sbDeviceManagerObsolete:5
49  */
50 #ifdef PR_LOGGING
51 static PRLogModuleInfo* gDevicemanagerLog = nsnull;
52 #define LOG(args) PR_LOG(gDevicemanagerLog, PR_LOG_DEBUG, args)
53 #else
54 #define LOG(args) /* nothing */
55 #endif
56 
57 #define SB_DEVICE_PREFIX "@songbirdnest.com/Songbird/OldDeviceImpl/"
58 
59 // This allows us to be initialized once and only once.
60 PRBool sbDeviceManagerObsolete::sServiceInitialized = PR_FALSE;
61 
62 // Whether or not we've already loaded all supported devices
63 PRBool sbDeviceManagerObsolete::sDevicesLoaded = PR_FALSE;
64 
65 // This is a sanity check to make sure that we're finalizing properly
66 PRBool sbDeviceManagerObsolete::sServiceFinalized = PR_FALSE;
67 
71 
73 : mLock(nsnull),
74  mLastRequestedIndex(nsnull)
75 {
76 #ifdef PR_LOGGING
77  if (!gDevicemanagerLog)
78  gDevicemanagerLog = PR_NewLogModule("sbDeviceManagerObsolete");
79 #endif
80 
81  LOG(("DeviceManagerObsolete[0x%x] - Created", this));
82 }
83 
84 sbDeviceManagerObsolete::~sbDeviceManagerObsolete()
85 {
86  NS_ASSERTION(sbDeviceManagerObsolete::sServiceFinalized,
87  "DeviceManagerObsolete never finalized!");
88  if (mLock)
89  nsAutoLock::DestroyLock(mLock);
90 
91  LOG(("DeviceManagerObsolete[0x%x] - Destroyed", this));
92 }
93 
94 NS_IMETHODIMP
96 {
97  LOG(("DeviceManager[0x%x] - Initialize", this));
98 
99  // Test to make sure that we haven't been initialized yet. If consumers are
100  // doing the right thing (using getService) then we should never get here
101  // more than once. If they do the wrong thing (createInstance) then we'll
102  // fail on them so that they fix their code.
103  NS_ENSURE_FALSE(sbDeviceManagerObsolete::sServiceInitialized,
104  NS_ERROR_ALREADY_INITIALIZED);
105 
106  mLock = nsAutoLock::NewLock("sbDeviceManagerObsolete::mLock");
107  NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
108 
109  mLastRequestedCategory = EmptyString();
110 
111  // Register with the observer service to continue initialization after the.
112  // profile has been loaded. Also register for XPCOM shutdown notification.
113 
114  nsresult rv;
115  nsCOMPtr<nsIObserverService> observerService =
116  do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
117  NS_ENSURE_SUCCESS(rv, rv);
118 
119  // We can't really start until the library manager has loaded
120  rv = observerService->AddObserver(this, SB_LIBRARY_MANAGER_READY_TOPIC,
121  PR_FALSE);
122  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to add library manager observer");
123 
124  // Since we depend on the library, we need to shut down before it.
125  rv = observerService->AddObserver(this, SB_LIBRARY_MANAGER_BEFORE_SHUTDOWN_TOPIC,
126  PR_FALSE);
127  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
128  "Failed to add library before shutdown observer");
129 
130  // "xpcom-shutdown" is called right before the app will terminate
131  rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
132  PR_FALSE);
133  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to add shutdown observer");
134 
135 
136  // XXX Don't add any calls here that could possibly fail! We've already added
137  // ourselves to the observer service so if we fail now the observer
138  // service will hold an invalid pointer and later cause a crash at
139  // shutdown. Add any dangerous calls above *before* the call to
140  // AddObserver.
141 
142  // Set the static variable so that we won't initialize again.
143  sbDeviceManagerObsolete::sServiceInitialized = PR_TRUE;
144 
145  return NS_OK;
146 }
147 
148 NS_IMETHODIMP
149 sbDeviceManagerObsolete::Finalize()
150 {
151  LOG(("DeviceManagerObsolete[0x%x] - Finalize", this));
152 
153  // Make sure we aren't called more than once
154  NS_ENSURE_FALSE(sbDeviceManagerObsolete::sServiceFinalized, NS_ERROR_UNEXPECTED);
155 
156  // Loop through the array and call Finalize() on all the devices.
157  nsresult rv;
158 
159  nsAutoLock autoLock(mLock);
160 
161  PRInt32 count = mSupportedDevices.Count();
162  for (PRInt32 index = 0; index < count; index++) {
163  nsCOMPtr<sbIDeviceBase> device = mSupportedDevices.ObjectAt(index);
164  NS_ASSERTION(device, "Null pointer in mSupportedDevices");
165 
166  rv = device->Finalize();
167  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "A device failed to finalize");
168  }
169 
170  sbDeviceManagerObsolete::sServiceFinalized = PR_TRUE;
171 
172  return NS_OK;
173 }
174 
175 // Instantiate all supported devices.
176 // This is done by iterating through all registered XPCOM components and
177 // finding the components with @songbirdnest.com/Songbird/Device/ prefix for the
178 // contract ID for the interface.
179 NS_IMETHODIMP
180 sbDeviceManagerObsolete::LoadSupportedDevices()
181 {
182  LOG(("DeviceManagerObsolete[0x%x] - LoadSupportedDevices", this));
183 
184  // Make sure we aren't called more than once
185  NS_ENSURE_TRUE(sbDeviceManagerObsolete::sServiceInitialized,
186  NS_ERROR_ALREADY_INITIALIZED);
187  NS_ENSURE_FALSE(sbDeviceManagerObsolete::sDevicesLoaded, NS_ERROR_UNEXPECTED);
188 
189  nsAutoLock autoLock(mLock);
190 
191  // Get the component registrar
192  nsresult rv;
193  nsCOMPtr<nsIComponentRegistrar> registrar;
194  rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
195  NS_ENSURE_SUCCESS(rv, rv);
196 
197  nsCOMPtr<nsISimpleEnumerator> simpleEnumerator;
198  rv = registrar->EnumerateContractIDs(getter_AddRefs(simpleEnumerator));
199  NS_ENSURE_SUCCESS(rv, rv);
200 
201  // Enumerate through the contractIDs and look for our prefix
202  nsCOMPtr<nsISupports> element;
203  PRBool more = PR_FALSE;
204  while(NS_SUCCEEDED(simpleEnumerator->HasMoreElements(&more)) && more) {
205 
206  rv = simpleEnumerator->GetNext(getter_AddRefs(element));
207  NS_ENSURE_SUCCESS(rv, rv);
208 
209  nsCOMPtr<nsISupportsCString> contractString =
210  do_QueryInterface(element, &rv);
211  if NS_FAILED(rv) {
212  NS_WARNING("QueryInterface failed");
213  continue;
214  }
215 
216  nsCAutoString contractID;
217  rv = contractString->GetData(contractID);
218  if NS_FAILED(rv) {
219  NS_WARNING("GetData failed");
220  continue;
221  }
222 
223  NS_NAMED_LITERAL_CSTRING(prefix, SB_DEVICE_PREFIX);
224 
225  if (!StringBeginsWith(contractID, prefix))
226  continue;
227 
228  // Create an instance of the device
229  nsCOMPtr<sbIDeviceBase> device =
230  do_CreateInstance(contractID.get(), &rv);
231  if (!device) {
232  NS_WARNING("Failed to create device!");
233  continue;
234  }
235 
236  // And initialize the device
237  rv = device->Initialize();
238 
239  if(NS_FAILED(rv)) {
240  NS_WARNING("Device failed to initialize!");
241  continue;
242  }
243 
244  // If everything has succeeded then we can add it to our array
245  PRBool ok = mSupportedDevices.AppendObject(device);
246 
247  // Make sure that our array is behaving properly. If not we're in trouble.
248  NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
249  }
250 
251  sbDeviceManagerObsolete::sDevicesLoaded = PR_TRUE;
252 
253  return NS_OK;
254 }
255 
256 NS_IMETHODIMP
257 sbDeviceManagerObsolete::GetDeviceCount(PRUint32* aDeviceCount)
258 {
259  NS_ENSURE_ARG_POINTER(aDeviceCount);
260  NS_ENSURE_TRUE(sbDeviceManagerObsolete::sDevicesLoaded, NS_ERROR_UNEXPECTED);
261 
262  nsAutoLock autoLock(mLock);
263 
264  *aDeviceCount = (PRUint32)mSupportedDevices.Count();
265  return NS_OK;
266 }
267 
268 NS_IMETHODIMP
269 sbDeviceManagerObsolete::GetCategoryByIndex(PRUint32 aIndex,
270  nsAString& _retval)
271 {
272  NS_ENSURE_TRUE(sbDeviceManagerObsolete::sDevicesLoaded, NS_ERROR_UNEXPECTED);
273 
274  nsAutoLock autoLock(mLock);
275 
276  NS_ENSURE_ARG_MAX(aIndex, (PRUint32)mSupportedDevices.Count());
277 
278  nsCOMPtr<sbIDeviceBase> device = mSupportedDevices.ObjectAt(aIndex);
279  NS_ENSURE_TRUE(device, NS_ERROR_NULL_POINTER);
280 
281  nsresult rv = device->GetDeviceCategory(_retval);
282  NS_ENSURE_SUCCESS(rv, rv);
283 
284  return NS_OK;
285 }
286 
287 NS_IMETHODIMP
288 sbDeviceManagerObsolete::GetDeviceByIndex(PRUint32 aIndex,
289  sbIDeviceBase** _retval)
290 {
291  NS_ENSURE_ARG_POINTER(_retval);
292  NS_ENSURE_TRUE(sbDeviceManagerObsolete::sDevicesLoaded, NS_ERROR_UNEXPECTED);
293 
294  nsAutoLock autoLock(mLock);
295 
296  NS_ENSURE_ARG_MAX(aIndex, (PRUint32)mSupportedDevices.Count());
297 
298  nsCOMPtr<sbIDeviceBase> device = mSupportedDevices.ObjectAt(aIndex);
299  NS_ENSURE_TRUE(device, NS_ERROR_UNEXPECTED);
300 
301  NS_ADDREF(*_retval = device);
302 
303  return NS_OK;
304 }
305 
306 NS_IMETHODIMP
307 sbDeviceManagerObsolete::HasDeviceForCategory(const nsAString& aCategory,
308  PRBool* _retval)
309 {
310  NS_ENSURE_ARG_POINTER(_retval);
311  NS_ENSURE_TRUE(sbDeviceManagerObsolete::sDevicesLoaded, NS_ERROR_UNEXPECTED);
312 
313  nsAutoLock autoLock(mLock);
314 
315  PRUint32 dummy;
316  nsresult rv = GetIndexForCategory(aCategory, &dummy);
317 
318  *_retval = NS_SUCCEEDED(rv);
319  return NS_OK;
320 }
321 
322 NS_IMETHODIMP
323 sbDeviceManagerObsolete::GetDeviceByCategory(const nsAString& aCategory,
324  sbIDeviceBase** _retval)
325 {
326  NS_ENSURE_ARG_POINTER(_retval);
327  NS_ENSURE_TRUE(sbDeviceManagerObsolete::sDevicesLoaded, NS_ERROR_UNEXPECTED);
328 
329  nsAutoLock autoLock(mLock);
330 
331  PRUint32 index;
332  nsresult rv = GetIndexForCategory(aCategory, &index);
333 
334  // If a supporting device wasn't found then return an error
335  NS_ENSURE_SUCCESS(rv, NS_ERROR_NOT_AVAILABLE);
336 
337  nsCOMPtr<sbIDeviceBase> device =
338  do_QueryInterface(mSupportedDevices.ObjectAt(index));
339  NS_ENSURE_TRUE(device, NS_ERROR_UNEXPECTED);
340 
341  NS_ADDREF(*_retval = device);
342  return NS_OK;
343 }
344 
345 NS_IMETHODIMP
346 sbDeviceManagerObsolete::GetIndexForCategory(const nsAString& aCategory,
347  PRUint32* _retval)
348 {
349  // We don't bother checking arguments or locking because we assume that we
350  // have already done so in our public methods.
351 
352  // First check to see if we've already looked up the result.
353  if (!mLastRequestedCategory.IsEmpty() &&
354  aCategory.Equals(mLastRequestedCategory)) {
355  *_retval = mLastRequestedIndex;
356  return NS_OK;
357  }
358 
359  // Otherwise loop through the array and try to find the category.
360  PRInt32 count = mSupportedDevices.Count();
361  for (PRInt32 index = 0; index < count; index++) {
362  nsCOMPtr<sbIDeviceBase> device = mSupportedDevices.ObjectAt(index);
363  if (!device) {
364  NS_WARNING("Null pointer in mSupportedDevices");
365  continue;
366  }
367 
368  nsAutoString category;
369  nsresult rv = device->GetDeviceCategory(category);
370  if (NS_FAILED(rv)) {
371  NS_WARNING("GetDeviceCategory Failed");
372  continue;
373  }
374 
375  if (category.Equals(aCategory)) {
376  mLastRequestedCategory = category;
377  *_retval = mLastRequestedIndex = index;
378  return NS_OK;
379  }
380  }
381 
382  // Not found
383  mLastRequestedCategory = EmptyString();
384  return NS_ERROR_NOT_AVAILABLE;
385 }
386 
387 NS_IMETHODIMP
388 sbDeviceManagerObsolete::Observe(nsISupports* aSubject,
389  const char* aTopic,
390  const PRUnichar* aData)
391 {
392  LOG(("DeviceManagerObsolete[0x%x] - Observe: %s", this, aTopic));
393 
394  nsresult rv;
395  nsCOMPtr<nsIObserverService> observerService =
396  do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
397  NS_ENSURE_SUCCESS(rv, rv);
398 
399  if (strcmp(aTopic, SB_LIBRARY_MANAGER_READY_TOPIC) == 0) {
400  // The profile has been loaded so now we can go hunting for devices
401  rv = LoadSupportedDevices();
402  NS_ENSURE_SUCCESS(rv, rv);
403 
404  // Notify any observers that we're ready to go.
405  rv = observerService->NotifyObservers(NS_ISUPPORTS_CAST(sbIDeviceManager*, this),
407  nsnull);
408  NS_ENSURE_SUCCESS(rv, rv);
409  }
410  else if (strcmp(aTopic, SB_LIBRARY_MANAGER_BEFORE_SHUTDOWN_TOPIC) == 0) {
411  // The profile is about to be unloaded so finalize our devices
412  rv = Finalize();
413  NS_ENSURE_SUCCESS(rv, rv);
414  }
415  else if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
416  // Remove ourselves from the observer service
417  rv = observerService->RemoveObserver(this, SB_LIBRARY_MANAGER_READY_TOPIC);
418  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
419  "Failed to remove library manager observer");
420 
421  rv = observerService->RemoveObserver(this,
423  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
424  "Failed to remove library manager before shutdown observer");
425 
426  rv = observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
427  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
428  "Failed to remove shutdown observer");
429 
430  }
431 
432  return NS_OK;
433 }
return NS_OK
var registrar
#define SB_DEVICE_PREFIX
const SB_LIBRARY_MANAGER_READY_TOPIC
static nsCOMPtr< nsIObserverService > observerService
Definition: UnityProxy.cpp:6
const SB_DEVICE_MANAGER_READY_TOPIC
sbDeviceFirmwareAutoCheckForUpdate prototype contractID
NS_IMPL_THREADSAFE_ISUPPORTS2(sbDeviceManagerObsolete, sbIDeviceManager, nsIObserver) sbDeviceManagerObsolete
Songbird WMDevice Component Definition.
var count
Definition: test_bug7406.js:32
[SOON TO BE DEPRECATED AFTER 0.3] Base interface for all supported devices.
#define LOG(args)
Songbird DeviceBase Component Definition.
const SB_LIBRARY_MANAGER_BEFORE_SHUTDOWN_TOPIC
_updateTextAndScrollDataForFrame aData