Merge b2g-inbound to m-c

This commit is contained in:
Wes Kocher 2013-12-12 18:02:54 -08:00
commit c1b0f6e109
35 changed files with 654 additions and 760 deletions

View File

@ -18,7 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 934646 needs a clobber -- the icon resources previously copied
into $OBJDIR/mobile/android/base/res will conflict with those in
$BRANDING_DIRECTORY/res.
Bug 946047 - Windows needs a clobber for webidl changes.

View File

@ -7,6 +7,9 @@
pref("toolkit.defaultChromeURI", "chrome://browser/content/shell.html");
pref("browser.chromeURL", "chrome://browser/content/");
// Bug 945235: Prevent all bars to be considered visible:
pref("toolkit.defaultChromeFeatures", "chrome,dialog=no,close,resizable,scrollbars,extrachrome");
// Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
pref("browser.viewport.scaleRatio", -1);

View File

@ -1,4 +1,4 @@
{
"revision": "5bfef5faac50d14e055f642a44ed2df8483fb2fe",
"revision": "9271d94f35a54995e4442da711e51cff0244741d",
"repo_path": "/integration/gaia-central"
}

View File

@ -148,9 +148,7 @@ VideoTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
VideoChunk chunk = *iter;
if (!chunk.IsNull()) {
gfxIntSize imgsize = chunk.mFrame.GetImage()->GetSize();
int width = (imgsize.width + 1) / 2 * 2;
int height = (imgsize.height + 1) / 2 * 2;
nsresult rv = Init(width, height, aTrackRate);
nsresult rv = Init(imgsize.width, imgsize.height, aTrackRate);
if (NS_FAILED(rv)) {
LOG("[VideoTrackEncoder]: Fail to initialize the encoder!");
NotifyCancel();

View File

@ -41,6 +41,25 @@ using namespace mozilla;
namespace mozilla {
class ReleaseOmxDecoderRunnable : public nsRunnable
{
public:
ReleaseOmxDecoderRunnable(const android::sp<android::OmxDecoder>& aOmxDecoder)
: mOmxDecoder(aOmxDecoder)
{
}
NS_METHOD Run() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
mOmxDecoder = nullptr; // release OmxDecoder
return NS_OK;
}
private:
android::sp<android::OmxDecoder> mOmxDecoder;
};
class OmxDecoderProcessCachedDataTask : public Task
{
public:
@ -53,7 +72,13 @@ public:
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(mOmxDecoder.get());
mOmxDecoder->ProcessCachedData(mOffset, false);
int64_t rem = mOmxDecoder->ProcessCachedData(mOffset, false);
if (rem <= 0) {
ReleaseOmxDecoderRunnable* r = new ReleaseOmxDecoderRunnable(mOmxDecoder);
mOmxDecoder.clear();
NS_DispatchToMainThread(r);
}
}
private:
@ -292,6 +317,8 @@ OmxDecoder::OmxDecoder(MediaResource *aResource,
OmxDecoder::~OmxDecoder()
{
MOZ_ASSERT(NS_IsMainThread());
ReleaseMediaResources();
// unregister AMessage handler from ALooper.
@ -398,7 +425,7 @@ bool OmxDecoder::TryLoad() {
// Feed MP3 parser with cached data. Local files will be fully
// cached already, network streams will update with sucessive
// calls to NotifyDataArrived.
if (ProcessCachedData(0, true)) {
if (ProcessCachedData(0, true) >= 0) {
durationUs = mMP3FrameParser.GetDuration();
if (durationUs > totalDurationUs) {
totalDurationUs = durationUs;
@ -1017,7 +1044,7 @@ void OmxDecoder::ReleaseAllPendingVideoBuffersLocked()
releasingVideoBuffers.clear();
}
bool OmxDecoder::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
int64_t OmxDecoder::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
{
// We read data in chunks of 32 KiB. We can reduce this
// value if media, such as sdcards, is too slow.
@ -1030,10 +1057,10 @@ bool OmxDecoder::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
MOZ_ASSERT(mResource);
int64_t resourceLength = mResource->GetCachedDataEnd(0);
NS_ENSURE_TRUE(resourceLength >= 0, false);
NS_ENSURE_TRUE(resourceLength >= 0, -1);
if (aOffset >= resourceLength) {
return true; // Cache is empty, nothing to do
return 0; // Cache is empty, nothing to do
}
int64_t bufferLength = std::min<int64_t>(resourceLength-aOffset, sReadSize);
@ -1041,7 +1068,7 @@ bool OmxDecoder::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
nsAutoArrayPtr<char> buffer(new char[bufferLength]);
nsresult rv = mResource->ReadFromCache(buffer.get(), aOffset, bufferLength);
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_SUCCESS(rv, -1);
nsRefPtr<OmxDecoderNotifyDataArrivedRunnable> runnable(
new OmxDecoderNotifyDataArrivedRunnable(this,
@ -1051,11 +1078,11 @@ bool OmxDecoder::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
resourceLength));
rv = NS_DispatchToMainThread(runnable.get());
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_SUCCESS(rv, -1);
if (aWaitForCompletion) {
runnable->WaitForCompletion();
}
return true;
return resourceLength - aOffset - bufferLength;
}

View File

@ -238,7 +238,7 @@ public:
// Called on ALooper thread.
void onMessageReceived(const sp<AMessage> &msg);
bool ProcessCachedData(int64_t aOffset, bool aWaitForCompletion);
int64_t ProcessCachedData(int64_t aOffset, bool aWaitForCompletion);
};
}

View File

@ -22,44 +22,5 @@ MediaDecoderStateMachine* RtspOmxDecoder::CreateStateMachine()
mResource->IsRealTime());
}
void RtspOmxDecoder::ApplyStateToStateMachine(PlayState aState)
{
MOZ_ASSERT(NS_IsMainThread());
GetReentrantMonitor().AssertCurrentThreadIn();
MediaDecoder::ApplyStateToStateMachine(aState);
// Send play/pause commands here through the nsIStreamingProtocolController
// except seek command. We need to clear the decoded/un-decoded buffer data
// before sending seek command. So the seek calling path to controller is:
// mDecoderStateMachine::Seek-> RtspOmxReader::Seek-> RtspResource::SeekTime->
// controller->Seek(). RtspOmxReader::Seek will clear the decoded buffer and
// the RtspResource::SeekTime will clear the un-decoded buffer.
RtspMediaResource* rtspResource = mResource->GetRtspPointer();
MOZ_ASSERT(rtspResource);
nsIStreamingProtocolController* controller =
rtspResource->GetMediaStreamController();
if (mDecoderStateMachine) {
switch (aState) {
case PLAY_STATE_PLAYING:
if (controller) {
controller->Play();
}
break;
case PLAY_STATE_PAUSED:
if (controller) {
controller->Pause();
}
break;
default:
/* No action needed */
break;
}
}
}
} // namespace mozilla

View File

@ -32,10 +32,6 @@ public:
virtual MediaDecoder* Clone() MOZ_OVERRIDE;
virtual MediaDecoderStateMachine* CreateStateMachine() MOZ_OVERRIDE;
// Called by |ChangeState|, override it to send the Rtsp play/pause commands
// through |nsIStreamingProtocolController|.
// Call on the main thread only and the lock must be obtained.
virtual void ApplyStateToStateMachine(PlayState aState) MOZ_OVERRIDE;
};
} // namespace mozilla

View File

@ -289,4 +289,44 @@ nsresult RtspOmxReader::Seek(int64_t aTime, int64_t aStartTime,
return MediaOmxReader::Seek(aTime, aStartTime, aEndTime, aCurrentTime);
}
void RtspOmxReader::OnDecodeThreadStart() {
// Start RTSP streaming right after starting the decoding thread in
// MediaDecoderStateMachine and before starting OMXCodec decoding.
if (mRtspResource) {
nsIStreamingProtocolController* controller =
mRtspResource->GetMediaStreamController();
if (controller) {
controller->Play();
}
}
// Call parent class to start OMXCodec decoding.
MediaOmxReader::OnDecodeThreadStart();
}
void RtspOmxReader::OnDecodeThreadFinish() {
// Call parent class to pause OMXCodec decoding.
MediaOmxReader::OnDecodeThreadFinish();
// Stop RTSP streaming right before destroying the decoding thread in
// MediaDecoderStateMachine and after pausing OMXCodec decoding.
// RTSP streaming should not be paused until OMXCodec has been paused and
// until the decoding thread in MediaDecoderStateMachine is about to be
// destroyed. Otherwise, RtspMediaSource::read() would block the binder
// thread of OMXCodecObserver::onMessage() --> OMXCodec::on_message() -->
// OMXCodec::drainInputBuffer() due to network data starvation. Because
// OMXCodec::mLock is held by the binder thread in this case, all other
// threads would be blocked when they try to lock this mutex. As a result, the
// decoding thread in MediaDecoderStateMachine would be blocked forever in
// OMXCodec::read() if there is no enough data for RtspMediaSource::read() to
// return.
if (mRtspResource) {
nsIStreamingProtocolController* controller =
mRtspResource->GetMediaStreamController();
if (controller) {
controller->Pause();
}
}
}
} // namespace mozilla

View File

@ -71,6 +71,10 @@ public:
return nullptr;
}
virtual void OnDecodeThreadStart() MOZ_OVERRIDE;
virtual void OnDecodeThreadFinish() MOZ_OVERRIDE;
private:
// A pointer to RtspMediaResource for calling the Rtsp specific function.
// The lifetime of mRtspResource is controlled by MediaDecoder. MediaDecoder

View File

@ -108,6 +108,9 @@ extern bool gBluetoothDebugFlag;
#define BLUETOOTH_ADDRESS_NONE "00:00:00:00:00:00"
#define BLUETOOTH_ADDRESS_BYTES 6
// Bluetooth stack internal error, such as I/O error
#define ERR_INTERNAL_ERROR "InternalError"
BEGIN_BLUETOOTH_NAMESPACE
enum BluetoothSocketType {

View File

@ -167,12 +167,6 @@ static const char* sBluetoothDBusSignals[] =
"type='signal',interface='org.bluez.Control'"
};
/**
* DBus Connection held for the BluetoothCommandThread to use. Should never be
* used by any other thread.
*/
static nsRefPtr<RawDBusConnection> gThreadConnection;
// Only A2DP and HID are authorized.
static nsTArray<BluetoothServiceClass> sAuthorizedServiceClass;
@ -497,6 +491,14 @@ RunDBusCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable,
nsAutoString replyError;
BluetoothValue v;
aFunc(aMsg, nullptr, v, replyError);
// Bug 941462. When blueZ replys 'I/O error', we treat it as 'internal error'.
// This usually happned when the first pairing request has not yet finished,
// the second pairing request issued immediately.
if (replyError.EqualsLiteral("I/O error")) {
replyError.AssignLiteral(ERR_INTERNAL_ERROR);
}
DispatchBluetoothReply(replyRunnable, v, replyError);
}
@ -966,9 +968,9 @@ AppendDeviceName(BluetoothSignal& aSignal)
nsString devicePath = arr[0].value().get_nsString();
nsRefPtr<RawDBusConnection> threadConnection = gThreadConnection;
RawDBusConnection* connection = GetDBusConnection();
if (!threadConnection.get()) {
if (!connection) {
BT_WARNING("%s: DBus connection has been closed.", __FUNCTION__);
return;
}
@ -977,7 +979,7 @@ AppendDeviceName(BluetoothSignal& aSignal)
new AppendDeviceNameReplyHandler(nsCString(DBUS_DEVICE_IFACE),
devicePath, aSignal);
bool success = threadConnection->SendWithReply(
bool success = connection->SendWithReply(
AppendDeviceNameReplyHandler::Callback, handler.get(), 1000,
NS_ConvertUTF16toUTF8(devicePath).get(), DBUS_DEVICE_IFACE,
"GetProperties", DBUS_TYPE_INVALID);
@ -1211,9 +1213,9 @@ public:
return;
}
nsRefPtr<RawDBusConnection> threadConnection = gThreadConnection;
RawDBusConnection* connection = GetDBusConnection();
if (!threadConnection.get()) {
if (!connection) {
BT_WARNING("%s: DBus connection has been closed.", __FUNCTION__);
return;
}
@ -1221,7 +1223,7 @@ public:
// There is no "RegisterAgent" function defined in device interface.
// When we call "CreatePairedDevice", it will do device agent registration
// for us. (See maemo.org/api_refs/5.0/beta/bluez/adapter.html)
if (!dbus_connection_register_object_path(threadConnection->GetConnection(),
if (!dbus_connection_register_object_path(connection->GetConnection(),
KEY_REMOTE_AGENT,
mAgentVTable,
nullptr)) {
@ -1297,9 +1299,9 @@ private:
const char* agentPath = KEY_LOCAL_AGENT;
const char* capabilities = B2G_AGENT_CAPABILITIES;
nsRefPtr<RawDBusConnection> threadConnection = gThreadConnection;
RawDBusConnection* connection = GetDBusConnection();
if (!threadConnection.get()) {
if (!connection) {
BT_WARNING("%s: DBus connection has been closed.", __FUNCTION__);
return false;
}
@ -1310,7 +1312,7 @@ private:
// signal will be passed to local agent. If we start pairing process with
// calling CreatePairedDevice, we'll get signal which should be passed to
// device agent.
if (!dbus_connection_register_object_path(threadConnection->GetConnection(),
if (!dbus_connection_register_object_path(connection->GetConnection(),
KEY_LOCAL_AGENT,
aAgentVTable,
nullptr)) {
@ -1324,7 +1326,7 @@ private:
MOZ_ASSERT(handler.get());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
bool success = threadConnection->SendWithReply(
bool success = connection->SendWithReply(
RegisterAgentReplyHandler::Callback, handler.get(), -1,
NS_ConvertUTF16toUTF8(sAdapterPath).get(),
DBUS_ADAPTER_IFACE, "RegisterAgent",
@ -1359,9 +1361,9 @@ public:
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<RawDBusConnection> threadConnection = gThreadConnection;
RawDBusConnection* connection = GetDBusConnection();
if (!threadConnection.get()) {
if (!connection) {
BT_WARNING("%s: DBus connection has been closed.", __FUNCTION__);
return NS_ERROR_FAILURE;
}
@ -1375,7 +1377,7 @@ public:
const dbus_uint32_t* services = sServices;
bool success = threadConnection->SendWithReply(
bool success = connection->SendWithReply(
DBusReplyHandler::Callback, handler.get(), -1,
NS_ConvertUTF16toUTF8(sAdapterPath).get(),
DBUS_ADAPTER_IFACE, "AddReservedServiceRecords",
@ -1719,7 +1721,7 @@ OnDefaultAdapterReply(DBusMessage* aReply, void* aData)
bool
BluetoothDBusService::IsReady()
{
if (!IsEnabled() || !mConnection || !gThreadConnection || IsToggling()) {
if (!IsEnabled() || !GetDBusConnection() || IsToggling()) {
BT_WARNING("Bluetooth service is not ready yet!");
return false;
}
@ -1737,25 +1739,8 @@ BluetoothDBusService::StartInternal()
return NS_ERROR_FAILURE;
}
if (mConnection) {
return NS_OK;
}
mConnection = new RawDBusConnection();
if (NS_FAILED(mConnection->EstablishDBusConnection())) {
BT_WARNING("Cannot start Main Thread DBus connection!");
StopDBus();
return NS_ERROR_FAILURE;
}
gThreadConnection = new RawDBusConnection();
if (NS_FAILED(gThreadConnection->EstablishDBusConnection())) {
BT_WARNING("Cannot start Sync Thread DBus connection!");
StopDBus();
return NS_ERROR_FAILURE;
}
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
DBusError err;
dbus_error_init(&err);
@ -1765,7 +1750,7 @@ BluetoothDBusService::StartInternal()
// signals we want, register all of them in this thread at startup.
// The event handler will sort the destinations out as needed.
for (uint32_t i = 0; i < ArrayLength(sBluetoothDBusSignals); ++i) {
dbus_bus_add_match(mConnection->GetConnection(),
dbus_bus_add_match(connection->GetConnection(),
sBluetoothDBusSignals[i],
&err);
if (dbus_error_is_set(&err)) {
@ -1774,7 +1759,7 @@ BluetoothDBusService::StartInternal()
}
// Add a filter for all incoming messages_base
if (!dbus_connection_add_filter(mConnection->GetConnection(),
if (!dbus_connection_add_filter(connection->GetConnection(),
EventFilter, nullptr, nullptr)) {
BT_WARNING("Cannot create DBus Event Filter for DBus Thread!");
return NS_ERROR_FAILURE;
@ -1792,11 +1777,11 @@ BluetoothDBusService::StartInternal()
* explicitly here.
*/
if (sAdapterPath.IsEmpty()) {
bool success = mConnection->SendWithReply(OnDefaultAdapterReply, nullptr,
1000, "/",
DBUS_MANAGER_IFACE,
"DefaultAdapter",
DBUS_TYPE_INVALID);
bool success = connection->SendWithReply(OnDefaultAdapterReply, nullptr,
1000, "/",
DBUS_MANAGER_IFACE,
"DefaultAdapter",
DBUS_TYPE_INVALID);
if (!success) {
BT_WARNING("Failed to query default adapter!");
}
@ -1826,15 +1811,16 @@ BluetoothDBusService::StopInternal()
}
}
if (!mConnection) {
StopDBus();
RawDBusConnection* connection = GetDBusConnection();
if (!connection) {
return NS_OK;
}
DBusError err;
dbus_error_init(&err);
for (uint32_t i = 0; i < ArrayLength(sBluetoothDBusSignals); ++i) {
dbus_bus_remove_match(mConnection->GetConnection(),
dbus_bus_remove_match(connection->GetConnection(),
sBluetoothDBusSignals[i],
&err);
if (dbus_error_is_set(&err)) {
@ -1842,24 +1828,21 @@ BluetoothDBusService::StopInternal()
}
}
dbus_connection_remove_filter(mConnection->GetConnection(),
dbus_connection_remove_filter(connection->GetConnection(),
EventFilter, nullptr);
if (!dbus_connection_unregister_object_path(gThreadConnection->GetConnection(),
if (!dbus_connection_unregister_object_path(connection->GetConnection(),
KEY_LOCAL_AGENT)) {
BT_WARNING("%s: Can't unregister object path %s for agent!",
__FUNCTION__, KEY_LOCAL_AGENT);
}
if (!dbus_connection_unregister_object_path(gThreadConnection->GetConnection(),
if (!dbus_connection_unregister_object_path(connection->GetConnection(),
KEY_REMOTE_AGENT)) {
BT_WARNING("%s: Can't unregister object path %s for agent!",
__FUNCTION__, KEY_REMOTE_AGENT);
}
mConnection = nullptr;
gThreadConnection = nullptr;
// unref stored DBusMessages before clear the hashtable
sPairingReqTable->EnumerateRead(UnrefDBusMessages, nullptr);
sPairingReqTable->Clear();
@ -1943,14 +1926,14 @@ protected:
// Acquire another reference to this reply handler
nsRefPtr<DefaultAdapterPathReplyHandler> handler = this;
nsRefPtr<RawDBusConnection> threadConnection = gThreadConnection;
RawDBusConnection* connection = GetDBusConnection();
if (!threadConnection.get()) {
if (!connection) {
aReplyError = NS_LITERAL_STRING("DBus connection has been closed.");
return false;
}
bool success = threadConnection->SendWithReply(
bool success = connection->SendWithReply(
DefaultAdapterPathReplyHandler::Callback, handler.get(), 1000,
NS_ConvertUTF16toUTF8(mAdapterPath).get(),
DBUS_ADAPTER_IFACE, "GetProperties", DBUS_TYPE_INVALID);
@ -2011,7 +1994,10 @@ BluetoothDBusService::GetDefaultAdapterPathInternal(
nsRefPtr<DefaultAdapterPathReplyHandler> handler =
new DefaultAdapterPathReplyHandler(aRunnable);
bool success = mConnection->SendWithReply(
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
bool success = connection->SendWithReply(
DefaultAdapterPathReplyHandler::Callback,
handler.get(), 1000,
"/", DBUS_MANAGER_IFACE, "DefaultAdapter",
@ -2056,7 +2042,10 @@ BluetoothDBusService::SendDiscoveryMessage(const char* aMessageName,
nsRefPtr<BluetoothReplyRunnable> runnable(aRunnable);
bool success = mConnection->SendWithReply(
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
bool success = connection->SendWithReply(
OnSendDiscoveryMessageReply,
static_cast<void*>(aRunnable), -1,
NS_ConvertUTF16toUTF8(sAdapterPath).get(),
@ -2096,13 +2085,12 @@ BluetoothDBusService::SendAsyncDBusMessage(const nsAString& aObjectPath,
DBusReplyCallback aCallback)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mConnection);
MOZ_ASSERT(IsEnabled());
MOZ_ASSERT(aCallback);
MOZ_ASSERT(!aObjectPath.IsEmpty());
MOZ_ASSERT(aInterface);
NS_ENSURE_TRUE(mConnection, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(GetDBusConnection(), NS_ERROR_FAILURE);
nsAutoPtr<BluetoothServiceClass> serviceClass(new BluetoothServiceClass());
if (!strcmp(aInterface, DBUS_SINK_IFACE)) {
@ -2114,7 +2102,10 @@ BluetoothDBusService::SendAsyncDBusMessage(const nsAString& aObjectPath,
return NS_ERROR_FAILURE;
}
bool ret = mConnection->SendWithReply(
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
bool ret = connection->SendWithReply(
aCallback, static_cast<void*>(serviceClass.forget()), -1,
NS_ConvertUTF16toUTF8(aObjectPath).get(),
aInterface, NS_ConvertUTF16toUTF8(aMessage).get(),
@ -2259,16 +2250,16 @@ protected:
mObjectPath = GetObjectPathFromAddress(sAdapterPath,
mDeviceAddresses[mProcessedDeviceAddresses]);
nsRefPtr<RawDBusConnection> threadConnection = gThreadConnection;
RawDBusConnection* connection = GetDBusConnection();
if (!threadConnection.get()) {
if (!connection) {
BT_WARNING("%s: DBus connection has been closed.", __FUNCTION__);
return false;
}
nsRefPtr<BluetoothArrayOfDevicePropertiesReplyHandler> handler = this;
bool success = threadConnection->SendWithReply(
bool success = connection->SendWithReply(
BluetoothArrayOfDevicePropertiesReplyHandler::Callback,
handler.get(), 1000,
NS_ConvertUTF16toUTF8(mObjectPath).get(),
@ -2427,10 +2418,13 @@ BluetoothDBusService::SetProperty(BluetoothObjectType aType,
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
// msg is unref'd as part of SendWithReply
bool success = mConnection->SendWithReply(GetVoidCallback,
(void*)aRunnable,
1000, msg);
bool success = connection->SendWithReply(GetVoidCallback,
(void*)aRunnable,
1000, msg);
if (!success) {
BT_WARNING("SendWithReply failed");
return NS_ERROR_FAILURE;
@ -2468,9 +2462,12 @@ BluetoothDBusService::CreatePairedDeviceInternal(
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
MOZ_ASSERT(!sAdapterPath.IsEmpty());
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
// Then send CreatePairedDevice, it will register a temp device agent then
// unregister it after pairing process is over
bool ret = mConnection->SendWithReply(
bool ret = connection->SendWithReply(
GetObjectPathCallback, (void*)runnable, aTimeout,
NS_ConvertUTF16toUTF8(sAdapterPath).get(),
DBUS_ADAPTER_IFACE,
@ -2523,7 +2520,10 @@ BluetoothDBusService::RemoveDeviceInternal(const nsAString& aDeviceAddress,
nsRefPtr<BluetoothReplyRunnable> runnable(aRunnable);
bool success = mConnection->SendWithReply(
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
bool success = connection->SendWithReply(
OnRemoveDeviceReply, static_cast<void*>(runnable.get()), -1,
NS_ConvertUTF16toUTF8(sAdapterPath).get(),
DBUS_ADAPTER_IFACE, "RemoveDevice",
@ -2574,7 +2574,9 @@ BluetoothDBusService::SetPinCodeInternal(const nsAString& aDeviceAddress,
errorStr.AssignLiteral("Couldn't append arguments to dbus message.");
result = false;
} else {
result = mConnection->Send(reply);
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
result = connection->Send(reply);
}
dbus_message_unref(msg);
@ -2620,7 +2622,9 @@ BluetoothDBusService::SetPasskeyInternal(const nsAString& aDeviceAddress,
errorStr.AssignLiteral("Couldn't append arguments to dbus message.");
result = false;
} else {
result = mConnection->Send(reply);
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
result = connection->Send(reply);
}
dbus_message_unref(msg);
@ -2664,7 +2668,10 @@ BluetoothDBusService::SetPairingConfirmationInternal(
return false;
}
bool result = mConnection->Send(reply);
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
bool result = connection->Send(reply);
if (!result) {
errorStr.AssignLiteral("Can't send message!");
}
@ -2907,7 +2914,10 @@ BluetoothDBusService::GetServiceChannel(const nsAString& aDeviceAddress,
nsRefPtr<OnGetServiceChannelReplyHandler> handler =
new OnGetServiceChannelReplyHandler(objectPath, aServiceUUID, aManager);
bool success = mConnection->SendWithReply(
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
bool success = connection->SendWithReply(
OnGetServiceChannelReplyHandler::Callback, handler, -1,
NS_ConvertUTF16toUTF8(objectPath).get(),
DBUS_DEVICE_IFACE, "GetServiceAttributeValue",
@ -2952,7 +2962,6 @@ BluetoothDBusService::UpdateSdpRecords(const nsAString& aDeviceAddress,
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
MOZ_ASSERT(aManager);
MOZ_ASSERT(mConnection);
nsString objectPath(GetObjectPathFromAddress(sAdapterPath, aDeviceAddress));
@ -2961,13 +2970,16 @@ BluetoothDBusService::UpdateSdpRecords(const nsAString& aDeviceAddress,
OnUpdateSdpRecordsRunnable* callbackRunnable =
new OnUpdateSdpRecordsRunnable(objectPath, aManager);
return mConnection->SendWithReply(DiscoverServicesCallback,
(void*)callbackRunnable, -1,
NS_ConvertUTF16toUTF8(objectPath).get(),
DBUS_DEVICE_IFACE,
"DiscoverServices",
DBUS_TYPE_STRING, &EmptyCString(),
DBUS_TYPE_INVALID);
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
return connection->SendWithReply(DiscoverServicesCallback,
(void*)callbackRunnable, -1,
NS_ConvertUTF16toUTF8(objectPath).get(),
DBUS_DEVICE_IFACE,
"DiscoverServices",
DBUS_TYPE_STRING, &EmptyCString(),
DBUS_TYPE_INVALID);
}
void
@ -3144,7 +3156,10 @@ BluetoothDBusService::SendMetaData(const nsAString& aTitle,
nsRefPtr<BluetoothReplyRunnable> runnable(aRunnable);
bool ret = mConnection->SendWithReply(
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
bool ret = connection->SendWithReply(
GetVoidCallback, (void*)runnable.get(), -1,
NS_ConvertUTF16toUTF8(objectPath).get(),
DBUS_CTL_IFACE, "UpdateMetaData",
@ -3243,7 +3258,10 @@ BluetoothDBusService::SendPlayStatus(int64_t aDuration,
nsRefPtr<BluetoothReplyRunnable> runnable(aRunnable);
bool ret = mConnection->SendWithReply(
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
bool ret = connection->SendWithReply(
GetVoidCallback, (void*)runnable.get(), -1,
NS_ConvertUTF16toUTF8(objectPath).get(),
DBUS_CTL_IFACE, "UpdatePlayStatus",
@ -3292,7 +3310,10 @@ BluetoothDBusService::UpdatePlayStatus(uint32_t aDuration,
uint32_t tempPlayStatus = aPlayStatus;
bool ret = mConnection->SendWithReply(
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
bool ret = connection->SendWithReply(
ControlCallback, nullptr, -1,
NS_ConvertUTF16toUTF8(objectPath).get(),
DBUS_CTL_IFACE, "UpdatePlayStatus",
@ -3322,7 +3343,10 @@ BluetoothDBusService::UpdateNotification(ControlEventId aEventId,
GetObjectPathFromAddress(sAdapterPath, address);
uint16_t eventId = aEventId;
bool ret = mConnection->SendWithReply(
RawDBusConnection* connection = GetDBusConnection();
MOZ_ASSERT(connection);
bool ret = connection->SendWithReply(
ControlCallback, nullptr, -1,
NS_ConvertUTF16toUTF8(objectPath).get(),
DBUS_CTL_IFACE, "UpdateNotification",

View File

@ -194,8 +194,6 @@ private:
const char* aInterface,
const nsAString& aMessage,
mozilla::ipc::DBusReplyCallback aCallback);
nsRefPtr<mozilla::ipc::RawDBusConnection> mConnection;
};
END_BLUETOOTH_NAMESPACE

View File

@ -45,21 +45,16 @@ const ContentPanning = {
this.watchedEventsType = 'mouse';
}
// If we are using an AsyncPanZoomController for the parent frame,
// it will handle subframe scrolling too. We don't need to listen for
// these events.
if (!docShell.asyncPanZoomEnabled) {
let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
events.forEach(function(type) {
// Using the system group for mouse/touch events to avoid
// missing events if .stopPropagation() has been called.
els.addSystemEventListener(global, type,
this.handleEvent.bind(this),
/* useCapture = */ false);
}.bind(this));
}
events.forEach(function(type) {
// Using the system group for mouse/touch events to avoid
// missing events if .stopPropagation() has been called.
els.addSystemEventListener(global, type,
this.handleEvent.bind(this),
/* useCapture = */ false);
}.bind(this));
addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
@ -70,6 +65,8 @@ const ContentPanning = {
},
handleEvent: function cp_handleEvent(evt) {
this._tryDelayMouseEvents();
if (evt.defaultPrevented || evt.multipleActionsPrevented) {
// clean up panning state even if touchend/mouseup has been preventDefault.
if(evt.type === 'touchend' || evt.type === 'mouseup') {
@ -82,13 +79,6 @@ const ContentPanning = {
return;
}
let start = Date.now();
let thread = Services.tm.currentThread;
while (this._delayEvents && (Date.now() - start) < this._activeDurationMs) {
thread.processNextEvent(true);
}
this._delayEvents = false;
switch (evt.type) {
case 'mousedown':
case 'touchstart':
@ -189,7 +179,8 @@ const ContentPanning = {
// We prevent start events to avoid sending a focus event at the end of this
// touch series. See bug 889717.
if (this.panning || this.preventNextClick) {
if (docShell.asyncPanZoomEnabled === false &&
(this.panning || this.preventNextClick)) {
evt.preventDefault();
}
},
@ -228,7 +219,7 @@ const ContentPanning = {
let view = target.ownerDocument ? target.ownerDocument.defaultView
: target;
view.addEventListener('click', this, true, true);
} else {
} else if (docShell.asyncPanZoomEnabled === false) {
// We prevent end events to avoid sending a focus event. See bug 889717.
evt.preventDefault();
}
@ -236,12 +227,7 @@ const ContentPanning = {
this.notify(this._activationTimer);
this._delayEvents = true;
let start = Date.now();
let thread = Services.tm.currentThread;
while (this._delayEvents && (Date.now() - start) < this._activeDurationMs) {
thread.processNextEvent(true);
}
this._delayEvents = false;
this._tryDelayMouseEvents();
}
this._finishPanning();
@ -278,7 +264,12 @@ const ContentPanning = {
}
let isPan = KineticPanning.isPan();
this.scrollCallback(delta.scale(-1));
// If the application is not managed by the AsyncPanZoomController, then
// scroll manually.
if (docShell.asyncPanZoomEnabled === false) {
this.scrollCallback(delta.scale(-1));
}
// If we've detected a pan gesture, cancel the active state of the
// current target.
@ -454,6 +445,15 @@ const ContentPanning = {
return this._activeDurationMs = duration;
},
_tryDelayMouseEvents: function cp_tryDelayMouseEvents() {
let start = Date.now();
let thread = Services.tm.currentThread;
while (this._delayEvents && (Date.now() - start) < this._activeDurationMs) {
thread.processNextEvent(true);
}
this._delayEvents = false;
},
_resetActive: function cp_resetActive() {
let elt = this.pointerDownTarget || this.target;
let root = elt.ownerDocument || elt.document;
@ -594,7 +594,9 @@ const ContentPanning = {
delete this.primaryPointerId;
this._activationTimer.cancel();
if (this.panning) {
// If there is a scroll action but the application is not managed by
// the AsyncPanZoom controller, let's do a manual kinetic panning action.
if (this.panning && docShell.asyncPanZoomEnabled === false) {
KineticPanning.start(this);
}
}

View File

@ -11,7 +11,7 @@ const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
this.EXPORTED_SYMBOLS = [];
this.EXPORTED_SYMBOLS = ["ContactService"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -31,7 +31,7 @@ let ContactService = {
"child-process-shutdown", "Contacts:GetRevision",
"Contacts:GetCount"];
this._children = [];
this._cursors = {};
this._cursors = new Map();
this._messages.forEach(function(msgName) {
ppmm.addMessageListener(msgName, this);
}.bind(this));
@ -120,18 +120,21 @@ let ContactService = {
if (!this.assertPermission(aMessage, "contacts-read")) {
return null;
}
if (!this._cursors[mm]) {
this._cursors[mm] = [];
let cursorList = this._cursors.get(mm);
if (!cursorList) {
cursorList = [];
this._cursors.set(mm, cursorList);
}
this._cursors[mm].push(msg.cursorId);
cursorList.push(msg.cursorId);
this._db.getAll(
function(aContacts) {
try {
mm.sendAsyncMessage("Contacts:GetAll:Next", {cursorId: msg.cursorId, contacts: aContacts});
if (aContacts === null) {
let index = this._cursors[mm].indexOf(msg.cursorId);
this._cursors[mm].splice(index, 1);
let cursorList = this._cursors.get(mm);
let index = cursorList.indexOf(msg.cursorId);
cursorList.splice(index, 1);
}
} catch (e) {
if (DEBUG) debug("Child is dead, DB should stop sending contacts");
@ -240,11 +243,12 @@ let ContactService = {
if (DEBUG) debug("Unregister index: " + index);
this._children.splice(index, 1);
}
if (this._cursors[mm]) {
for (let id of this._cursors[mm]) {
cursorList = this._cursors.get(mm);
if (cursorList) {
for (let id of cursorList) {
this._db.clearDispatcher(id);
}
delete this._cursors[mm];
this._cursors.delete(mm);
}
break;
default:

View File

@ -1,3 +1,6 @@
[DEFAULT]
[test_contacts_shutdown.xul]
skip-if = os == "android"
[test_contacts_upgrade.xul]

View File

@ -0,0 +1,103 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<window title="Mozilla Bug 945948"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript;version=1.7">
<![CDATA[
"use strict";
const { 'utils': Cu } = Components;
Cu.import("resource://gre/modules/ContactService.jsm", window);
//
// Mock message manager
//
function MockMessageManager() { }
MockMessageManager.prototype.assertPermission = function() { return true; };
MockMessageManager.prototype.sendAsyncMessage = function(name, data) { };
//
// Mock ContactDB
//
function MockContactDB() { }
MockContactDB.prototype.getAll = function(cb) {
cb([]);
};
MockContactDB.prototype.clearDispatcher = function() { }
MockContactDB.prototype.close = function() { }
let realContactDB = ContactService._db;
function before() {
ok(true, "Install mock ContactDB object");
ContactService._db = new MockContactDB();
}
function after() {
ok(true, "Restore real ContactDB object");
ContactService._db = realContactDB;
}
function steps() {
let mm1 = new MockMessageManager();
let mm2 = new MockMessageManager();
is(ContactService._cursors.size, 0, "Verify clean contact init");
ContactService.receiveMessage({
target: mm1,
name: "Contacts:GetAll",
data: { cursorId: 1 },
findOptions: {}
});
is(ContactService._cursors.size, 1, "Add contact cursor 1");
ContactService.receiveMessage({
target: mm2,
name: "Contacts:GetAll",
data: { cursorId: 2 },
findOptions: {}
});
is(ContactService._cursors.size, 2, "Add contact cursor 2");
ContactService.receiveMessage({
target: mm1,
name: "child-process-shutdown"
});
is(ContactService._cursors.size, 1, "Shutdown contact cursor 1");
ContactService.receiveMessage({
target: mm2,
name: "child-process-shutdown"
});
is(ContactService._cursors.size, 0, "Shutdown contact cursor 2");
}
function runTests() {
SimpleTest.waitForExplicitFinish();
try {
before();
steps();
} finally {
after();
SimpleTest.finish();
}
}
runTests();
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=945948"
target="_blank">Mozilla Bug 945948</a>
</body>
</window>

View File

@ -385,7 +385,6 @@ var interfaceNamesInGlobalScope =
"MozMobileMessageThread",
"MozNamedAttrMap",
{name: "MozNdefRecord", b2g: true},
{name: "MozNfc", b2g: true},
{name: "MozNFCPeer", b2g: true},
{name: "MozNFCTag", b2g: true},
{name: "MozOtaStatusEvent", b2g: true, pref: "dom.mobileconnection.enabled"},

View File

@ -5,7 +5,8 @@
/* Copyright © 2013 Deutsche Telekom, Inc. */
[JSImplementation="@mozilla.org/navigatorNfc;1",
NavigatorProperty="mozNfc"]
NavigatorProperty="mozNfc",
Func="Navigator::HasNfcSupport"]
interface MozNfc : EventTarget {
MozNFCTag getNFCTag(DOMString sessionId);
MozNFCPeer getNFCPeer(DOMString sessionId);

View File

@ -175,7 +175,8 @@ Layer::Layer(LayerManager* aManager, void* aImplData) :
mIsFixedPosition(false),
mMargins(0, 0, 0, 0),
mStickyPositionData(nullptr),
mIsScrollbar(false),
mScrollbarTargetId(FrameMetrics::NULL_SCROLL_ID),
mScrollbarDirection(ScrollDirection::NONE),
mDebugColorIndex(0),
mAnimationGeneration(0)
{}
@ -1268,12 +1269,11 @@ Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
aTo += " [componentAlpha]";
}
if (GetIsScrollbar()) {
if (GetScrollbarDirection() == VERTICAL) {
aTo.AppendPrintf(" [vscrollbar=%lld]", GetScrollbarTargetContainerId());
} else {
aTo.AppendPrintf(" [hscrollbar=%lld]", GetScrollbarTargetContainerId());
}
if (GetScrollbarDirection() == VERTICAL) {
aTo.AppendPrintf(" [vscrollbar=%lld]", GetScrollbarTargetContainerId());
}
if (GetScrollbarDirection() == HORIZONTAL) {
aTo.AppendPrintf(" [hscrollbar=%lld]", GetScrollbarTargetContainerId());
}
if (GetIsFixedPosition()) {
aTo.AppendPrintf(" [isFixedPosition anchor=%f,%f]", mAnchor.x, mAnchor.y);

View File

@ -967,6 +967,7 @@ public:
}
enum ScrollDirection {
NONE,
VERTICAL,
HORIZONTAL
};
@ -978,11 +979,9 @@ public:
*/
void SetScrollbarData(FrameMetrics::ViewID aScrollId, ScrollDirection aDir)
{
if (mIsScrollbar ||
mScrollbarTargetId != aScrollId ||
if (mScrollbarTargetId != aScrollId ||
mScrollbarDirection != aDir) {
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScrollbarData", this));
mIsScrollbar = true;
mScrollbarTargetId = aScrollId;
mScrollbarDirection = aDir;
Mutated();
@ -1013,7 +1012,6 @@ public:
FrameMetrics::ViewID GetStickyScrollContainerId() { return mStickyPositionData->mScrollId; }
const LayerRect& GetStickyScrollRangeOuter() { return mStickyPositionData->mOuter; }
const LayerRect& GetStickyScrollRangeInner() { return mStickyPositionData->mInner; }
bool GetIsScrollbar() { return mIsScrollbar; }
FrameMetrics::ViewID GetScrollbarTargetContainerId() { return mScrollbarTargetId; }
ScrollDirection GetScrollbarDirection() { return mScrollbarDirection; }
Layer* GetMaskLayer() const { return mMaskLayer; }
@ -1387,7 +1385,6 @@ protected:
LayerRect mInner;
};
nsAutoPtr<StickyPositionData> mStickyPositionData;
bool mIsScrollbar;
FrameMetrics::ViewID mScrollbarTargetId;
ScrollDirection mScrollbarDirection;
DebugOnly<uint32_t> mDebugColorIndex;

View File

@ -525,7 +525,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram
appliedTransform = true;
}
if (container->GetIsScrollbar()) {
if (container->GetScrollbarDirection() != Layer::NONE) {
ApplyAsyncTransformToScrollbar(container);
}
return appliedTransform;

View File

@ -1276,7 +1276,9 @@ void AsyncPanZoomController::RequestContentRepaint() {
mFrameMetrics.mScrollOffset.x) < EPSILON &&
fabsf(mLastPaintRequestMetrics.mScrollOffset.y -
mFrameMetrics.mScrollOffset.y) < EPSILON &&
mFrameMetrics.mZoom == mLastPaintRequestMetrics.mZoom) {
mFrameMetrics.mZoom == mLastPaintRequestMetrics.mZoom &&
fabsf(mFrameMetrics.mViewport.width - mLastPaintRequestMetrics.mViewport.width) < EPSILON &&
fabsf(mFrameMetrics.mViewport.height - mLastPaintRequestMetrics.mViewport.height) < EPSILON) {
return;
}
@ -1463,8 +1465,10 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
aLayerMetrics.mCompositionBounds.height == mFrameMetrics.mCompositionBounds.height) {
// Remote content has sync'd up to the composition geometry
// change, so we can accept the viewport it's calculated.
if (mFrameMetrics.mViewport.width != aLayerMetrics.mViewport.width)
if (mFrameMetrics.mViewport.width != aLayerMetrics.mViewport.width ||
mFrameMetrics.mViewport.height != aLayerMetrics.mViewport.height) {
needContentRepaint = true;
}
mFrameMetrics.mViewport = aLayerMetrics.mViewport;
}

View File

@ -280,10 +280,8 @@ LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
common.stickyScrollRangeOuter(),
common.stickyScrollRangeInner());
}
if (common.isScrollbar()) {
layer->SetScrollbarData(common.scrollbarTargetContainerId(),
static_cast<Layer::ScrollDirection>(common.scrollbarDirection()));
}
layer->SetScrollbarData(common.scrollbarTargetContainerId(),
static_cast<Layer::ScrollDirection>(common.scrollbarDirection()));
if (PLayerParent* maskLayer = common.maskLayerParent()) {
layer->SetMaskLayer(cast(maskLayer)->AsLayer());
} else {

View File

@ -198,7 +198,6 @@ struct CommonLayerAttributes {
uint64_t stickyScrollContainerId;
LayerRect stickyScrollRangeOuter;
LayerRect stickyScrollRangeInner;
bool isScrollbar;
uint64_t scrollbarTargetContainerId;
uint32_t scrollbarDirection;
nullable PLayer maskLayer;

View File

@ -501,11 +501,8 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies, bool
common.stickyScrollRangeOuter() = mutant->GetStickyScrollRangeOuter();
common.stickyScrollRangeInner() = mutant->GetStickyScrollRangeInner();
}
common.isScrollbar() = mutant->GetIsScrollbar();
if (mutant->GetIsScrollbar()) {
common.scrollbarTargetContainerId() = mutant->GetScrollbarTargetContainerId();
common.scrollbarDirection() = mutant->GetScrollbarDirection();
}
common.scrollbarTargetContainerId() = mutant->GetScrollbarTargetContainerId();
common.scrollbarDirection() = mutant->GetScrollbarDirection();
if (Layer* maskLayer = mutant->GetMaskLayer()) {
common.maskLayerChild() = Shadow(maskLayer->AsShadowableLayer());
} else {

View File

@ -66,544 +66,214 @@
#define LOG(args...) if (BTDEBUG) printf(args);
#endif
#define DEFAULT_INITIAL_POLLFD_COUNT 8
namespace mozilla {
namespace ipc {
class DBusWatcher : public RawDBusConnection
class DBusWatcher : public MessageLoopForIO::Watcher
{
public:
DBusWatcher()
{ }
DBusWatcher(RawDBusConnection* aConnection, DBusWatch* aWatch)
: mConnection(aConnection),
mWatch(aWatch)
{
MOZ_ASSERT(mConnection);
MOZ_ASSERT(mWatch);
}
~DBusWatcher()
{ }
bool Initialize();
void CleanUp();
void WakeUp();
bool Stop();
bool Poll();
bool AddWatch(DBusWatch* aWatch);
void RemoveWatch(DBusWatch* aWatch);
void HandleWatchAdd();
void HandleWatchRemove();
// Information about the sockets we're polling. Socket counts
// increase/decrease depending on how many add/remove watch signals
// we're received via the control sockets.
nsTArray<pollfd> mPollData;
nsTArray<DBusWatch*> mWatchData;
// Sockets for receiving dbus control information (watch
// add/removes, loop shutdown, etc...)
ScopedClose mControlFdR;
ScopedClose mControlFdW;
private:
struct PollFdComparator {
bool Equals(const pollfd& a, const pollfd& b) const {
return ((a.fd == b.fd) && (a.events == b.events));
}
bool LessThan(const pollfd& a, const pollfd&b) const {
return false;
}
};
enum DBusEventTypes {
DBUS_EVENT_LOOP_EXIT = 1,
DBUS_EVENT_LOOP_ADD = 2,
DBUS_EVENT_LOOP_REMOVE = 3,
DBUS_EVENT_LOOP_WAKEUP = 4
};
static unsigned int UnixEventsToDBusFlags(short events);
static short DBusFlagsToUnixEvents(unsigned int flags);
void StartWatching();
void StopWatching();
static void FreeFunction(void* aData);
static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData);
static void RemoveWatchFunction(DBusWatch* aWatch, void* aData);
static void ToggleWatchFunction(DBusWatch* aWatch, void* aData);
static void DBusWakeupFunction(void* aData);
bool SetUp();
RawDBusConnection* GetConnection();
private:
void OnFileCanReadWithoutBlocking(int aFd);
void OnFileCanWriteWithoutBlocking(int aFd);
// Read watcher for libevent. Only to be accessed on IO Thread.
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
// Write watcher for libevent. Only to be accessed on IO Thread.
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
// DBus structures
RawDBusConnection* mConnection;
DBusWatch* mWatch;
};
bool
DBusWatcher::Initialize()
RawDBusConnection*
DBusWatcher::GetConnection()
{
if (!SetUp()) {
CleanUp();
return false;
}
return true;
return mConnection;
}
void
DBusWatcher::CleanUp()
void DBusWatcher::StartWatching()
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(mWatch);
int fd = dbus_watch_get_unix_fd(mWatch);
MessageLoopForIO* ioLoop = MessageLoopForIO::current();
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
&mReadWatcher, this);
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
&mWriteWatcher, this);
}
void DBusWatcher::StopWatching()
{
MOZ_ASSERT(!NS_IsMainThread());
dbus_connection_set_wakeup_main_function(mConnection, nullptr,
nullptr, nullptr);
dbus_bool_t success = dbus_connection_set_watch_functions(mConnection,
nullptr, nullptr,
nullptr, nullptr,
nullptr);
if (success != TRUE) {
NS_WARNING("dbus_connection_set_watch_functions failed");
}
#ifdef DEBUG
LOG("Removing DBus Sockets\n");
#endif
if (mControlFdW.get()) {
mControlFdW.dispose();
}
if (mControlFdR.get()) {
mControlFdR.dispose();
}
mPollData.Clear();
// DBusWatch pointers are maintained by DBus, so we won't leak by
// clearing.
mWatchData.Clear();
}
void
DBusWatcher::WakeUp()
{
static const char control = DBUS_EVENT_LOOP_WAKEUP;
struct pollfd fds = {
mControlFdW.get(),
POLLOUT,
0
};
int nfds = TEMP_FAILURE_RETRY(poll(&fds, 1, 0));
NS_ENSURE_TRUE_VOID(nfds == 1);
NS_ENSURE_TRUE_VOID(fds.revents == POLLOUT);
ssize_t res = TEMP_FAILURE_RETRY(
write(mControlFdW.get(), &control, sizeof(control)));
if (res < 0) {
NS_WARNING("Cannot write wakeup bit to DBus controller!");
}
}
bool
DBusWatcher::Stop()
{
static const char data = DBUS_EVENT_LOOP_EXIT;
ssize_t res =
TEMP_FAILURE_RETRY(write(mControlFdW.get(), &data, sizeof(data)));
NS_ENSURE_TRUE(res == 1, false);
return true;
}
bool
DBusWatcher::Poll()
{
int res = TEMP_FAILURE_RETRY(poll(mPollData.Elements(),
mPollData.Length(), -1));
NS_ENSURE_TRUE(res > 0, false);
bool continueThread = true;
nsTArray<pollfd>::size_type i = 0;
while (i < mPollData.Length()) {
if (mPollData[i].revents == POLLIN) {
if (mPollData[i].fd == mControlFdR.get()) {
char data;
res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &data, sizeof(data)));
NS_ENSURE_TRUE(res > 0, false);
switch (data) {
case DBUS_EVENT_LOOP_EXIT:
continueThread = false;
break;
case DBUS_EVENT_LOOP_ADD:
HandleWatchAdd();
break;
case DBUS_EVENT_LOOP_REMOVE:
HandleWatchRemove();
// don't increment i, or we'll skip one element
continue;
case DBUS_EVENT_LOOP_WAKEUP:
NS_ProcessPendingEvents(NS_GetCurrentThread(),
PR_INTERVAL_NO_TIMEOUT);
break;
default:
#if DEBUG
nsCString warning("unknown command ");
warning.AppendInt(data);
NS_WARNING(warning.get());
#endif
break;
}
} else {
short events = mPollData[i].revents;
mPollData[i].revents = 0;
dbus_watch_handle(mWatchData[i], UnixEventsToDBusFlags(events));
DBusDispatchStatus dbusDispatchStatus;
do {
dbusDispatchStatus = dbus_connection_dispatch(GetConnection());
} while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
// Break at this point since we don't know if the operation
// was destructive
break;
}
}
++i;
}
return continueThread;
}
bool
DBusWatcher::AddWatch(DBusWatch* aWatch)
{
static const char control = DBUS_EVENT_LOOP_ADD;
if (dbus_watch_get_enabled(aWatch) == FALSE) {
return true;
}
// note that we can't just send the watch and inspect it later
// because we may get a removeWatch call before this data is reacted
// to by our eventloop and remove this watch.. reading the add first
// and then inspecting the recently deceased watch would be bad.
ssize_t res =
TEMP_FAILURE_RETRY(write(mControlFdW.get(),&control, sizeof(control)));
if (res < 0) {
LOG("Cannot write DBus add watch control data to socket!\n");
return false;
}
int fd = dbus_watch_get_unix_fd(aWatch);
res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &fd, sizeof(fd)));
if (res < 0) {
LOG("Cannot write DBus add watch descriptor data to socket!\n");
return false;
}
unsigned int flags = dbus_watch_get_flags(aWatch);
res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &flags, sizeof(flags)));
if (res < 0) {
LOG("Cannot write DBus add watch flag data to socket!\n");
return false;
}
res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &aWatch, sizeof(aWatch)));
if (res < 0) {
LOG("Cannot write DBus add watch struct data to socket!\n");
return false;
}
return true;
}
void
DBusWatcher::RemoveWatch(DBusWatch* aWatch)
{
static const char control = DBUS_EVENT_LOOP_REMOVE;
ssize_t res =
TEMP_FAILURE_RETRY(write(mControlFdW.get(), &control, sizeof(control)));
if (res < 0) {
LOG("Cannot write DBus remove watch control data to socket!\n");
return;
}
int fd = dbus_watch_get_unix_fd(aWatch);
res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &fd, sizeof(fd)));
if (res < 0) {
LOG("Cannot write DBus remove watch descriptor data to socket!\n");
return;
}
unsigned int flags = dbus_watch_get_flags(aWatch);
res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &flags, sizeof(flags)));
if (res < 0) {
LOG("Cannot write DBus remove watch flag data to socket!\n");
return;
}
}
void
DBusWatcher::HandleWatchAdd()
{
int fd;
ssize_t res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &fd, sizeof(fd)));
if (res < 0) {
LOG("Cannot read DBus watch add descriptor data from socket!\n");
return;
}
unsigned int flags;
res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &flags, sizeof(flags)));
if (res < 0) {
LOG("Cannot read DBus watch add flag data from socket!\n");
return;
}
DBusWatch* watch;
res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &watch, sizeof(watch)));
if (res < 0) {
LOG("Cannot read DBus watch add watch data from socket!\n");
return;
}
struct pollfd p = {
fd, // .fd
DBusFlagsToUnixEvents(flags), // .events
0 // .revents
};
if (mPollData.Contains(p, PollFdComparator())) {
return;
}
mPollData.AppendElement(p);
mWatchData.AppendElement(watch);
}
void
DBusWatcher::HandleWatchRemove()
{
int fd;
ssize_t res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &fd, sizeof(fd)));
if (res < 0) {
LOG("Cannot read DBus watch remove descriptor data from socket!\n");
return;
}
unsigned int flags;
res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &flags, sizeof(flags)));
if (res < 0) {
LOG("Cannot read DBus watch remove flag data from socket!\n");
return;
}
struct pollfd p = {
fd, // .fd
DBusFlagsToUnixEvents(flags), // .events
0 // .revents
};
int index = mPollData.IndexOf(p, 0, PollFdComparator());
// There are times where removes can be requested for watches that
// haven't been added (for example, whenever gecko comes up after
// adapters have already been enabled), so check to make sure we're
// using the watch in the first place
if (index < 0) {
LOG("DBus requested watch removal of non-existant socket, ignoring...");
return;
}
mPollData.RemoveElementAt(index);
// DBusWatch pointers are maintained by DBus, so we won't leak by
// removing.
mWatchData.RemoveElementAt(index);
}
// Flag conversion
unsigned int
DBusWatcher::UnixEventsToDBusFlags(short events)
{
return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
(events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
(events & DBUS_WATCH_ERROR ? POLLERR : 0) |
(events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
}
short
DBusWatcher::DBusFlagsToUnixEvents(unsigned int flags)
{
return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
(flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
(flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
(flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
mReadWatcher.StopWatchingFileDescriptor();
mWriteWatcher.StopWatchingFileDescriptor();
}
// DBus utility functions, used as function pointers in DBus setup
void
DBusWatcher::FreeFunction(void* aData)
{
delete static_cast<DBusWatcher*>(aData);
}
dbus_bool_t
DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
{
MOZ_ASSERT(aData);
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
return dbusWatcher->AddWatch(aWatch);
MOZ_ASSERT(!NS_IsMainThread());
RawDBusConnection* connection = static_cast<RawDBusConnection*>(aData);
DBusWatcher* dbusWatcher = new DBusWatcher(connection, aWatch);
dbus_watch_set_data(aWatch, dbusWatcher, DBusWatcher::FreeFunction);
if (dbus_watch_get_enabled(aWatch)) {
dbusWatcher->StartWatching();
}
return TRUE;
}
void
DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
{
MOZ_ASSERT(aData);
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
dbusWatcher->RemoveWatch(aWatch);
MOZ_ASSERT(!NS_IsMainThread());
DBusWatcher* dbusWatcher =
static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
dbusWatcher->StopWatching();
}
void
DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
{
MOZ_ASSERT(aData);
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
MOZ_ASSERT(!NS_IsMainThread());
DBusWatcher* dbusWatcher =
static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
if (dbus_watch_get_enabled(aWatch)) {
dbusWatcher->AddWatch(aWatch);
dbusWatcher->StartWatching();
} else {
dbusWatcher->RemoveWatch(aWatch);
dbusWatcher->StopWatching();
}
}
void
DBusWatcher::DBusWakeupFunction(void* aData)
{
MOZ_ASSERT(aData);
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
dbusWatcher->WakeUp();
}
bool
DBusWatcher::SetUp()
DBusWatcher::OnFileCanReadWithoutBlocking(int aFd)
{
MOZ_ASSERT(!NS_IsMainThread());
// If we already have a connection, exit
if (mConnection) {
return false;
}
dbus_watch_handle(mWatch, DBUS_WATCH_READABLE);
// socketpair opens two sockets for the process to communicate on.
// This is how android's implementation of the dbus event loop
// communicates with itself in relation to IPC signals. These
// sockets are contained sequentially in the same struct in the
// android code, but we break them out into class members here.
// Therefore we read into a local array and then copy.
int sockets[2];
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets) < 0) {
return false;
}
mControlFdR.rwget() = sockets[0];
mControlFdW.rwget() = sockets[1];
pollfd* p = mPollData.AppendElement();
p->fd = mControlFdR.get();
p->events = POLLIN;
p->revents = 0;
// Due to the fact that mPollData and mWatchData have to match, we
// push a null to the front of mWatchData since it has the control
// fd in the first slot of mPollData.
mWatchData.AppendElement(static_cast<DBusWatch*>(nullptr));
// If we can't establish a connection to dbus, nothing else will work
nsresult rv = EstablishDBusConnection();
if (NS_FAILED(rv)) {
NS_WARNING("Cannot create DBus Connection for DBus Thread!");
return false;
}
dbus_bool_t success =
dbus_connection_set_watch_functions(mConnection, AddWatchFunction,
RemoveWatchFunction,
ToggleWatchFunction, this, nullptr);
NS_ENSURE_TRUE(success == TRUE, false);
dbus_connection_set_wakeup_main_function(mConnection, DBusWakeupFunction,
this, nullptr);
return true;
DBusDispatchStatus dbusDispatchStatus;
do {
dbusDispatchStatus =
dbus_connection_dispatch(mConnection->GetConnection());
} while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
}
// Main task for polling the DBus system
void
DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd)
{
MOZ_ASSERT(!NS_IsMainThread());
class DBusPollTask : public nsRunnable
dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE);
}
class WatchDBusConnectionTask : public Task
{
public:
DBusPollTask(DBusWatcher* aDBusWatcher)
: mDBusWatcher(aDBusWatcher)
{ }
WatchDBusConnectionTask(RawDBusConnection* aConnection)
: mConnection(aConnection)
{
MOZ_ASSERT(mConnection);
}
NS_IMETHOD Run()
void Run()
{
MOZ_ASSERT(!NS_IsMainThread());
bool continueThread;
do {
continueThread = mDBusWatcher->Poll();
} while (continueThread);
mDBusWatcher->CleanUp();
nsIThread* thread;
nsresult rv = NS_GetCurrentThread(&thread);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(thread, &nsIThread::Shutdown);
rv = NS_DispatchToMainThread(runnable);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
dbus_bool_t success =
dbus_connection_set_watch_functions(mConnection->GetConnection(),
DBusWatcher::AddWatchFunction,
DBusWatcher::RemoveWatchFunction,
DBusWatcher::ToggleWatchFunction,
mConnection, nullptr);
NS_ENSURE_TRUE_VOID(success == TRUE);
}
private:
nsRefPtr<DBusWatcher> mDBusWatcher;
RawDBusConnection* mConnection;
};
static StaticRefPtr<DBusWatcher> gDBusWatcher;
static StaticRefPtr<nsIThread> gDBusServiceThread;
class DeleteDBusConnectionTask : public Task
{
public:
DeleteDBusConnectionTask(RawDBusConnection* aConnection)
: mConnection(aConnection)
{
MOZ_ASSERT(mConnection);
}
// Startup/Shutdown utility functions
void Run()
{
MOZ_ASSERT(!NS_IsMainThread());
// This command closes the DBus connection and all instances of
// DBusWatch will be removed and free'd.
delete mConnection;
}
private:
RawDBusConnection* mConnection;
};
// Startup/Shutdown utility functions
static RawDBusConnection* gDBusConnection;
bool
StartDBus()
{
MOZ_ASSERT(!NS_IsMainThread());
NS_ENSURE_TRUE(!gDBusWatcher, true);
NS_ENSURE_TRUE(!gDBusConnection, true);
nsRefPtr<DBusWatcher> dbusWatcher(new DBusWatcher());
bool eventLoopStarted = dbusWatcher->Initialize();
NS_ENSURE_TRUE(eventLoopStarted, false);
nsresult rv;
if (!gDBusServiceThread) {
nsIThread* dbusServiceThread;
rv = NS_NewNamedThread("DBus Thread", &dbusServiceThread);
NS_ENSURE_SUCCESS(rv, false);
gDBusServiceThread = dbusServiceThread;
}
#ifdef DEBUG
LOG("DBus Thread Starting\n");
#endif
nsRefPtr<nsIRunnable> pollTask(new DBusPollTask(dbusWatcher));
NS_ENSURE_TRUE(pollTask, false);
rv = gDBusServiceThread->Dispatch(pollTask, NS_DISPATCH_NORMAL);
RawDBusConnection* connection = new RawDBusConnection();
nsresult rv = connection->EstablishDBusConnection();
NS_ENSURE_SUCCESS(rv, false);
gDBusWatcher = dbusWatcher;
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new WatchDBusConnectionTask(connection));
gDBusConnection = connection;
return true;
}
@ -612,36 +282,32 @@ bool
StopDBus()
{
MOZ_ASSERT(!NS_IsMainThread());
NS_ENSURE_TRUE(gDBusServiceThread, true);
NS_ENSURE_TRUE(gDBusConnection, true);
nsRefPtr<DBusWatcher> dbusWatcher(gDBusWatcher);
gDBusWatcher = nullptr;
RawDBusConnection* connection = gDBusConnection;
gDBusConnection = nullptr;
if (dbusWatcher && !dbusWatcher->Stop()) {
return false;
}
gDBusServiceThread = nullptr;
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new DeleteDBusConnectionTask(connection));
return true;
}
nsresult
DispatchToDBusThread(nsIRunnable* event)
DispatchToDBusThread(Task* task)
{
nsRefPtr<nsIThread> dbusServiceThread(gDBusServiceThread);
nsRefPtr<DBusWatcher> dbusWatcher(gDBusWatcher);
NS_ENSURE_TRUE(dbusServiceThread.get() && dbusWatcher.get(),
NS_ERROR_NOT_INITIALIZED);
nsresult rv = dbusServiceThread->Dispatch(event, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
dbusWatcher->WakeUp();
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, task);
return NS_OK;
}
RawDBusConnection*
GetDBusConnection()
{
NS_ENSURE_TRUE(gDBusConnection, nullptr);
return gDBusConnection;
}
}
}

View File

@ -9,11 +9,13 @@
#include "nscore.h"
class nsIRunnable;
class Task;
namespace mozilla {
namespace ipc {
class RawDBusConnection;
/**
* Starts the DBus thread, which handles returning signals to objects
* that call asynchronous functions. This should be called from the
@ -32,13 +34,21 @@ bool StartDBus();
bool StopDBus();
/**
* Dispatch an event to the DBus thread
* Dispatch a task to the DBus I/O thread
*
* @param event An nsIRunnable to run in the DBus thread
* @param task A task to run on the DBus I/O thread
* @return NS_OK on success, or an error code otherwise
*/
nsresult
DispatchToDBusThread(nsIRunnable* event);
DispatchToDBusThread(Task* task);
/**
* Returns the connection to the DBus server
*
* @return The DBus connection on success, or nullptr otherwise
*/
RawDBusConnection*
GetDBusConnection(void);
}
}

View File

@ -5,6 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <dbus/dbus.h>
#include "base/message_loop.h"
#include "mozilla/Monitor.h"
#include "nsThreadUtils.h"
#include "DBusThread.h"
@ -34,11 +35,15 @@ using namespace mozilla::ipc;
namespace mozilla {
namespace ipc {
class DBusConnectionSendRunnableBase : public nsRunnable
class DBusConnectionSendTaskBase : public Task
{
public:
virtual ~DBusConnectionSendTaskBase()
{ }
protected:
DBusConnectionSendRunnableBase(DBusConnection* aConnection,
DBusMessage* aMessage)
DBusConnectionSendTaskBase(DBusConnection* aConnection,
DBusMessage* aMessage)
: mConnection(aConnection),
mMessage(aMessage)
{
@ -46,9 +51,6 @@ protected:
MOZ_ASSERT(mMessage);
}
virtual ~DBusConnectionSendRunnableBase()
{ }
DBusConnection* mConnection;
DBusMessageRefPtr mMessage;
};
@ -57,35 +59,33 @@ protected:
// Sends a message and returns the message's serial number to the
// disaptching thread. Only run it in DBus thread.
//
class DBusConnectionSendRunnable : public DBusConnectionSendRunnableBase
class DBusConnectionSendTask : public DBusConnectionSendTaskBase
{
public:
DBusConnectionSendRunnable(DBusConnection* aConnection,
DBusMessage* aMessage)
: DBusConnectionSendRunnableBase(aConnection, aMessage)
DBusConnectionSendTask(DBusConnection* aConnection,
DBusMessage* aMessage)
: DBusConnectionSendTaskBase(aConnection, aMessage)
{ }
NS_IMETHOD Run()
virtual ~DBusConnectionSendTask()
{ }
void Run() MOZ_OVERRIDE
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(MessageLoop::current());
dbus_bool_t success = dbus_connection_send(mConnection, mMessage, nullptr);
NS_ENSURE_TRUE(success == TRUE, NS_ERROR_FAILURE);
return NS_OK;
dbus_bool_t success = dbus_connection_send(mConnection,
mMessage,
nullptr);
NS_ENSURE_TRUE_VOID(success == TRUE);
}
protected:
~DBusConnectionSendRunnable()
{ }
};
//
// Sends a message and executes a callback function for the reply. Only
// run it in DBus thread.
//
class DBusConnectionSendWithReplyRunnable : public DBusConnectionSendRunnableBase
class DBusConnectionSendWithReplyTask : public DBusConnectionSendTaskBase
{
private:
class NotifyData
@ -130,24 +130,27 @@ private:
}
public:
DBusConnectionSendWithReplyRunnable(DBusConnection* aConnection,
DBusMessage* aMessage,
int aTimeout,
DBusReplyCallback aCallback,
void* aData)
: DBusConnectionSendRunnableBase(aConnection, aMessage),
DBusConnectionSendWithReplyTask(DBusConnection* aConnection,
DBusMessage* aMessage,
int aTimeout,
DBusReplyCallback aCallback,
void* aData)
: DBusConnectionSendTaskBase(aConnection, aMessage),
mCallback(aCallback),
mData(aData),
mTimeout(aTimeout)
{ }
NS_IMETHOD Run()
virtual ~DBusConnectionSendWithReplyTask()
{ }
void Run() MOZ_OVERRIDE
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(MessageLoop::current());
// Freed at end of Notify
nsAutoPtr<NotifyData> data(new NotifyData(mCallback, mData));
NS_ENSURE_TRUE(data, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE_VOID(data);
DBusPendingCall* call;
@ -155,21 +158,15 @@ public:
mMessage,
&call,
mTimeout);
NS_ENSURE_TRUE(success == TRUE, NS_ERROR_FAILURE);
NS_ENSURE_TRUE_VOID(success == TRUE);
success = dbus_pending_call_set_notify(call, Notify, data, nullptr);
NS_ENSURE_TRUE(success == TRUE, NS_ERROR_FAILURE);
NS_ENSURE_TRUE_VOID(success == TRUE);
data.forget();
dbus_message_unref(mMessage);
return NS_OK;
};
protected:
~DBusConnectionSendWithReplyRunnable()
{ }
private:
DBusReplyCallback mCallback;
void* mData;
@ -202,7 +199,7 @@ nsresult RawDBusConnection::EstablishDBusConnection()
}
DBusError err;
dbus_error_init(&err);
mConnection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
mConnection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
if (dbus_error_is_set(&err)) {
dbus_error_free(&err);
return NS_ERROR_FAILURE;
@ -214,14 +211,15 @@ nsresult RawDBusConnection::EstablishDBusConnection()
void RawDBusConnection::ScopedDBusConnectionPtrTraits::release(DBusConnection* ptr)
{
if (ptr) {
dbus_connection_close(ptr);
dbus_connection_unref(ptr);
}
}
bool RawDBusConnection::Send(DBusMessage* aMessage)
{
nsRefPtr<DBusConnectionSendRunnable> t(
new DBusConnectionSendRunnable(mConnection, aMessage));
DBusConnectionSendTask* t =
new DBusConnectionSendTask(mConnection, aMessage);
MOZ_ASSERT(t);
nsresult rv = DispatchToDBusThread(t);
@ -241,9 +239,9 @@ bool RawDBusConnection::SendWithReply(DBusReplyCallback aCallback,
int aTimeout,
DBusMessage* aMessage)
{
nsRefPtr<nsIRunnable> t(
new DBusConnectionSendWithReplyRunnable(mConnection, aMessage,
aTimeout, aCallback, aData));
DBusConnectionSendWithReplyTask* t =
new DBusConnectionSendWithReplyTask(mConnection, aMessage, aTimeout,
aCallback, aData);
MOZ_ASSERT(t);
nsresult rv = DispatchToDBusThread(t);

View File

@ -14,7 +14,6 @@
#include <string>
#include "nscore.h"
#include "mozilla/Scoped.h"
#include <mozilla/RefPtr.h>
#include <mozilla/Mutex.h>
struct DBusConnection;
@ -26,7 +25,7 @@ namespace ipc {
typedef void (*DBusReplyCallback)(DBusMessage*, void*);
class RawDBusConnection : public AtomicRefCounted<RawDBusConnection>
class RawDBusConnection
{
struct ScopedDBusConnectionPtrTraits : ScopedFreePtrTraits<DBusConnection>
{

View File

@ -215,4 +215,41 @@ nsFrame::PrintDisplayList(nsDisplayListBuilder* aBuilder,
PrintDisplayListTo(aBuilder, aList, aFile, aDumpHtml);
}
static void
PrintDisplayListSetItem(nsDisplayListBuilder* aBuilder,
const char* aItemName,
const nsDisplayList& aList,
FILE* aFile,
bool aDumpHtml)
{
if (aDumpHtml) {
fprintf_stderr(aFile, "<li>");
}
fprintf_stderr(aFile, "%s", aItemName);
PrintDisplayListTo(aBuilder, aList, aFile, aDumpHtml);
if (aDumpHtml) {
fprintf_stderr(aFile, "</li>");
}
}
void
nsFrame::PrintDisplayListSet(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aSet,
FILE *aFile,
bool aDumpHtml)
{
if (aDumpHtml) {
fprintf_stderr(aFile, "<ul>");
}
PrintDisplayListSetItem(aBuilder, "[BorderBackground]", *(aSet.BorderBackground()), aFile, aDumpHtml);
PrintDisplayListSetItem(aBuilder, "[BlockBorderBackgrounds]", *(aSet.BlockBorderBackgrounds()), aFile, aDumpHtml);
PrintDisplayListSetItem(aBuilder, "[Floats]", *(aSet.Floats()), aFile, aDumpHtml);
PrintDisplayListSetItem(aBuilder, "[PositionedDescendants]", *(aSet.PositionedDescendants()), aFile, aDumpHtml);
PrintDisplayListSetItem(aBuilder, "[Outlines]", *(aSet.Outlines()), aFile, aDumpHtml);
PrintDisplayListSetItem(aBuilder, "[Content]", *(aSet.Content()), aFile, aDumpHtml);
if (aDumpHtml) {
fprintf_stderr(aFile, "</ul>");
}
}
#endif

View File

@ -713,6 +713,10 @@ public:
const nsDisplayList& aList,
FILE* aFile = stdout,
bool aDumpHtml = false);
static void PrintDisplayListSet(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aList,
FILE* aFile = stdout,
bool aDumpHtml = false);
#endif
};

View File

@ -6,6 +6,7 @@
[include:dom/mobilemessage/tests/xpcshell.ini]
[include:dom/network/tests/unit_stats/xpcshell.ini]
[include:dom/system/gonk/tests/xpcshell.ini]
[include:dom/wappush/tests/xpcshell.ini]
[include:toolkit/devtools/apps/tests/unit/xpcshell.ini]
[include:toolkit/devtools/debugger/tests/unit/xpcshell.ini]
[include:toolkit/devtools/sourcemap/tests/unit/xpcshell.ini]

View File

@ -64,6 +64,7 @@ HwcComposer2D::HwcComposer2D()
, mColorFill(false)
, mRBSwapSupport(false)
, mPrevRetireFence(-1)
, mPrepared(false)
{
}
@ -451,7 +452,6 @@ HwcComposer2D::TryHwComposition()
if (!(fbsurface && fbsurface->lastHandle)) {
LOGD("H/W Composition failed. FBSurface not initialized.");
mList->numHwLayers = 0;
return false;
}
@ -460,7 +460,6 @@ HwcComposer2D::TryHwComposition()
if (idx >= mMaxLayerCount) {
if (!ReallocLayerList() || idx >= mMaxLayerCount) {
LOGE("TryHwComposition failed! Could not add FB layer");
mList->numHwLayers = 0;
return false;
}
}
@ -495,7 +494,6 @@ HwcComposer2D::TryHwComposition()
// No composition on FB layer, so closing releaseFenceFd
close(mList->hwLayers[idx].releaseFenceFd);
mList->numHwLayers = 0;
return true;
}
@ -515,7 +513,7 @@ HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur)
return false;
}
if (mList->numHwLayers != 0) {
if (mPrepared) {
// No mHwc prepare, if already prepared in current draw cycle
mList->hwLayers[mList->numHwLayers - 1].handle = fbsurface->lastHandle;
mList->hwLayers[mList->numHwLayers - 1].acquireFenceFd = fbsurface->lastFenceFD;
@ -535,7 +533,6 @@ HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur)
Commit();
GetGonkDisplay()->SetFBReleaseFd(mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd);
mList->numHwLayers = 0;
return true;
}
@ -566,7 +563,11 @@ HwcComposer2D::Prepare(buffer_handle_t fbHandle, int fence)
mList->hwLayers[idx].releaseFenceFd = -1;
mList->hwLayers[idx].planeAlpha = 0xFF;
if (mPrepared) {
LOGE("Multiple hwc prepare calls!");
}
mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
mPrepared = true;
}
bool
@ -609,8 +610,19 @@ HwcComposer2D::Commit()
}
}
mPrepared = false;
return !err;
}
void
HwcComposer2D::Reset()
{
LOGD("hwcomposer is already prepared, reset with null set");
hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr };
displays[HWC_DISPLAY_PRIMARY] = nullptr;
mHwc->set(mHwc, HWC_DISPLAY_PRIMARY, displays);
mPrepared = false;
}
#else
bool
HwcComposer2D::TryHwComposition()
@ -623,6 +635,12 @@ HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur)
{
return GetGonkDisplay()->SwapBuffers(dpy, sur);
}
void
HwcComposer2D::Reset()
{
mPrepared = false;
}
#endif
bool
@ -640,6 +658,10 @@ HwcComposer2D::TryRender(Layer* aRoot,
mHwcLayerMap.Clear();
}
if (mPrepared) {
Reset();
}
// XXX: The clear() below means all rect vectors will be have to be
// reallocated. We may want to avoid this if possible
mVisibleRegions.clear();
@ -651,9 +673,6 @@ HwcComposer2D::TryRender(Layer* aRoot,
aGLWorldTransform))
{
LOGD("Render aborted. Nothing was drawn to the screen");
if (mList) {
mList->numHwLayers = 0;
}
return false;
}

View File

@ -63,6 +63,7 @@ public:
bool Render(EGLDisplay dpy, EGLSurface sur);
private:
void Reset();
void Prepare(buffer_handle_t fbHandle, int fence);
bool Commit();
bool TryHwComposition();
@ -84,6 +85,7 @@ private:
nsTArray<int> mPrevReleaseFds;
int mPrevRetireFence;
nsTArray<layers::LayerComposite*> mHwcLayerMap;
bool mPrepared;
};
} // namespace mozilla