GCC Code Coverage Report


Directory: ./
File: src/power-profiles-daemon.c
Date: 2024-09-13 00:56:02
Exec Total Coverage
Lines: 763 846 90.2%
Functions: 60 63 95.2%
Branches: 340 474 71.7%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2014-2016, 2020-2021 Bastien Nocera <hadess@hadess.net>
3 * Copyright (c) 2021 David Redondo <kde@david-redondo.de>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 3 as published by
7 * the Free Software Foundation.
8 *
9 */
10
11 #define G_LOG_DOMAIN "Core"
12
13 #include "config.h"
14
15 #include <glib-unix.h>
16 #include <locale.h>
17 #include <polkit/polkit.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20
21 #include "power-profiles-daemon-resources.h"
22 #include "power-profiles-daemon.h"
23 #include "ppd-driver-cpu.h"
24 #include "ppd-driver-platform.h"
25 #include "ppd-action.h"
26 #include "ppd-enums.h"
27
28 #define POWER_PROFILES_DBUS_NAME "org.freedesktop.UPower.PowerProfiles"
29 #define POWER_PROFILES_DBUS_PATH "/org/freedesktop/UPower/PowerProfiles"
30 #define POWER_PROFILES_IFACE_NAME POWER_PROFILES_DBUS_NAME
31
32 #define POWER_PROFILES_LEGACY_DBUS_NAME "net.hadess.PowerProfiles"
33 #define POWER_PROFILES_LEGACY_DBUS_PATH "/net/hadess/PowerProfiles"
34 #define POWER_PROFILES_LEGACY_IFACE_NAME POWER_PROFILES_LEGACY_DBUS_NAME
35
36 #define POWER_PROFILES_POLICY_NAMESPACE "org.freedesktop.UPower.PowerProfiles"
37
38 #define POWER_PROFILES_RESOURCES_PATH "/org/freedesktop/UPower/PowerProfiles"
39
40 #define UPOWER_DBUS_NAME "org.freedesktop.UPower"
41 #define UPOWER_DBUS_PATH "/org/freedesktop/UPower"
42 #define UPOWER_DBUS_INTERFACE "org.freedesktop.UPower"
43
44 #define UPOWER_DBUS_DISPLAY_DEVICE_PATH "/org/freedesktop/UPower/devices/DisplayDevice"
45 #define UPOWER_DBUS_DEVICE_INTERFACE "org.freedesktop.UPower.Device"
46
47 #define LOGIND_DBUS_NAME "org.freedesktop.login1"
48 #define LOGIND_DBUS_PATH "/org/freedesktop/login1"
49 #define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager"
50
51 #ifndef POLKIT_HAS_AUTOPOINTERS
52 /* FIXME: Remove this once we're fine to depend on polkit 0.114 */
53 G_DEFINE_AUTOPTR_CLEANUP_FUNC (PolkitAuthorizationResult, g_object_unref)
54 G_DEFINE_AUTOPTR_CLEANUP_FUNC (PolkitSubject, g_object_unref)
55 #endif
56
57 typedef struct {
58 GOptionGroup *group;
59 GLogLevelFlags log_level;
60 gboolean replace;
61 gboolean disable_upower;
62 gboolean disable_logind;
63 GStrv blocked_drivers;
64 GStrv blocked_actions;
65 } DebugOptions;
66
67 typedef struct {
68 GMainLoop *main_loop;
69 GDBusConnection *connection;
70 GCancellable *cancellable;
71 guint name_id;
72 guint legacy_name_id;
73 gboolean was_started;
74 int ret;
75
76 GKeyFile *config;
77 char *config_path;
78
79 PolkitAuthority *auth;
80
81 PpdProfile active_profile;
82 PpdProfile selected_profile;
83 GPtrArray *probed_drivers;
84 PpdDriverCpu *cpu_driver;
85 PpdDriverPlatform *platform_driver;
86 GPtrArray *actions;
87 GHashTable *profile_holds;
88
89 GDBusProxy *upower_proxy;
90 GDBusProxy *upower_display_proxy;
91 gulong upower_watch_id;
92 gulong upower_display_watch_id;
93 gulong upower_properties_id;
94 gulong upower_display_properties_id;
95 PpdPowerChangedReason power_changed_reason;
96
97 guint logind_sleep_signal_id;
98
99 DebugOptions *debug_options;
100 } PpdApp;
101
102 typedef struct {
103 PpdProfile profile;
104 char *reason;
105 char *application_id;
106 char *requester;
107 char *requester_iface;
108 } ProfileHold;
109
110 static void
111 132 debug_options_free(DebugOptions *options)
112 {
113 132 g_strfreev (options->blocked_drivers);
114 132 g_strfreev (options->blocked_actions);
115 132 g_free (options);
116 132 }
117 G_DEFINE_AUTOPTR_CLEANUP_FUNC (DebugOptions, debug_options_free)
118
119 static void
120 40 profile_hold_free (ProfileHold *hold)
121 {
122
1/2
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
40 if (hold == NULL)
123 return;
124 40 g_free (hold->reason);
125 40 g_free (hold->application_id);
126 40 g_free (hold->requester);
127 40 g_free (hold->requester_iface);
128 40 g_free (hold);
129 }
130
131 static PpdApp *ppd_app = NULL;
132
133 static void stop_profile_drivers (PpdApp *data);
134 static void start_profile_drivers (PpdApp *data);
135 static void upower_battery_set_power_changed_reason (PpdApp *, PpdPowerChangedReason);
136
137 /* profile drivers and actions */
138 #include "ppd-action-trickle-charge.h"
139 #include "ppd-action-amdgpu-panel-power.h"
140 #include "ppd-action-amdgpu-dpm.h"
141 #include "ppd-driver-placeholder.h"
142 #include "ppd-driver-platform-profile.h"
143 #include "ppd-driver-intel-pstate.h"
144 #include "ppd-driver-amd-pstate.h"
145 #include "ppd-driver-fake.h"
146
147 typedef GType (*GTypeGetFunc) (void);
148
149 static GTypeGetFunc objects[] = {
150 /* Hardware specific profile drivers */
151 ppd_driver_fake_get_type,
152 ppd_driver_platform_profile_get_type,
153 ppd_driver_intel_pstate_get_type,
154 ppd_driver_amd_pstate_get_type,
155
156 /* Generic profile driver */
157 ppd_driver_placeholder_get_type,
158
159 /* Actions */
160 ppd_action_trickle_charge_get_type,
161 ppd_action_amdgpu_panel_power_get_type,
162 ppd_action_amdgpu_dpm_get_type,
163 };
164
165 typedef enum {
166 PROP_ACTIVE_PROFILE = 1 << 0,
167 PROP_INHIBITED = 1 << 1,
168 PROP_PROFILES = 1 << 2,
169 PROP_ACTIONS = 1 << 3,
170 PROP_DEGRADED = 1 << 4,
171 PROP_ACTIVE_PROFILE_HOLDS = 1 << 5,
172 PROP_VERSION = 1 << 6,
173 } PropertiesMask;
174
175 #define PROP_ALL (PROP_ACTIVE_PROFILE | \
176 PROP_INHIBITED | \
177 PROP_PROFILES | \
178 PROP_ACTIONS | \
179 PROP_DEGRADED | \
180 PROP_ACTIVE_PROFILE_HOLDS | \
181 PROP_VERSION)
182
183 static gboolean
184 8972 driver_profile_support (PpdDriver *driver,
185 PpdProfile profile)
186 {
187
2/2
✓ Branch 1 taken 5426 times.
✓ Branch 2 taken 3546 times.
8972 if (!PPD_IS_DRIVER (driver))
188 return FALSE;
189 5426 return (ppd_driver_get_profiles (driver) & profile) != 0;
190 }
191
192 static gboolean
193 2306 get_profile_available (PpdApp *data,
194 PpdProfile profile)
195 {
196
4/4
✓ Branch 1 taken 1772 times.
✓ Branch 2 taken 534 times.
✓ Branch 3 taken 1410 times.
✓ Branch 4 taken 362 times.
4078 return driver_profile_support (PPD_DRIVER (data->cpu_driver), profile) ||
197 1772 driver_profile_support (PPD_DRIVER (data->platform_driver), profile);
198 }
199
200 static const char *
201 1607 get_active_profile (PpdApp *data)
202 {
203 1607 return ppd_profile_to_str (data->active_profile);
204 }
205
206 static char *
207 482 get_performance_degraded (PpdApp *data)
208 {
209 482 const gchar *cpu_degraded = NULL;
210 482 const gchar *platform_degraded = NULL;
211
212
2/2
✓ Branch 1 taken 208 times.
✓ Branch 2 taken 274 times.
482 if (driver_profile_support (PPD_DRIVER (data->platform_driver), PPD_PROFILE_PERFORMANCE))
213 208 platform_degraded = ppd_driver_get_performance_degraded (PPD_DRIVER (data->platform_driver));
214
215
2/2
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 332 times.
482 if (driver_profile_support (PPD_DRIVER (data->cpu_driver), PPD_PROFILE_PERFORMANCE))
216 150 cpu_degraded = ppd_driver_get_performance_degraded (PPD_DRIVER (data->cpu_driver));
217
218
2/2
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 38 times.
482 if (!cpu_degraded && !platform_degraded)
219 444 return g_strdup ("");
220
221
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 26 times.
38 if (!cpu_degraded)
222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
24 return g_strdup (platform_degraded);
223
224
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 6 times.
26 if (!platform_degraded)
225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
40 return g_strdup (cpu_degraded);
226
227 6 return g_strjoin (",", cpu_degraded, platform_degraded, NULL);
228 }
229
230 static GVariant *
231 682 get_profiles_variant (PpdApp *data)
232 {
233 682 GVariantBuilder builder;
234 682 guint i;
235
236 682 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
237
238
2/2
✓ Branch 1 taken 2046 times.
✓ Branch 2 taken 682 times.
3410 for (i = 0; i < NUM_PROFILES; i++) {
239 2046 PpdDriver *platform_driver = PPD_DRIVER (data->platform_driver);
240 2046 PpdDriver *cpu_driver = PPD_DRIVER (data->cpu_driver);
241 2046 PpdProfile profile = 1 << i;
242 2046 GVariantBuilder asv_builder;
243 2046 gboolean cpu, platform;
244 2046 const gchar *driver = NULL;
245
246 /* check if any of the drivers support */
247
2/2
✓ Branch 1 taken 356 times.
✓ Branch 2 taken 1690 times.
2046 if (!get_profile_available (data, profile))
248 356 continue;
249
250 1690 g_variant_builder_init (&asv_builder, G_VARIANT_TYPE ("a{sv}"));
251 1690 g_variant_builder_add (&asv_builder, "{sv}", "Profile",
252 1690 g_variant_new_string (ppd_profile_to_str (profile)));
253 1690 cpu = driver_profile_support (cpu_driver, profile);
254 1690 platform = driver_profile_support (platform_driver, profile);
255
2/2
✓ Branch 0 taken 462 times.
✓ Branch 1 taken 1228 times.
1690 if (cpu)
256 462 g_variant_builder_add (&asv_builder, "{sv}", "CpuDriver",
257 462 g_variant_new_string (ppd_driver_get_driver_name (cpu_driver)));
258
2/2
✓ Branch 0 taken 1560 times.
✓ Branch 1 taken 130 times.
1690 if (platform)
259 1560 g_variant_builder_add (&asv_builder, "{sv}", "PlatformDriver",
260 1560 g_variant_new_string (ppd_driver_get_driver_name (platform_driver)));
261
262 /* compatibility with older API */
263
2/2
✓ Branch 0 taken 1358 times.
✓ Branch 1 taken 332 times.
1690 if (cpu && platform)
264 driver = "multiple";
265
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 1228 times.
1358 else if (cpu)
266 130 driver = ppd_driver_get_driver_name (cpu_driver);
267
1/2
✓ Branch 0 taken 1228 times.
✗ Branch 1 not taken.
1228 else if (platform)
268 1228 driver = ppd_driver_get_driver_name (platform_driver);
269
270
1/2
✓ Branch 0 taken 1358 times.
✗ Branch 1 not taken.
1358 if (driver)
271 1690 g_variant_builder_add (&asv_builder, "{sv}", "Driver",
272 g_variant_new_string (driver));
273
274 1690 g_variant_builder_add (&builder, "a{sv}", &asv_builder);
275 }
276
277 682 return g_variant_builder_end (&builder);
278 }
279
280 static GVariant *
281 448 get_actions_variant (PpdApp *data)
282 {
283 448 GVariantBuilder builder;
284 448 guint i;
285
286 448 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
287
288
2/2
✓ Branch 1 taken 518 times.
✓ Branch 2 taken 448 times.
1414 for (i = 0; i < data->actions->len; i++) {
289 518 PpdAction *action = g_ptr_array_index (data->actions, i);
290
291 518 g_variant_builder_add (&builder, "s", ppd_action_get_action_name (action));
292 }
293
294 448 return g_variant_builder_end (&builder);
295 }
296
297 static GVariant *
298 604 get_profile_holds_variant (PpdApp *data)
299 {
300 604 GVariantBuilder builder;
301 604 GHashTableIter iter;
302 604 gpointer value;
303
304 604 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
305 604 g_hash_table_iter_init (&iter, data->profile_holds);
306
307
2/2
✓ Branch 2 taken 118 times.
✓ Branch 3 taken 604 times.
722 while (g_hash_table_iter_next (&iter, NULL, &value)) {
308 118 GVariantBuilder asv_builder;
309 118 ProfileHold *hold = value;
310
311 118 g_variant_builder_init (&asv_builder, G_VARIANT_TYPE ("a{sv}"));
312 118 g_variant_builder_add (&asv_builder, "{sv}", "ApplicationId",
313 118 g_variant_new_string (hold->application_id));
314 118 g_variant_builder_add (&asv_builder, "{sv}", "Profile",
315 118 g_variant_new_string (ppd_profile_to_str (hold->profile)));
316 118 g_variant_builder_add (&asv_builder, "{sv}", "Reason", g_variant_new_string (hold->reason));
317
318 118 g_variant_builder_add (&builder, "a{sv}", &asv_builder);
319 }
320
321 604 return g_variant_builder_end (&builder);
322 }
323
324 static void
325 584 send_dbus_event_iface (PpdApp *data,
326 PropertiesMask mask,
327 const gchar *iface,
328 const gchar *path)
329 {
330 584 GVariantBuilder props_builder;
331 584 GVariant *props_changed = NULL;
332
333
1/2
✓ Branch 0 taken 584 times.
✗ Branch 1 not taken.
584 g_return_if_fail (data->connection);
334
335
1/2
✓ Branch 0 taken 584 times.
✗ Branch 1 not taken.
584 if (mask == 0)
336 return;
337
338
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 584 times.
584 g_return_if_fail ((mask & PROP_ALL) != 0);
339
340 584 g_variant_builder_init (&props_builder, G_VARIANT_TYPE ("a{sv}"));
341
342
2/2
✓ Branch 0 taken 544 times.
✓ Branch 1 taken 40 times.
584 if (mask & PROP_ACTIVE_PROFILE) {
343 1088 g_variant_builder_add (&props_builder, "{sv}", "ActiveProfile",
344 544 g_variant_new_string (get_active_profile (data)));
345 }
346
2/2
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 316 times.
584 if (mask & PROP_INHIBITED) {
347 268 g_variant_builder_add (&props_builder, "{sv}", "PerformanceInhibited",
348 g_variant_new_string (""));
349 }
350
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 292 times.
584 if (mask & PROP_DEGRADED) {
351 292 gchar *degraded = get_performance_degraded (data);
352 292 g_variant_builder_add (&props_builder, "{sv}", "PerformanceDegraded",
353 292 g_variant_new_take_string (g_steal_pointer (&degraded)));
354 }
355
2/2
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 316 times.
584 if (mask & PROP_PROFILES) {
356 268 g_variant_builder_add (&props_builder, "{sv}", "Profiles",
357 get_profiles_variant (data));
358 }
359
2/2
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 316 times.
584 if (mask & PROP_ACTIONS) {
360 268 g_variant_builder_add (&props_builder, "{sv}", "Actions",
361 get_actions_variant (data));
362 }
363
2/2
✓ Branch 0 taken 424 times.
✓ Branch 1 taken 160 times.
584 if (mask & PROP_ACTIVE_PROFILE_HOLDS) {
364 424 g_variant_builder_add (&props_builder, "{sv}", "ActiveProfileHolds",
365 get_profile_holds_variant (data));
366 }
367
2/2
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 316 times.
584 if (mask & PROP_VERSION) {
368 268 g_variant_builder_add (&props_builder, "{sv}", "Version",
369 g_variant_new_string (VERSION));
370 }
371
372 584 props_changed = g_variant_new ("(s@a{sv}@as)", iface,
373 g_variant_builder_end (&props_builder),
374 g_variant_new_strv (NULL, 0));
375
376 584 g_dbus_connection_emit_signal (data->connection,
377 NULL,
378 path,
379 "org.freedesktop.DBus.Properties",
380 "PropertiesChanged",
381 props_changed, NULL);
382 }
383
384 static void
385 292 send_dbus_event (PpdApp *data,
386 PropertiesMask mask)
387 {
388 292 send_dbus_event_iface (data, mask,
389 POWER_PROFILES_IFACE_NAME,
390 POWER_PROFILES_DBUS_PATH);
391 292 send_dbus_event_iface (data, mask,
392 POWER_PROFILES_LEGACY_IFACE_NAME,
393 POWER_PROFILES_LEGACY_DBUS_PATH);
394 292 }
395
396 static void
397 70 save_configuration (PpdApp *data)
398 {
399 140 g_autoptr(GError) error = NULL;
400
401
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 44 times.
70 if (PPD_IS_DRIVER_CPU (data->cpu_driver)) {
402 26 g_key_file_set_string (data->config, "State", "CpuDriver",
403 26 ppd_driver_get_driver_name (PPD_DRIVER (data->cpu_driver)));
404 }
405
406
1/2
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
70 if (PPD_IS_DRIVER_PLATFORM (data->platform_driver)) {
407 70 g_key_file_set_string (data->config, "State", "PlatformDriver",
408 70 ppd_driver_get_driver_name (PPD_DRIVER (data->platform_driver)));
409 }
410
411 70 g_key_file_set_string (data->config, "State", "Profile",
412 70 ppd_profile_to_str (data->active_profile));
413
414
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
70 if (!g_key_file_save_to_file (data->config, data->config_path, &error))
415 g_warning ("Could not save configuration file '%s': %s", data->config_path, error->message);
416 70 }
417
418 static gboolean
419 134 apply_configuration (PpdApp *data)
420 {
421 268 g_autofree char *platform_driver = NULL;
422 134 g_autofree char *profile_str = NULL;
423 134 g_autofree char *cpu_driver = NULL;
424 134 PpdProfile profile;
425
426 134 cpu_driver = g_key_file_get_string (data->config, "State", "CpuDriver", NULL);
427
4/4
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 94 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 38 times.
174 if (PPD_IS_DRIVER_CPU (data->cpu_driver) &&
428 40 g_strcmp0 (ppd_driver_get_driver_name (PPD_DRIVER (data->cpu_driver)), cpu_driver) != 0)
429 return FALSE;
430
431 96 platform_driver = g_key_file_get_string (data->config, "State", "PlatformDriver", NULL);
432
433
3/4
✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 90 times.
✓ Branch 4 taken 6 times.
192 if (PPD_IS_DRIVER_PLATFORM (data->platform_driver) &&
434 96 g_strcmp0 (ppd_driver_get_driver_name (PPD_DRIVER (data->platform_driver)), platform_driver) != 0)
435 return FALSE;
436
437 6 profile_str = g_key_file_get_string (data->config, "State", "Profile", NULL);
438
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (profile_str == NULL)
439 return FALSE;
440
441 6 profile = ppd_profile_from_str (profile_str);
442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (profile == PPD_PROFILE_UNSET) {
443 g_debug ("Resetting invalid configuration profile '%s'", profile_str);
444 g_key_file_remove_key (data->config, "State", "Profile", NULL);
445 return FALSE;
446 }
447
448 6 g_debug ("Applying profile '%s' from configuration file", profile_str);
449 6 data->active_profile = profile;
450 6 return TRUE;
451 }
452
453 static void
454 132 load_configuration (PpdApp *data)
455 {
456 264 g_autoptr(GError) error = NULL;
457
458
2/2
✓ Branch 1 taken 130 times.
✓ Branch 2 taken 2 times.
132 if (g_getenv ("UMOCKDEV_DIR") != NULL)
459 130 data->config_path = g_build_filename (g_getenv ("UMOCKDEV_DIR"), "ppd_test_conf.ini", NULL);
460 else
461 2 data->config_path = g_strdup ("/var/lib/power-profiles-daemon/state.ini");
462 132 data->config = g_key_file_new ();
463
2/2
✓ Branch 1 taken 124 times.
✓ Branch 2 taken 8 times.
132 if (!g_key_file_load_from_file (data->config, data->config_path, G_KEY_FILE_KEEP_COMMENTS, &error))
464 124 g_debug ("Could not load configuration file '%s': %s", data->config_path, error->message);
465 132 }
466
467 static void
468 270 actions_activate_profile (GPtrArray *actions,
469 PpdProfile profile)
470 {
471 270 guint i;
472
473
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 270 times.
270 g_return_if_fail (actions != NULL);
474
475
2/2
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 270 times.
570 for (i = 0; i < actions->len; i++) {
476 300 g_autoptr(GError) error = NULL;
477 300 PpdAction *action;
478
479 300 action = g_ptr_array_index (actions, i);
480
481
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 300 times.
300 if (!ppd_action_activate_profile (action, profile, &error))
482 g_warning ("Failed to activate action '%s' to profile %s: %s",
483 ppd_profile_to_str (profile),
484 ppd_action_get_action_name (action),
485 error->message);
486 }
487 }
488
489 static gboolean
490 278 activate_target_profile (PpdApp *data,
491 PpdProfile target_profile,
492 PpdProfileActivationReason reason,
493 GError **error)
494 {
495 278 PpdProfile current_profile = data->active_profile;
496
497 278 g_info ("Setting active profile '%s' for reason '%s' (current: '%s')",
498 ppd_profile_to_str (target_profile),
499 ppd_profile_activation_reason_to_str (reason),
500 ppd_profile_to_str (current_profile));
501
502 /* Try CPU first */
503
4/4
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 206 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 66 times.
350 if (driver_profile_support (PPD_DRIVER (data->cpu_driver), target_profile) &&
504 72 !ppd_driver_activate_profile (PPD_DRIVER (data->cpu_driver),
505 target_profile, reason, error)) {
506 12 g_prefix_error (error, "Failed to activate CPU driver '%s': ",
507 6 ppd_driver_get_driver_name (PPD_DRIVER (data->cpu_driver)));
508 6 return FALSE;
509 }
510
511 /* Then try platform */
512
4/4
✓ Branch 1 taken 262 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 260 times.
534 if (driver_profile_support (PPD_DRIVER (data->platform_driver), target_profile) &&
513 262 !ppd_driver_activate_profile (PPD_DRIVER (data->platform_driver),
514 target_profile, reason, error)) {
515 2 g_autoptr(GError) recovery_error = NULL;
516
517 2 g_prefix_error (error, "Failed to activate platform driver '%s': ",
518 2 ppd_driver_get_driver_name (PPD_DRIVER (data->platform_driver)));
519
520
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (!PPD_IS_DRIVER (data->cpu_driver))
521 return FALSE;
522
523 2 g_debug ("Reverting CPU driver '%s' to profile '%s'",
524 ppd_driver_get_driver_name (PPD_DRIVER (data->cpu_driver)),
525 ppd_profile_to_str (current_profile));
526
527
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!ppd_driver_activate_profile (PPD_DRIVER (data->cpu_driver),
528 current_profile, PPD_PROFILE_ACTIVATION_REASON_INTERNAL,
529 &recovery_error)) {
530 g_warning ("Failed to revert CPU driver '%s': %s",
531 ppd_driver_get_driver_name (PPD_DRIVER (data->cpu_driver)),
532 recovery_error->message);
533 }
534
535 2 return FALSE;
536 }
537
538 270 actions_activate_profile (data->actions, target_profile);
539
540 270 data->active_profile = target_profile;
541
542 270 if (reason == PPD_PROFILE_ACTIVATION_REASON_USER ||
543
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 200 times.
270 reason == PPD_PROFILE_ACTIVATION_REASON_INTERNAL)
544 70 save_configuration (data);
545
546 return TRUE;
547 }
548
549 static void
550 40 release_hold_notify (PpdApp *data,
551 ProfileHold *hold,
552 guint cookie)
553 {
554 40 const char *req_path = POWER_PROFILES_DBUS_PATH;
555
556
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 28 times.
40 if (g_strcmp0 (hold->requester_iface, POWER_PROFILES_LEGACY_IFACE_NAME) == 0)
557 12 req_path = POWER_PROFILES_LEGACY_DBUS_PATH;
558
559 40 g_dbus_connection_emit_signal (data->connection, hold->requester, req_path,
560 40 hold->requester_iface, "ProfileReleased",
561 g_variant_new ("(u)", cookie), NULL);
562 40 }
563
564 static void
565 138 release_all_profile_holds (PpdApp *data)
566 {
567 138 GHashTableIter iter;
568 138 gpointer key, value;
569
570 138 g_hash_table_iter_init (&iter, data->profile_holds);
571
2/2
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 138 times.
142 while (g_hash_table_iter_next (&iter, &key, &value)) {
572 4 ProfileHold *hold = value;
573 4 guint cookie = GPOINTER_TO_UINT (key);
574
575 4 release_hold_notify (data, hold, cookie);
576 4 g_bus_unwatch_name (cookie);
577 }
578 138 g_hash_table_remove_all (data->profile_holds);
579 138 }
580
581 static gboolean
582 86 set_active_profile (PpdApp *data,
583 const char *profile,
584 GError **error)
585 {
586 86 PpdProfile target_profile;
587 86 guint mask = PROP_ACTIVE_PROFILE;
588
589 86 target_profile = ppd_profile_from_str (profile);
590
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 84 times.
86 if (target_profile == PPD_PROFILE_UNSET) {
591 2 g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
592 "Invalid profile name '%s'", profile);
593 2 return FALSE;
594 }
595
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 80 times.
84 if (!get_profile_available (data, target_profile)) {
596 4 g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
597 "Cannot switch to unavailable profile '%s'", profile);
598 4 return FALSE;
599 }
600
601
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 74 times.
80 if (target_profile == data->active_profile)
602 return TRUE;
603
604 74 g_debug ("Transitioning active profile from '%s' to '%s' by user request",
605 ppd_profile_to_str (data->active_profile), profile);
606
607
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 72 times.
74 if (g_hash_table_size (data->profile_holds) != 0 ) {
608 2 g_debug ("Releasing active profile holds");
609 2 release_all_profile_holds (data);
610 2 mask |= PROP_ACTIVE_PROFILE_HOLDS;
611 }
612
613
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 68 times.
74 if (!activate_target_profile (data, target_profile, PPD_PROFILE_ACTIVATION_REASON_USER, error))
614 return FALSE;
615 68 data->selected_profile = target_profile;
616 68 send_dbus_event (data, mask);
617
618 68 return TRUE;
619 }
620
621 static PpdProfile
622 44 effective_hold_profile (PpdApp *data)
623 {
624 44 GHashTableIter iter;
625 44 gpointer value;
626 44 PpdProfile profile = PPD_PROFILE_UNSET;
627
628 44 g_hash_table_iter_init (&iter, data->profile_holds);
629
2/2
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 30 times.
78 while (g_hash_table_iter_next (&iter, NULL, &value)) {
630 48 ProfileHold *hold = value;
631
632
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 14 times.
48 if (hold->profile == PPD_PROFILE_POWER_SAVER) {
633 profile = PPD_PROFILE_POWER_SAVER;
634 break;
635 }
636 profile = hold->profile;
637 }
638 44 return profile;
639 }
640
641 static void
642 12 driver_performance_degraded_changed_cb (GObject *gobject,
643 GParamSpec *pspec,
644 gpointer user_data)
645 {
646 12 PpdApp *data = user_data;
647 12 PpdDriver *driver = PPD_DRIVER (gobject);
648 12 const char *prop_str = pspec->name;
649
650
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if (g_strcmp0 (prop_str, "performance-degraded") != 0) {
651 g_warning ("Ignoring '%s' property change on profile driver '%s'",
652 prop_str, ppd_driver_get_driver_name (driver));
653 return;
654 }
655
656
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if (!(ppd_driver_get_profiles (driver) & PPD_PROFILE_PERFORMANCE)) {
657 g_warning ("Ignored 'performance-degraded' change on non-performance driver '%s'",
658 ppd_driver_get_driver_name (driver));
659 return;
660 }
661
662 12 send_dbus_event (data, PROP_DEGRADED);
663 }
664
665 static void
666 2 driver_profile_changed_cb (PpdDriver *driver,
667 PpdProfile new_profile,
668 gpointer user_data)
669 {
670 2 PpdApp *data = user_data;
671
672 2 g_debug ("Driver '%s' switched internally to profile '%s' (current: '%s')",
673 ppd_driver_get_driver_name (driver),
674 ppd_profile_to_str (new_profile),
675 ppd_profile_to_str (data->active_profile));
676
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (new_profile == data->active_profile)
677 return;
678
679 2 activate_target_profile (data, new_profile, PPD_PROFILE_ACTIVATION_REASON_INTERNAL, NULL);
680 2 send_dbus_event (data, PROP_ACTIVE_PROFILE);
681 }
682
683 static void
684 36 release_profile_hold (PpdApp *data,
685 guint cookie)
686 {
687 36 guint mask = PROP_ACTIVE_PROFILE_HOLDS;
688 36 ProfileHold *hold;
689 36 PpdProfile hold_profile, next_profile;
690
691 36 hold = g_hash_table_lookup (data->profile_holds, GUINT_TO_POINTER (cookie));
692
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (!hold) {
693 g_debug ("No hold with cookie %d", cookie);
694 return;
695 }
696
697 36 g_bus_unwatch_name (cookie);
698 36 hold_profile = hold->profile;
699 36 release_hold_notify (data, hold, cookie);
700 36 g_hash_table_remove (data->profile_holds, GUINT_TO_POINTER (cookie));
701
702
2/2
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 8 times.
36 if (g_hash_table_size (data->profile_holds) == 0 &&
703
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 hold_profile != data->selected_profile) {
704 28 g_debug ("No profile holds anymore going back to last manually activated profile");
705 28 activate_target_profile (data, data->selected_profile, PPD_PROFILE_ACTIVATION_REASON_PROGRAM_HOLD, NULL);
706 28 mask |= PROP_ACTIVE_PROFILE;
707
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 } else if (hold_profile == data->active_profile) {
708 4 next_profile = effective_hold_profile (data);
709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (next_profile != PPD_PROFILE_UNSET &&
710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 next_profile != data->active_profile) {
711 4 g_debug ("Next profile is %s", ppd_profile_to_str (next_profile));
712 4 activate_target_profile (data, next_profile, PPD_PROFILE_ACTIVATION_REASON_PROGRAM_HOLD, NULL);
713 4 mask |= PROP_ACTIVE_PROFILE;
714 }
715 }
716
717 36 send_dbus_event (data, mask);
718 }
719
720 static void
721 holder_disappeared (GDBusConnection *connection,
722 const gchar *name,
723 gpointer user_data)
724 {
725 PpdApp *data = user_data;
726 GHashTableIter iter;
727 gpointer key, value;
728 GPtrArray *cookies;
729 guint i;
730
731 cookies = g_ptr_array_new ();
732 g_hash_table_iter_init (&iter, data->profile_holds);
733 while (g_hash_table_iter_next (&iter, &key, (gpointer *) &value)) {
734 guint cookie = GPOINTER_TO_UINT (key);
735 ProfileHold *hold = value;
736
737 if (g_strcmp0 (hold->requester, name) != 0)
738 continue;
739
740 g_debug ("Holder %s with cookie %u disappeared, adding to list", name, cookie);
741 g_ptr_array_add (cookies, GUINT_TO_POINTER (cookie));
742 }
743
744 for (i = 0; i < cookies->len; i++) {
745 guint cookie = GPOINTER_TO_UINT (cookies->pdata[i]);
746 g_debug ("Removing profile hold for cookie %u", cookie);
747 release_profile_hold (data, cookie);
748 }
749 g_ptr_array_free (cookies, TRUE);
750 }
751
752 static void
753 42 hold_profile (PpdApp *data,
754 GVariant *parameters,
755 GDBusMethodInvocation *invocation)
756 {
757 42 const char *profile_name;
758 42 const char *reason;
759 42 const char *application_id;
760 42 PpdProfile profile;
761 42 ProfileHold *hold;
762 42 guint watch_id;
763 42 guint mask;
764
765 42 g_variant_get (parameters, "(&s&s&s)", &profile_name, &reason, &application_id);
766 42 profile = ppd_profile_from_str (profile_name);
767 42 if (profile != PPD_PROFILE_PERFORMANCE &&
768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 profile != PPD_PROFILE_POWER_SAVER) {
769 g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
770 "Only profiles 'performance' and 'power-saver' can be a hold profile");
771 2 return;
772 }
773
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 40 times.
42 if (!get_profile_available (data, profile)) {
774 2 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
775 "Cannot hold profile '%s' as it is not available",
776 profile_name);
777 2 return;
778 }
779
780 40 hold = g_new0 (ProfileHold, 1);
781 40 hold->profile = profile;
782
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 hold->reason = g_strdup (reason);
783
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 hold->application_id = g_strdup (application_id);
784
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 hold->requester = g_strdup (g_dbus_method_invocation_get_sender (invocation));
785
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 hold->requester_iface = g_strdup (g_dbus_method_invocation_get_interface_name (invocation));
786
787 40 g_debug ("%s (%s) requesting to hold profile '%s', reason: '%s'", application_id,
788 hold->requester, profile_name, reason);
789 40 watch_id = g_bus_watch_name_on_connection (data->connection, hold->requester,
790 G_BUS_NAME_WATCHER_FLAGS_NONE, NULL,
791 holder_disappeared, data, NULL);
792 40 g_hash_table_insert (data->profile_holds, GUINT_TO_POINTER (watch_id), hold);
793 40 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", watch_id));
794 40 mask = PROP_ACTIVE_PROFILE_HOLDS;
795
796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (profile != data->active_profile) {
797 40 PpdProfile target_profile = effective_hold_profile (data);
798
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (target_profile != PPD_PROFILE_UNSET &&
799
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 36 times.
40 target_profile != data->active_profile) {
800 36 activate_target_profile (data, target_profile, PPD_PROFILE_ACTIVATION_REASON_PROGRAM_HOLD, NULL);
801 36 mask |= PROP_ACTIVE_PROFILE;
802 }
803 }
804
805 40 send_dbus_event (data, mask);
806 }
807
808 static void
809 36 release_profile (PpdApp *data,
810 GVariant *parameters,
811 GDBusMethodInvocation *invocation)
812 {
813 36 guint cookie;
814 36 g_variant_get (parameters, "(u)", &cookie);
815
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
36 if (!g_hash_table_contains (data->profile_holds, GUINT_TO_POINTER (cookie))) {
816 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
817 "No hold with cookie %d", cookie);
818 return;
819 }
820 36 release_profile_hold (data, cookie);
821 36 g_dbus_method_invocation_return_value (invocation, NULL);
822 }
823
824 static gboolean
825 132 check_action_permission (PpdApp *data,
826 const char *sender,
827 const char *action,
828 GError **error)
829 {
830 264 g_autoptr(GError) local_error = NULL;
831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
132 g_autoptr(PolkitAuthorizationResult) result = NULL;
832
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_autoptr(PolkitSubject) subject = NULL;
833
834 132 subject = polkit_system_bus_name_new (sender);
835 132 result = polkit_authority_check_authorization_sync (data->auth,
836 subject,
837 action,
838 NULL,
839 POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE,
840 NULL, &local_error);
841
3/4
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 128 times.
264 if (result == NULL ||
842 132 !polkit_authorization_result_get_is_authorized (result))
843 {
844 4 g_set_error (error, G_DBUS_ERROR,
845 G_DBUS_ERROR_ACCESS_DENIED,
846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 "Not Authorized: %s", local_error ? local_error->message : action);
847 4 return FALSE;
848 }
849
850 return TRUE;
851
852 }
853
854 static GVariant *
855 2365 handle_get_property (GDBusConnection *connection,
856 const gchar *sender,
857 const gchar *object_path,
858 const gchar *interface_name,
859 const gchar *property_name,
860 GError **error,
861 gpointer user_data)
862 {
863 2365 PpdApp *data = user_data;
864
865
1/2
✓ Branch 0 taken 2365 times.
✗ Branch 1 not taken.
2365 g_return_val_if_fail (data->connection, NULL);
866
867
2/2
✓ Branch 1 taken 1063 times.
✓ Branch 2 taken 1302 times.
2365 if (g_strcmp0 (property_name, "ActiveProfile") == 0)
868 1063 return g_variant_new_string (get_active_profile (data));
869
2/2
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 1134 times.
1302 if (g_strcmp0 (property_name, "PerformanceInhibited") == 0)
870 168 return g_variant_new_string ("");
871
2/2
✓ Branch 1 taken 414 times.
✓ Branch 2 taken 720 times.
1134 if (g_strcmp0 (property_name, "Profiles") == 0)
872 414 return get_profiles_variant (data);
873
2/2
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 540 times.
720 if (g_strcmp0 (property_name, "Actions") == 0)
874 180 return get_actions_variant (data);
875
2/2
✓ Branch 1 taken 190 times.
✓ Branch 2 taken 350 times.
540 if (g_strcmp0 (property_name, "PerformanceDegraded") == 0) {
876 190 gchar *degraded = get_performance_degraded (data);
877 190 return g_variant_new_take_string (g_steal_pointer (&degraded));
878 }
879
2/2
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 170 times.
350 if (g_strcmp0 (property_name, "ActiveProfileHolds") == 0)
880 180 return get_profile_holds_variant (data);
881
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 170 times.
170 if (g_strcmp0 (property_name, "Version") == 0)
882 170 return g_variant_new_string (VERSION);
883 return NULL;
884 }
885
886 static gboolean
887 88 handle_set_property (GDBusConnection *connection,
888 const gchar *sender,
889 const gchar *object_path,
890 const gchar *interface_name,
891 const gchar *property_name,
892 GVariant *value,
893 GError **error,
894 gpointer user_data)
895 {
896 88 PpdApp *data = user_data;
897 88 const char *profile;
898
899
1/2
✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
88 g_return_val_if_fail (data->connection, FALSE);
900
901
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
88 if (g_strcmp0 (property_name, "ActiveProfile") != 0) {
902 g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
903 "No such property: %s", property_name);
904 return FALSE;
905 }
906
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 86 times.
88 if (!check_action_permission (data, sender,
907 POWER_PROFILES_POLICY_NAMESPACE ".switch-profile",
908 error))
909 return FALSE;
910
911 86 g_variant_get (value, "&s", &profile);
912 86 return set_active_profile (data, profile, error);
913 }
914
915 static void
916 80 handle_method_call (GDBusConnection *connection,
917 const gchar *sender,
918 const gchar *object_path,
919 const gchar *interface_name,
920 const gchar *method_name,
921 GVariant *parameters,
922 GDBusMethodInvocation *invocation,
923 gpointer user_data)
924 {
925 80 PpdApp *data = user_data;
926
1/2
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
80 g_return_if_fail (data->connection);
927
928
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 56 times.
80 if (!g_str_equal (interface_name, POWER_PROFILES_IFACE_NAME) &&
929
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 !g_str_equal (interface_name, POWER_PROFILES_LEGACY_IFACE_NAME)) {
930 g_dbus_method_invocation_return_error (invocation,G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_INTERFACE,
931 "Unknown interface %s", interface_name);
932 return;
933 }
934
935
2/2
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 36 times.
80 if (g_strcmp0 (method_name, "HoldProfile") == 0) {
936 44 g_autoptr(GError) local_error = NULL;
937
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 42 times.
44 if (!check_action_permission (data,
938 44 g_dbus_method_invocation_get_sender (invocation),
939 POWER_PROFILES_POLICY_NAMESPACE ".hold-profile",
940 &local_error)) {
941 2 g_dbus_method_invocation_return_gerror (invocation, local_error);
942
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 return;
943 }
944
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
42 hold_profile (data, parameters, invocation);
945
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 } else if (g_strcmp0 (method_name, "ReleaseProfile") == 0) {
946 36 release_profile (data, parameters, invocation);
947 } else {
948 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
949 "No such method %s in interface %s", interface_name,
950 method_name);
951 }
952 }
953
954
955 static const GDBusInterfaceVTable interface_vtable =
956 {
957 handle_method_call,
958 handle_get_property,
959 handle_set_property
960 };
961
962 typedef struct {
963 PpdApp *app;
964 GBusNameOwnerFlags flags;
965 GDBusInterfaceInfo *interface;
966 GDBusInterfaceInfo *legacy_interface;
967 } PpdBusOwnData;
968
969 static void
970 2 ppd_bus_own_data_free (PpdBusOwnData *data)
971 {
972
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 g_clear_pointer (&data->interface, g_dbus_interface_info_unref);
973
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 g_clear_pointer (&data->legacy_interface, g_dbus_interface_info_unref);
974 2 g_free (data);
975 2 }
976
977 static void
978 2 name_lost_handler (GDBusConnection *connection,
979 const gchar *name,
980 gpointer user_data)
981 {
982 2 PpdBusOwnData *data = user_data;
983 2 PpdApp *app = data->app;
984
985 2 g_warning ("power-profiles-daemon is already running, or it cannot own its D-Bus name. Verify installation.");
986
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!app->was_started)
987 2 app->ret = EXIT_FAILURE;
988
989 2 g_main_loop_quit (app->main_loop);
990 2 }
991
992 static void
993 130 legacy_name_acquired_handler (GDBusConnection *connection,
994 const gchar *name,
995 gpointer user_data)
996 {
997 130 g_debug ("Name '%s' acquired", name);
998 130 }
999
1000 static void
1001 130 bus_acquired_handler (GDBusConnection *connection,
1002 const gchar *name,
1003 gpointer user_data)
1004 {
1005 130 PpdBusOwnData *data = user_data;
1006
1007 130 g_dbus_connection_register_object (connection,
1008 POWER_PROFILES_DBUS_PATH,
1009 data->interface,
1010 &interface_vtable,
1011 130 data->app,
1012 NULL,
1013 NULL);
1014
1015 130 g_dbus_connection_register_object (connection,
1016 POWER_PROFILES_LEGACY_DBUS_PATH,
1017 data->legacy_interface,
1018 &interface_vtable,
1019 130 data->app,
1020 NULL,
1021 NULL);
1022
1023 130 data->app->legacy_name_id = g_bus_own_name_on_connection (connection,
1024 POWER_PROFILES_LEGACY_DBUS_NAME,
1025 data->flags,
1026 legacy_name_acquired_handler,
1027 name_lost_handler,
1028 data,
1029 NULL);
1030
1031 130 data->app->connection = g_object_ref (connection);
1032 130 }
1033
1034 static void
1035 66 upower_source_update_from_value (PpdApp *data,
1036 GVariant *battery_val)
1037 {
1038 66 PpdPowerChangedReason reason;
1039
1040
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 44 times.
66 if (!battery_val)
1041 reason = PPD_POWER_CHANGED_REASON_UNKNOWN;
1042
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 14 times.
22 else if (g_variant_get_boolean (battery_val))
1043 reason = PPD_POWER_CHANGED_REASON_BATTERY;
1044 else
1045 8 reason = PPD_POWER_CHANGED_REASON_AC;
1046
1047 66 upower_battery_set_power_changed_reason (data, reason);
1048 66 }
1049
1050 static void
1051 54 upower_source_update (PpdApp *data)
1052 {
1053 108 g_autoptr(GVariant) battery_val = NULL;
1054
1055 54 battery_val = g_dbus_proxy_get_cached_property (data->upower_proxy, "OnBattery");
1056
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 44 times.
54 upower_source_update_from_value (data, battery_val);
1057 54 }
1058
1059 static void
1060 10 upower_battery_changed (PpdApp *data, gdouble level)
1061 {
1062 10 g_info ("Battery level changed to %f", level);
1063
1064
2/2
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 10 times.
40 for (guint i = 0; i < data->actions->len; i++) {
1065 30 g_autoptr(GError) error = NULL;
1066 30 PpdAction *action;
1067
1068 30 action = g_ptr_array_index (data->actions, i);
1069
1070
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
30 if (!ppd_action_battery_changed (action, level, &error)) {
1071 g_warning ("failed to update action %s: %s",
1072 ppd_action_get_action_name (action),
1073 error->message);
1074 g_clear_error (&error);
1075 continue;
1076 }
1077 }
1078
1079
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (PPD_IS_DRIVER_CPU (data->cpu_driver)) {
1080 g_autoptr(GError) error = NULL;
1081
1082 if (!ppd_driver_battery_changed (PPD_DRIVER (data->cpu_driver), level, &error)) {
1083 g_warning ("failed to update driver %s: %s",
1084 ppd_driver_get_driver_name (PPD_DRIVER (data->cpu_driver)),
1085 error->message);
1086 }
1087 }
1088
1089
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 if (PPD_IS_DRIVER_PLATFORM (data->platform_driver)) {
1090 10 g_autoptr(GError) error = NULL;
1091
1092
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (!ppd_driver_battery_changed (PPD_DRIVER (data->platform_driver), level, &error)) {
1093 g_warning ("failed to update driver %s: %s",
1094 ppd_driver_get_driver_name (PPD_DRIVER (data->platform_driver)),
1095 error->message);
1096 }
1097 }
1098 10 }
1099
1100 static void
1101 8 upower_battery_update (PpdApp *data)
1102 {
1103 16 g_autoptr(GVariant) val = NULL;
1104
1105 8 val = g_dbus_proxy_get_cached_property (data->upower_display_proxy, "Percentage");
1106
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (val)
1107 2 upower_battery_changed(data, g_variant_get_double (val));
1108 8 }
1109
1110 static void
1111 29 upower_properties_changed (GDBusProxy *proxy,
1112 GVariant *changed_properties,
1113 GStrv invalidated_properties,
1114 PpdApp *data)
1115 {
1116 58 g_auto(GVariantDict) props_dict = G_VARIANT_DICT_INIT (changed_properties);
1117 29 g_autoptr(GVariant) battery_val = NULL;
1118
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 17 times.
29 g_autoptr(GVariant) percent_val = NULL;
1119
1120 29 battery_val = g_variant_dict_lookup_value (&props_dict, "OnBattery",
1121 G_VARIANT_TYPE_BOOLEAN);
1122
1123
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 17 times.
29 if (battery_val)
1124 12 upower_source_update_from_value (data, battery_val);
1125
1126 29 percent_val = g_variant_dict_lookup_value (&props_dict, "Percentage",
1127 G_VARIANT_TYPE_DOUBLE);
1128
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 21 times.
29 if (percent_val)
1129 8 upower_battery_changed (data, g_variant_get_double (percent_val));
1130 29 }
1131
1132 static void
1133 209 upower_battery_set_power_changed_reason (PpdApp *data,
1134 PpdPowerChangedReason reason)
1135 {
1136
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 169 times.
209 if (data->power_changed_reason == reason)
1137 return;
1138
1139 40 data->power_changed_reason = reason;
1140 40 g_info ("Power Changed because of reason %s",
1141 ppd_power_changed_reason_to_str (reason));
1142
1143
2/2
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 40 times.
88 for (guint i = 0; i < data->actions->len; i++) {
1144 48 g_autoptr(GError) error = NULL;
1145 48 PpdAction *action;
1146
1147 48 action = g_ptr_array_index (data->actions, i);
1148
1149
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
48 if (!ppd_action_power_changed (action, reason, &error)) {
1150 g_warning ("failed to update action %s: %s",
1151 ppd_action_get_action_name (action),
1152 error->message);
1153 g_clear_error (&error);
1154 continue;
1155 }
1156 }
1157
1158
2/2
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 4 times.
40 if (PPD_IS_DRIVER_CPU (data->cpu_driver)) {
1159 36 g_autoptr(GError) error = NULL;
1160
1161
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
36 if (!ppd_driver_power_changed (PPD_DRIVER (data->cpu_driver), reason, &error)) {
1162 g_warning ("failed to update driver %s: %s",
1163 ppd_driver_get_driver_name (PPD_DRIVER (data->cpu_driver)),
1164 error->message);
1165 }
1166 }
1167
1168
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 if (PPD_IS_DRIVER_PLATFORM (data->platform_driver)) {
1169 40 g_autoptr(GError) error = NULL;
1170
1171
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 if (!ppd_driver_power_changed (PPD_DRIVER (data->platform_driver), reason, &error)) {
1172 g_warning ("failed to update driver %s: %s",
1173 ppd_driver_get_driver_name (PPD_DRIVER (data->platform_driver)),
1174 error->message);
1175 }
1176 }
1177 }
1178
1179 static void
1180 15 upower_name_owner_changed (GObject *object,
1181 GParamSpec *pspec,
1182 gpointer user_data)
1183 {
1184 15 PpdApp *data = user_data;
1185 15 GDBusProxy *upower_proxy = G_DBUS_PROXY (object);
1186 15 g_autofree char *name_owner = NULL;
1187
1188 15 name_owner = g_dbus_proxy_get_name_owner (upower_proxy);
1189
1190
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 7 times.
15 if (name_owner != NULL) {
1191 8 g_debug ("%s appeared", UPOWER_DBUS_NAME);
1192 8 upower_source_update (data);
1193 8 return;
1194 }
1195
1196 7 g_debug ("%s vanished", UPOWER_DBUS_NAME);
1197 7 upower_battery_set_power_changed_reason (data, PPD_POWER_CHANGED_REASON_UNKNOWN);
1198 }
1199
1200 static void
1201 46 on_upower_proxy_cb (GObject *source_object,
1202 GAsyncResult *res,
1203 gpointer user_data)
1204 {
1205 46 PpdApp *data = user_data;
1206 46 g_autoptr(GDBusProxy) upower_proxy = NULL;
1207
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
46 g_autoptr(GError) error = NULL;
1208
1209 46 upower_proxy = g_dbus_proxy_new_finish (res, &error);
1210
1211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (upower_proxy == NULL) {
1212 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1213 return;
1214
1215 g_warning ("failed to connect to upower: %s", error->message);
1216 return;
1217 }
1218
1219
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 g_return_if_fail (data->upower_proxy == NULL);
1220 46 data->upower_proxy = g_steal_pointer (&upower_proxy);
1221
1222 46 data->upower_properties_id = g_signal_connect (data->upower_proxy,
1223 "g-properties-changed",
1224 G_CALLBACK (upower_properties_changed),
1225 data);
1226
1227
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (!data->upower_display_watch_id) {
1228 46 data->upower_watch_id = g_signal_connect (data->upower_proxy,
1229 "notify::g-name-owner",
1230 G_CALLBACK (upower_name_owner_changed),
1231 data);
1232 }
1233
1234
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
46 upower_source_update (data);
1235 }
1236
1237 static void
1238 8 on_upower_display_proxy_cb (GObject *source_object,
1239 GAsyncResult *res,
1240 gpointer user_data)
1241 {
1242 8 PpdApp *data = user_data;
1243 8 g_autoptr(GDBusProxy) proxy = NULL;
1244
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
8 g_autoptr(GError) error = NULL;
1245
1246 8 proxy = g_dbus_proxy_new_finish (res, &error);
1247
1248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (proxy == NULL) {
1249 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1250 return;
1251
1252 g_warning ("failed to connect to upower: %s", error->message);
1253 return;
1254 }
1255
1256
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 g_return_if_fail (data->upower_display_proxy == NULL);
1257 8 data->upower_display_proxy = g_steal_pointer (&proxy);
1258
1259 8 data->upower_display_properties_id = g_signal_connect (data->upower_display_proxy,
1260 "g-properties-changed",
1261 G_CALLBACK (upower_properties_changed),
1262 data);
1263
1264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!data->upower_watch_id) {
1265 data->upower_display_watch_id = g_signal_connect (data->upower_display_proxy,
1266 "notify::g-name-owner",
1267 G_CALLBACK (upower_name_owner_changed),
1268 data);
1269 }
1270
1271
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 upower_battery_update (data);
1272 }
1273
1274 static void
1275 4 on_logind_prepare_for_sleep_cb (GDBusConnection *connection,
1276 const gchar *sender_name,
1277 const gchar *object_path,
1278 const gchar *interface_name,
1279 const gchar *signal_name,
1280 GVariant *parameters,
1281 gpointer user_data)
1282 {
1283 4 PpdApp *data = user_data;
1284 4 gboolean start;
1285
1286 4 g_variant_get (parameters, "(b)", &start);
1287
1288
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (start)
1289 2 g_debug ("System preparing for suspend");
1290 else
1291 2 g_debug ("System woke up from suspend");
1292
1293
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (PPD_IS_DRIVER_CPU (data->cpu_driver)) {
1294 4 g_autoptr(GError) error = NULL;
1295
1296
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (!ppd_driver_prepare_to_sleep (PPD_DRIVER (data->cpu_driver), start, &error)) {
1297 g_warning ("failed to notify driver %s: %s",
1298 ppd_driver_get_driver_name (PPD_DRIVER (data->cpu_driver)),
1299 error->message);
1300 }
1301 }
1302
1303
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (PPD_IS_DRIVER_PLATFORM (data->platform_driver)) {
1304 4 g_autoptr(GError) error = NULL;
1305
1306
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (!ppd_driver_prepare_to_sleep (PPD_DRIVER (data->platform_driver), start, &error)) {
1307 g_warning ("failed to notify driver %s: %s",
1308 ppd_driver_get_driver_name (PPD_DRIVER (data->platform_driver)),
1309 error->message);
1310 }
1311 }
1312 4 }
1313
1314 static gboolean
1315 134 has_required_drivers (PpdApp *data)
1316 {
1317
3/4
✓ Branch 1 taken 94 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 94 times.
228 if (!PPD_IS_DRIVER_CPU (data->cpu_driver) &&
1318 94 !PPD_IS_DRIVER_PLATFORM (data->platform_driver))
1319 return FALSE;
1320
1321
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
134 if (!get_profile_available (data, PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER))
1322 return FALSE;
1323
1324 return TRUE;
1325 }
1326
1327 static void
1328 4 restart_profile_drivers (PpdApp *data)
1329 {
1330 4 stop_profile_drivers (data);
1331 4 start_profile_drivers (data);
1332 }
1333
1334 static void
1335 4 driver_probe_request_cb (PpdDriver *driver,
1336 gpointer user_data)
1337 {
1338 4 PpdApp *data = user_data;
1339
1340 4 restart_profile_drivers (data);
1341 4 }
1342
1343 static void
1344 272 disconnect_array_objects_signals_by_data (GPtrArray *array,
1345 void *data)
1346 {
1347
2/2
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 272 times.
428 for (guint i = 0; i < array->len; ++i) {
1348 156 GObject *object = g_ptr_array_index (array, i);
1349
1350 156 g_signal_handlers_disconnect_by_data (object, data);
1351 }
1352 272 }
1353
1354 static void
1355 544 maybe_disconnect_object_by_data (void *object,
1356 void *data)
1357 {
1358
2/2
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 316 times.
544 if (!G_IS_OBJECT (object))
1359 return;
1360
1361 228 g_signal_handlers_disconnect_by_data (object, data);
1362 }
1363
1364 static void
1365 136 stop_profile_drivers (PpdApp *data)
1366 {
1367
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 114 times.
136 if (data->logind_sleep_signal_id) {
1368 22 g_dbus_connection_signal_unsubscribe (data->connection, data->logind_sleep_signal_id);
1369 22 data->logind_sleep_signal_id = 0;
1370 }
1371
1372 136 upower_battery_set_power_changed_reason (data, PPD_POWER_CHANGED_REASON_UNKNOWN);
1373 136 release_all_profile_holds (data);
1374 136 g_cancellable_cancel (data->cancellable);
1375 136 disconnect_array_objects_signals_by_data (data->probed_drivers, data);
1376 136 g_ptr_array_set_size (data->probed_drivers, 0);
1377 136 disconnect_array_objects_signals_by_data (data->actions, data);
1378 136 g_ptr_array_set_size (data->actions, 0);
1379
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 90 times.
136 g_clear_signal_handler (&data->upower_watch_id, data->upower_proxy);
1380
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 90 times.
136 g_clear_signal_handler (&data->upower_properties_id, data->upower_proxy);
1381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 136 times.
136 g_clear_signal_handler (&data->upower_display_watch_id, data->upower_display_proxy);
1382
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 128 times.
136 g_clear_signal_handler (&data->upower_display_properties_id, data->upower_display_proxy);
1383
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 2 times.
136 g_clear_object (&data->cancellable);
1384 136 maybe_disconnect_object_by_data (data->upower_proxy, data);
1385
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 90 times.
136 g_clear_object (&data->upower_proxy);
1386 136 maybe_disconnect_object_by_data (data->upower_display_proxy, data);
1387
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 128 times.
136 g_clear_object (&data->upower_display_proxy);
1388 136 maybe_disconnect_object_by_data (data->cpu_driver, data);
1389
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 96 times.
136 g_clear_object (&data->cpu_driver);
1390 136 maybe_disconnect_object_by_data (data->platform_driver, data);
1391
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 2 times.
136 g_clear_object (&data->platform_driver);
1392 136 }
1393
1394 static gboolean
1395 402 action_blocked (PpdApp *app, PpdAction *action)
1396 {
1397 402 const gchar *action_name = ppd_action_get_action_name (action);
1398 402 gboolean blocked;
1399
1400
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 396 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
402 if (app->debug_options->blocked_actions == NULL || g_strv_length (app->debug_options->blocked_actions) == 0)
1401 396 return FALSE;
1402
1403 6 blocked = g_strv_contains ((const gchar *const *) app->debug_options->blocked_actions, action_name);
1404
1405
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (blocked)
1406 2 g_debug ("Action '%s' is blocked", action_name);
1407 return blocked;
1408 }
1409
1410 static gboolean
1411 670 driver_blocked (PpdApp *app, PpdDriver *driver)
1412 {
1413 670 const gchar *driver_name = ppd_driver_get_driver_name (driver);
1414 670 gboolean blocked;
1415
1416
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 650 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
670 if (app->debug_options->blocked_drivers == NULL || g_strv_length (app->debug_options->blocked_drivers) == 0)
1417 650 return FALSE;
1418
1419 20 blocked = g_strv_contains ((const gchar *const *) app->debug_options->blocked_drivers, driver_name);
1420
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 14 times.
20 if (blocked)
1421 6 g_debug ("Driver '%s' is blocked", driver_name);
1422 return blocked;
1423 }
1424
1425 static void
1426 134 start_profile_drivers (PpdApp *data)
1427 {
1428 134 guint i;
1429 134 g_autoptr(GError) initial_error = NULL;
1430 134 gboolean needs_battery_state_monitor = FALSE;
1431 134 gboolean needs_battery_change_monitor = FALSE;
1432 134 gboolean needs_suspend_monitor = FALSE;
1433
1434 134 data->cancellable = g_cancellable_new ();
1435
1436
2/2
✓ Branch 0 taken 1072 times.
✓ Branch 1 taken 134 times.
1206 for (i = 0; i < G_N_ELEMENTS (objects); i++) {
1437
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
1072 g_autoptr(GObject) object = NULL;
1438
1439 1072 object = g_object_new (objects[i] (), NULL);
1440
1441
2/2
✓ Branch 1 taken 670 times.
✓ Branch 2 taken 402 times.
1072 if (PPD_IS_DRIVER (object)) {
1442
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
1742 g_autoptr(PpdDriver) driver = PPD_DRIVER (g_steal_pointer (&object));
1443 670 PpdProfile profiles;
1444 670 PpdProbeResult result;
1445
1446 670 g_debug ("Handling driver '%s'", ppd_driver_get_driver_name (driver));
1447
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 664 times.
670 if (driver_blocked (data, driver)) {
1448 6 g_debug ("Driver '%s' is blocked, skipping", ppd_driver_get_driver_name (driver));
1449 6 continue;
1450 }
1451
1452
4/4
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 600 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 40 times.
664 if (PPD_IS_DRIVER_CPU (data->cpu_driver) && PPD_IS_DRIVER_CPU (driver)) {
1453 24 g_debug ("CPU driver '%s' already probed, skipping driver '%s'",
1454 ppd_driver_get_driver_name (PPD_DRIVER (data->cpu_driver)),
1455 ppd_driver_get_driver_name (driver));
1456 24 continue;
1457 }
1458
1459
4/4
✓ Branch 1 taken 154 times.
✓ Branch 2 taken 486 times.
✓ Branch 4 taken 54 times.
✓ Branch 5 taken 100 times.
640 if (PPD_IS_DRIVER_PLATFORM (data->platform_driver) && PPD_IS_DRIVER_PLATFORM (driver)) {
1460 54 g_debug ("Platform driver '%s' already probed, skipping driver '%s'",
1461 ppd_driver_get_driver_name (PPD_DRIVER (data->platform_driver)),
1462 ppd_driver_get_driver_name (driver));
1463 54 continue;
1464 }
1465
1466 586 profiles = ppd_driver_get_profiles (driver);
1467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 586 times.
586 if (!(profiles & PPD_PROFILE_ALL)) {
1468 g_warning ("Profile Driver '%s' implements invalid profiles '0x%X'",
1469 ppd_driver_get_driver_name (driver),
1470 profiles);
1471 continue;
1472 }
1473
1474 586 result = ppd_driver_probe (driver);
1475
2/2
✓ Branch 0 taken 408 times.
✓ Branch 1 taken 178 times.
586 if (result == PPD_PROBE_RESULT_FAIL) {
1476 408 g_debug ("probe () failed for driver %s, skipping",
1477 ppd_driver_get_driver_name (driver));
1478 408 continue;
1479 }
1480
1481
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 174 times.
178 if (result == PPD_PROBE_RESULT_DEFER) {
1482 4 g_signal_connect (G_OBJECT (driver), "probe-request",
1483 G_CALLBACK (driver_probe_request_cb), data);
1484 4 g_ptr_array_add (data->probed_drivers, g_steal_pointer (&driver));
1485 4 continue;
1486 }
1487
1488
2/2
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 134 times.
174 if (PPD_IS_DRIVER_CPU (driver))
1489 40 g_set_object (&data->cpu_driver, PPD_DRIVER_CPU (driver));
1490
1/2
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
134 else if (PPD_IS_DRIVER_PLATFORM (driver))
1491 134 g_set_object (&data->platform_driver, PPD_DRIVER_PLATFORM (driver));
1492 else
1493 g_return_if_reached ();
1494
1495
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 134 times.
174 if (PPD_DRIVER_GET_CLASS (driver)->power_changed != NULL)
1496 40 needs_battery_state_monitor = TRUE;
1497
1498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 174 times.
174 if (PPD_DRIVER_GET_CLASS (driver)->battery_changed != NULL)
1499 needs_battery_change_monitor = TRUE;
1500
1501
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 150 times.
174 if (PPD_DRIVER_GET_CLASS (driver)->prepare_to_sleep != NULL)
1502 24 needs_suspend_monitor = TRUE;
1503
1504 174 g_info ("Driver '%s' loaded", ppd_driver_get_driver_name (driver));
1505
1506 174 g_signal_connect (G_OBJECT (driver), "notify::performance-degraded",
1507 G_CALLBACK (driver_performance_degraded_changed_cb), data);
1508 174 g_signal_connect (G_OBJECT (driver), "profile-changed",
1509 G_CALLBACK (driver_profile_changed_cb), data);
1510 174 continue;
1511 }
1512
1513
1/2
✓ Branch 1 taken 402 times.
✗ Branch 2 not taken.
402 if (PPD_IS_ACTION (object)) {
1514 402 g_autoptr(PpdAction) action = PPD_ACTION (g_steal_pointer (&object));
1515
1516 402 g_debug ("Handling action '%s'", ppd_action_get_action_name (action));
1517
1518
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 400 times.
402 if (action_blocked (data, action)) {
1519 2 g_debug ("Action '%s' is blocked, skipping", ppd_action_get_action_name (action));
1520 2 continue;
1521 }
1522
1523
2/2
✓ Branch 1 taken 248 times.
✓ Branch 2 taken 152 times.
400 if (ppd_action_probe (action) == PPD_PROBE_RESULT_FAIL) {
1524 248 g_debug ("probe () failed for action '%s', skipping",
1525 ppd_action_get_action_name (action));
1526 248 continue;
1527 }
1528
1529
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 144 times.
152 if (PPD_ACTION_GET_CLASS (action)->power_changed != NULL)
1530 8 needs_battery_state_monitor = TRUE;
1531
1532
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 144 times.
152 if (PPD_ACTION_GET_CLASS (action)->battery_changed != NULL)
1533 8 needs_battery_change_monitor = TRUE;
1534
1535 152 g_info ("Action '%s' loaded", ppd_action_get_action_name (action));
1536 152 g_ptr_array_add (data->actions, g_steal_pointer (&action));
1537 152 continue;
1538 }
1539
1540
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
1072 g_return_if_reached ();
1541 }
1542
1543
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
134 if (!has_required_drivers (data)) {
1544 data->ret = EXIT_FAILURE;
1545 g_warning ("Some non-optional profile drivers are missing, programmer error");
1546 g_main_loop_quit (data->main_loop);
1547 }
1548
1549 /* Set initial state either from configuration, or using the currently selected profile */
1550 134 apply_configuration (data);
1551
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 132 times.
134 if (!activate_target_profile (data, data->active_profile, PPD_PROFILE_ACTIVATION_REASON_RESET, &initial_error))
1552 2 g_warning ("Failed to activate initial profile: %s", initial_error->message);
1553
1554 134 send_dbus_event (data, PROP_ALL);
1555 134 data->was_started = TRUE;
1556
1557
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 132 times.
134 if (data->debug_options->disable_upower) {
1558 2 g_debug ("upower is disabled, let's skip it");
1559
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 86 times.
132 } else if (needs_battery_state_monitor || needs_battery_change_monitor) {
1560 /* start watching for power changes */
1561
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (needs_battery_state_monitor) {
1562 46 g_debug ("Battery state monitor required, connecting to upower...");
1563 46 g_dbus_proxy_new (data->connection,
1564 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
1565 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1566 NULL,
1567 UPOWER_DBUS_NAME,
1568 UPOWER_DBUS_PATH,
1569 UPOWER_DBUS_INTERFACE,
1570 data->cancellable,
1571 on_upower_proxy_cb,
1572 data);
1573 }
1574
1575
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 38 times.
46 if (needs_battery_change_monitor) {
1576 8 g_debug ("Battery change monitor required, connecting to upower...");
1577 8 g_dbus_proxy_new (data->connection,
1578 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
1579 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1580 NULL,
1581 UPOWER_DBUS_NAME,
1582 UPOWER_DBUS_DISPLAY_DEVICE_PATH,
1583 UPOWER_DBUS_DEVICE_INTERFACE,
1584 data->cancellable,
1585 on_upower_display_proxy_cb,
1586 data);
1587 }
1588 } else {
1589 86 g_debug ("No battery state monitor required by any driver, let's skip it");
1590 }
1591
1592
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 132 times.
134 if (data->debug_options->disable_logind) {
1593 2 g_debug ("logind is disabled, let's skip it");
1594
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 110 times.
132 } else if (needs_suspend_monitor) {
1595 22 g_debug ("Suspension state monitor required, monitoring logind...");
1596 22 data->logind_sleep_signal_id =
1597 22 g_dbus_connection_signal_subscribe (data->connection,
1598 LOGIND_DBUS_NAME,
1599 LOGIND_DBUS_INTERFACE,
1600 "PrepareForSleep",
1601 LOGIND_DBUS_PATH,
1602 NULL,
1603 G_DBUS_SIGNAL_FLAGS_NONE,
1604 on_logind_prepare_for_sleep_cb,
1605 data,
1606 NULL);
1607 } else {
1608 110 g_debug ("No suspension monitor required by any driver, let's skip it");
1609 }
1610 }
1611
1612 void
1613 restart_profile_drivers_for_default_app (void)
1614 {
1615 restart_profile_drivers (ppd_app);
1616 }
1617
1618
1619 static void
1620 130 name_acquired_handler (GDBusConnection *connection,
1621 const gchar *name,
1622 gpointer user_data)
1623 {
1624 130 PpdBusOwnData *data = user_data;
1625
1626 130 g_debug ("Name '%s' acquired", name);
1627
1628 130 start_profile_drivers (data->app);
1629 130 }
1630
1631 static gboolean
1632 132 setup_dbus (PpdApp *data,
1633 GError **error)
1634 {
1635 264 g_autoptr(GBytes) iface_data = NULL;
1636
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_autoptr(GBytes) legacy_iface_data = NULL;
1637
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_autoptr(GDBusNodeInfo) introspection_data = NULL;
1638
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_autoptr(GDBusNodeInfo) legacy_introspection_data = NULL;
1639 132 PpdBusOwnData *own_data;
1640
1641 132 iface_data = g_resources_lookup_data (POWER_PROFILES_RESOURCES_PATH "/"
1642 POWER_PROFILES_DBUS_NAME ".xml",
1643 G_RESOURCE_LOOKUP_FLAGS_NONE,
1644 error);
1645
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 if (!iface_data)
1646 return FALSE;
1647
1648 132 legacy_iface_data = g_resources_lookup_data (POWER_PROFILES_RESOURCES_PATH "/"
1649 POWER_PROFILES_LEGACY_DBUS_NAME ".xml",
1650 G_RESOURCE_LOOKUP_FLAGS_NONE,
1651 error);
1652
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
132 if (!legacy_iface_data)
1653 return FALSE;
1654
1655 132 introspection_data = g_dbus_node_info_new_for_xml (g_bytes_get_data (iface_data, NULL),
1656 error);
1657
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 if (!introspection_data)
1658 return FALSE;
1659
1660 132 legacy_introspection_data = g_dbus_node_info_new_for_xml (g_bytes_get_data (legacy_iface_data, NULL),
1661 error);
1662
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 if (!legacy_introspection_data)
1663 return FALSE;
1664
1665 132 own_data = g_new0 (PpdBusOwnData, 1);
1666 132 own_data->app = data;
1667 132 own_data->interface = g_dbus_interface_info_ref (introspection_data->interfaces[0]);
1668 132 own_data->legacy_interface = g_dbus_interface_info_ref (legacy_introspection_data->interfaces[0]);
1669
1670 132 own_data->flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
1671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
132 if (data->debug_options->replace)
1672 own_data->flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE;
1673
1674 132 data->name_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1675 POWER_PROFILES_DBUS_NAME,
1676 own_data->flags,
1677 bus_acquired_handler,
1678 name_acquired_handler,
1679 name_lost_handler,
1680 own_data,
1681 (GDestroyNotify) ppd_bus_own_data_free);
1682
1683 132 return TRUE;
1684 }
1685
1686 static void
1687 132 free_app_data (PpdApp *data)
1688 {
1689
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 if (data == NULL)
1690 return;
1691
1692 132 stop_profile_drivers (data);
1693
1694
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_clear_handle_id (&data->name_id, g_bus_unown_name);
1695
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 2 times.
132 g_clear_handle_id (&data->legacy_name_id, g_bus_unown_name);
1696
1697
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_clear_pointer (&data->debug_options, debug_options_free);
1698
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_clear_pointer (&data->config_path, g_free);
1699
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_clear_pointer (&data->config, g_key_file_unref);
1700
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_clear_pointer (&data->probed_drivers, g_ptr_array_unref);
1701
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_clear_pointer (&data->actions, g_ptr_array_unref);
1702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
132 g_clear_object (&data->cpu_driver);
1703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
132 g_clear_object (&data->platform_driver);
1704 132 g_hash_table_destroy (data->profile_holds);
1705
1706
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 2 times.
132 g_clear_object (&data->auth);
1707
1708
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_clear_pointer (&data->main_loop, g_main_loop_unref);
1709
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 2 times.
132 g_clear_object (&data->connection);
1710 132 g_free (data);
1711 132 ppd_app = NULL;
1712 }
1713
1714 132 G_DEFINE_AUTOPTR_CLEANUP_FUNC (PpdApp, free_app_data)
1715
1716 void
1717 main_loop_quit (void)
1718 {
1719 g_main_loop_quit (ppd_app->main_loop);
1720 }
1721
1722 static inline gboolean
1723 5610 use_colored_ouput (void)
1724 {
1725
1/2
✓ Branch 1 taken 5610 times.
✗ Branch 2 not taken.
5610 if (g_getenv ("NO_COLOR"))
1726 return FALSE;
1727 5610 return isatty (fileno (stdout));
1728 }
1729
1730 static void
1731 5614 debug_handler_cb (const gchar *log_domain,
1732 GLogLevelFlags log_level,
1733 const gchar *message,
1734 gpointer user_data)
1735 {
1736 5614 DebugOptions *data = user_data;
1737 5610 g_autoptr(GString) domain = NULL;
1738 5614 gboolean use_color;
1739 5614 gint color;
1740
1741 /* not in verbose mode */
1742
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5610 times.
5614 if (log_level > data->log_level)
1743 4 return;
1744
1745 5610 domain = g_string_new (log_domain);
1746 5610 use_color = use_colored_ouput ();
1747
1748
2/2
✓ Branch 0 taken 48436 times.
✓ Branch 1 taken 5610 times.
54046 for (gsize i = domain->len; i < 15; i++)
1749
1/2
✓ Branch 0 taken 48436 times.
✗ Branch 1 not taken.
96872 g_string_append_c (domain, ' ');
1750 5610 g_print ("%s", domain->str);
1751
1752
2/2
✓ Branch 0 taken 5604 times.
✓ Branch 1 taken 6 times.
5610 switch (log_level) {
1753 case G_LOG_LEVEL_ERROR:
1754 case G_LOG_LEVEL_CRITICAL:
1755 case G_LOG_LEVEL_WARNING:
1756 color = 31; /* red */
1757 break;
1758 5604 default:
1759 5604 color = 34; /* blue */
1760 5604 break;
1761 }
1762
1763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5610 times.
5610 if (use_color)
1764 g_print ("%c[%dm%s\n%c[%dm", 0x1B, color, message, 0x1B, 0);
1765 else
1766 5610 g_print ("%s\n", message);
1767 }
1768
1769 static gboolean
1770 130 quit_signal_callback (gpointer user_data)
1771 {
1772 130 PpdApp *data = user_data;
1773
1774 130 g_main_loop_quit (data->main_loop);
1775 130 return FALSE;
1776 }
1777
1778 static gboolean
1779 260 verbose_arg_cb (const gchar *option_name,
1780 const gchar *value,
1781 gpointer user_data,
1782 GError **error)
1783 {
1784 260 DebugOptions *data = user_data;
1785
1786
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 130 times.
260 if (data->log_level == G_LOG_LEVEL_MESSAGE) {
1787 130 data->log_level = G_LOG_LEVEL_INFO;
1788 130 return TRUE;
1789 }
1790
1/2
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
130 if (data->log_level == G_LOG_LEVEL_INFO) {
1791 130 data->log_level = G_LOG_LEVEL_DEBUG;
1792 130 return TRUE;
1793 }
1794 g_set_error_literal (error,
1795 G_OPTION_ERROR,
1796 G_OPTION_ERROR_FAILED,
1797 "No further debug level supported");
1798 return FALSE;
1799 }
1800
1801 static gboolean
1802 132 debug_pre_parse_hook (GOptionContext *context,
1803 GOptionGroup *group,
1804 gpointer user_data,
1805 GError **error)
1806 {
1807 132 DebugOptions *data = user_data;
1808
1809 132 const GOptionEntry options[] = {
1810 {
1811 "verbose",
1812 'v',
1813 G_OPTION_FLAG_NO_ARG,
1814 G_OPTION_ARG_CALLBACK,
1815 (GOptionArgFunc)verbose_arg_cb,
1816 "Show extra debugging information",
1817 NULL,
1818 },
1819 {
1820 "replace",
1821 'r',
1822 G_OPTION_FLAG_NONE,
1823 G_OPTION_ARG_NONE,
1824 132 &data->replace,
1825 "Replace the running instance of power-profiles-daemon",
1826 NULL,
1827 },
1828 {
1829 "block-driver",
1830 0,
1831 G_OPTION_FLAG_NONE,
1832 G_OPTION_ARG_STRING_ARRAY,
1833 132 &data->blocked_drivers,
1834 "Block driver(s) from loading",
1835 NULL,
1836 },
1837 {
1838 "block-action",
1839 0,
1840 G_OPTION_FLAG_NONE,
1841 G_OPTION_ARG_STRING_ARRAY,
1842 132 &data->blocked_actions,
1843 "Block action(s) from loading",
1844 NULL,
1845 },
1846 {
1847 "disable-upower",
1848 0,
1849 G_OPTION_FLAG_NONE,
1850 G_OPTION_ARG_NONE,
1851 132 &data->disable_upower,
1852 "Disable upower integration",
1853 NULL,
1854 },
1855 {
1856 "disable-logind",
1857 0,
1858 G_OPTION_FLAG_NONE,
1859 G_OPTION_ARG_NONE,
1860 132 &data->disable_logind,
1861 "Disable logind integration",
1862 NULL,
1863 },
1864 { NULL }
1865 };
1866 132 g_option_group_add_entries (group, options);
1867
1868 132 return TRUE;
1869 }
1870
1871 static gboolean
1872 132 debug_post_parse_hook (GOptionContext *context,
1873 GOptionGroup *group,
1874 gpointer user_data,
1875 GError **error)
1876 {
1877 132 DebugOptions *debug = (DebugOptions *)user_data;
1878
1879 132 g_log_set_default_handler (debug_handler_cb, debug);
1880
1881 132 return TRUE;
1882 }
1883
1884 132 int main (int argc, char **argv)
1885 {
1886 132 g_autoptr(DebugOptions) debug_options = g_new0 (DebugOptions, 1);
1887
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
132 g_autoptr(PpdApp) data = NULL;
1888
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_autoptr(GOptionContext) option_context = NULL;
1889
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 g_autoptr(GError) error = NULL;
1890
1891 132 debug_options->log_level = G_LOG_LEVEL_MESSAGE;
1892 132 debug_options->group = g_option_group_new ("debug",
1893 "Debugging Options",
1894 "Show debugging options",
1895 debug_options,
1896 NULL);
1897 132 g_option_group_set_parse_hooks (debug_options->group,
1898 debug_pre_parse_hook,
1899 debug_post_parse_hook);
1900
1901 132 setlocale (LC_ALL, "");
1902 132 option_context = g_option_context_new ("");
1903 132 g_option_context_add_group (option_context, debug_options->group);
1904
1905
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 132 times.
132 if (!g_option_context_parse (option_context, &argc, &argv, &error)) {
1906 g_print ("Failed to parse arguments: %s\n", error->message);
1907 return EXIT_FAILURE;
1908 }
1909
1910 132 data = g_new0 (PpdApp, 1);
1911 132 data->main_loop = g_main_loop_new (NULL, TRUE);
1912 132 data->auth = polkit_authority_get_sync (NULL, NULL);
1913 132 data->probed_drivers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
1914 132 data->actions = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
1915 132 data->profile_holds = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) profile_hold_free);
1916 132 data->active_profile = PPD_PROFILE_BALANCED;
1917 132 data->selected_profile = PPD_PROFILE_BALANCED;
1918 132 data->debug_options = g_steal_pointer(&debug_options);
1919
1920 132 g_unix_signal_add (SIGTERM, quit_signal_callback, data);
1921 132 g_unix_signal_add (SIGINT, quit_signal_callback, data);
1922
1923 132 g_info ("Starting power-profiles-daemon version "VERSION);
1924
1925 132 load_configuration (data);
1926 132 ppd_app = data;
1927
1928 /* Set up D-Bus */
1929
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 132 times.
132 if (!setup_dbus (data, &error)) {
1930 g_error ("Failed to start dbus: %s", error->message);
1931 return EXIT_FAILURE;
1932 }
1933
1934 132 g_main_loop_run (data->main_loop);
1935
1936 132 return data->ret;
1937 }
1938