Bug 836654 - Part 4: Add PowerManagerService::NewWakeLockOnBehalfOfProcess. r=cjones

This commit is contained in:
Justin Lebar 2013-02-14 15:41:30 -05:00
Родитель 0c5ba48e65
Коммит e8a7bef2e4
5 изменённых файлов: 130 добавлений и 6 удалений

Просмотреть файл

@ -199,6 +199,16 @@ PowerManagerService::NewWakeLock(const nsAString &aTopic,
return NS_OK;
}
already_AddRefed<nsIDOMMozWakeLock>
PowerManagerService::NewWakeLockOnBehalfOfProcess(const nsAString& aTopic,
ContentParent* aContentParent)
{
nsRefPtr<WakeLock> wakelock = new WakeLock();
nsresult rv = wakelock->Init(aTopic, aContentParent);
NS_ENSURE_SUCCESS(rv, nullptr);
return wakelock.forget();
}
} // power
} // dom
} // mozilla

Просмотреть файл

@ -16,6 +16,9 @@
namespace mozilla {
namespace dom {
class ContentParent;
namespace power {
class PowerManagerService
@ -33,6 +36,22 @@ public:
// Implement WakeLockObserver
void Notify(const hal::WakeLockInformation& aWakeLockInfo);
/**
* Acquire a wake lock on behalf of a given process (aContentParent).
*
* This method stands in contrast to nsIPowerManagerService::NewWakeLock,
* which acquires a wake lock on behalf of the /current/ process.
*
* NewWakeLockOnBehalfOfProcess is different from NewWakeLock in that
*
* - The wake lock unlocks itself if the /given/ process dies, and
* - The /given/ process shows up in WakeLockInfo::lockingProcesses.
*
*/
already_AddRefed<nsIDOMMozWakeLock>
NewWakeLockOnBehalfOfProcess(const nsAString& aTopic,
ContentParent* aContentParent);
private:
~PowerManagerService();

Просмотреть файл

@ -3,6 +3,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WakeLock.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/Hal.h"
#include "mozilla/HalWakeLock.h"
#include "nsDOMClassInfoID.h"
@ -13,10 +15,11 @@
#include "nsIDOMEventTarget.h"
#include "nsPIDOMWindow.h"
#include "PowerManager.h"
#include "WakeLock.h"
DOMCI_DATA(MozWakeLock, mozilla::dom::power::WakeLock)
using namespace mozilla::hal;
namespace mozilla {
namespace dom {
namespace power {
@ -25,6 +28,8 @@ NS_INTERFACE_MAP_BEGIN(WakeLock)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozWakeLock)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozWakeLock)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozWakeLock)
NS_INTERFACE_MAP_END
@ -34,6 +39,7 @@ NS_IMPL_RELEASE(WakeLock)
WakeLock::WakeLock()
: mLocked(false)
, mHidden(true)
, mContentParentID(CONTENT_PROCESS_ID_UNKNOWN)
{
}
@ -46,6 +52,13 @@ WakeLock::~WakeLock()
nsresult
WakeLock::Init(const nsAString &aTopic, nsIDOMWindow *aWindow)
{
// Don't Init() a WakeLock twice.
MOZ_ASSERT(mTopic.IsEmpty());
if (aTopic.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
mTopic.Assign(aTopic);
mWindow = do_GetWeakReference(aWindow);
@ -67,15 +80,73 @@ WakeLock::Init(const nsAString &aTopic, nsIDOMWindow *aWindow)
return NS_OK;
}
nsresult
WakeLock::Init(const nsAString& aTopic, ContentParent* aContentParent)
{
// Don't Init() a WakeLock twice.
MOZ_ASSERT(mTopic.IsEmpty());
MOZ_ASSERT(aContentParent);
if (aTopic.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
mTopic.Assign(aTopic);
mContentParentID = aContentParent->ChildID();
mHidden = false;
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->AddObserver(this, "ipc:content-shutdown", /* ownsWeak */ true);
}
DoLock();
return NS_OK;
}
NS_IMETHODIMP
WakeLock::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* data)
{
// If this wake lock was acquired on behalf of another process, unlock it
// when that process dies.
//
// Note that we do /not/ call DoUnlock() here! The wake lock back-end is
// already listening for ipc:content-shutdown messages and will clear out its
// tally for the process when it dies. All we need to do here is ensure that
// unlock() becomes a nop.
MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
if (!props) {
NS_WARNING("ipc:content-shutdown message without property bag as subject");
return NS_OK;
}
uint64_t childID = 0;
nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"),
&childID);
if (NS_SUCCEEDED(rv)) {
if (childID == mContentParentID) {
mLocked = false;
}
} else {
NS_WARNING("ipc:content-shutdown message without childID property");
}
return NS_OK;
}
void
WakeLock::DoLock()
{
if (!mLocked) {
// Change the flag immediately to prevent recursive reentering
mLocked = true;
hal::ModifyWakeLock(mTopic,
hal::WAKE_LOCK_ADD_ONE,
mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_NO_CHANGE);
mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_NO_CHANGE,
mContentParentID);
}
}
@ -85,9 +156,11 @@ WakeLock::DoUnlock()
if (mLocked) {
// Change the flag immediately to prevent recursive reentering
mLocked = false;
hal::ModifyWakeLock(mTopic,
hal::WAKE_LOCK_REMOVE_ONE,
mHidden ? hal::WAKE_LOCK_REMOVE_ONE : hal::WAKE_LOCK_NO_CHANGE);
mHidden ? hal::WAKE_LOCK_REMOVE_ONE : hal::WAKE_LOCK_NO_CHANGE,
mContentParentID);
}
}
@ -181,7 +254,8 @@ WakeLock::HandleEvent(nsIDOMEvent *aEvent)
if (mLocked && oldHidden != mHidden) {
hal::ModifyWakeLock(mTopic,
hal::WAKE_LOCK_NO_CHANGE,
mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE);
mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE,
mContentParentID);
}
return NS_OK;

Просмотреть файл

@ -9,6 +9,7 @@
#include "nsCOMPtr.h"
#include "nsIDOMWakeLock.h"
#include "nsIDOMEventListener.h"
#include "nsIObserver.h"
#include "nsString.h"
#include "nsWeakReference.h"
@ -16,21 +17,35 @@ class nsIDOMWindow;
namespace mozilla {
namespace dom {
class ContentParent;
namespace power {
class WakeLock
: public nsIDOMMozWakeLock
, public nsIDOMEventListener
, public nsIObserver
, public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMMOZWAKELOCK
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_NSIOBSERVER
WakeLock();
virtual ~WakeLock();
nsresult Init(const nsAString &aTopic, nsIDOMWindow *aWindow);
// Initialize this wake lock on behalf of the given window. Null windows are
// allowed; a lock without an associated window is always considered
// invisible.
nsresult Init(const nsAString &aTopic, nsIDOMWindow* aWindow);
// Initialize this wake lock on behalf of the given process. If the process
// dies, the lock is released. A wake lock initialized via this method is
// always considered visible.
nsresult Init(const nsAString &aTopic, ContentParent* aContentParent);
private:
void DoUnlock();
@ -40,6 +55,11 @@ private:
bool mLocked;
bool mHidden;
// The ID of the ContentParent on behalf of whom we acquired this lock, or
// CONTENT_PROCESS_UNKNOWN_ID if this lock was acquired on behalf of the
// current process.
uint64_t mContentParentID;
nsString mTopic;
// window that this was created for. Weak reference.

Просмотреть файл

@ -8,6 +8,7 @@
#define mozilla_Hal_h
#include "mozilla/hal_sandbox/PHal.h"
#include "mozilla/HalTypes.h"
#include "base/basictypes.h"
#include "mozilla/Types.h"
#include "nsTArray.h"
@ -359,7 +360,7 @@ void UnregisterWakeLockObserver(WakeLockObserver* aObserver);
void ModifyWakeLock(const nsAString &aTopic,
hal::WakeLockControl aLockAdjust,
hal::WakeLockControl aHiddenAdjust,
uint64_t aProcessID = CONTENT_PROCESS_ID_UNKNOWN);
uint64_t aProcessID = hal::CONTENT_PROCESS_ID_UNKNOWN);
/**
* Query the wake lock numbers of aTopic.