Bug 806363 - Remove wake locks on content-shutdown. r=jlebar

This commit is contained in:
Kan-Ru Chen (陳侃如) 2012-11-17 23:05:18 +08:00
parent 41e92624f2
commit 5a97ac6956
7 changed files with 176 additions and 54 deletions

View File

@ -631,6 +631,8 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
props->Init();
props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), mChildID);
if (AbnormalShutdown == why) {
props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true);
@ -644,9 +646,8 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
nsAutoString dumpID(crashReporter->ChildDumpID());
props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID);
#endif
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr);
}
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr);
}
MessageLoop::current()->
@ -702,6 +703,7 @@ ContentParent::ContentParent(const nsAString& aAppManifestURL,
ChildOSPrivileges aOSPrivileges)
: mSubprocess(nullptr)
, mOSPrivileges(aOSPrivileges)
, mChildID(-1)
, mGeolocationWatchID(-1)
, mRunToCompletionDepth(0)
, mShouldCallUnblockChild(false)
@ -1125,7 +1127,7 @@ bool
ContentParent::RecvGetProcessAttributes(uint64_t* aId, bool* aStartBackground,
bool* aIsForApp, bool* aIsForBrowser)
{
*aId = gContentChildID++;
*aId = mChildID = gContentChildID++;
*aStartBackground =
(mAppManifestURL == MAGIC_PREALLOCATED_APP_MANIFEST_URL);
*aIsForApp = IsForApp();

View File

@ -311,6 +311,7 @@ private:
GeckoChildProcessHost* mSubprocess;
ChildOSPrivileges mOSPrivileges;
uint64_t mChildID;
int32_t mGeolocationWatchID;
int mRunToCompletionDepth;
bool mShouldCallUnblockChild;

View File

@ -21,6 +21,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "WindowIdentifier.h"
#include "mozilla/dom/ScreenOrientation.h"
#include "mozilla/dom/ContentChild.h"
#ifdef XP_WIN
#include <process.h>
@ -641,16 +642,29 @@ UnregisterWakeLockObserver(WakeLockObserver* aObserver)
}
void
ModifyWakeLock(const nsAString &aTopic,
ModifyWakeLock(const nsAString& aTopic,
WakeLockControl aLockAdjust,
WakeLockControl aHiddenAdjust)
{
AssertMainThread();
PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust));
uint64_t processID = InSandbox() ? dom::ContentChild::GetSingleton()->GetID() : 0;
PROXY_IF_SANDBOXED(ModifyWakeLockInternal(aTopic, aLockAdjust, aHiddenAdjust, processID));
}
void
GetWakeLockInfo(const nsAString &aTopic, WakeLockInformation *aWakeLockInfo)
ModifyWakeLockInternal(const nsAString& aTopic,
WakeLockControl aLockAdjust,
WakeLockControl aHiddenAdjust,
uint64_t aProcessID)
{
AssertMainThread();
// TODO: Bug 812403 - support wake locks in nested content processes.
AssertMainProcess();
PROXY_IF_SANDBOXED(ModifyWakeLockInternal(aTopic, aLockAdjust, aHiddenAdjust, aProcessID));
}
void
GetWakeLockInfo(const nsAString& aTopic, WakeLockInformation* aWakeLockInfo)
{
AssertMainThread();
PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));

View File

@ -340,7 +340,7 @@ void RegisterWakeLockObserver(WakeLockObserver* aObserver);
void UnregisterWakeLockObserver(WakeLockObserver* aObserver);
/**
* Adjust the internal wake lock counts.
* Adjust the wake lock counts.
* @param aTopic lock topic
* @param aLockAdjust to increase or decrease active locks
* @param aHiddenAdjust to increase or decrease hidden locks
@ -349,6 +349,18 @@ void ModifyWakeLock(const nsAString &aTopic,
hal::WakeLockControl aLockAdjust,
hal::WakeLockControl aHiddenAdjust);
/**
* Adjust the wake lock counts. Do not call this function directly.
* @param aTopic lock topic
* @param aLockAdjust to increase or decrease active locks
* @param aHiddenAdjust to increase or decrease hidden locks
* @param aProcessID unique id per-ContentChild or 0 for chrome
*/
void ModifyWakeLockInternal(const nsAString &aTopic,
hal::WakeLockControl aLockAdjust,
hal::WakeLockControl aHiddenAdjust,
uint64_t aProcessID);
/**
* Query the wake lock numbers of aTopic.
* @param aTopic lock topic

View File

@ -6,9 +6,12 @@
#include "mozilla/Hal.h"
#include "mozilla/HalWakeLock.h"
#include "mozilla/Services.h"
#include "nsObserverService.h"
#include "mozilla/StaticPtr.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsIPropertyBag2.h"
#include "nsObserverService.h"
using namespace mozilla::hal;
@ -35,17 +38,44 @@ namespace hal_impl {
namespace {
struct LockCount {
LockCount()
: numLocks(0)
, numHidden(0)
{}
uint32_t numLocks;
uint32_t numHidden;
};
}
typedef nsDataHashtable<nsUint64HashKey, LockCount> ProcessLockTable;
typedef nsClassHashtable<nsStringHashKey, ProcessLockTable> LockTable;
static int sActiveChildren = 0;
static nsAutoPtr<nsDataHashtable<nsStringHashKey, LockCount> > sLockTable;
static int sActiveListeners = 0;
static StaticAutoPtr<LockTable> sLockTable;
static bool sInitialized = false;
static bool sIsShuttingDown = false;
namespace {
static PLDHashOperator
RemoveChildFromList(const nsAString& aKey, ProcessLockTable* aTable, void* aUserArg)
{
MOZ_ASSERT(aUserArg);
uint64_t childID = *static_cast<uint64_t*>(aUserArg);
aTable->Remove(childID);
return PL_DHASH_NEXT;
}
static PLDHashOperator
CountWakeLocks(const uint64_t& aKey, LockCount aCount, void* aUserArg)
{
MOZ_ASSERT(aUserArg);
LockCount* totalCount = static_cast<LockCount*>(aUserArg);
totalCount->numLocks += aCount.numLocks;
totalCount->numHidden += aCount.numHidden;
return PL_DHASH_NEXT;
}
class ClearHashtableOnShutdown MOZ_FINAL : public nsIObserver {
public:
NS_DECL_ISUPPORTS
@ -64,37 +94,73 @@ ClearHashtableOnShutdown::Observe(nsISupports* aSubject, const char* aTopic, con
return NS_OK;
}
} // anonymous namespace
class CleanupOnContentShutdown MOZ_FINAL : public nsIObserver {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
};
NS_IMPL_ISUPPORTS1(CleanupOnContentShutdown, nsIObserver)
NS_IMETHODIMP
CleanupOnContentShutdown::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* data)
{
MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
if (sIsShuttingDown) {
return NS_OK;
}
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)) {
sLockTable->EnumerateRead(RemoveChildFromList, &childID);
} else {
NS_WARNING("ipc:content-shutdown message without childID property");
}
return NS_OK;
}
static void
Init()
{
sLockTable = new nsDataHashtable<nsStringHashKey, LockCount>();
sLockTable = new LockTable();
sLockTable->Init();
sInitialized = true;
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(new ClearHashtableOnShutdown(), "xpcom-shutdown", false);
obs->AddObserver(new CleanupOnContentShutdown(), "ipc:content-shutdown", false);
}
}
} // anonymous namespace
void
EnableWakeLockNotifications()
{
sActiveChildren++;
sActiveListeners++;
}
void
DisableWakeLockNotifications()
{
sActiveChildren--;
sActiveListeners--;
}
void
ModifyWakeLock(const nsAString &aTopic,
hal::WakeLockControl aLockAdjust,
hal::WakeLockControl aHiddenAdjust)
ModifyWakeLockInternal(const nsAString& aTopic,
hal::WakeLockControl aLockAdjust,
hal::WakeLockControl aHiddenAdjust,
uint64_t aProcessID)
{
if (sIsShuttingDown) {
return;
@ -103,39 +169,55 @@ ModifyWakeLock(const nsAString &aTopic,
Init();
}
LockCount count;
count.numLocks = 0;
count.numHidden = 0;
sLockTable->Get(aTopic, &count);
MOZ_ASSERT(count.numLocks >= count.numHidden);
MOZ_ASSERT(aLockAdjust >= 0 || count.numLocks > 0);
MOZ_ASSERT(aHiddenAdjust >= 0 || count.numHidden > 0);
WakeLockState oldState = ComputeWakeLockState(count.numLocks, count.numHidden);
count.numLocks += aLockAdjust;
count.numHidden += aHiddenAdjust;
MOZ_ASSERT(count.numLocks >= count.numHidden);
if (count.numLocks) {
sLockTable->Put(aTopic, count);
ProcessLockTable* table = sLockTable->Get(aTopic);
LockCount processCount;
LockCount totalCount;
if (!table) {
table = new ProcessLockTable();
table->Init();
sLockTable->Put(aTopic, table);
} else {
table->Get(aProcessID, &processCount);
table->EnumerateRead(CountWakeLocks, &totalCount);
}
MOZ_ASSERT(processCount.numLocks >= processCount.numHidden);
MOZ_ASSERT(aLockAdjust >= 0 || processCount.numLocks > 0);
MOZ_ASSERT(aHiddenAdjust >= 0 || processCount.numHidden > 0);
MOZ_ASSERT(totalCount.numLocks >= totalCount.numHidden);
MOZ_ASSERT(aLockAdjust >= 0 || totalCount.numLocks > 0);
MOZ_ASSERT(aHiddenAdjust >= 0 || totalCount.numHidden > 0);
WakeLockState oldState = ComputeWakeLockState(totalCount.numLocks, totalCount.numHidden);
processCount.numLocks += aLockAdjust;
processCount.numHidden += aHiddenAdjust;
totalCount.numLocks += aLockAdjust;
totalCount.numHidden += aHiddenAdjust;
if (processCount.numLocks) {
table->Put(aProcessID, processCount);
} else {
table->Remove(aProcessID);
}
if (!totalCount.numLocks) {
sLockTable->Remove(aTopic);
}
WakeLockState newState = ComputeWakeLockState(count.numLocks, count.numHidden);
WakeLockState newState = ComputeWakeLockState(totalCount.numLocks, totalCount.numHidden);
if (sActiveChildren && oldState != newState) {
if (sActiveListeners && oldState != newState) {
WakeLockInformation info;
info.numLocks() = count.numLocks;
info.numHidden() = count.numHidden;
info.numLocks() = totalCount.numLocks;
info.numHidden() = totalCount.numHidden;
info.topic() = aTopic;
NotifyWakeLockChange(info);
}
}
void
GetWakeLockInfo(const nsAString &aTopic, WakeLockInformation *aWakeLockInfo)
GetWakeLockInfo(const nsAString& aTopic, WakeLockInformation* aWakeLockInfo)
{
if (sIsShuttingDown) {
NS_WARNING("You don't want to get wake lock information during xpcom-shutdown!");
@ -145,13 +227,17 @@ GetWakeLockInfo(const nsAString &aTopic, WakeLockInformation *aWakeLockInfo)
Init();
}
LockCount count;
count.numLocks = 0;
count.numHidden = 0;
sLockTable->Get(aTopic, &count);
aWakeLockInfo->numLocks() = count.numLocks;
aWakeLockInfo->numHidden() = count.numHidden;
ProcessLockTable* table = sLockTable->Get(aTopic);
if (!table) {
aWakeLockInfo->numLocks() = 0;
aWakeLockInfo->numHidden() = 0;
aWakeLockInfo->topic() = aTopic;
return;
}
LockCount totalCount;
table->EnumerateRead(CountWakeLocks, &totalCount);
aWakeLockInfo->numLocks() = totalCount.numLocks;
aWakeLockInfo->numHidden() = totalCount.numHidden;
aWakeLockInfo->topic() = aTopic;
}

View File

@ -152,7 +152,10 @@ parent:
sync GetLight(LightType light)
returns (LightConfiguration aConfig, bool status);
ModifyWakeLock(nsString aTopic, WakeLockControl aLockAdjust, WakeLockControl aHiddenAdjust);
ModifyWakeLock(nsString aTopic,
WakeLockControl aLockAdjust,
WakeLockControl aHiddenAdjust,
uint64_t aProcessID);
EnableWakeLockNotifications();
DisableWakeLockNotifications();
sync GetWakeLockInfo(nsString aTopic)

View File

@ -276,9 +276,12 @@ DisableWakeLockNotifications()
}
void
ModifyWakeLock(const nsAString &aTopic, WakeLockControl aLockAdjust, WakeLockControl aHiddenAdjust)
ModifyWakeLockInternal(const nsAString &aTopic,
WakeLockControl aLockAdjust,
WakeLockControl aHiddenAdjust,
uint64_t aProcessID)
{
Hal()->SendModifyWakeLock(nsString(aTopic), aLockAdjust, aHiddenAdjust);
Hal()->SendModifyWakeLock(nsString(aTopic), aLockAdjust, aHiddenAdjust, aProcessID);
}
void
@ -703,12 +706,13 @@ public:
}
virtual bool
RecvModifyWakeLock(const nsString &aTopic,
const WakeLockControl &aLockAdjust,
const WakeLockControl &aHiddenAdjust) MOZ_OVERRIDE
RecvModifyWakeLock(const nsString& aTopic,
const WakeLockControl& aLockAdjust,
const WakeLockControl& aHiddenAdjust,
const uint64_t& aProcessID) MOZ_OVERRIDE
{
// We allow arbitrary content to use wake locks.
hal::ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust);
hal::ModifyWakeLockInternal(aTopic, aLockAdjust, aHiddenAdjust, aProcessID);
return true;
}