Bug 886842 - Add clang trunk builds for ASan. r=ehsan DONTBUILD
[gecko.git] / dom / devicestorage / DeviceStorageRequestParent.cpp
blobf624784d3c9c6265c30208075f77dc7109c56a27
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "DeviceStorageRequestParent.h"
7 #include "nsDOMFile.h"
8 #include "nsIMIMEService.h"
9 #include "nsCExternalHandlerService.h"
10 #include "mozilla/unused.h"
11 #include "mozilla/dom/ipc/Blob.h"
12 #include "ContentParent.h"
13 #include "nsProxyRelease.h"
14 #include "AppProcessChecker.h"
15 #include "mozilla/Preferences.h"
17 namespace mozilla {
18 namespace dom {
19 namespace devicestorage {
21 DeviceStorageRequestParent::DeviceStorageRequestParent(const DeviceStorageParams& aParams)
22 : mParams(aParams)
23 , mMutex("DeviceStorageRequestParent::mMutex")
24 , mActorDestoryed(false)
26 MOZ_COUNT_CTOR(DeviceStorageRequestParent);
28 DebugOnly<DeviceStorageUsedSpaceCache*> usedSpaceCache = DeviceStorageUsedSpaceCache::CreateOrGet();
29 NS_ASSERTION(usedSpaceCache, "DeviceStorageUsedSpaceCache is null");
32 void
33 DeviceStorageRequestParent::Dispatch()
35 switch (mParams.type()) {
36 case DeviceStorageParams::TDeviceStorageAddParams:
38 DeviceStorageAddParams p = mParams;
40 nsRefPtr<DeviceStorageFile> dsf =
41 new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
43 BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
44 nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
46 nsCOMPtr<nsIInputStream> stream;
47 blob->GetInternalStream(getter_AddRefs(stream));
49 nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream);
51 nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
52 NS_ASSERTION(target, "Must have stream transport service");
53 target->Dispatch(r, NS_DISPATCH_NORMAL);
54 break;
57 case DeviceStorageParams::TDeviceStorageGetParams:
59 DeviceStorageGetParams p = mParams;
60 nsRefPtr<DeviceStorageFile> dsf =
61 new DeviceStorageFile(p.type(), p.storageName(), p.rootDir(), p.relpath());
62 nsRefPtr<CancelableRunnable> r = new ReadFileEvent(this, dsf);
64 nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
65 NS_ASSERTION(target, "Must have stream transport service");
66 target->Dispatch(r, NS_DISPATCH_NORMAL);
67 break;
70 case DeviceStorageParams::TDeviceStorageDeleteParams:
72 DeviceStorageDeleteParams p = mParams;
74 nsRefPtr<DeviceStorageFile> dsf =
75 new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
76 nsRefPtr<CancelableRunnable> r = new DeleteFileEvent(this, dsf);
78 nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
79 NS_ASSERTION(target, "Must have stream transport service");
80 target->Dispatch(r, NS_DISPATCH_NORMAL);
81 break;
84 case DeviceStorageParams::TDeviceStorageFreeSpaceParams:
86 DeviceStorageFreeSpaceParams p = mParams;
88 nsRefPtr<DeviceStorageFile> dsf =
89 new DeviceStorageFile(p.type(), p.storageName());
90 nsRefPtr<FreeSpaceFileEvent> r = new FreeSpaceFileEvent(this, dsf);
92 nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
93 NS_ASSERTION(target, "Must have stream transport service");
94 target->Dispatch(r, NS_DISPATCH_NORMAL);
95 break;
98 case DeviceStorageParams::TDeviceStorageUsedSpaceParams:
100 DeviceStorageUsedSpaceCache* usedSpaceCache = DeviceStorageUsedSpaceCache::CreateOrGet();
101 NS_ASSERTION(usedSpaceCache, "DeviceStorageUsedSpaceCache is null");
103 DeviceStorageUsedSpaceParams p = mParams;
105 nsRefPtr<DeviceStorageFile> dsf =
106 new DeviceStorageFile(p.type(), p.storageName());
107 nsRefPtr<UsedSpaceFileEvent> r = new UsedSpaceFileEvent(this, dsf);
109 usedSpaceCache->Dispatch(r);
110 break;
113 case DeviceStorageParams::TDeviceStorageAvailableParams:
115 DeviceStorageAvailableParams p = mParams;
117 nsRefPtr<DeviceStorageFile> dsf =
118 new DeviceStorageFile(p.type(), p.storageName());
119 nsRefPtr<PostAvailableResultEvent> r = new PostAvailableResultEvent(this, dsf);
120 NS_DispatchToMainThread(r);
121 break;
124 case DeviceStorageParams::TDeviceStorageEnumerationParams:
126 DeviceStorageEnumerationParams p = mParams;
127 nsRefPtr<DeviceStorageFile> dsf
128 = new DeviceStorageFile(p.type(), p.storageName(), p.rootdir(), NS_LITERAL_STRING(""));
129 nsRefPtr<CancelableRunnable> r = new EnumerateFileEvent(this, dsf, p.since());
131 nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
132 NS_ASSERTION(target, "Must have stream transport service");
133 target->Dispatch(r, NS_DISPATCH_NORMAL);
134 break;
136 default:
138 NS_RUNTIMEABORT("not reached");
139 break;
144 bool
145 DeviceStorageRequestParent::EnsureRequiredPermissions(mozilla::dom::ContentParent* aParent)
147 if (mozilla::Preferences::GetBool("device.storage.testing", false)) {
148 return true;
151 nsString type;
152 DeviceStorageRequestType requestType;
154 switch (mParams.type())
156 case DeviceStorageParams::TDeviceStorageAddParams:
158 DeviceStorageAddParams p = mParams;
159 type = p.type();
160 requestType = DEVICE_STORAGE_REQUEST_CREATE;
161 break;
164 case DeviceStorageParams::TDeviceStorageGetParams:
166 DeviceStorageGetParams p = mParams;
167 type = p.type();
168 requestType = DEVICE_STORAGE_REQUEST_READ;
169 break;
172 case DeviceStorageParams::TDeviceStorageDeleteParams:
174 DeviceStorageDeleteParams p = mParams;
175 type = p.type();
176 requestType = DEVICE_STORAGE_REQUEST_DELETE;
177 break;
180 case DeviceStorageParams::TDeviceStorageFreeSpaceParams:
182 DeviceStorageFreeSpaceParams p = mParams;
183 type = p.type();
184 requestType = DEVICE_STORAGE_REQUEST_FREE_SPACE;
185 break;
188 case DeviceStorageParams::TDeviceStorageUsedSpaceParams:
190 DeviceStorageUsedSpaceParams p = mParams;
191 type = p.type();
192 requestType = DEVICE_STORAGE_REQUEST_FREE_SPACE;
193 break;
196 case DeviceStorageParams::TDeviceStorageAvailableParams:
198 DeviceStorageAvailableParams p = mParams;
199 type = p.type();
200 requestType = DEVICE_STORAGE_REQUEST_AVAILABLE;
201 break;
204 case DeviceStorageParams::TDeviceStorageEnumerationParams:
206 DeviceStorageEnumerationParams p = mParams;
207 type = p.type();
208 requestType = DEVICE_STORAGE_REQUEST_READ;
209 break;
212 default:
214 return false;
218 // The 'apps' type is special. We only want this exposed
219 // if the caller has the "webapps-manage" permission.
220 if (type.EqualsLiteral("apps")) {
221 if (!AssertAppProcessPermission(aParent, "webapps-manage")) {
222 return false;
226 nsAutoCString permissionName;
227 nsresult rv = DeviceStorageTypeChecker::GetPermissionForType(type, permissionName);
228 if (NS_FAILED(rv)) {
229 return false;
232 nsCString access;
233 rv = DeviceStorageTypeChecker::GetAccessForRequest(requestType, access);
234 if (NS_FAILED(rv)) {
235 return false;
238 permissionName.AppendLiteral("-");
239 permissionName.Append(access);
241 if (!AssertAppProcessPermission(aParent, permissionName.get())) {
242 return false;
245 return true;
248 DeviceStorageRequestParent::~DeviceStorageRequestParent()
250 MOZ_COUNT_DTOR(DeviceStorageRequestParent);
253 NS_IMPL_THREADSAFE_ADDREF(DeviceStorageRequestParent)
254 NS_IMPL_THREADSAFE_RELEASE(DeviceStorageRequestParent)
256 void
257 DeviceStorageRequestParent::ActorDestroy(ActorDestroyReason)
259 MutexAutoLock lock(mMutex);
260 mActorDestoryed = true;
261 int32_t count = mRunnables.Length();
262 for (int32_t index = 0; index < count; index++) {
263 mRunnables[index]->Cancel();
267 DeviceStorageRequestParent::PostFreeSpaceResultEvent::PostFreeSpaceResultEvent(DeviceStorageRequestParent* aParent,
268 uint64_t aFreeSpace)
269 : CancelableRunnable(aParent)
270 , mFreeSpace(aFreeSpace)
274 DeviceStorageRequestParent::PostFreeSpaceResultEvent::~PostFreeSpaceResultEvent() {}
276 nsresult
277 DeviceStorageRequestParent::PostFreeSpaceResultEvent::CancelableRun() {
278 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
280 FreeSpaceStorageResponse response(mFreeSpace);
281 unused << mParent->Send__delete__(mParent, response);
282 return NS_OK;
285 DeviceStorageRequestParent::PostUsedSpaceResultEvent::PostUsedSpaceResultEvent(DeviceStorageRequestParent* aParent,
286 const nsAString& aType,
287 uint64_t aUsedSpace)
288 : CancelableRunnable(aParent)
289 , mType(aType)
290 , mUsedSpace(aUsedSpace)
294 DeviceStorageRequestParent::PostUsedSpaceResultEvent::~PostUsedSpaceResultEvent() {}
296 nsresult
297 DeviceStorageRequestParent::PostUsedSpaceResultEvent::CancelableRun() {
298 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
300 UsedSpaceStorageResponse response(mUsedSpace);
301 unused << mParent->Send__delete__(mParent, response);
302 return NS_OK;
305 DeviceStorageRequestParent::PostErrorEvent::PostErrorEvent(DeviceStorageRequestParent* aParent,
306 const char* aError)
307 : CancelableRunnable(aParent)
309 CopyASCIItoUTF16(aError, mError);
312 DeviceStorageRequestParent::PostErrorEvent::~PostErrorEvent() {}
314 nsresult
315 DeviceStorageRequestParent::PostErrorEvent::CancelableRun() {
316 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
318 ErrorResponse response(mError);
319 unused << mParent->Send__delete__(mParent, response);
320 return NS_OK;
323 DeviceStorageRequestParent::PostSuccessEvent::PostSuccessEvent(DeviceStorageRequestParent* aParent)
324 : CancelableRunnable(aParent)
328 DeviceStorageRequestParent::PostSuccessEvent::~PostSuccessEvent() {}
330 nsresult
331 DeviceStorageRequestParent::PostSuccessEvent::CancelableRun() {
332 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
334 SuccessResponse response;
335 unused << mParent->Send__delete__(mParent, response);
336 return NS_OK;
339 DeviceStorageRequestParent::PostBlobSuccessEvent::PostBlobSuccessEvent(DeviceStorageRequestParent* aParent,
340 DeviceStorageFile* aFile,
341 uint32_t aLength,
342 nsACString& aMimeType,
343 uint64_t aLastModifiedDate)
344 : CancelableRunnable(aParent)
345 , mLength(aLength)
346 , mLastModificationDate(aLastModifiedDate)
347 , mFile(aFile)
348 , mMimeType(aMimeType)
352 DeviceStorageRequestParent::PostBlobSuccessEvent::~PostBlobSuccessEvent() {}
354 nsresult
355 DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
356 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
358 nsString mime;
359 CopyASCIItoUTF16(mMimeType, mime);
361 nsString compositePath;
362 mFile->GetCompositePath(compositePath);
363 nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(compositePath, mime, mLength, mFile->mFile, mLastModificationDate);
365 ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
366 BlobParent* actor = cp->GetOrCreateActorForBlob(blob);
367 if (!actor) {
368 ErrorResponse response(NS_LITERAL_STRING(POST_ERROR_EVENT_UNKNOWN));
369 unused << mParent->Send__delete__(mParent, response);
370 return NS_OK;
373 BlobResponse response;
374 response.blobParent() = actor;
376 unused << mParent->Send__delete__(mParent, response);
377 return NS_OK;
380 DeviceStorageRequestParent::PostEnumerationSuccessEvent::PostEnumerationSuccessEvent(DeviceStorageRequestParent* aParent,
381 const nsAString& aStorageType,
382 const nsAString& aRelPath,
383 InfallibleTArray<DeviceStorageFileValue>& aPaths)
384 : CancelableRunnable(aParent)
385 , mStorageType(aStorageType)
386 , mRelPath(aRelPath)
387 , mPaths(aPaths)
391 DeviceStorageRequestParent::PostEnumerationSuccessEvent::~PostEnumerationSuccessEvent() {}
393 nsresult
394 DeviceStorageRequestParent::PostEnumerationSuccessEvent::CancelableRun() {
395 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
397 EnumerationResponse response(mStorageType, mRelPath, mPaths);
398 unused << mParent->Send__delete__(mParent, response);
399 return NS_OK;
402 DeviceStorageRequestParent::WriteFileEvent::WriteFileEvent(DeviceStorageRequestParent* aParent,
403 DeviceStorageFile* aFile,
404 nsIInputStream* aInputStream)
405 : CancelableRunnable(aParent)
406 , mFile(aFile)
407 , mInputStream(aInputStream)
411 DeviceStorageRequestParent::WriteFileEvent::~WriteFileEvent()
415 nsresult
416 DeviceStorageRequestParent::WriteFileEvent::CancelableRun()
418 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
420 nsRefPtr<nsRunnable> r;
422 if (!mInputStream) {
423 r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
424 NS_DispatchToMainThread(r);
425 return NS_OK;
428 bool check = false;
429 mFile->mFile->Exists(&check);
430 if (check) {
431 nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_EXISTS);
432 NS_DispatchToMainThread(event);
433 return NS_OK;
436 nsresult rv = mFile->Write(mInputStream);
438 if (NS_FAILED(rv)) {
439 r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
441 else {
442 r = new PostPathResultEvent(mParent, mFile->mPath);
445 NS_DispatchToMainThread(r);
446 return NS_OK;
450 DeviceStorageRequestParent::DeleteFileEvent::DeleteFileEvent(DeviceStorageRequestParent* aParent,
451 DeviceStorageFile* aFile)
452 : CancelableRunnable(aParent)
453 , mFile(aFile)
457 DeviceStorageRequestParent::DeleteFileEvent::~DeleteFileEvent()
461 nsresult
462 DeviceStorageRequestParent::DeleteFileEvent::CancelableRun()
464 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
466 mFile->Remove();
468 nsRefPtr<nsRunnable> r;
470 bool check = false;
471 mFile->mFile->Exists(&check);
472 if (check) {
473 r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
475 else {
476 r = new PostPathResultEvent(mParent, mFile->mPath);
479 NS_DispatchToMainThread(r);
480 return NS_OK;
483 DeviceStorageRequestParent::FreeSpaceFileEvent::FreeSpaceFileEvent(DeviceStorageRequestParent* aParent,
484 DeviceStorageFile* aFile)
485 : CancelableRunnable(aParent)
486 , mFile(aFile)
490 DeviceStorageRequestParent::FreeSpaceFileEvent::~FreeSpaceFileEvent()
494 nsresult
495 DeviceStorageRequestParent::FreeSpaceFileEvent::CancelableRun()
497 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
499 int64_t freeSpace = 0;
500 if (mFile) {
501 mFile->GetDiskFreeSpace(&freeSpace);
504 nsCOMPtr<nsIRunnable> r;
505 r = new PostFreeSpaceResultEvent(mParent, static_cast<uint64_t>(freeSpace));
506 NS_DispatchToMainThread(r);
507 return NS_OK;
510 DeviceStorageRequestParent::UsedSpaceFileEvent::UsedSpaceFileEvent(DeviceStorageRequestParent* aParent,
511 DeviceStorageFile* aFile)
512 : CancelableRunnable(aParent)
513 , mFile(aFile)
517 DeviceStorageRequestParent::UsedSpaceFileEvent::~UsedSpaceFileEvent()
521 nsresult
522 DeviceStorageRequestParent::UsedSpaceFileEvent::CancelableRun()
524 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
526 uint64_t picturesUsage = 0, videosUsage = 0, musicUsage = 0, totalUsage = 0;
527 mFile->AccumDiskUsage(&picturesUsage, &videosUsage,
528 &musicUsage, &totalUsage);
529 nsCOMPtr<nsIRunnable> r;
530 if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_PICTURES)) {
531 r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, picturesUsage);
533 else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) {
534 r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, videosUsage);
536 else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_MUSIC)) {
537 r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, musicUsage);
538 } else {
539 r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, totalUsage);
541 NS_DispatchToMainThread(r);
542 return NS_OK;
545 DeviceStorageRequestParent::ReadFileEvent::ReadFileEvent(DeviceStorageRequestParent* aParent,
546 DeviceStorageFile* aFile)
547 : CancelableRunnable(aParent)
548 , mFile(aFile)
550 nsCOMPtr<nsIMIMEService> mimeService = do_GetService(NS_MIMESERVICE_CONTRACTID);
551 if (mimeService) {
552 nsresult rv = mimeService->GetTypeFromFile(mFile->mFile, mMimeType);
553 if (NS_FAILED(rv)) {
554 mMimeType.Truncate();
559 DeviceStorageRequestParent::ReadFileEvent::~ReadFileEvent()
563 nsresult
564 DeviceStorageRequestParent::ReadFileEvent::CancelableRun()
566 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
568 nsCOMPtr<nsIRunnable> r;
569 bool check = false;
570 mFile->mFile->Exists(&check);
572 if (!check) {
573 r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST);
574 NS_DispatchToMainThread(r);
575 return NS_OK;
578 int64_t fileSize;
579 nsresult rv = mFile->mFile->GetFileSize(&fileSize);
580 if (NS_FAILED(rv)) {
581 r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
582 NS_DispatchToMainThread(r);
583 return NS_OK;
586 PRTime modDate;
587 rv = mFile->mFile->GetLastModifiedTime(&modDate);
588 if (NS_FAILED(rv)) {
589 r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
590 NS_DispatchToMainThread(r);
591 return NS_OK;
594 r = new PostBlobSuccessEvent(mParent, mFile, static_cast<uint64_t>(fileSize), mMimeType, modDate);
595 NS_DispatchToMainThread(r);
596 return NS_OK;
599 DeviceStorageRequestParent::EnumerateFileEvent::EnumerateFileEvent(DeviceStorageRequestParent* aParent,
600 DeviceStorageFile* aFile,
601 uint64_t aSince)
602 : CancelableRunnable(aParent)
603 , mFile(aFile)
604 , mSince(aSince)
608 DeviceStorageRequestParent::EnumerateFileEvent::~EnumerateFileEvent()
612 nsresult
613 DeviceStorageRequestParent::EnumerateFileEvent::CancelableRun()
615 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
617 nsCOMPtr<nsIRunnable> r;
618 if (mFile->mFile) {
619 bool check = false;
620 mFile->mFile->Exists(&check);
621 if (!check) {
622 r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST);
623 NS_DispatchToMainThread(r);
624 return NS_OK;
628 nsTArray<nsRefPtr<DeviceStorageFile> > files;
629 mFile->CollectFiles(files, mSince);
631 InfallibleTArray<DeviceStorageFileValue> values;
633 uint32_t count = files.Length();
634 for (uint32_t i = 0; i < count; i++) {
635 DeviceStorageFileValue dsvf(files[i]->mStorageName, files[i]->mPath);
636 values.AppendElement(dsvf);
639 r = new PostEnumerationSuccessEvent(mParent, mFile->mStorageType, mFile->mRootDir, values);
640 NS_DispatchToMainThread(r);
641 return NS_OK;
645 DeviceStorageRequestParent::PostPathResultEvent::PostPathResultEvent(DeviceStorageRequestParent* aParent,
646 const nsAString& aPath)
647 : CancelableRunnable(aParent)
648 , mPath(aPath)
652 DeviceStorageRequestParent::PostPathResultEvent::~PostPathResultEvent()
656 nsresult
657 DeviceStorageRequestParent::PostPathResultEvent::CancelableRun()
659 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
661 SuccessResponse response;
662 unused << mParent->Send__delete__(mParent, response);
663 return NS_OK;
666 DeviceStorageRequestParent::PostAvailableResultEvent::PostAvailableResultEvent(DeviceStorageRequestParent* aParent,
667 DeviceStorageFile* aFile)
668 : CancelableRunnable(aParent)
669 , mFile(aFile)
673 DeviceStorageRequestParent::PostAvailableResultEvent::~PostAvailableResultEvent()
677 nsresult
678 DeviceStorageRequestParent::PostAvailableResultEvent::CancelableRun()
680 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
682 nsString state = NS_LITERAL_STRING("unavailable");
683 if (mFile) {
684 mFile->GetStatus(state);
687 AvailableStorageResponse response(state);
688 unused << mParent->Send__delete__(mParent, response);
689 return NS_OK;
692 } // namespace devicestorage
693 } // namespace dom
694 } // namespace mozilla