summaryrefslogtreecommitdiff
path: root/hal/linux/UPowerClient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hal/linux/UPowerClient.cpp')
-rw-r--r--hal/linux/UPowerClient.cpp508
1 files changed, 0 insertions, 508 deletions
diff --git a/hal/linux/UPowerClient.cpp b/hal/linux/UPowerClient.cpp
deleted file mode 100644
index 9f6e04379e..0000000000
--- a/hal/linux/UPowerClient.cpp
+++ /dev/null
@@ -1,508 +0,0 @@
-/* -*- 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 used by 'PropertiesChanged' signal.
- * This method is called when the the battery level changes.
- * (Only with upower >= 0.99)
- */
- static void PropertiesChanged(DBusGProxy* aProxy, const gchar*,
- GHashTable*, char**,
- 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) {
- dbus_g_proxy_disconnect_signal(mTrackedDeviceProxy, "PropertiesChanged",
- G_CALLBACK (PropertiesChanged), this);
-
- 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) {
- dbus_g_proxy_disconnect_signal(mTrackedDeviceProxy, "PropertiesChanged",
- G_CALLBACK (PropertiesChanged), this);
-
- 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);
- }
-
- if (mTrackedDeviceProxy) {
- dbus_g_proxy_add_signal(mTrackedDeviceProxy, "PropertiesChanged",
- G_TYPE_STRING,
- dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
- G_TYPE_VALUE),
- G_TYPE_STRV, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(mTrackedDeviceProxy, "PropertiesChanged",
- G_CALLBACK (PropertiesChanged), this, nullptr);
- }
-
- 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 */ void
-UPowerClient::PropertiesChanged(DBusGProxy* aProxy, const gchar*, GHashTable*,
- char**, UPowerClient* aListener)
-{
- 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