Merge mozilla-central and b2g-inbound

This commit is contained in:
Ed Morley 2013-10-25 12:12:23 +01:00
commit ae834488ea
14 changed files with 653 additions and 393 deletions

View File

@ -1,4 +1,4 @@
{
"revision": "e3564b8656fcd189d4a83379e94bef1ab7d657b5",
"revision": "d9d422e52a7a45dfb075fd2bf4fd48c956276baa",
"repo_path": "/integration/gaia-central"
}

View File

@ -1578,27 +1578,31 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
return DBUS_HANDLER_RESULT_HANDLED;
}
static bool
GetDefaultAdapterPath(BluetoothValue& aValue, nsString& aError)
static void
OnDefaultAdapterReply(DBusMessage* aReply, void* aData)
{
// This could block. It should never be run on the main thread.
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!NS_IsMainThread()); // DBus thread
if (!aReply || dbus_message_is_error(aReply, DBUS_ERROR_TIMEOUT)) {
return;
}
DBusError err;
dbus_error_init(&err);
DBusMessage* msg;
bool success = gThreadConnection->SendWithError(&msg, &err, 1000, "/",
DBUS_MANAGER_IFACE,
"DefaultAdapter",
DBUS_TYPE_INVALID);
NS_ENSURE_TRUE(success, false);
BluetoothValue v;
nsAutoString errorString;
UnpackObjectPathMessage(msg, &err, aValue, aError);
UnpackObjectPathMessage(aReply, &err, v, errorString);
dbus_message_unref(msg);
if (!errorString.IsEmpty()) {
return;
}
return aError.IsEmpty();
nsRefPtr<PrepareAdapterRunnable> b = new PrepareAdapterRunnable(v.get_nsString());
if (NS_FAILED(NS_DispatchToMainThread(b))) {
BT_WARNING("Failed to dispatch to main thread!");
}
}
bool
@ -1669,17 +1673,17 @@ BluetoothDBusService::StartInternal()
sPairingReqTable = new nsDataHashtable<nsStringHashKey, DBusMessage* >;
}
BluetoothValue v;
nsAutoString replyError;
if (!GetDefaultAdapterPath(v, replyError)) {
// Adapter path is not ready yet
// Let's do PrepareAdapterRunnable when we receive signal 'AdapterAdded'
} else {
// Adapter path has been ready. let's do PrepareAdapterRunnable now
nsRefPtr<PrepareAdapterRunnable> b = new PrepareAdapterRunnable(v.get_nsString());
if (NS_FAILED(NS_DispatchToMainThread(b))) {
BT_WARNING("Failed to dispatch to main thread!");
}
// Normally we'll receive the signal 'AdapterAdded' for the default
// adapter from the DBus daemon during start up. If we restart after
// a crash, the default adapter might already be available, so we ask
// the daemon explicitly here.
bool success = mConnection->SendWithReply(OnDefaultAdapterReply, nullptr,
1000, "/",
DBUS_ADAPTER_IFACE,
"DefaultAdapter",
DBUS_TYPE_INVALID);
if (!success) {
BT_WARNING("Failed to query default adapter!");
}
return NS_OK;

View File

@ -18,7 +18,6 @@
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
Cu.import("resource://gre/modules/ObjectWrapper.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -1768,8 +1767,7 @@ RILContentHelper.prototype = {
return contact;
});
this.fireRequestSuccess(message.requestId,
ObjectWrapper.wrap(result, window));
this.fireRequestSuccess(message.requestId, result);
},
handleVoicemailNotification: function handleVoicemailNotification(message) {

View File

@ -3237,8 +3237,10 @@ RILNetworkInterface.prototype = {
classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINTERFACE_CID,
classDescription: "RILNetworkInterface",
interfaces: [Ci.nsINetworkInterface,
Ci.nsIRilNetworkInterface,
Ci.nsIRILDataCallback]}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface,
Ci.nsIRilNetworkInterface,
Ci.nsIRILDataCallback]),
// nsINetworkInterface
@ -3304,6 +3306,15 @@ RILNetworkInterface.prototype = {
return this.apnSetting.port || '';
},
get serviceId() {
return this.radioInterface.clientId;
},
get iccId() {
let iccInfo = this.radioInterface.rilContext.iccInfo;
return iccInfo && iccInfo.iccid;
},
debug: function debug(s) {
dump("-*- RILNetworkInterface[" + this.radioInterface.clientId + ":" +
this.type + "]: " + s + "\n");

View File

@ -3,11 +3,19 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
#include "nsINetworkManager.idl"
interface nsIDOMMozIccInfo;
interface nsIDOMMozMobileConnectionInfo;
interface nsIMobileMessageCallback;
[scriptable, uuid(a15769f1-538e-4b4b-81da-c52866d38f88)]
interface nsIRilNetworkInterface : nsINetworkInterface
{
readonly attribute unsigned long serviceId;
readonly attribute DOMString iccId;
};
[scriptable, uuid(1e602d20-d066-4399-8997-daf36b3158ef)]
interface nsIRILDataCallInfo : nsISupports
{

View File

@ -86,6 +86,9 @@ let RILQUIRKS_EXTRA_UINT32_2ND_CALL = libcutils.property_get("ro.moz.ril.extra_i
// On the emulator we support querying the number of lock retries
let RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = libcutils.property_get("ro.moz.ril.query_icc_count", "false") == "true";
// Ril quirk to Send STK Profile Download
let RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") == "true";
// Marker object.
let PENDING_NETWORK_TYPE = {};
@ -3014,10 +3017,14 @@ let RIL = {
ICCRecordHelper.readICCPhase();
ICCRecordHelper.fetchICCRecords();
} else if (this.appType == CARD_APPTYPE_USIM) {
this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) {
this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
}
ICCRecordHelper.fetchICCRecords();
} else if (this.appType == CARD_APPTYPE_RUIM) {
this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) {
this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
}
RuimRecordHelper.fetchRuimRecords();
}
this.reportStkServiceIsRunning();
@ -10382,7 +10389,7 @@ let ComprehensionTlvHelper = {
} else {
RIL.sendStkTerminalResponse({
resultCode: STK_RESULT_CMD_DATA_NOT_UNDERSTOOD});
throw new Error("Invalid octet in Comprehension TLV :" + length);
throw new Error("Invalid octet in Comprehension TLV :" + temp);
}
let ctlv = {
@ -11026,7 +11033,8 @@ let ICCRecordHelper = {
let phase = GsmPDUHelper.readHexOctet();
// If EF_phase is coded '03' or greater, an ME supporting STK shall
// perform the PROFILE DOWNLOAD procedure.
if (phase >= ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED) {
if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD &&
phase >= ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED) {
RIL.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
}

View File

@ -61,6 +61,31 @@ function newUint8SupportOutgoingIndexWorker() {
}
// Test RIL requests related to STK.
/**
* Verify if RIL.sendStkTerminalProfile be called.
*/
add_test(function test_if_send_stk_terminal_profile() {
let worker = newUint8Worker();
let profileSend = false;
worker.RIL.sendStkTerminalProfile = function (data) {
profileSend = true;
};
let iccStatus = {
gsmUmtsSubscriptionAppIndex: 0,
apps: [{
app_state: CARD_APPSTATE_READY,
app_type: CARD_APPTYPE_USIM
}],
};
worker.RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = false;
worker.RIL._processICCStatus(iccStatus);
do_check_eq(profileSend, false);
run_next_test();
});
/**
* Verify RIL.sendStkTerminalProfile

View File

@ -117,7 +117,11 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
apzc = container->GetAsyncPanZoomController();
bool newApzc = (apzc == nullptr);
// The APZC we get off the layer may have been destroyed previously if the layer was inactive
// or omitted from the layer tree for whatever reason from a layers update. If it later comes
// back it will have a reference to a destroyed APZC and so we need to throw that out and make
// a new one.
bool newApzc = (apzc == nullptr || apzc->IsDestroyed());
if (newApzc) {
apzc = new AsyncPanZoomController(aLayersId, this, state->mController,
AsyncPanZoomController::USE_GESTURE_DETECTOR);

View File

@ -326,6 +326,12 @@ AsyncPanZoomController::Destroy()
mTreeManager = nullptr;
}
bool
AsyncPanZoomController::IsDestroyed()
{
return mTreeManager == nullptr;
}
/* static */float
AsyncPanZoomController::GetTouchStartTolerance()
{

View File

@ -203,6 +203,11 @@ public:
*/
void Destroy();
/**
* Returns true if Destroy() has already been called on this APZC instance.
*/
bool IsDestroyed();
/**
* Returns the incremental transformation corresponding to the async pan/zoom
* in progress. That is, when this transform is multiplied with the layer's

View File

@ -69,56 +69,31 @@
#define DEFAULT_INITIAL_POLLFD_COUNT 8
// Functions for converting between unix events in the poll struct,
// and their dbus definitions
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)
{
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);
}
static short 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);
}
namespace mozilla {
namespace ipc {
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;
}
};
// DBus Thread Class prototype
struct DBusThread : public RawDBusConnection
class DBusWatcher : public RawDBusConnection
{
DBusThread();
~DBusThread();
public:
DBusWatcher()
{ }
~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
@ -131,131 +106,302 @@ struct DBusThread : public RawDBusConnection
ScopedClose mControlFdR;
ScopedClose mControlFdW;
protected:
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);
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();
};
// DBus utility functions
// Free statics, as they're used as function pointers in dbus setup
static dbus_bool_t
AddWatch(DBusWatch *aWatch, void *aData)
bool
DBusWatcher::Initialize()
{
DBusThread *dbt = (DBusThread *)aData;
if (dbus_watch_get_enabled(aWatch)) {
// 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.
char control = DBUS_EVENT_LOOP_ADD;
if (write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
LOG("Cannot write DBus add watch control data to socket!\n");
return false;
}
int fd = dbus_watch_get_unix_fd(aWatch);
if (write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
LOG("Cannot write DBus add watch descriptor data to socket!\n");
return false;
}
unsigned int flags = dbus_watch_get_flags(aWatch);
if (write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
LOG("Cannot write DBus add watch flag data to socket!\n");
return false;
}
if (write(dbt->mControlFdW.get(), &aWatch, sizeof(DBusWatch*)) < 0) {
LOG("Cannot write DBus add watch struct data to socket!\n");
return false;
}
if (!SetUp()) {
CleanUp();
return false;
}
return true;
}
static void
RemoveWatch(DBusWatch *aWatch, void *aData)
void
DBusWatcher::CleanUp()
{
DBusThread *dbt = (DBusThread *)aData;
MOZ_ASSERT(!NS_IsMainThread());
char control = DBUS_EVENT_LOOP_REMOVE;
if (write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
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, NS_OK);
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;
unsigned int flags = UnixEventsToDBusFlags(events);
dbus_watch_handle(mWatchData[i], flags);
mPollData[i].revents = 0;
// Break at this point since we don't know if the operation
// was destructive
break;
}
DBusDispatchStatus dbusDispatchStatus;
do {
dbusDispatchStatus = dbus_connection_dispatch(GetConnection());
} while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
}
++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);
if (write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
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);
if (write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
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;
}
}
static void
ToggleWatch(DBusWatch *aWatch, void *aData)
void
DBusWatcher::HandleWatchAdd()
{
if (dbus_watch_get_enabled(aWatch)) {
AddWatch(aWatch, aData);
} else {
RemoveWatch(aWatch, aData);
}
}
static void
HandleWatchAdd(DBusThread* aDbt)
{
DBusWatch *watch;
int newFD;
unsigned int flags;
if (read(aDbt->mControlFdR.get(), &newFD, sizeof(int)) < 0) {
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;
}
if (read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
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;
}
if (read(aDbt->mControlFdR.get(), &watch, sizeof(DBusWatch *)) < 0) {
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;
}
short events = DBusFlagsToUnixEvents(flags);
pollfd p;
p.fd = newFD;
p.revents = 0;
p.events = events;
if (aDbt->mPollData.Contains(p, PollFdComparator())) return;
aDbt->mPollData.AppendElement(p);
aDbt->mWatchData.AppendElement(watch);
struct pollfd p = {
fd, // .fd
DBusFlagsToUnixEvents(flags), // .events
0 // .revents
};
if (mPollData.Contains(p, PollFdComparator())) {
return;
}
mPollData.AppendElement(p);
mWatchData.AppendElement(watch);
}
static void
HandleWatchRemove(DBusThread* aDbt)
void
DBusWatcher::HandleWatchRemove()
{
int removeFD;
unsigned int flags;
if (read(aDbt->mControlFdR.get(), &removeFD, sizeof(int)) < 0) {
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;
}
if (read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
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;
}
short events = DBusFlagsToUnixEvents(flags);
pollfd p;
p.fd = removeFD;
p.events = events;
int index = aDbt->mPollData.IndexOf(p, 0, PollFdComparator());
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
@ -264,34 +410,74 @@ HandleWatchRemove(DBusThread* aDbt)
LOG("DBus requested watch removal of non-existant socket, ignoring...");
return;
}
aDbt->mPollData.RemoveElementAt(index);
mPollData.RemoveElementAt(index);
// DBusWatch pointers are maintained by DBus, so we won't leak by
// removing.
aDbt->mWatchData.RemoveElementAt(index);
mWatchData.RemoveElementAt(index);
}
static
void DBusWakeup(void* aData)
// 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);
}
// DBus utility functions, used as function pointers in DBus setup
dbus_bool_t
DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
{
MOZ_ASSERT(aData);
DBusThread* dbusThread = static_cast<DBusThread*>(aData);
dbusThread->WakeUp();
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
return dbusWatcher->AddWatch(aWatch);
}
// DBus Thread Implementation
DBusThread::DBusThread()
void
DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
{
MOZ_ASSERT(aData);
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
dbusWatcher->RemoveWatch(aWatch);
}
DBusThread::~DBusThread()
void
DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
{
MOZ_ASSERT(aData);
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
if (dbus_watch_get_enabled(aWatch)) {
dbusWatcher->AddWatch(aWatch);
} else {
dbusWatcher->RemoveWatch(aWatch);
}
}
void
DBusWatcher::DBusWakeupFunction(void* aData)
{
MOZ_ASSERT(aData);
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
dbusWatcher->WakeUp();
}
bool
DBusThread::SetUp()
DBusWatcher::SetUp()
{
MOZ_ASSERT(!NS_IsMainThread());
@ -315,7 +501,7 @@ DBusThread::SetUp()
mControlFdR.rwget() = sockets[0];
mControlFdW.rwget() = sockets[1];
pollfd *p = mPollData.AppendElement();
pollfd* p = mPollData.AppendElement();
p->fd = mControlFdR.get();
p->events = POLLIN;
@ -335,161 +521,55 @@ DBusThread::SetUp()
}
dbus_bool_t success =
dbus_connection_set_watch_functions(mConnection, AddWatch, RemoveWatch,
ToggleWatch, this, nullptr);
dbus_connection_set_watch_functions(mConnection, AddWatchFunction,
RemoveWatchFunction,
ToggleWatchFunction, this, nullptr);
NS_ENSURE_TRUE(success == TRUE, false);
dbus_connection_set_wakeup_main_function(mConnection, DBusWakeup, this, nullptr);
dbus_connection_set_wakeup_main_function(mConnection, DBusWakeupFunction,
this, nullptr);
return true;
}
bool
DBusThread::Initialize()
{
if (!SetUp()) {
CleanUp();
return false;
}
return true;
}
void
DBusThread::CleanUp()
{
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
DBusThread::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 rv = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &control, sizeof(control)));
if (rv < 0) {
NS_WARNING("Cannot write wakeup bit to DBus controller!");
}
}
// Main task for polling the DBus system
class DBusPollTask : public nsRunnable
{
public:
DBusPollTask(DBusThread* aConnection)
: mConnection(aConnection)
DBusPollTask(DBusWatcher* aDBusWatcher)
: mDBusWatcher(aDBusWatcher)
{ }
NS_IMETHOD Run()
{
MOZ_ASSERT(!NS_IsMainThread());
bool exitThread = false;
bool continueThread;
while (!exitThread) {
do {
continueThread = mDBusWatcher->Poll();
} while (continueThread);
int res = TEMP_FAILURE_RETRY(poll(mConnection->mPollData.Elements(),
mConnection->mPollData.Length(),
-1));
NS_ENSURE_TRUE(res > 0, NS_OK);
mDBusWatcher->CleanUp();
nsTArray<pollfd>::size_type i = 0;
nsIThread* thread;
nsresult rv = NS_GetCurrentThread(&thread);
NS_ENSURE_SUCCESS(rv, rv);
while (i < mConnection->mPollData.Length()) {
if (mConnection->mPollData[i].revents == POLLIN) {
if (mConnection->mPollData[i].fd == mConnection->mControlFdR.get()) {
char data;
res = TEMP_FAILURE_RETRY(read(mConnection->mControlFdR.get(), &data, sizeof(data)));
NS_ENSURE_TRUE(res > 0, NS_OK);
switch (data) {
case DBUS_EVENT_LOOP_EXIT:
exitThread = true;
break;
case DBUS_EVENT_LOOP_ADD:
HandleWatchAdd(mConnection);
break;
case DBUS_EVENT_LOOP_REMOVE:
HandleWatchRemove(mConnection);
// 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 = mConnection->mPollData[i].revents;
unsigned int flags = UnixEventsToDBusFlags(events);
dbus_watch_handle(mConnection->mWatchData[i], flags);
mConnection->mPollData[i].revents = 0;
// Break at this point since we don't know if the operation
// was destructive
break;
}
while (dbus_connection_dispatch(mConnection->GetConnection()) ==
DBUS_DISPATCH_DATA_REMAINS)
{}
}
++i;
}
}
mConnection->CleanUp();
nsRefPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(thread, &nsIThread::Shutdown);
rv = NS_DispatchToMainThread(runnable);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
private:
nsRefPtr<DBusThread> mConnection;
nsRefPtr<DBusWatcher> mDBusWatcher;
};
static StaticRefPtr<DBusThread> gDBusThread;
static StaticRefPtr<nsIThread> gDBusServiceThread;
static StaticRefPtr<DBusWatcher> gDBusWatcher;
static StaticRefPtr<nsIThread> gDBusServiceThread;
// Startup/Shutdown utility functions
@ -497,11 +577,11 @@ bool
StartDBus()
{
MOZ_ASSERT(!NS_IsMainThread());
NS_ENSURE_TRUE(!gDBusThread, true);
NS_ENSURE_TRUE(!gDBusWatcher, true);
nsRefPtr<DBusThread> dbusThread(new DBusThread());
nsRefPtr<DBusWatcher> dbusWatcher(new DBusWatcher());
bool eventLoopStarted = dbusThread->Initialize();
bool eventLoopStarted = dbusWatcher->Initialize();
NS_ENSURE_TRUE(eventLoopStarted, false);
nsresult rv;
@ -517,13 +597,13 @@ StartDBus()
LOG("DBus Thread Starting\n");
#endif
nsRefPtr<nsIRunnable> pollTask(new DBusPollTask(dbusThread));
nsRefPtr<nsIRunnable> pollTask(new DBusPollTask(dbusWatcher));
NS_ENSURE_TRUE(pollTask, false);
rv = gDBusServiceThread->Dispatch(pollTask, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, false);
gDBusThread = dbusThread;
gDBusWatcher = dbusWatcher;
return true;
}
@ -534,24 +614,15 @@ StopDBus()
MOZ_ASSERT(!NS_IsMainThread());
NS_ENSURE_TRUE(gDBusServiceThread, true);
nsRefPtr<DBusThread> dbusThread(gDBusThread);
gDBusThread = nullptr;
nsRefPtr<DBusWatcher> dbusWatcher(gDBusWatcher);
gDBusWatcher = nullptr;
if (dbusThread) {
static const char data = DBUS_EVENT_LOOP_EXIT;
ssize_t wret = TEMP_FAILURE_RETRY(write(dbusThread->mControlFdW.get(),
&data, sizeof(data)));
NS_ENSURE_TRUE(wret == 1, false);
if (dbusWatcher && !dbusWatcher->Stop()) {
return false;
}
nsRefPtr<nsIThread> dbusServiceThread(gDBusServiceThread);
gDBusServiceThread = nullptr;
nsRefPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(dbusServiceThread, &nsIThread::Shutdown);
nsresult rv = NS_DispatchToMainThread(runnable);
NS_ENSURE_SUCCESS(rv, false);
return true;
}
@ -559,15 +630,15 @@ nsresult
DispatchToDBusThread(nsIRunnable* event)
{
nsRefPtr<nsIThread> dbusServiceThread(gDBusServiceThread);
nsRefPtr<DBusThread> dbusThread(gDBusThread);
nsRefPtr<DBusWatcher> dbusWatcher(gDBusWatcher);
NS_ENSURE_TRUE(dbusServiceThread.get() && dbusThread.get(),
NS_ENSURE_TRUE(dbusServiceThread.get() && dbusWatcher.get(),
NS_ERROR_NOT_INITIALIZED);
nsresult rv = dbusServiceThread->Dispatch(event, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
dbusThread->WakeUp();
dbusWatcher->WakeUp();
return NS_OK;
}

View File

@ -456,39 +456,93 @@ void Sampler::UnregisterCurrentThread()
static struct sigaction old_sigstart_signal_handler;
const int SIGSTART = SIGUSR2;
static void StartSignalHandler(int signal, siginfo_t* info, void* context) {
static void freeArray(const char** array, int size) {
for (int i = 0; i < size; i++) {
free((void*) array[i]);
}
}
static uint32_t readCSVArray(char* csvList, const char** buffer) {
uint32_t count;
char* savePtr;
int newlinePos = strlen(csvList) - 1;
if (csvList[newlinePos] == '\n') {
csvList[newlinePos] = '\0';
}
char* item = strtok_r(csvList, ",", &savePtr);
for (count = 0; item; item = strtok_r(NULL, ",", &savePtr)) {
int length = strlen(item) + 1; // Include \0
char* newBuf = (char*) malloc(sizeof(char) * length);
buffer[count] = newBuf;
strncpy(newBuf, item, length);
count++;
}
return count;
}
// Currently support only the env variables
// reported in read_profiler_env
static void ReadProfilerVars(const char* fileName, const char** features,
uint32_t* featureCount, const char** threadNames, uint32_t* threadCount) {
FILE* file = fopen(fileName, "r");
const int bufferSize = 1024;
char line[bufferSize];
char* feature;
char* value;
char* savePtr;
if (file) {
while (fgets(line, bufferSize, file) != NULL) {
feature = strtok_r(line, "=", &savePtr);
value = strtok_r(NULL, "", &savePtr);
if (strncmp(feature, PROFILER_MODE, bufferSize) == 0) {
set_profiler_mode(value);
} else if (strncmp(feature, PROFILER_INTERVAL, bufferSize) == 0) {
set_profiler_interval(value);
} else if (strncmp(feature, PROFILER_ENTRIES, bufferSize) == 0) {
set_profiler_entries(value);
} else if (strncmp(feature, PROFILER_STACK, bufferSize) == 0) {
set_profiler_scan(value);
} else if (strncmp(feature, PROFILER_FEATURES, bufferSize) == 0) {
*featureCount = readCSVArray(value, features);
} else if (strncmp(feature, "threads", bufferSize) == 0) {
*threadCount = readCSVArray(value, threadNames);
}
}
fclose(file);
}
}
static void StartSignalHandler(int signal, siginfo_t* info, void* context) {
// XXX: Everything we do here is NOT async signal safe. We risk nasty things
// like deadlocks but we typically only do this once so it tends to be ok.
// See bug 909403
const char* threadName = NULL;
uint32_t threadCount = 0;
char thread[256];
// TODO support selecting features from profiler.options
const char* features[3] = {NULL, NULL, NULL};
uint32_t featureCount = 0;
features[0] = "leaf";
featureCount++;
features[1] = "js";
featureCount++;
const char* threadFeature = "threads";
uint32_t threadCount = 0;
std::ifstream infile;
infile.open("/data/local/tmp/profiler.options");
if (infile.is_open()) {
infile.getline(thread, 256);
threadName = thread;
threadCount = 1;
features[featureCount] = threadFeature;
featureCount++;
printf_stderr("Profiling only %s\n", threadName);
}
infile.close();
// Just allocate 10 features for now
// FIXME: these don't really point to const chars*
// So we free them later, but we don't want to change the const char**
// declaration in profiler_start. Annoying but ok for now.
const char* threadNames[10];
const char* features[10];
const char* profilerConfigFile = "/data/local/tmp/profiler.options";
ReadProfilerVars(profilerConfigFile, features, &featureCount, threadNames, &threadCount);
MOZ_ASSERT(featureCount < 10);
MOZ_ASSERT(threadCount < 10);
profiler_start(PROFILE_DEFAULT_ENTRY, 1,
features, featureCount,
&threadName, threadCount);
features, featureCount,
threadNames, threadCount);
freeArray(threadNames, threadCount);
freeArray(features, featureCount);
}
void OS::RegisterStartHandler()

View File

@ -46,6 +46,13 @@ int sLastFrameNumber = 0;
int sInitCount = 0; // Each init must have a matched shutdown.
static bool sIsProfiling = false; // is raced on
// env variables to control the profiler
const char* PROFILER_MODE = "MOZ_PROFILER_MODE";
const char* PROFILER_INTERVAL = "MOZ_PROFILER_INTERVAL";
const char* PROFILER_ENTRIES = "MOZ_PROFILER_ENTRIES";
const char* PROFILER_STACK = "MOZ_PROFILER_STACK_SCAN";
const char* PROFILER_FEATURES = "MOZ_PROFILING_FEATURES";
/* used to keep track of the last event that we sampled during */
unsigned int sLastSampledEventGeneration = 0;
@ -252,68 +259,112 @@ static inline const char* name_UnwMode(UnwMode m)
}
}
bool set_profiler_mode(const char* mode) {
if (mode) {
if (0 == strcmp(mode, "pseudo")) {
sUnwindMode = UnwPSEUDO;
return true;
}
else if (0 == strcmp(mode, "native") && is_native_unwinding_avail()) {
sUnwindMode = UnwNATIVE;
return true;
}
else if (0 == strcmp(mode, "combined") && is_native_unwinding_avail()) {
sUnwindMode = UnwCOMBINED;
return true;
} else {
return false;
}
}
return true;
}
bool set_profiler_interval(const char* interval) {
if (interval) {
errno = 0;
long int n = strtol(interval, (char**)NULL, 10);
if (errno == 0 && n >= 1 && n <= 1000) {
sUnwindInterval = n;
return true;
}
return false;
}
return true;
}
bool set_profiler_entries(const char* entries) {
if (entries) {
errno = 0;
long int n = strtol(entries, (char**)NULL, 10);
if (errno == 0 && n > 0) {
sProfileEntries = n;
return true;
}
return false;
}
return true;
}
bool set_profiler_scan(const char* scanCount) {
if (scanCount) {
errno = 0;
long int n = strtol(scanCount, (char**)NULL, 10);
if (errno == 0 && n >= 0 && n <= 100) {
sUnwindStackScan = n;
return true;
}
return false;
}
return true;
}
bool is_native_unwinding_avail() {
# if defined(HAVE_NATIVE_UNWIND)
return true;
#else
return false;
#endif
}
// Read env vars at startup, so as to set sUnwindMode and sInterval.
void read_profiler_env_vars()
{
bool nativeAvail = false;
# if defined(HAVE_NATIVE_UNWIND)
nativeAvail = true;
# endif
MOZ_ASSERT(sUnwindMode == UnwINVALID);
MOZ_ASSERT(sUnwindInterval == 0);
MOZ_ASSERT(sProfileEntries == 0);
bool nativeAvail = is_native_unwinding_avail();
/* Set defaults */
sUnwindMode = nativeAvail ? UnwCOMBINED : UnwPSEUDO;
sUnwindInterval = 0; /* We'll have to look elsewhere */
sProfileEntries = 0;
const char* strM = PR_GetEnv("MOZ_PROFILER_MODE");
const char* strI = PR_GetEnv("MOZ_PROFILER_INTERVAL");
const char* strE = PR_GetEnv("MOZ_PROFILER_ENTRIES");
const char* strF = PR_GetEnv("MOZ_PROFILER_STACK_SCAN");
const char* stackMode = PR_GetEnv(PROFILER_MODE);
const char* interval = PR_GetEnv(PROFILER_INTERVAL);
const char* entries = PR_GetEnv(PROFILER_ENTRIES);
const char* scanCount = PR_GetEnv(PROFILER_STACK);
if (strM) {
if (0 == strcmp(strM, "pseudo"))
sUnwindMode = UnwPSEUDO;
else if (0 == strcmp(strM, "native") && nativeAvail)
sUnwindMode = UnwNATIVE;
else if (0 == strcmp(strM, "combined") && nativeAvail)
sUnwindMode = UnwCOMBINED;
else goto usage;
if (!set_profiler_mode(stackMode) ||
!set_profiler_interval(interval) ||
!set_profiler_entries(entries) ||
!set_profiler_scan(scanCount)) {
profiler_usage();
} else {
LOG( "SPS:");
LOGF("SPS: Unwind mode = %s", name_UnwMode(sUnwindMode));
LOGF("SPS: Sampling interval = %d ms (zero means \"platform default\")",
(int)sUnwindInterval);
LOGF("SPS: Entry store size = %d (zero means \"platform default\")",
(int)sProfileEntries);
LOGF("SPS: UnwindStackScan = %d (max dubious frames per unwind).",
(int)sUnwindStackScan);
LOG( "SPS: Use env var MOZ_PROFILER_MODE=help for further information.");
LOG( "SPS:");
}
}
if (strI) {
errno = 0;
long int n = strtol(strI, (char**)NULL, 10);
if (errno == 0 && n >= 1 && n <= 1000) {
sUnwindInterval = n;
}
else goto usage;
}
if (strE) {
errno = 0;
long int n = strtol(strE, (char**)NULL, 10);
if (errno == 0 && n > 0) {
sProfileEntries = n;
}
else goto usage;
}
if (strF) {
errno = 0;
long int n = strtol(strF, (char**)NULL, 10);
if (errno == 0 && n >= 0 && n <= 100) {
sUnwindStackScan = n;
}
else goto usage;
}
goto out;
usage:
void profiler_usage() {
LOG( "SPS: ");
LOG( "SPS: Environment variable usage:");
LOG( "SPS: ");
@ -339,15 +390,15 @@ void read_profiler_env_vars()
LOG( "SPS: Needs to be set to use Breakpad-based unwinding.");
LOG( "SPS: ");
LOGF("SPS: This platform %s native unwinding.",
nativeAvail ? "supports" : "does not support");
is_native_unwinding_avail() ? "supports" : "does not support");
LOG( "SPS: ");
/* Re-set defaults */
sUnwindMode = nativeAvail ? UnwCOMBINED : UnwPSEUDO;
sUnwindMode = is_native_unwinding_avail() ? UnwCOMBINED : UnwPSEUDO;
sUnwindInterval = 0; /* We'll have to look elsewhere */
sProfileEntries = 0;
sUnwindStackScan = 0;
out:
LOG( "SPS:");
LOGF("SPS: Unwind mode = %s", name_UnwMode(sUnwindMode));
LOGF("SPS: Sampling interval = %d ms (zero means \"platform default\")",

View File

@ -240,7 +240,22 @@ class Thread {
/* Some values extracted at startup from environment variables, that
control the behaviour of the breakpad unwinder. */
extern const char* PROFILER_MODE;
extern const char* PROFILER_INTERVAL;
extern const char* PROFILER_ENTRIES;
extern const char* PROFILER_STACK;
extern const char* PROFILER_FEATURES;
void read_profiler_env_vars();
void profiler_usage();
// Helper methods to expose modifying profiler behavior
bool set_profiler_mode(const char*);
bool set_profiler_interval(const char*);
bool set_profiler_entries(const char*);
bool set_profiler_scan(const char*);
bool is_native_unwinding_avail();
typedef enum { UnwINVALID, UnwNATIVE, UnwPSEUDO, UnwCOMBINED } UnwMode;
extern UnwMode sUnwindMode; /* what mode? */
extern int sUnwindInterval; /* in milliseconds */