blob: 3d4423ef25d252a0f33250725d349c761b46528d [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 Behra818a1e2016-10-26 19:46:22 -0700234static bool dbus_method_call0_bool(const char* service_name,
235 const char* service_path,
236 const char* service_interface,
237 const char* method)
238{
239 DBusMessage* msg = NULL;
240 DBusMessage* reply = NULL;
241 int res = false;
242
243 if (!dbus) {
244 LOG(ERROR, "dbus not initialized");
245 return false;
246 }
247
248 msg = dbus_message_new_method_call(service_name,
249 service_path, service_interface, method);
250
251 if (!msg)
252 return false;
253
254 reply = dbus_connection_send_with_reply_and_block(dbus->conn,
255 msg, DBUS_DEFAULT_DELAY, NULL);
256 if (!reply) {
257 dbus_message_unref(msg);
258 return false;
259 }
260
261 dbus_message_get_args(reply, NULL, DBUS_TYPE_BOOLEAN, &res, DBUS_TYPE_INVALID);
262
263 dbus_connection_flush(dbus->conn);
264 dbus_message_unref(msg);
265 dbus_message_unref(reply);
266
267 return (bool)res;
268}
269
Dominik Behr797a3832016-01-11 15:53:11 -0800270static bool dbus_method_call1(const char* service_name,
271 const char* service_path,
272 const char* service_interface,
273 const char* method, int arg_type, void* param)
David Sodmanbbcb0522014-09-19 10:34:07 -0700274{
Dominik Behr797a3832016-01-11 15:53:11 -0800275 DBusMessage* msg = NULL;
276 if (!dbus) {
277 LOG(ERROR, "dbus not initialized");
278 return false;
279 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700280
281 msg = dbus_message_new_method_call(service_name,
282 service_path, service_interface, method);
283
284 if (!msg)
285 return false;
286
287 if (!dbus_message_append_args(msg,
David Sodman19e4f9d2015-03-10 11:11:09 -0700288 arg_type, param, DBUS_TYPE_INVALID)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700289 dbus_message_unref(msg);
290 return false;
291 }
292
293 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800294 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700295 dbus_message_unref(msg);
296 return false;
297 }
298
299 dbus_connection_flush(dbus->conn);
300 dbus_message_unref(msg);
301
302 return true;
303}
304
Dominik Behr797a3832016-01-11 15:53:11 -0800305void dbus_destroy(void)
David Sodmanbbcb0522014-09-19 10:34:07 -0700306{
307 /* FIXME - not sure what the right counterpart to
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800308 * dbus_bus_get() is, unref documentation is rather
309 * unclear. Not a big issue but it would be nice to
310 * clean up properly here
311 */
David Sodmanbbcb0522014-09-19 10:34:07 -0700312 /* dbus_connection_unref(dbus->conn); */
Dominik Behr797a3832016-01-11 15:53:11 -0800313 if (dbus) {
David Sodman8ef20062015-01-06 09:23:40 -0800314 free(dbus);
Dominik Behr797a3832016-01-11 15:53:11 -0800315 dbus = NULL;
316 }
David Sodman8ef20062015-01-06 09:23:40 -0800317}
318
Dominik Behrd7112672016-01-20 16:59:34 -0800319void dbus_add_fds(fd_set* read_set, fd_set* exception_set, int *maxfd)
David Sodman8ef20062015-01-06 09:23:40 -0800320{
Dominik Behr797a3832016-01-11 15:53:11 -0800321 if (!dbus)
Dominik Behrd7112672016-01-20 16:59:34 -0800322 return;
Dominik Behr797a3832016-01-11 15:53:11 -0800323
David Sodman8ef20062015-01-06 09:23:40 -0800324 if (dbus->fd < 0)
325 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
326
327 if (dbus->fd >= 0) {
328 FD_SET(dbus->fd, read_set);
329 FD_SET(dbus->fd, exception_set);
330 }
David Sodman8ef20062015-01-06 09:23:40 -0800331
Dominik Behrd7112672016-01-20 16:59:34 -0800332 if (dbus->fd > *maxfd)
333 *maxfd = dbus->fd;
David Sodman8ef20062015-01-06 09:23:40 -0800334}
335
Dominik Behr797a3832016-01-11 15:53:11 -0800336void dbus_dispatch_io(void)
David Sodman8ef20062015-01-06 09:23:40 -0800337{
Dominik Behr797a3832016-01-11 15:53:11 -0800338 if (!dbus)
339 return;
340
David Sodman8ef20062015-01-06 09:23:40 -0800341 dbus_watch_handle(dbus->watch, DBUS_WATCH_READABLE);
342 while (dbus_connection_get_dispatch_status(dbus->conn)
343 == DBUS_DISPATCH_DATA_REMAINS) {
344 dbus_connection_dispatch(dbus->conn);
345 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700346}
Dominik Behr797a3832016-01-11 15:53:11 -0800347
348void dbus_report_user_activity(int activity_type)
349{
350 dbus_bool_t allow_off = false;
351 if (!dbus)
352 return;
353
354 dbus_method_call1(kPowerManagerServiceName,
355 kPowerManagerServicePath,
356 kPowerManagerInterface,
357 kHandleUserActivityMethod,
358 DBUS_TYPE_INT32, &activity_type);
359
360 switch (activity_type) {
361 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
362 (void)dbus_method_call0(kPowerManagerServiceName,
363 kPowerManagerServicePath,
364 kPowerManagerInterface,
365 kIncreaseScreenBrightnessMethod);
366 break;
367 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
368 /*
369 * Shouldn't allow the screen to go
370 * completely off while frecon is active
371 * so passing false to allow_off
372 */
373 (void)dbus_method_call1(kPowerManagerServiceName,
374 kPowerManagerServicePath,
375 kPowerManagerInterface,
376 kDecreaseScreenBrightnessMethod,
377 DBUS_TYPE_BOOLEAN, &allow_off);
378 break;
379 }
380}
381
Dominik Behr46c567f2016-03-08 15:11:48 -0800382/*
383 * tell Chrome to take ownership of the display (DRM master)
384 */
Dominik Behra818a1e2016-10-26 19:46:22 -0700385bool dbus_take_display_ownership(void)
Dominik Behr797a3832016-01-11 15:53:11 -0800386{
387 if (!dbus)
Dominik Behra818a1e2016-10-26 19:46:22 -0700388 return true;
389 return dbus_method_call0_bool(kLibCrosServiceName,
390 kLibCrosServicePath,
391 kLibCrosServiceInterface,
392 kTakeDisplayOwnership);
Dominik Behr797a3832016-01-11 15:53:11 -0800393}
394
Dominik Behr46c567f2016-03-08 15:11:48 -0800395/*
396 * ask Chrome to give up display ownership (DRM master)
397 */
Dominik Behr83864df2016-04-21 12:35:08 -0700398bool dbus_release_display_ownership(void)
Dominik Behr797a3832016-01-11 15:53:11 -0800399{
400 if (!dbus)
Dominik Behr83864df2016-04-21 12:35:08 -0700401 return true;
Dominik Behra818a1e2016-10-26 19:46:22 -0700402 return dbus_method_call0_bool(kLibCrosServiceName,
403 kLibCrosServicePath,
404 kLibCrosServiceInterface,
405 kReleaseDisplayOwnership);
Dominik Behr797a3832016-01-11 15:53:11 -0800406}
407
Dominik Behr46c567f2016-03-08 15:11:48 -0800408void dbus_set_login_prompt_visible_callback(void (*callback)(void*),
409 void* userptr)
410{
411 if (chrome_is_already_up) {
412 if (callback)
413 callback(userptr);
414 } else {
415 if (login_prompt_visible_callback && callback) {
416 LOG(ERROR, "trying to register login prompt visible callback multiple times");
417 return;
418 }
419 login_prompt_visible_callback = callback;
420 login_prompt_visible_callback_userptr = userptr;
421 }
422}
Dominik Behrf50c98f2016-03-31 14:05:29 -0700423
Dominik Behr1883c042016-04-27 12:31:02 -0700424void dbus_set_suspend_done_callback(void (*callback)(void*),
425 void* userptr)
426{
427 if (suspend_done_callback && callback) {
428 LOG(ERROR, "trying to register login prompt visible callback multiple times");
429 return;
430 }
431 suspend_done_callback = callback;
432 suspend_done_callback_userptr = userptr;
433}
434
Dominik Behrf50c98f2016-03-31 14:05:29 -0700435#else
436
437#include <stdlib.h>
438#include <stdbool.h>
439
440bool dbus_init()
441{
442 return true;
443}
444
445bool dbus_init_wait()
446{
447 return true;
448}
449
450void dbus_destroy(void)
451{
452}
453
454void dbus_add_fds(fd_set* read_set, fd_set* exception_set, int *maxfd)
455{
456}
457
458void dbus_dispatch_io(void)
459{
460}
461
462void dbus_report_user_activity(int activity_type)
463{
464}
465
Dominik Behra818a1e2016-10-26 19:46:22 -0700466bool dbus_take_display_ownership(void)
Dominik Behrf50c98f2016-03-31 14:05:29 -0700467{
Dominik Behra818a1e2016-10-26 19:46:22 -0700468 return true;
Dominik Behrf50c98f2016-03-31 14:05:29 -0700469}
470
Dominik Behr83864df2016-04-21 12:35:08 -0700471bool dbus_release_display_ownership(void)
Dominik Behrf50c98f2016-03-31 14:05:29 -0700472{
Dominik Behr83864df2016-04-21 12:35:08 -0700473 return true;
Dominik Behrf50c98f2016-03-31 14:05:29 -0700474}
475
476bool dbus_is_initialized(void)
477{
478 return true;
479}
480
481void dbus_set_login_prompt_visible_callback(void (*callback)(void*),
482 void* userptr)
483{
484}
485
Dominik Behr1883c042016-04-27 12:31:02 -0700486void dbus_set_suspend_done_callback(void (*callback)(void*),
487 void* userptr)
488{
489}
490
Mike Frysinger006bdb22016-09-14 13:43:48 -0400491#endif