blob: f715e92be554c03328954373ff863ef6bd67b74c [file] [log] [blame]
David Sodmanbbcb0522014-09-19 10:34:07 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Dominik Behrf50c98f2016-03-31 14:05:29 -07007#if DBUS
8#include <dbus/dbus.h>
David Sodmanbbcb0522014-09-19 10:34:07 -07009#include <stdlib.h>
Mike Frysinger006bdb22016-09-14 13:43:48 -040010#include <unistd.h>
David Sodman8ef20062015-01-06 09:23:40 -080011
Stéphane Marchesin62561a12015-12-11 17:32:37 -080012#include "dbus.h"
David Sodman8ef20062015-01-06 09:23:40 -080013#include "dbus_interface.h"
14#include "image.h"
Dominik Behr46c567f2016-03-08 15:11:48 -080015#include "main.h"
David Sodman8ef20062015-01-06 09:23:40 -080016#include "term.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070017#include "util.h"
18
Dominik Behr5f6742f2016-03-10 18:03:54 -080019#define DBUS_WAIT_DELAY_US (50000)
David Sodman8ef20062015-01-06 09:23:40 -080020#define DBUS_DEFAULT_DELAY 3000
Dominik Behr5f6742f2016-03-10 18:03:54 -080021#define DBUS_INIT_TIMEOUT_MS (60*1000)
David Sodman8ef20062015-01-06 09:23:40 -080022
Dominik Behr797a3832016-01-11 15:53:11 -080023typedef struct _dbus_t dbus_t;
24
Dominik Behr46c567f2016-03-08 15:11:48 -080025static void (*login_prompt_visible_callback)(void*) = NULL;
26static void* login_prompt_visible_callback_userptr = NULL;
Dominik Behr1883c042016-04-27 12:31:02 -070027static void (*suspend_done_callback)(void*) = NULL;
28static void* suspend_done_callback_userptr = NULL;
Dominik Behr46c567f2016-03-08 15:11:48 -080029static bool chrome_is_already_up = false;
Dominik Behr5f6742f2016-03-10 18:03:54 -080030static bool dbus_connect_fail = false;
31static int64_t dbus_connect_fail_time;
32static bool dbus_first_init = true;
33static int64_t dbus_first_init_time;
Dominik Behr46c567f2016-03-08 15:11:48 -080034
David Sodmanbbcb0522014-09-19 10:34:07 -070035struct _dbus_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080036 DBusConnection* conn;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080037 DBusWatch* watch;
David Sodman8ef20062015-01-06 09:23:40 -080038 int fd;
David Sodmanbbcb0522014-09-19 10:34:07 -070039};
40
Dominik Behr797a3832016-01-11 15:53:11 -080041static dbus_t *dbus = NULL;
42
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080043static void frecon_dbus_unregister(DBusConnection* connection, void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -080044{
45}
46
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080047static DBusHandlerResult frecon_dbus_message_handler(DBusConnection* connection,
48 DBusMessage* message,
49 void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -080050{
David Sodman8ef20062015-01-06 09:23:40 -080051 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
David Sodman8ef20062015-01-06 09:23:40 -080052}
53
54static DBusObjectPathVTable
55frecon_vtable = {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -080056 frecon_dbus_unregister,
57 frecon_dbus_message_handler,
David Sodman8ef20062015-01-06 09:23:40 -080058 NULL
59};
60
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080061static dbus_bool_t add_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -080062{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080063 dbus_t* dbus = (dbus_t*)data;
David Sodman8ef20062015-01-06 09:23:40 -080064 dbus->watch = w;
65
66 return TRUE;
67}
68
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080069static void remove_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -080070{
71}
72
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080073static void toggle_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -080074{
75}
76
Dominik Behr46c567f2016-03-08 15:11:48 -080077static DBusHandlerResult handle_login_prompt_visible(DBusMessage* message)
78{
79 if (login_prompt_visible_callback) {
80 login_prompt_visible_callback(login_prompt_visible_callback_userptr);
81 login_prompt_visible_callback = NULL;
82 login_prompt_visible_callback_userptr = NULL;
83 }
84 chrome_is_already_up = true;
85
86 return DBUS_HANDLER_RESULT_HANDLED;
87}
88
Dominik Behr1883c042016-04-27 12:31:02 -070089static DBusHandlerResult handle_suspend_done(DBusMessage* message)
90{
91 if (suspend_done_callback)
92 suspend_done_callback(suspend_done_callback_userptr);
93
94 return DBUS_HANDLER_RESULT_HANDLED;
95}
96
Dominik Behr46c567f2016-03-08 15:11:48 -080097static DBusHandlerResult frecon_dbus_message_filter(DBusConnection* connection,
98 DBusMessage* message,
99 void* user_data)
100{
101 if (dbus_message_is_signal(message,
Dominik Behr5f6742f2016-03-10 18:03:54 -0800102 kSessionManagerInterface, kLoginPromptVisibleSignal))
Dominik Behr46c567f2016-03-08 15:11:48 -0800103 return handle_login_prompt_visible(message);
Dominik Behr1883c042016-04-27 12:31:02 -0700104 else if (dbus_message_is_signal(message,
105 kPowerManagerInterface, kSuspendDoneSignal))
106 return handle_suspend_done(message);
Dominik Behr46c567f2016-03-08 15:11:48 -0800107
108 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
109}
110
Dominik Behr797a3832016-01-11 15:53:11 -0800111bool dbus_is_initialized(void)
112{
113 return !!dbus;
114}
115
116bool dbus_init()
David Sodmanbbcb0522014-09-19 10:34:07 -0700117{
118 dbus_t* new_dbus;
119 DBusError err;
David Sodman8ef20062015-01-06 09:23:40 -0800120 int result;
121 dbus_bool_t stat;
David Sodmanbbcb0522014-09-19 10:34:07 -0700122
Dominik Behr5f6742f2016-03-10 18:03:54 -0800123 if (dbus_first_init) {
124 dbus_first_init = false;
125 dbus_first_init_time = get_monotonic_time_ms();
126 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700127 dbus_error_init(&err);
128
129 new_dbus = (dbus_t*)calloc(1, sizeof(*new_dbus));
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800130
131 if (!new_dbus)
Dominik Behr797a3832016-01-11 15:53:11 -0800132 return false;
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800133
David Sodman8ef20062015-01-06 09:23:40 -0800134 new_dbus->fd = -1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700135
136 new_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
137 if (dbus_error_is_set(&err)) {
Dominik Behr5f6742f2016-03-10 18:03:54 -0800138 if (!dbus_connect_fail) {
139 LOG(ERROR, "Cannot get DBUS connection");
140 dbus_connect_fail = true;
141 dbus_connect_fail_time = get_monotonic_time_ms();
142 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700143 free(new_dbus);
Dominik Behr797a3832016-01-11 15:53:11 -0800144 return false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700145 }
146
Dominik Behr5f6742f2016-03-10 18:03:54 -0800147 if (dbus_connect_fail) {
148 int64_t t = get_monotonic_time_ms() - dbus_connect_fail_time;
149 LOG(INFO, "DBUS connected after %.1f seconds", (float)t / 1000.0f);
150 }
151
David Sodman8ef20062015-01-06 09:23:40 -0800152 result = dbus_bus_request_name(new_dbus->conn, kFreconDbusInterface,
153 DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
154
155 if (result <= 0) {
156 LOG(ERROR, "Unable to get name for server");
157 }
158
159 stat = dbus_connection_register_object_path(new_dbus->conn,
160 kFreconDbusPath,
161 &frecon_vtable,
162 NULL);
163
164 if (!stat) {
165 LOG(ERROR, "failed to register object path");
166 }
167
Dominik Behr46c567f2016-03-08 15:11:48 -0800168 dbus_bus_add_match(new_dbus->conn, kLoginPromptVisibleRule, &err);
Dominik Behr1883c042016-04-27 12:31:02 -0700169 dbus_bus_add_match(new_dbus->conn, kSuspendDoneRule, &err);
Dominik Behr46c567f2016-03-08 15:11:48 -0800170
171 stat = dbus_connection_add_filter(new_dbus->conn, frecon_dbus_message_filter, NULL, NULL);
172 if (!stat) {
173 LOG(ERROR, "failed to add message filter");
174 }
175
David Sodman8ef20062015-01-06 09:23:40 -0800176 stat = dbus_connection_set_watch_functions(new_dbus->conn,
177 add_watch, remove_watch, toggle_watch,
178 new_dbus, NULL);
179
180 if (!stat) {
181 LOG(ERROR, "Failed to set watch functions");
182 }
183
David Sodmanbbcb0522014-09-19 10:34:07 -0700184 dbus_connection_set_exit_on_disconnect(new_dbus->conn, FALSE);
185
Dominik Behr797a3832016-01-11 15:53:11 -0800186 dbus = new_dbus;
187 return true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700188}
189
Dominik Behr5f6742f2016-03-10 18:03:54 -0800190bool dbus_init_wait()
191{
192 while (!dbus_is_initialized()) {
193 if (!dbus_init()) {
194 int64_t t = get_monotonic_time_ms() - dbus_first_init_time;
195 if (t >= DBUS_INIT_TIMEOUT_MS) {
196 LOG(ERROR, "DBUS init failed after a timeout of %u sec", DBUS_INIT_TIMEOUT_MS/1000);
197 return false;
198 }
199 }
200 usleep(DBUS_WAIT_DELAY_US);
201 }
202 return true;
203}
204
Dominik Behr797a3832016-01-11 15:53:11 -0800205static bool dbus_method_call0(const char* service_name,
206 const char* service_path,
207 const char* service_interface,
208 const char* method)
David Sodman003faed2014-11-03 09:02:10 -0800209{
Dominik Behr797a3832016-01-11 15:53:11 -0800210 DBusMessage* msg = NULL;
211 if (!dbus) {
212 LOG(ERROR, "dbus not initialized");
213 return false;
214 }
David Sodman003faed2014-11-03 09:02:10 -0800215
216 msg = dbus_message_new_method_call(service_name,
217 service_path, service_interface, method);
218
219 if (!msg)
220 return false;
221
222 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800223 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodman003faed2014-11-03 09:02:10 -0800224 dbus_message_unref(msg);
225 return false;
226 }
227
228 dbus_connection_flush(dbus->conn);
229 dbus_message_unref(msg);
230
231 return true;
232}
233
Dominik Behr797a3832016-01-11 15:53:11 -0800234static bool dbus_method_call1(const char* service_name,
235 const char* service_path,
236 const char* service_interface,
237 const char* method, int arg_type, void* param)
David Sodmanbbcb0522014-09-19 10:34:07 -0700238{
Dominik Behr797a3832016-01-11 15:53:11 -0800239 DBusMessage* msg = NULL;
240 if (!dbus) {
241 LOG(ERROR, "dbus not initialized");
242 return false;
243 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700244
245 msg = dbus_message_new_method_call(service_name,
246 service_path, service_interface, method);
247
248 if (!msg)
249 return false;
250
251 if (!dbus_message_append_args(msg,
David Sodman19e4f9d2015-03-10 11:11:09 -0700252 arg_type, param, DBUS_TYPE_INVALID)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700253 dbus_message_unref(msg);
254 return false;
255 }
256
257 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800258 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700259 dbus_message_unref(msg);
260 return false;
261 }
262
263 dbus_connection_flush(dbus->conn);
264 dbus_message_unref(msg);
265
266 return true;
267}
268
Dominik Behr797a3832016-01-11 15:53:11 -0800269void dbus_destroy(void)
David Sodmanbbcb0522014-09-19 10:34:07 -0700270{
271 /* FIXME - not sure what the right counterpart to
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800272 * dbus_bus_get() is, unref documentation is rather
273 * unclear. Not a big issue but it would be nice to
274 * clean up properly here
275 */
David Sodmanbbcb0522014-09-19 10:34:07 -0700276 /* dbus_connection_unref(dbus->conn); */
Dominik Behr797a3832016-01-11 15:53:11 -0800277 if (dbus) {
David Sodman8ef20062015-01-06 09:23:40 -0800278 free(dbus);
Dominik Behr797a3832016-01-11 15:53:11 -0800279 dbus = NULL;
280 }
David Sodman8ef20062015-01-06 09:23:40 -0800281}
282
Dominik Behrd7112672016-01-20 16:59:34 -0800283void dbus_add_fds(fd_set* read_set, fd_set* exception_set, int *maxfd)
David Sodman8ef20062015-01-06 09:23:40 -0800284{
Dominik Behr797a3832016-01-11 15:53:11 -0800285 if (!dbus)
Dominik Behrd7112672016-01-20 16:59:34 -0800286 return;
Dominik Behr797a3832016-01-11 15:53:11 -0800287
David Sodman8ef20062015-01-06 09:23:40 -0800288 if (dbus->fd < 0)
289 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
290
291 if (dbus->fd >= 0) {
292 FD_SET(dbus->fd, read_set);
293 FD_SET(dbus->fd, exception_set);
294 }
David Sodman8ef20062015-01-06 09:23:40 -0800295
Dominik Behrd7112672016-01-20 16:59:34 -0800296 if (dbus->fd > *maxfd)
297 *maxfd = dbus->fd;
David Sodman8ef20062015-01-06 09:23:40 -0800298}
299
Dominik Behr797a3832016-01-11 15:53:11 -0800300void dbus_dispatch_io(void)
David Sodman8ef20062015-01-06 09:23:40 -0800301{
Dominik Behr797a3832016-01-11 15:53:11 -0800302 if (!dbus)
303 return;
304
David Sodman8ef20062015-01-06 09:23:40 -0800305 dbus_watch_handle(dbus->watch, DBUS_WATCH_READABLE);
306 while (dbus_connection_get_dispatch_status(dbus->conn)
307 == DBUS_DISPATCH_DATA_REMAINS) {
308 dbus_connection_dispatch(dbus->conn);
309 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700310}
Dominik Behr797a3832016-01-11 15:53:11 -0800311
312void dbus_report_user_activity(int activity_type)
313{
314 dbus_bool_t allow_off = false;
315 if (!dbus)
316 return;
317
318 dbus_method_call1(kPowerManagerServiceName,
319 kPowerManagerServicePath,
320 kPowerManagerInterface,
321 kHandleUserActivityMethod,
322 DBUS_TYPE_INT32, &activity_type);
323
324 switch (activity_type) {
325 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
326 (void)dbus_method_call0(kPowerManagerServiceName,
327 kPowerManagerServicePath,
328 kPowerManagerInterface,
329 kIncreaseScreenBrightnessMethod);
330 break;
331 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
332 /*
333 * Shouldn't allow the screen to go
334 * completely off while frecon is active
335 * so passing false to allow_off
336 */
337 (void)dbus_method_call1(kPowerManagerServiceName,
338 kPowerManagerServicePath,
339 kPowerManagerInterface,
340 kDecreaseScreenBrightnessMethod,
341 DBUS_TYPE_BOOLEAN, &allow_off);
342 break;
343 }
344}
345
Dominik Behr46c567f2016-03-08 15:11:48 -0800346/*
347 * tell Chrome to take ownership of the display (DRM master)
348 */
Dominik Behr797a3832016-01-11 15:53:11 -0800349void dbus_take_display_ownership(void)
350{
351 if (!dbus)
352 return;
353 (void)dbus_method_call0(kLibCrosServiceName,
354 kLibCrosServicePath,
355 kLibCrosServiceInterface,
356 kTakeDisplayOwnership);
357}
358
Dominik Behr46c567f2016-03-08 15:11:48 -0800359/*
360 * ask Chrome to give up display ownership (DRM master)
361 */
Dominik Behr83864df2016-04-21 12:35:08 -0700362bool dbus_release_display_ownership(void)
Dominik Behr797a3832016-01-11 15:53:11 -0800363{
364 if (!dbus)
Dominik Behr83864df2016-04-21 12:35:08 -0700365 return true;
366 return dbus_method_call0(kLibCrosServiceName,
367 kLibCrosServicePath,
368 kLibCrosServiceInterface,
369 kReleaseDisplayOwnership);
Dominik Behr797a3832016-01-11 15:53:11 -0800370}
371
Dominik Behr46c567f2016-03-08 15:11:48 -0800372void dbus_set_login_prompt_visible_callback(void (*callback)(void*),
373 void* userptr)
374{
375 if (chrome_is_already_up) {
376 if (callback)
377 callback(userptr);
378 } else {
379 if (login_prompt_visible_callback && callback) {
380 LOG(ERROR, "trying to register login prompt visible callback multiple times");
381 return;
382 }
383 login_prompt_visible_callback = callback;
384 login_prompt_visible_callback_userptr = userptr;
385 }
386}
Dominik Behrf50c98f2016-03-31 14:05:29 -0700387
Dominik Behr1883c042016-04-27 12:31:02 -0700388void dbus_set_suspend_done_callback(void (*callback)(void*),
389 void* userptr)
390{
391 if (suspend_done_callback && callback) {
392 LOG(ERROR, "trying to register login prompt visible callback multiple times");
393 return;
394 }
395 suspend_done_callback = callback;
396 suspend_done_callback_userptr = userptr;
397}
398
Dominik Behrf50c98f2016-03-31 14:05:29 -0700399#else
400
401#include <stdlib.h>
402#include <stdbool.h>
403
404bool dbus_init()
405{
406 return true;
407}
408
409bool dbus_init_wait()
410{
411 return true;
412}
413
414void dbus_destroy(void)
415{
416}
417
418void dbus_add_fds(fd_set* read_set, fd_set* exception_set, int *maxfd)
419{
420}
421
422void dbus_dispatch_io(void)
423{
424}
425
426void dbus_report_user_activity(int activity_type)
427{
428}
429
430void dbus_take_display_ownership(void)
431{
432}
433
Dominik Behr83864df2016-04-21 12:35:08 -0700434bool dbus_release_display_ownership(void)
Dominik Behrf50c98f2016-03-31 14:05:29 -0700435{
Dominik Behr83864df2016-04-21 12:35:08 -0700436 return true;
Dominik Behrf50c98f2016-03-31 14:05:29 -0700437}
438
439bool dbus_is_initialized(void)
440{
441 return true;
442}
443
444void dbus_set_login_prompt_visible_callback(void (*callback)(void*),
445 void* userptr)
446{
447}
448
Dominik Behr1883c042016-04-27 12:31:02 -0700449void dbus_set_suspend_done_callback(void (*callback)(void*),
450 void* userptr)
451{
452}
453
Mike Frysinger006bdb22016-09-14 13:43:48 -0400454#endif