blob: 9028ae2f082243f4226ce6536d3404ec40697c8f [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#include <dbus/dbus.h>
David Sodmanbbcb0522014-09-19 10:34:07 -07008#include <stdlib.h>
Mike Frysinger006bdb22016-09-14 13:43:48 -04009#include <unistd.h>
David Sodman8ef20062015-01-06 09:23:40 -080010
Stéphane Marchesin62561a12015-12-11 17:32:37 -080011#include "dbus.h"
David Sodman8ef20062015-01-06 09:23:40 -080012#include "dbus_interface.h"
13#include "image.h"
Dominik Behr46c567f2016-03-08 15:11:48 -080014#include "main.h"
David Sodman8ef20062015-01-06 09:23:40 -080015#include "term.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070016#include "util.h"
17
Dominik Behr5f6742f2016-03-10 18:03:54 -080018#define DBUS_WAIT_DELAY_US (50000)
David Sodman8ef20062015-01-06 09:23:40 -080019#define DBUS_DEFAULT_DELAY 3000
Dominik Behr5f6742f2016-03-10 18:03:54 -080020#define DBUS_INIT_TIMEOUT_MS (60*1000)
David Sodman8ef20062015-01-06 09:23:40 -080021
Dominik Behr797a3832016-01-11 15:53:11 -080022typedef struct _dbus_t dbus_t;
23
Dominik Behr6e0f6fd2016-12-02 17:54:08 -080024static void (*login_prompt_visible_callback)(void) = NULL;
Dominik Behr1883c042016-04-27 12:31:02 -070025static void (*suspend_done_callback)(void*) = NULL;
26static void* suspend_done_callback_userptr = NULL;
Dominik Behr46c567f2016-03-08 15:11:48 -080027static bool chrome_is_already_up = false;
Dominik Behr5f6742f2016-03-10 18:03:54 -080028static bool dbus_connect_fail = false;
29static int64_t dbus_connect_fail_time;
30static bool dbus_first_init = true;
31static int64_t dbus_first_init_time;
Dominik Behr46c567f2016-03-08 15:11:48 -080032
David Sodmanbbcb0522014-09-19 10:34:07 -070033struct _dbus_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080034 DBusConnection* conn;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080035 DBusWatch* watch;
David Sodman8ef20062015-01-06 09:23:40 -080036 int fd;
David Sodmanbbcb0522014-09-19 10:34:07 -070037};
38
Dominik Behr797a3832016-01-11 15:53:11 -080039static dbus_t *dbus = NULL;
40
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080041static void frecon_dbus_unregister(DBusConnection* connection, void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -080042{
43}
44
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080045static DBusHandlerResult frecon_dbus_message_handler(DBusConnection* connection,
46 DBusMessage* message,
47 void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -080048{
David Sodman8ef20062015-01-06 09:23:40 -080049 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
David Sodman8ef20062015-01-06 09:23:40 -080050}
51
52static DBusObjectPathVTable
53frecon_vtable = {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -080054 frecon_dbus_unregister,
55 frecon_dbus_message_handler,
David Sodman8ef20062015-01-06 09:23:40 -080056 NULL
57};
58
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080059static dbus_bool_t add_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -080060{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080061 dbus_t* dbus = (dbus_t*)data;
David Sodman8ef20062015-01-06 09:23:40 -080062 dbus->watch = w;
63
64 return TRUE;
65}
66
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080067static void remove_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -080068{
69}
70
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080071static void toggle_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -080072{
73}
74
Dominik Behr46c567f2016-03-08 15:11:48 -080075static DBusHandlerResult handle_login_prompt_visible(DBusMessage* message)
76{
77 if (login_prompt_visible_callback) {
Dominik Behr6e0f6fd2016-12-02 17:54:08 -080078 login_prompt_visible_callback();
Dominik Behr46c567f2016-03-08 15:11:48 -080079 login_prompt_visible_callback = NULL;
Dominik Behr46c567f2016-03-08 15:11:48 -080080 }
81 chrome_is_already_up = true;
82
83 return DBUS_HANDLER_RESULT_HANDLED;
84}
85
Dominik Behr1883c042016-04-27 12:31:02 -070086static DBusHandlerResult handle_suspend_done(DBusMessage* message)
87{
88 if (suspend_done_callback)
89 suspend_done_callback(suspend_done_callback_userptr);
90
91 return DBUS_HANDLER_RESULT_HANDLED;
92}
93
Dominik Behr46c567f2016-03-08 15:11:48 -080094static DBusHandlerResult frecon_dbus_message_filter(DBusConnection* connection,
95 DBusMessage* message,
96 void* user_data)
97{
98 if (dbus_message_is_signal(message,
Dominik Behr5f6742f2016-03-10 18:03:54 -080099 kSessionManagerInterface, kLoginPromptVisibleSignal))
Dominik Behr46c567f2016-03-08 15:11:48 -0800100 return handle_login_prompt_visible(message);
Dominik Behr1883c042016-04-27 12:31:02 -0700101 else if (dbus_message_is_signal(message,
102 kPowerManagerInterface, kSuspendDoneSignal))
103 return handle_suspend_done(message);
Dominik Behr46c567f2016-03-08 15:11:48 -0800104
105 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
106}
107
Dominik Behr797a3832016-01-11 15:53:11 -0800108bool dbus_is_initialized(void)
109{
110 return !!dbus;
111}
112
113bool dbus_init()
David Sodmanbbcb0522014-09-19 10:34:07 -0700114{
115 dbus_t* new_dbus;
116 DBusError err;
David Sodman8ef20062015-01-06 09:23:40 -0800117 int result;
118 dbus_bool_t stat;
David Sodmanbbcb0522014-09-19 10:34:07 -0700119
Dominik Behr5f6742f2016-03-10 18:03:54 -0800120 if (dbus_first_init) {
121 dbus_first_init = false;
122 dbus_first_init_time = get_monotonic_time_ms();
123 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700124 dbus_error_init(&err);
125
126 new_dbus = (dbus_t*)calloc(1, sizeof(*new_dbus));
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800127
128 if (!new_dbus)
Dominik Behr797a3832016-01-11 15:53:11 -0800129 return false;
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800130
David Sodman8ef20062015-01-06 09:23:40 -0800131 new_dbus->fd = -1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700132
133 new_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
134 if (dbus_error_is_set(&err)) {
Dominik Behr5f6742f2016-03-10 18:03:54 -0800135 if (!dbus_connect_fail) {
Nicolas Boichat4f044ad2021-03-22 15:18:44 +0800136 LOG(DEBUG, "Cannot get DBUS connection");
Dominik Behr5f6742f2016-03-10 18:03:54 -0800137 dbus_connect_fail = true;
138 dbus_connect_fail_time = get_monotonic_time_ms();
139 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700140 free(new_dbus);
Dominik Behr797a3832016-01-11 15:53:11 -0800141 return false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700142 }
143
Dominik Behr5f6742f2016-03-10 18:03:54 -0800144 if (dbus_connect_fail) {
145 int64_t t = get_monotonic_time_ms() - dbus_connect_fail_time;
Nicolas Boichat4f044ad2021-03-22 15:18:44 +0800146 LOG(DEBUG, "DBUS connected after %.1f seconds", (float)t / 1000.0f);
Dominik Behr5f6742f2016-03-10 18:03:54 -0800147 }
148
David Sodman8ef20062015-01-06 09:23:40 -0800149 result = dbus_bus_request_name(new_dbus->conn, kFreconDbusInterface,
150 DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
151
152 if (result <= 0) {
153 LOG(ERROR, "Unable to get name for server");
154 }
155
156 stat = dbus_connection_register_object_path(new_dbus->conn,
157 kFreconDbusPath,
158 &frecon_vtable,
159 NULL);
160
161 if (!stat) {
162 LOG(ERROR, "failed to register object path");
163 }
164
Dominik Behr46c567f2016-03-08 15:11:48 -0800165 dbus_bus_add_match(new_dbus->conn, kLoginPromptVisibleRule, &err);
Dominik Behr1883c042016-04-27 12:31:02 -0700166 dbus_bus_add_match(new_dbus->conn, kSuspendDoneRule, &err);
Dominik Behr46c567f2016-03-08 15:11:48 -0800167
168 stat = dbus_connection_add_filter(new_dbus->conn, frecon_dbus_message_filter, NULL, NULL);
169 if (!stat) {
170 LOG(ERROR, "failed to add message filter");
171 }
172
David Sodman8ef20062015-01-06 09:23:40 -0800173 stat = dbus_connection_set_watch_functions(new_dbus->conn,
174 add_watch, remove_watch, toggle_watch,
175 new_dbus, NULL);
176
177 if (!stat) {
178 LOG(ERROR, "Failed to set watch functions");
179 }
180
David Sodmanbbcb0522014-09-19 10:34:07 -0700181 dbus_connection_set_exit_on_disconnect(new_dbus->conn, FALSE);
182
Dominik Behr797a3832016-01-11 15:53:11 -0800183 dbus = new_dbus;
184 return true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700185}
186
Dominik Behr5f6742f2016-03-10 18:03:54 -0800187bool dbus_init_wait()
188{
189 while (!dbus_is_initialized()) {
190 if (!dbus_init()) {
191 int64_t t = get_monotonic_time_ms() - dbus_first_init_time;
192 if (t >= DBUS_INIT_TIMEOUT_MS) {
193 LOG(ERROR, "DBUS init failed after a timeout of %u sec", DBUS_INIT_TIMEOUT_MS/1000);
194 return false;
195 }
196 }
197 usleep(DBUS_WAIT_DELAY_US);
198 }
199 return true;
200}
201
Dominik Behr797a3832016-01-11 15:53:11 -0800202static bool dbus_method_call0(const char* service_name,
203 const char* service_path,
204 const char* service_interface,
205 const char* method)
David Sodman003faed2014-11-03 09:02:10 -0800206{
Dominik Behr797a3832016-01-11 15:53:11 -0800207 DBusMessage* msg = NULL;
208 if (!dbus) {
209 LOG(ERROR, "dbus not initialized");
210 return false;
211 }
David Sodman003faed2014-11-03 09:02:10 -0800212
213 msg = dbus_message_new_method_call(service_name,
214 service_path, service_interface, method);
215
216 if (!msg)
217 return false;
218
219 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800220 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodman003faed2014-11-03 09:02:10 -0800221 dbus_message_unref(msg);
222 return false;
223 }
224
225 dbus_connection_flush(dbus->conn);
226 dbus_message_unref(msg);
227
228 return true;
229}
230
Dominik Behra818a1e2016-10-26 19:46:22 -0700231static bool dbus_method_call0_bool(const char* service_name,
232 const char* service_path,
233 const char* service_interface,
234 const char* method)
235{
236 DBusMessage* msg = NULL;
237 DBusMessage* reply = NULL;
238 int res = false;
239
240 if (!dbus) {
241 LOG(ERROR, "dbus not initialized");
242 return false;
243 }
244
245 msg = dbus_message_new_method_call(service_name,
246 service_path, service_interface, method);
247
248 if (!msg)
249 return false;
250
251 reply = dbus_connection_send_with_reply_and_block(dbus->conn,
252 msg, DBUS_DEFAULT_DELAY, NULL);
253 if (!reply) {
254 dbus_message_unref(msg);
255 return false;
256 }
257
258 dbus_message_get_args(reply, NULL, DBUS_TYPE_BOOLEAN, &res, DBUS_TYPE_INVALID);
259
260 dbus_connection_flush(dbus->conn);
261 dbus_message_unref(msg);
262 dbus_message_unref(reply);
263
264 return (bool)res;
265}
266
Dominik Behr797a3832016-01-11 15:53:11 -0800267static bool dbus_method_call1(const char* service_name,
268 const char* service_path,
269 const char* service_interface,
270 const char* method, int arg_type, void* param)
David Sodmanbbcb0522014-09-19 10:34:07 -0700271{
Dominik Behr797a3832016-01-11 15:53:11 -0800272 DBusMessage* msg = NULL;
273 if (!dbus) {
274 LOG(ERROR, "dbus not initialized");
275 return false;
276 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700277
278 msg = dbus_message_new_method_call(service_name,
279 service_path, service_interface, method);
280
281 if (!msg)
282 return false;
283
284 if (!dbus_message_append_args(msg,
David Sodman19e4f9d2015-03-10 11:11:09 -0700285 arg_type, param, DBUS_TYPE_INVALID)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700286 dbus_message_unref(msg);
287 return false;
288 }
289
290 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800291 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700292 dbus_message_unref(msg);
293 return false;
294 }
295
296 dbus_connection_flush(dbus->conn);
297 dbus_message_unref(msg);
298
299 return true;
300}
301
Dominik Behr797a3832016-01-11 15:53:11 -0800302void dbus_destroy(void)
David Sodmanbbcb0522014-09-19 10:34:07 -0700303{
304 /* FIXME - not sure what the right counterpart to
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800305 * dbus_bus_get() is, unref documentation is rather
306 * unclear. Not a big issue but it would be nice to
307 * clean up properly here
308 */
David Sodmanbbcb0522014-09-19 10:34:07 -0700309 /* dbus_connection_unref(dbus->conn); */
Dominik Behr797a3832016-01-11 15:53:11 -0800310 if (dbus) {
David Sodman8ef20062015-01-06 09:23:40 -0800311 free(dbus);
Dominik Behr797a3832016-01-11 15:53:11 -0800312 dbus = NULL;
313 }
David Sodman8ef20062015-01-06 09:23:40 -0800314}
315
Dominik Behrd7112672016-01-20 16:59:34 -0800316void dbus_add_fds(fd_set* read_set, fd_set* exception_set, int *maxfd)
David Sodman8ef20062015-01-06 09:23:40 -0800317{
Dominik Behr797a3832016-01-11 15:53:11 -0800318 if (!dbus)
Dominik Behrd7112672016-01-20 16:59:34 -0800319 return;
Dominik Behr797a3832016-01-11 15:53:11 -0800320
David Sodman8ef20062015-01-06 09:23:40 -0800321 if (dbus->fd < 0)
322 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
323
324 if (dbus->fd >= 0) {
325 FD_SET(dbus->fd, read_set);
326 FD_SET(dbus->fd, exception_set);
327 }
David Sodman8ef20062015-01-06 09:23:40 -0800328
Dominik Behrd7112672016-01-20 16:59:34 -0800329 if (dbus->fd > *maxfd)
330 *maxfd = dbus->fd;
David Sodman8ef20062015-01-06 09:23:40 -0800331}
332
Dominik Behr797a3832016-01-11 15:53:11 -0800333void dbus_dispatch_io(void)
David Sodman8ef20062015-01-06 09:23:40 -0800334{
Dominik Behr797a3832016-01-11 15:53:11 -0800335 if (!dbus)
336 return;
337
David Sodman8ef20062015-01-06 09:23:40 -0800338 dbus_watch_handle(dbus->watch, DBUS_WATCH_READABLE);
339 while (dbus_connection_get_dispatch_status(dbus->conn)
340 == DBUS_DISPATCH_DATA_REMAINS) {
341 dbus_connection_dispatch(dbus->conn);
342 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700343}
Dominik Behr797a3832016-01-11 15:53:11 -0800344
345void dbus_report_user_activity(int activity_type)
346{
347 dbus_bool_t allow_off = false;
348 if (!dbus)
349 return;
350
351 dbus_method_call1(kPowerManagerServiceName,
352 kPowerManagerServicePath,
353 kPowerManagerInterface,
354 kHandleUserActivityMethod,
355 DBUS_TYPE_INT32, &activity_type);
356
357 switch (activity_type) {
358 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
359 (void)dbus_method_call0(kPowerManagerServiceName,
360 kPowerManagerServicePath,
361 kPowerManagerInterface,
362 kIncreaseScreenBrightnessMethod);
363 break;
364 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
365 /*
366 * Shouldn't allow the screen to go
367 * completely off while frecon is active
368 * so passing false to allow_off
369 */
370 (void)dbus_method_call1(kPowerManagerServiceName,
371 kPowerManagerServicePath,
372 kPowerManagerInterface,
373 kDecreaseScreenBrightnessMethod,
374 DBUS_TYPE_BOOLEAN, &allow_off);
375 break;
376 }
377}
378
Dominik Behr46c567f2016-03-08 15:11:48 -0800379/*
380 * tell Chrome to take ownership of the display (DRM master)
381 */
Dominik Behra818a1e2016-10-26 19:46:22 -0700382bool dbus_take_display_ownership(void)
Dominik Behr797a3832016-01-11 15:53:11 -0800383{
384 if (!dbus)
Dominik Behra818a1e2016-10-26 19:46:22 -0700385 return true;
Lann Martin059fe662017-07-24 15:22:39 -0600386 return dbus_method_call0_bool(kDisplayServiceName,
387 kDisplayServicePath,
388 kDisplayServiceInterface,
389 kTakeOwnership);
Dominik Behr797a3832016-01-11 15:53:11 -0800390}
391
Dominik Behr46c567f2016-03-08 15:11:48 -0800392/*
393 * ask Chrome to give up display ownership (DRM master)
394 */
Dominik Behr83864df2016-04-21 12:35:08 -0700395bool dbus_release_display_ownership(void)
Dominik Behr797a3832016-01-11 15:53:11 -0800396{
397 if (!dbus)
Dominik Behr83864df2016-04-21 12:35:08 -0700398 return true;
Lann Martin059fe662017-07-24 15:22:39 -0600399 return dbus_method_call0_bool(kDisplayServiceName,
400 kDisplayServicePath,
401 kDisplayServiceInterface,
402 kReleaseOwnership);
Dominik Behr797a3832016-01-11 15:53:11 -0800403}
404
Dominik Behr6e0f6fd2016-12-02 17:54:08 -0800405void dbus_set_login_prompt_visible_callback(void (*callback)(void))
Dominik Behr46c567f2016-03-08 15:11:48 -0800406{
407 if (chrome_is_already_up) {
408 if (callback)
Dominik Behr6e0f6fd2016-12-02 17:54:08 -0800409 callback();
Dominik Behr46c567f2016-03-08 15:11:48 -0800410 } else {
411 if (login_prompt_visible_callback && callback) {
412 LOG(ERROR, "trying to register login prompt visible callback multiple times");
413 return;
414 }
415 login_prompt_visible_callback = callback;
Dominik Behr46c567f2016-03-08 15:11:48 -0800416 }
417}
Dominik Behrf50c98f2016-03-31 14:05:29 -0700418
Dominik Behr1883c042016-04-27 12:31:02 -0700419void dbus_set_suspend_done_callback(void (*callback)(void*),
420 void* userptr)
421{
422 if (suspend_done_callback && callback) {
423 LOG(ERROR, "trying to register login prompt visible callback multiple times");
424 return;
425 }
426 suspend_done_callback = callback;
427 suspend_done_callback_userptr = userptr;
428}