Files
palemoon27/hal/linux/UPowerClient.cpp
T
roytam1 54262da9aa import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 915880 - Add onclose event handlers in the MozInterAppMessagePort. r=ehsan,fabrice (5c57a3d571)
- Bug 1227206 - Location.assign and Location.replace should use USVStrings instead DOMStrings, r=bz (5069baa300)
- Bug 912342 - Add MediaStreamTrack.applyConstraints webidl. r=smaug (b43b0e0533)
- Bug 1160123 - Add support for LTE/WCDMA only network selection. r=hsinyi (82f0d18d75)
- Bug 993311 - Convert Network Stats API to WebIDL. r=bzbarsky. (4815cd4b57)
- Bug 993311 - Followup to fix b2g builds r=khuey (1294ac6d8e)
- Bug 1224944 - Improve the comments in NavigatorLanguage interface, r=bz (767104d09f)
- Bug 1233702 - Remove dom.permissions.enabled pref. r=baku (fc6a65d714)
- Bug 1224892 - Caching oscpu' and buildID' like other attributes related to User Agent. r=smaug (2e815d46af)
- Bug 1238205 - Mark Navigator.serviceWorker as SameObject; r=baku (66be34314b)
- Bug 1167541 - Implemented SpeechSynthesisEvent::utterance. r=smaug (eb2239ec4f)
- Bug 1167542 - Implement SpeechSynthesisErrorEvent. r=smaug (bd01bdb144)
- Bug 1238680 - Make dictionary arguments where a dictionary has a required member non-optional; r=bzbarsky (26a34e5279)
- fix tests (0198243cef)
- Bug 1192492 - Support masking of passwords in XUL tree columns. r=Enn,smaug (8594fafcb7)
- Bug 1170452 - Remove constants for texture swizzle and prim restart.  r=smaug (16e00c7565)
- Bug 1237783 - Make sure we correctly turn off appcache. r=ehsan (49f25a95ee)
- Bug 1218152 - Make Window.caches and WorkerGlobalScope.caches SameObject; r=bzbarsky (adf893fdb5)
- Bug 1137398 - disallow creating nested workers from ServiceWorker. r=baku (d720f362eb)
- Bug 931243 - Remove the XMLHttpRequest APIs from ServiceWorkerGlobalScope; r=bzbarsky (52110da15d)
- Bug 1238576 - disable mozApps API on desktop/Android; r=ehsan,ochameau,bz,mcmanus,jmaher,marco (79143c24b3)
- Bug 1233234 - part 1 - use UniquePtr<T[]> instead of nsAutoArrayPtr<T> in openPrefFile; r=njn (9b2d083dd0)
- Bug 1233234 - part 2 - use UniquePtr<T[]> instead of nsAutoArrayPtr<T> in pref_savePrefs; r=njn (4946a07998)
- Bug 1244982 - Fix minor double-reporting of memory in prefs code. r=erahm. (872c2c9b32)
- Bug 1233234 - part 3 - clean up UniquePtr usage in WritePrefFile; r=njn (1a37c3dca1)
- Bug 1241549 - Annotate intentional switch fallthrough in hal/linux/UPowerClient.cpp. r=gsvelto (7072ad9642)
- Bug 1167581 - Inconsistent pre-zeroing of ioctl buffers in gecko/hal/gonk/GonkFMRadio.cpp. r=mwu. (9e529cb0ac)
- Bug 1194721: Support Gonk sensors daemon, r=gsvelto (f2f47914ed)
- Bug 1137151: Marked destructors of ref-counted GonkHAL classes as protected, r=dhylands (7fb6a4792f)
- Bug 1116368 - Implementation of battery charging remaining time. r=dhylands (9b04442b6a)
- Bug 1163245 - [Battery][Gonk] Implementation of battery discharging remaining time. r=dhylands (96fb254ae9)
- Bug 1125084 - Uninitialised value use in mozilla::hal_impl::SetScreenBrightness(double). r=dhylands. (41f37994e5)
- Bug 1123628 - mozilla::hal_impl::PriorityClass::~PriorityClass() closes not-open files. r=dhylands. (4ae357d587)
- Bug 1208418: Shut down UeventPoller on XPCOM shutdown to fix the crash when the chrome process exits. r=dhylands (5b1192f310)
- Bug 1194721: Add registry interface and module for Gonk sensors, r=gsvelto (3936dcf96a)
- Bug 1194721: Add poll interface and module for Gonk sensors, r=gsvelto (101c0a2cf2)
- Bug 1194721: Add interface for Gonk sensors daemon, r=gsvelto (5a8ea8e2ad)
- Bug 1150232 - Stop gap solution until we can integrate the graphics docs. r=mstange (5a77195fb2)
- Bug 1235740 - Remove warning for missing Oculus VR Library from terminal output, as it is spammy and not necessary r=dholbert (628eaddc43)
- Bug 1235803 - Remove erroneous assertion r=dholbert (68287ff5ca)
- Bug 1222569 - remove unused variable in gfxDWriteFonts.cpp; r=Bas (c940b5f1e4)
- Bug 1212731 p1 - move GetSampleLangForGroup into base class. r=m_kato (a3cc3da7a7)
- Bug 1212731 p2 - add system font cascade to fontlist for -apple-system generic. r=m_kato (18056700de)
- Bug 1212731 p3 - reftest for system generic handling. r=m_kato (9aa64348b3)
- bit of Bug 1212731 p2 (0a0be8302c)
- Bug 1244017 - remove system font cascade for OSX. r=m_kato (742097b19e)
- Bug 1251995 part 1 - Add helper functions to simplify code. r=jfkthame (f533af33bb)
- Bug 1240739 - Support opacity when rendering color fonts (e.g. emoji). r=jdaggett (27c87cb70b)
- Bug 1251995 part 2 - Add gfxTextRun::Range to replace parameter pairs like (offset, length) and (start, end). r=jfkthame (e87c55be94)
- Bug 1251995 part 3 - Use struct to pass params for gfxTextRun::Draw.  r=jfkthame (fbe0cc3f7d)
- Bug 1251995 part 4 - Use struct to pass params for nsTextFrame::DrawText* functions. r=jfkthame (7d78727d65)
- Remove an extra assignment from gfxSparseBitSet::TestRange, no bug (065a8c74e1)
- Bug 1239603 - don't reject format 12 cmap with odd encoding. r=jfkthame (448ec8ab5e)
- Bug 724538 - When ICU is available in the build, replace most of nsCharProps2 fields with ICU property accessors. r=emk (3578679d8e)
- Bug 1228540 - pt 2 - Remove our HBGetGlyphHOrigin callback, as the default behavior is sufficient. r=jdaggett (9af85e376d)
- Bug 1235407 - Part 1: Add telemetry probe to record forced resets. r=milan (fd1fee75a4)
- Bug 1235407 - Part 2: Add ability to force device resets through gfxWindowsPlatform. r=milan (18479d140c)
- TenFourFox backport of font stuff in attempt of 10.5 support (f9a55f3978)
- Bug 1249212 part 2 - Fix infinity handling in StickyTimeDurationValueCalculator::Multiply; r=froydnj (e696303246)
- Bug 1184695 - Fix some indentation in nsHashPropertyBag. r=poiru (6c1bed1ecd)
- Bug 1182926 - Fix "observer-service-suspect" bustage. r=poiru. (25964b3802)
- Bug 1234542 - Don't use fallible Add in SetStringProperty. r=froydnj (2c9b93264a)
- Bug 1233566: Drop unnecessary newline character from NS_WARNING in nsPersistentProperties. r=froydnj (4ed1b9680d)
- Bug 1193564 - Check result of Read32 in nsSupportsArray::Read. r=erahm (b6983798f9)
- Bug 996105 - Added tests for registry access. Fixed wrong condition in ReadStringValue code. r=bsmedberxg (5945256572)
2024-01-18 10:02:38 +08:00

476 lines
14 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Hal.h"
#include "HalLog.h"
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <mozilla/Attributes.h>
#include <mozilla/dom/battery/Constants.h>
#include "nsAutoRef.h"
#include <cmath>
/*
* Helper that manages the destruction of glib objects as soon as they leave
* the current scope.
*
* We are specializing nsAutoRef class.
*/
template <>
class nsAutoRefTraits<GHashTable> : public nsPointerRefTraits<GHashTable>
{
public:
static void Release(GHashTable* ptr) { g_hash_table_unref(ptr); }
};
using namespace mozilla::dom::battery;
namespace mozilla {
namespace hal_impl {
/**
* This is the declaration of UPowerClient class. This class is listening and
* communicating to upower daemon through DBus.
* There is no header file because this class shouldn't be public.
*/
class UPowerClient
{
public:
static UPowerClient* GetInstance();
void BeginListening();
void StopListening();
double GetLevel();
bool IsCharging();
double GetRemainingTime();
~UPowerClient();
private:
UPowerClient();
enum States {
eState_Unknown = 0,
eState_Charging,
eState_Discharging,
eState_Empty,
eState_FullyCharged,
eState_PendingCharge,
eState_PendingDischarge
};
/**
* Update the currently tracked device.
* @return whether everything went ok.
*/
void UpdateTrackedDeviceSync();
/**
* Returns a hash table with the properties of aDevice.
* Note: the caller has to unref the hash table.
*/
GHashTable* GetDevicePropertiesSync(DBusGProxy* aProxy);
void GetDevicePropertiesAsync(DBusGProxy* aProxy);
static void GetDevicePropertiesCallback(DBusGProxy* aProxy,
DBusGProxyCall* aCall,
void* aData);
/**
* Using the device properties (aHashTable), this method updates the member
* variable storing the values we care about.
*/
void UpdateSavedInfo(GHashTable* aHashTable);
/**
* Callback used by 'DeviceChanged' signal.
*/
static void DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath,
UPowerClient* aListener);
/**
* Callback called when mDBusConnection gets a signal.
*/
static DBusHandlerResult ConnectionSignalFilter(DBusConnection* aConnection,
DBusMessage* aMessage,
void* aData);
// The DBus connection object.
DBusGConnection* mDBusConnection;
// The DBus proxy object to upower.
DBusGProxy* mUPowerProxy;
// The path of the tracked device.
gchar* mTrackedDevice;
// The DBusGProxy for the tracked device.
DBusGProxy* mTrackedDeviceProxy;
double mLevel;
bool mCharging;
double mRemainingTime;
static UPowerClient* sInstance;
static const guint sDeviceTypeBattery = 2;
static const guint64 kUPowerUnknownRemainingTime = 0;
};
/*
* Implementation of mozilla::hal_impl::EnableBatteryNotifications,
* mozilla::hal_impl::DisableBatteryNotifications,
* and mozilla::hal_impl::GetCurrentBatteryInformation.
*/
void
EnableBatteryNotifications()
{
UPowerClient::GetInstance()->BeginListening();
}
void
DisableBatteryNotifications()
{
UPowerClient::GetInstance()->StopListening();
}
void
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
{
UPowerClient* upowerClient = UPowerClient::GetInstance();
aBatteryInfo->level() = upowerClient->GetLevel();
aBatteryInfo->charging() = upowerClient->IsCharging();
aBatteryInfo->remainingTime() = upowerClient->GetRemainingTime();
}
/*
* Following is the implementation of UPowerClient.
*/
UPowerClient* UPowerClient::sInstance = nullptr;
/* static */ UPowerClient*
UPowerClient::GetInstance()
{
if (!sInstance) {
sInstance = new UPowerClient();
}
return sInstance;
}
UPowerClient::UPowerClient()
: mDBusConnection(nullptr)
, mUPowerProxy(nullptr)
, mTrackedDevice(nullptr)
, mTrackedDeviceProxy(nullptr)
, mLevel(kDefaultLevel)
, mCharging(kDefaultCharging)
, mRemainingTime(kDefaultRemainingTime)
{
}
UPowerClient::~UPowerClient()
{
NS_ASSERTION(!mDBusConnection && !mUPowerProxy && !mTrackedDevice && !mTrackedDeviceProxy,
"The observers have not been correctly removed! "
"(StopListening should have been called)");
}
void
UPowerClient::BeginListening()
{
GError* error = nullptr;
mDBusConnection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
if (!mDBusConnection) {
HAL_LOG("Failed to open connection to bus: %s\n", error->message);
g_error_free(error);
return;
}
DBusConnection* dbusConnection =
dbus_g_connection_get_connection(mDBusConnection);
// Make sure we do not exit the entire program if DBus connection get lost.
dbus_connection_set_exit_on_disconnect(dbusConnection, false);
// Listening to signals the DBus connection is going to get so we will know
// when it is lost and we will be able to disconnect cleanly.
dbus_connection_add_filter(dbusConnection, ConnectionSignalFilter, this,
nullptr);
mUPowerProxy = dbus_g_proxy_new_for_name(mDBusConnection,
"org.freedesktop.UPower",
"/org/freedesktop/UPower",
"org.freedesktop.UPower");
UpdateTrackedDeviceSync();
/*
* TODO: we should probably listen to DeviceAdded and DeviceRemoved signals.
* If we do that, we would have to disconnect from those in StopListening.
* It's not yet implemented because it requires testing hot plugging and
* removal of a battery.
*/
dbus_g_proxy_add_signal(mUPowerProxy, "DeviceChanged", G_TYPE_STRING,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal(mUPowerProxy, "DeviceChanged",
G_CALLBACK (DeviceChanged), this, nullptr);
}
void
UPowerClient::StopListening()
{
// If mDBusConnection isn't initialized, that means we are not really listening.
if (!mDBusConnection) {
return;
}
dbus_connection_remove_filter(
dbus_g_connection_get_connection(mDBusConnection),
ConnectionSignalFilter, this);
dbus_g_proxy_disconnect_signal(mUPowerProxy, "DeviceChanged",
G_CALLBACK (DeviceChanged), this);
g_free(mTrackedDevice);
mTrackedDevice = nullptr;
if (mTrackedDeviceProxy) {
g_object_unref(mTrackedDeviceProxy);
mTrackedDeviceProxy = nullptr;
}
g_object_unref(mUPowerProxy);
mUPowerProxy = nullptr;
dbus_g_connection_unref(mDBusConnection);
mDBusConnection = nullptr;
// We should now show the default values, not the latest we got.
mLevel = kDefaultLevel;
mCharging = kDefaultCharging;
mRemainingTime = kDefaultRemainingTime;
}
void
UPowerClient::UpdateTrackedDeviceSync()
{
GType typeGPtrArray = dbus_g_type_get_collection("GPtrArray",
DBUS_TYPE_G_OBJECT_PATH);
GPtrArray* devices = nullptr;
GError* error = nullptr;
// Reset the current tracked device:
g_free(mTrackedDevice);
mTrackedDevice = nullptr;
// Reset the current tracked device proxy:
if (mTrackedDeviceProxy) {
g_object_unref(mTrackedDeviceProxy);
mTrackedDeviceProxy = nullptr;
}
// If that fails, that likely means upower isn't installed.
if (!dbus_g_proxy_call(mUPowerProxy, "EnumerateDevices", &error, G_TYPE_INVALID,
typeGPtrArray, &devices, G_TYPE_INVALID)) {
HAL_LOG("Error: %s\n", error->message);
g_error_free(error);
return;
}
/*
* We are looking for the first device that is a battery.
* TODO: we could try to combine more than one battery.
*/
for (guint i=0; i<devices->len; ++i) {
gchar* devicePath = static_cast<gchar*>(g_ptr_array_index(devices, i));
DBusGProxy* proxy = dbus_g_proxy_new_from_proxy(mUPowerProxy,
"org.freedesktop.DBus.Properties",
devicePath);
nsAutoRef<GHashTable> hashTable(GetDevicePropertiesSync(proxy));
if (g_value_get_uint(static_cast<const GValue*>(g_hash_table_lookup(hashTable, "Type"))) == sDeviceTypeBattery) {
UpdateSavedInfo(hashTable);
mTrackedDevice = devicePath;
mTrackedDeviceProxy = proxy;
break;
}
g_object_unref(proxy);
g_free(devicePath);
}
g_ptr_array_free(devices, true);
}
/* static */ void
UPowerClient::DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath, UPowerClient* aListener)
{
if (!aListener->mTrackedDevice) {
return;
}
#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 16
if (g_strcmp0(aObjectPath, aListener->mTrackedDevice)) {
#else
if (g_ascii_strcasecmp(aObjectPath, aListener->mTrackedDevice)) {
#endif
return;
}
aListener->GetDevicePropertiesAsync(aListener->mTrackedDeviceProxy);
}
/* static */ DBusHandlerResult
UPowerClient::ConnectionSignalFilter(DBusConnection* aConnection,
DBusMessage* aMessage, void* aData)
{
if (dbus_message_is_signal(aMessage, DBUS_INTERFACE_LOCAL, "Disconnected")) {
static_cast<UPowerClient*>(aData)->StopListening();
// We do not return DBUS_HANDLER_RESULT_HANDLED here because the connection
// might be shared and some other filters might want to do something.
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
GHashTable*
UPowerClient::GetDevicePropertiesSync(DBusGProxy* aProxy)
{
GError* error = nullptr;
GHashTable* hashTable = nullptr;
GType typeGHashTable = dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
G_TYPE_VALUE);
if (!dbus_g_proxy_call(aProxy, "GetAll", &error, G_TYPE_STRING,
"org.freedesktop.UPower.Device", G_TYPE_INVALID,
typeGHashTable, &hashTable, G_TYPE_INVALID)) {
HAL_LOG("Error: %s\n", error->message);
g_error_free(error);
return nullptr;
}
return hashTable;
}
/* static */ void
UPowerClient::GetDevicePropertiesCallback(DBusGProxy* aProxy,
DBusGProxyCall* aCall, void* aData)
{
GError* error = nullptr;
GHashTable* hashTable = nullptr;
GType typeGHashTable = dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
G_TYPE_VALUE);
if (!dbus_g_proxy_end_call(aProxy, aCall, &error, typeGHashTable,
&hashTable, G_TYPE_INVALID)) {
HAL_LOG("Error: %s\n", error->message);
g_error_free(error);
} else {
sInstance->UpdateSavedInfo(hashTable);
hal::NotifyBatteryChange(hal::BatteryInformation(sInstance->mLevel,
sInstance->mCharging,
sInstance->mRemainingTime));
g_hash_table_unref(hashTable);
}
}
void
UPowerClient::GetDevicePropertiesAsync(DBusGProxy* aProxy)
{
dbus_g_proxy_begin_call(aProxy, "GetAll", GetDevicePropertiesCallback, nullptr,
nullptr, G_TYPE_STRING,
"org.freedesktop.UPower.Device", G_TYPE_INVALID);
}
void
UPowerClient::UpdateSavedInfo(GHashTable* aHashTable)
{
bool isFull = false;
/*
* State values are confusing...
* First of all, after looking at upower sources (0.9.13), it seems that
* PendingDischarge and PendingCharge are not used.
* In addition, FullyCharged and Empty states are not clear because we do not
* know if the battery is actually charging or not. Those values come directly
* from sysfs (in the Linux kernel) which have four states: "Empty", "Full",
* "Charging" and "Discharging". In sysfs, "Empty" and "Full" are also only
* related to the level, not to the charging state.
* In this code, we are going to assume that Full means charging and Empty
* means discharging because if that is not the case, the state should not
* last a long time (actually, it should disappear at the following update).
* It might be even very hard to see real cases where the state is Empty and
* the battery is charging or the state is Full and the battery is discharging
* given that plugging/unplugging the battery should have an impact on the
* level.
*/
switch (g_value_get_uint(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "State")))) {
case eState_Unknown:
mCharging = kDefaultCharging;
break;
case eState_FullyCharged:
isFull = true;
MOZ_FALLTHROUGH;
case eState_Charging:
case eState_PendingCharge:
mCharging = true;
break;
case eState_Discharging:
case eState_Empty:
case eState_PendingDischarge:
mCharging = false;
break;
}
/*
* The battery level might be very close to 100% (like 99%) without
* increasing. It seems that upower sets the battery state as 'full' in that
* case so we should trust it and not even try to get the value.
*/
if (isFull) {
mLevel = 1.0;
} else {
mLevel = round(g_value_get_double(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "Percentage"))))*0.01;
}
if (isFull) {
mRemainingTime = 0;
} else {
mRemainingTime = mCharging ? g_value_get_int64(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "TimeToFull")))
: g_value_get_int64(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "TimeToEmpty")));
if (mRemainingTime == kUPowerUnknownRemainingTime) {
mRemainingTime = kUnknownRemainingTime;
}
}
}
double
UPowerClient::GetLevel()
{
return mLevel;
}
bool
UPowerClient::IsCharging()
{
return mCharging;
}
double
UPowerClient::GetRemainingTime()
{
return mRemainingTime;
}
} // namespace hal_impl
} // namespace mozilla