xref: /aosp_15_r20/external/libwebsockets/minimal-examples/dbus-server/minimal-dbus-server/main.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * lws-minimal-dbus-server
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Written in 2010-2019 by Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * This file is made available under the Creative Commons CC0 1.0
7*1c60b9acSAndroid Build Coastguard Worker  * Universal Public Domain Dedication.
8*1c60b9acSAndroid Build Coastguard Worker  *
9*1c60b9acSAndroid Build Coastguard Worker  * This demonstrates a minimal session dbus server that uses the lws event loop,
10*1c60b9acSAndroid Build Coastguard Worker  * making it possible to integrate it with other lws features.
11*1c60b9acSAndroid Build Coastguard Worker  *
12*1c60b9acSAndroid Build Coastguard Worker  * The dbus server parts are based on "Sample code illustrating basic use of
13*1c60b9acSAndroid Build Coastguard Worker  * D-BUS" (presumed Public Domain) here:
14*1c60b9acSAndroid Build Coastguard Worker  *
15*1c60b9acSAndroid Build Coastguard Worker  * https://github.com/fbuihuu/samples-dbus/blob/master/dbus-server.c
16*1c60b9acSAndroid Build Coastguard Worker  */
17*1c60b9acSAndroid Build Coastguard Worker 
18*1c60b9acSAndroid Build Coastguard Worker #include <stdbool.h>
19*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
20*1c60b9acSAndroid Build Coastguard Worker #include <stdio.h>
21*1c60b9acSAndroid Build Coastguard Worker #include <stdlib.h>
22*1c60b9acSAndroid Build Coastguard Worker #include <unistd.h>
23*1c60b9acSAndroid Build Coastguard Worker #include <signal.h>
24*1c60b9acSAndroid Build Coastguard Worker 
25*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
26*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets/lws-dbus.h>
27*1c60b9acSAndroid Build Coastguard Worker 
28*1c60b9acSAndroid Build Coastguard Worker static struct lws_context *context;
29*1c60b9acSAndroid Build Coastguard Worker static const char *version = "0.1";
30*1c60b9acSAndroid Build Coastguard Worker static int interrupted;
31*1c60b9acSAndroid Build Coastguard Worker static struct lws_dbus_ctx dbus_ctx, ctx_listener;
32*1c60b9acSAndroid Build Coastguard Worker static char session;
33*1c60b9acSAndroid Build Coastguard Worker 
34*1c60b9acSAndroid Build Coastguard Worker #define THIS_INTERFACE	 "org.libwebsockets.test"
35*1c60b9acSAndroid Build Coastguard Worker #define THIS_OBJECT	 "/org/libwebsockets/test"
36*1c60b9acSAndroid Build Coastguard Worker #define THIS_BUSNAME	 "org.libwebsockets.test"
37*1c60b9acSAndroid Build Coastguard Worker 
38*1c60b9acSAndroid Build Coastguard Worker #define THIS_LISTEN_PATH "unix:abstract=org.libwebsockets.test"
39*1c60b9acSAndroid Build Coastguard Worker 
40*1c60b9acSAndroid Build Coastguard Worker static const char *
41*1c60b9acSAndroid Build Coastguard Worker server_introspection_xml =
42*1c60b9acSAndroid Build Coastguard Worker 	DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
43*1c60b9acSAndroid Build Coastguard Worker 	"<node>\n"
44*1c60b9acSAndroid Build Coastguard Worker 	"  <interface name='" DBUS_INTERFACE_INTROSPECTABLE "'>\n"
45*1c60b9acSAndroid Build Coastguard Worker 	"    <method name='Introspect'>\n"
46*1c60b9acSAndroid Build Coastguard Worker 	"      <arg name='data' type='s' direction='out' />\n"
47*1c60b9acSAndroid Build Coastguard Worker 	"    </method>\n"
48*1c60b9acSAndroid Build Coastguard Worker 	"  </interface>\n"
49*1c60b9acSAndroid Build Coastguard Worker 
50*1c60b9acSAndroid Build Coastguard Worker 	"  <interface name='" DBUS_INTERFACE_PROPERTIES "'>\n"
51*1c60b9acSAndroid Build Coastguard Worker 	"    <method name='Get'>\n"
52*1c60b9acSAndroid Build Coastguard Worker 	"      <arg name='interface' type='s' direction='in' />\n"
53*1c60b9acSAndroid Build Coastguard Worker 	"      <arg name='property'  type='s' direction='in' />\n"
54*1c60b9acSAndroid Build Coastguard Worker 	"      <arg name='value'     type='s' direction='out' />\n"
55*1c60b9acSAndroid Build Coastguard Worker 	"    </method>\n"
56*1c60b9acSAndroid Build Coastguard Worker 	"    <method name='GetAll'>\n"
57*1c60b9acSAndroid Build Coastguard Worker 	"      <arg name='interface'  type='s'     direction='in'/>\n"
58*1c60b9acSAndroid Build Coastguard Worker 	"      <arg name='properties' type='a{sv}' direction='out'/>\n"
59*1c60b9acSAndroid Build Coastguard Worker 	"    </method>\n"
60*1c60b9acSAndroid Build Coastguard Worker 	"  </interface>\n"
61*1c60b9acSAndroid Build Coastguard Worker 
62*1c60b9acSAndroid Build Coastguard Worker 	"  <interface name='"THIS_INTERFACE"'>\n"
63*1c60b9acSAndroid Build Coastguard Worker 	"    <property name='Version' type='s' access='read' />\n"
64*1c60b9acSAndroid Build Coastguard Worker 	"    <method name='Ping' >\n"
65*1c60b9acSAndroid Build Coastguard Worker 	"      <arg type='s' direction='out' />\n"
66*1c60b9acSAndroid Build Coastguard Worker 	"    </method>\n"
67*1c60b9acSAndroid Build Coastguard Worker 	"    <method name='Echo'>\n"
68*1c60b9acSAndroid Build Coastguard Worker 	"      <arg name='string' direction='in' type='s'/>\n"
69*1c60b9acSAndroid Build Coastguard Worker 	"      <arg type='s' direction='out' />\n"
70*1c60b9acSAndroid Build Coastguard Worker 	"    </method>\n"
71*1c60b9acSAndroid Build Coastguard Worker 	"    <method name='EmitSignal'>\n"
72*1c60b9acSAndroid Build Coastguard Worker 	"    </method>\n"
73*1c60b9acSAndroid Build Coastguard Worker 	"    <method name='Quit'>\n"
74*1c60b9acSAndroid Build Coastguard Worker 	"    </method>\n"
75*1c60b9acSAndroid Build Coastguard Worker 	"    <signal name='OnEmitSignal'>\n"
76*1c60b9acSAndroid Build Coastguard Worker 	"    </signal>"
77*1c60b9acSAndroid Build Coastguard Worker 	"  </interface>\n"
78*1c60b9acSAndroid Build Coastguard Worker 
79*1c60b9acSAndroid Build Coastguard Worker 	"</node>\n";
80*1c60b9acSAndroid Build Coastguard Worker 
81*1c60b9acSAndroid Build Coastguard Worker static DBusHandlerResult
dmh_introspect(DBusConnection * c,DBusMessage * m,DBusMessage ** reply,void * d)82*1c60b9acSAndroid Build Coastguard Worker dmh_introspect(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
83*1c60b9acSAndroid Build Coastguard Worker {
84*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_append_args(*reply, DBUS_TYPE_STRING,
85*1c60b9acSAndroid Build Coastguard Worker 				 &server_introspection_xml, DBUS_TYPE_INVALID);
86*1c60b9acSAndroid Build Coastguard Worker 
87*1c60b9acSAndroid Build Coastguard Worker 	return DBUS_HANDLER_RESULT_HANDLED;
88*1c60b9acSAndroid Build Coastguard Worker }
89*1c60b9acSAndroid Build Coastguard Worker 
90*1c60b9acSAndroid Build Coastguard Worker static DBusHandlerResult
dmh_get(DBusConnection * c,DBusMessage * m,DBusMessage ** reply,void * d)91*1c60b9acSAndroid Build Coastguard Worker dmh_get(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
92*1c60b9acSAndroid Build Coastguard Worker {
93*1c60b9acSAndroid Build Coastguard Worker 	const char *interface, *property;
94*1c60b9acSAndroid Build Coastguard Worker 	DBusError err;
95*1c60b9acSAndroid Build Coastguard Worker 
96*1c60b9acSAndroid Build Coastguard Worker 	dbus_error_init(&err);
97*1c60b9acSAndroid Build Coastguard Worker 
98*1c60b9acSAndroid Build Coastguard Worker 	if (!dbus_message_get_args(m, &err, DBUS_TYPE_STRING, &interface,
99*1c60b9acSAndroid Build Coastguard Worker 					    DBUS_TYPE_STRING, &property,
100*1c60b9acSAndroid Build Coastguard Worker 					    DBUS_TYPE_INVALID)) {
101*1c60b9acSAndroid Build Coastguard Worker 		dbus_message_unref(*reply);
102*1c60b9acSAndroid Build Coastguard Worker 		*reply = dbus_message_new_error(m, err.name, err.message);
103*1c60b9acSAndroid Build Coastguard Worker 		dbus_error_free(&err);
104*1c60b9acSAndroid Build Coastguard Worker 
105*1c60b9acSAndroid Build Coastguard Worker 		return DBUS_HANDLER_RESULT_HANDLED;
106*1c60b9acSAndroid Build Coastguard Worker 	}
107*1c60b9acSAndroid Build Coastguard Worker 
108*1c60b9acSAndroid Build Coastguard Worker 	if (strcmp(property, "Version")) /* Unknown property */
109*1c60b9acSAndroid Build Coastguard Worker 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
110*1c60b9acSAndroid Build Coastguard Worker 
111*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_append_args(*reply, DBUS_TYPE_STRING, &version,
112*1c60b9acSAndroid Build Coastguard Worker 				 DBUS_TYPE_INVALID);
113*1c60b9acSAndroid Build Coastguard Worker 
114*1c60b9acSAndroid Build Coastguard Worker 	return DBUS_HANDLER_RESULT_HANDLED;
115*1c60b9acSAndroid Build Coastguard Worker }
116*1c60b9acSAndroid Build Coastguard Worker 
117*1c60b9acSAndroid Build Coastguard Worker static DBusHandlerResult
dmh_getall(DBusConnection * c,DBusMessage * m,DBusMessage ** reply,void * d)118*1c60b9acSAndroid Build Coastguard Worker dmh_getall(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
119*1c60b9acSAndroid Build Coastguard Worker {
120*1c60b9acSAndroid Build Coastguard Worker 	DBusMessageIter arr, di, iter, va;
121*1c60b9acSAndroid Build Coastguard Worker 	const char *property = "Version";
122*1c60b9acSAndroid Build Coastguard Worker 
123*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_iter_init_append(*reply, &iter);
124*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &arr);
125*1c60b9acSAndroid Build Coastguard Worker 
126*1c60b9acSAndroid Build Coastguard Worker 	/* Append all properties name/value pairs */
127*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_iter_open_container(&arr, DBUS_TYPE_DICT_ENTRY, NULL, &di);
128*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_iter_append_basic(&di, DBUS_TYPE_STRING, &property);
129*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_iter_open_container(&di, DBUS_TYPE_VARIANT, "s", &va);
130*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_iter_append_basic(&va, DBUS_TYPE_STRING, &version);
131*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_iter_close_container(&di, &va);
132*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_iter_close_container(&arr, &di);
133*1c60b9acSAndroid Build Coastguard Worker 
134*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_iter_close_container(&iter, &arr);
135*1c60b9acSAndroid Build Coastguard Worker 
136*1c60b9acSAndroid Build Coastguard Worker 	return DBUS_HANDLER_RESULT_HANDLED;
137*1c60b9acSAndroid Build Coastguard Worker }
138*1c60b9acSAndroid Build Coastguard Worker 
139*1c60b9acSAndroid Build Coastguard Worker static DBusHandlerResult
dmh_ping(DBusConnection * c,DBusMessage * m,DBusMessage ** reply,void * d)140*1c60b9acSAndroid Build Coastguard Worker dmh_ping(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
141*1c60b9acSAndroid Build Coastguard Worker {
142*1c60b9acSAndroid Build Coastguard Worker 	const char *pong = "Pong";
143*1c60b9acSAndroid Build Coastguard Worker 
144*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_append_args(*reply, DBUS_TYPE_STRING, &pong,
145*1c60b9acSAndroid Build Coastguard Worker 					 DBUS_TYPE_INVALID);
146*1c60b9acSAndroid Build Coastguard Worker 
147*1c60b9acSAndroid Build Coastguard Worker 	return DBUS_HANDLER_RESULT_HANDLED;
148*1c60b9acSAndroid Build Coastguard Worker }
149*1c60b9acSAndroid Build Coastguard Worker 
150*1c60b9acSAndroid Build Coastguard Worker static DBusHandlerResult
dmh_echo(DBusConnection * c,DBusMessage * m,DBusMessage ** reply,void * d)151*1c60b9acSAndroid Build Coastguard Worker dmh_echo(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
152*1c60b9acSAndroid Build Coastguard Worker {
153*1c60b9acSAndroid Build Coastguard Worker 	const char *msg;
154*1c60b9acSAndroid Build Coastguard Worker 	DBusError err;
155*1c60b9acSAndroid Build Coastguard Worker 
156*1c60b9acSAndroid Build Coastguard Worker 	dbus_error_init(&err);
157*1c60b9acSAndroid Build Coastguard Worker 
158*1c60b9acSAndroid Build Coastguard Worker 	if (!dbus_message_get_args(m, &err, DBUS_TYPE_STRING,
159*1c60b9acSAndroid Build Coastguard Worker 				   &msg, DBUS_TYPE_INVALID)) {
160*1c60b9acSAndroid Build Coastguard Worker 		dbus_message_unref(*reply);
161*1c60b9acSAndroid Build Coastguard Worker 		*reply = dbus_message_new_error(m, err.name, err.message);
162*1c60b9acSAndroid Build Coastguard Worker 		dbus_error_free(&err);
163*1c60b9acSAndroid Build Coastguard Worker 
164*1c60b9acSAndroid Build Coastguard Worker 		return DBUS_HANDLER_RESULT_HANDLED;
165*1c60b9acSAndroid Build Coastguard Worker 	}
166*1c60b9acSAndroid Build Coastguard Worker 
167*1c60b9acSAndroid Build Coastguard Worker 	dbus_message_append_args(*reply, DBUS_TYPE_STRING, &msg,
168*1c60b9acSAndroid Build Coastguard Worker 					 DBUS_TYPE_INVALID);
169*1c60b9acSAndroid Build Coastguard Worker 
170*1c60b9acSAndroid Build Coastguard Worker 	return DBUS_HANDLER_RESULT_HANDLED;
171*1c60b9acSAndroid Build Coastguard Worker }
172*1c60b9acSAndroid Build Coastguard Worker 
173*1c60b9acSAndroid Build Coastguard Worker static DBusHandlerResult
dmh_emit_signal(DBusConnection * c,DBusMessage * m,DBusMessage ** reply,void * d)174*1c60b9acSAndroid Build Coastguard Worker dmh_emit_signal(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
175*1c60b9acSAndroid Build Coastguard Worker {
176*1c60b9acSAndroid Build Coastguard Worker 	DBusMessage *r = dbus_message_new_signal(THIS_OBJECT, THIS_INTERFACE,
177*1c60b9acSAndroid Build Coastguard Worker 					         "OnEmitSignal");
178*1c60b9acSAndroid Build Coastguard Worker 
179*1c60b9acSAndroid Build Coastguard Worker 	if (!r)
180*1c60b9acSAndroid Build Coastguard Worker 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
181*1c60b9acSAndroid Build Coastguard Worker 
182*1c60b9acSAndroid Build Coastguard Worker 	if (!dbus_connection_send(c, r, NULL))
183*1c60b9acSAndroid Build Coastguard Worker 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
184*1c60b9acSAndroid Build Coastguard Worker 
185*1c60b9acSAndroid Build Coastguard Worker 	/* and send the original empty reply after */
186*1c60b9acSAndroid Build Coastguard Worker 
187*1c60b9acSAndroid Build Coastguard Worker 	return DBUS_HANDLER_RESULT_HANDLED;
188*1c60b9acSAndroid Build Coastguard Worker }
189*1c60b9acSAndroid Build Coastguard Worker 
190*1c60b9acSAndroid Build Coastguard Worker static DBusHandlerResult
dmh_emit_quit(DBusConnection * c,DBusMessage * m,DBusMessage ** reply,void * d)191*1c60b9acSAndroid Build Coastguard Worker dmh_emit_quit(DBusConnection *c, DBusMessage *m, DBusMessage **reply, void *d)
192*1c60b9acSAndroid Build Coastguard Worker {
193*1c60b9acSAndroid Build Coastguard Worker 	interrupted = 1;
194*1c60b9acSAndroid Build Coastguard Worker 
195*1c60b9acSAndroid Build Coastguard Worker 	return DBUS_HANDLER_RESULT_HANDLED;
196*1c60b9acSAndroid Build Coastguard Worker }
197*1c60b9acSAndroid Build Coastguard Worker 
198*1c60b9acSAndroid Build Coastguard Worker struct lws_dbus_methods {
199*1c60b9acSAndroid Build Coastguard Worker 	const char *inter;
200*1c60b9acSAndroid Build Coastguard Worker 	const char *call;
201*1c60b9acSAndroid Build Coastguard Worker 	lws_dbus_message_handler handler;
202*1c60b9acSAndroid Build Coastguard Worker } meths[] = {
203*1c60b9acSAndroid Build Coastguard Worker 	{ DBUS_INTERFACE_INTROSPECTABLE, "Introspect",	dmh_introspect	},
204*1c60b9acSAndroid Build Coastguard Worker 	{ DBUS_INTERFACE_PROPERTIES,	 "Get",		dmh_get		},
205*1c60b9acSAndroid Build Coastguard Worker 	{ DBUS_INTERFACE_PROPERTIES,	 "GetAll",	dmh_getall	},
206*1c60b9acSAndroid Build Coastguard Worker 	{ THIS_INTERFACE,		 "Ping",	dmh_ping	},
207*1c60b9acSAndroid Build Coastguard Worker 	{ THIS_INTERFACE,		 "Echo",	dmh_echo	},
208*1c60b9acSAndroid Build Coastguard Worker 	{ THIS_INTERFACE,		 "EmitSignal",	dmh_emit_signal },
209*1c60b9acSAndroid Build Coastguard Worker 	{ THIS_INTERFACE,		 "Quit",	dmh_emit_quit	},
210*1c60b9acSAndroid Build Coastguard Worker };
211*1c60b9acSAndroid Build Coastguard Worker 
212*1c60b9acSAndroid Build Coastguard Worker static DBusHandlerResult
server_message_handler(DBusConnection * conn,DBusMessage * message,void * data)213*1c60b9acSAndroid Build Coastguard Worker server_message_handler(DBusConnection *conn, DBusMessage *message, void *data)
214*1c60b9acSAndroid Build Coastguard Worker {
215*1c60b9acSAndroid Build Coastguard Worker 	struct lws_dbus_methods *mp = meths;
216*1c60b9acSAndroid Build Coastguard Worker 	DBusHandlerResult result;
217*1c60b9acSAndroid Build Coastguard Worker         DBusMessage *reply = NULL;
218*1c60b9acSAndroid Build Coastguard Worker 	size_t n;
219*1c60b9acSAndroid Build Coastguard Worker 
220*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: Got D-Bus request: %s.%s on %s\n", __func__,
221*1c60b9acSAndroid Build Coastguard Worker 		  dbus_message_get_interface(message),
222*1c60b9acSAndroid Build Coastguard Worker 		  dbus_message_get_member(message),
223*1c60b9acSAndroid Build Coastguard Worker 		  dbus_message_get_path(message));
224*1c60b9acSAndroid Build Coastguard Worker 
225*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < LWS_ARRAY_SIZE(meths); n++) {
226*1c60b9acSAndroid Build Coastguard Worker 		if (dbus_message_is_method_call(message, mp->inter, mp->call)) {
227*1c60b9acSAndroid Build Coastguard Worker 			reply = dbus_message_new_method_return(message);
228*1c60b9acSAndroid Build Coastguard Worker 			if (!reply)
229*1c60b9acSAndroid Build Coastguard Worker 				return DBUS_HANDLER_RESULT_NEED_MEMORY;
230*1c60b9acSAndroid Build Coastguard Worker 
231*1c60b9acSAndroid Build Coastguard Worker 			result = mp->handler(conn, message, &reply, data);
232*1c60b9acSAndroid Build Coastguard Worker 
233*1c60b9acSAndroid Build Coastguard Worker 			if (result == DBUS_HANDLER_RESULT_HANDLED &&
234*1c60b9acSAndroid Build Coastguard Worker 			    !dbus_connection_send(conn, reply, NULL))
235*1c60b9acSAndroid Build Coastguard Worker 				result = DBUS_HANDLER_RESULT_NEED_MEMORY;
236*1c60b9acSAndroid Build Coastguard Worker 
237*1c60b9acSAndroid Build Coastguard Worker 			dbus_message_unref(reply);
238*1c60b9acSAndroid Build Coastguard Worker 
239*1c60b9acSAndroid Build Coastguard Worker 			return result;
240*1c60b9acSAndroid Build Coastguard Worker 		}
241*1c60b9acSAndroid Build Coastguard Worker 
242*1c60b9acSAndroid Build Coastguard Worker 		mp++;
243*1c60b9acSAndroid Build Coastguard Worker 	}
244*1c60b9acSAndroid Build Coastguard Worker 
245*1c60b9acSAndroid Build Coastguard Worker 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
246*1c60b9acSAndroid Build Coastguard Worker }
247*1c60b9acSAndroid Build Coastguard Worker 
248*1c60b9acSAndroid Build Coastguard Worker static const DBusObjectPathVTable server_vtable = {
249*1c60b9acSAndroid Build Coastguard Worker 	.message_function = server_message_handler
250*1c60b9acSAndroid Build Coastguard Worker };
251*1c60b9acSAndroid Build Coastguard Worker 
252*1c60b9acSAndroid Build Coastguard Worker static void
destroy_dbus_server_conn(struct lws_dbus_ctx * ctx)253*1c60b9acSAndroid Build Coastguard Worker destroy_dbus_server_conn(struct lws_dbus_ctx *ctx)
254*1c60b9acSAndroid Build Coastguard Worker {
255*1c60b9acSAndroid Build Coastguard Worker 	if (!ctx->conn)
256*1c60b9acSAndroid Build Coastguard Worker 		return;
257*1c60b9acSAndroid Build Coastguard Worker 
258*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s\n", __func__);
259*1c60b9acSAndroid Build Coastguard Worker 
260*1c60b9acSAndroid Build Coastguard Worker 	dbus_connection_unregister_object_path(ctx->conn, THIS_OBJECT);
261*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_remove(&ctx->next);
262*1c60b9acSAndroid Build Coastguard Worker 	dbus_connection_unref(ctx->conn);
263*1c60b9acSAndroid Build Coastguard Worker }
264*1c60b9acSAndroid Build Coastguard Worker 
265*1c60b9acSAndroid Build Coastguard Worker static void
cb_closing(struct lws_dbus_ctx * ctx)266*1c60b9acSAndroid Build Coastguard Worker cb_closing(struct lws_dbus_ctx *ctx)
267*1c60b9acSAndroid Build Coastguard Worker {
268*1c60b9acSAndroid Build Coastguard Worker 	lwsl_err("%s: closing\n", __func__);
269*1c60b9acSAndroid Build Coastguard Worker 	destroy_dbus_server_conn(ctx);
270*1c60b9acSAndroid Build Coastguard Worker 
271*1c60b9acSAndroid Build Coastguard Worker 	free(ctx);
272*1c60b9acSAndroid Build Coastguard Worker }
273*1c60b9acSAndroid Build Coastguard Worker 
274*1c60b9acSAndroid Build Coastguard Worker 
275*1c60b9acSAndroid Build Coastguard Worker static void
new_conn(DBusServer * server,DBusConnection * conn,void * data)276*1c60b9acSAndroid Build Coastguard Worker new_conn(DBusServer *server, DBusConnection *conn, void *data)
277*1c60b9acSAndroid Build Coastguard Worker {
278*1c60b9acSAndroid Build Coastguard Worker 	struct lws_dbus_ctx *conn_ctx, *ctx = (struct lws_dbus_ctx *)data;
279*1c60b9acSAndroid Build Coastguard Worker 
280*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: vh %s\n", __func__, lws_get_vhost_name(ctx->vh));
281*1c60b9acSAndroid Build Coastguard Worker 
282*1c60b9acSAndroid Build Coastguard Worker 	conn_ctx = malloc(sizeof(*conn_ctx));
283*1c60b9acSAndroid Build Coastguard Worker 	if (!conn_ctx)
284*1c60b9acSAndroid Build Coastguard Worker 		return;
285*1c60b9acSAndroid Build Coastguard Worker 
286*1c60b9acSAndroid Build Coastguard Worker 	memset(conn_ctx, 0, sizeof(*conn_ctx));
287*1c60b9acSAndroid Build Coastguard Worker 
288*1c60b9acSAndroid Build Coastguard Worker 	conn_ctx->tsi = ctx->tsi;
289*1c60b9acSAndroid Build Coastguard Worker 	conn_ctx->vh = ctx->vh;
290*1c60b9acSAndroid Build Coastguard Worker 	conn_ctx->conn = conn;
291*1c60b9acSAndroid Build Coastguard Worker 
292*1c60b9acSAndroid Build Coastguard Worker 	if (lws_dbus_connection_setup(conn_ctx, conn, cb_closing)) {
293*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: connection bind to lws failed\n", __func__);
294*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
295*1c60b9acSAndroid Build Coastguard Worker 	}
296*1c60b9acSAndroid Build Coastguard Worker 
297*1c60b9acSAndroid Build Coastguard Worker 	if (!dbus_connection_register_object_path(conn, THIS_OBJECT,
298*1c60b9acSAndroid Build Coastguard Worker 						  &server_vtable, conn_ctx)) {
299*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: Failed to register object path\n", __func__);
300*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
301*1c60b9acSAndroid Build Coastguard Worker 	}
302*1c60b9acSAndroid Build Coastguard Worker 
303*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_add_head(&conn_ctx->next, &ctx->owner);
304*1c60b9acSAndroid Build Coastguard Worker 
305*1c60b9acSAndroid Build Coastguard Worker 	/* we take on responsibility for explicit close / unref with this... */
306*1c60b9acSAndroid Build Coastguard Worker 	dbus_connection_ref(conn);
307*1c60b9acSAndroid Build Coastguard Worker 
308*1c60b9acSAndroid Build Coastguard Worker 	return;
309*1c60b9acSAndroid Build Coastguard Worker 
310*1c60b9acSAndroid Build Coastguard Worker bail:
311*1c60b9acSAndroid Build Coastguard Worker 	free(conn_ctx);
312*1c60b9acSAndroid Build Coastguard Worker }
313*1c60b9acSAndroid Build Coastguard Worker 
314*1c60b9acSAndroid Build Coastguard Worker static int
create_dbus_listener(const char * ads)315*1c60b9acSAndroid Build Coastguard Worker create_dbus_listener(const char *ads)
316*1c60b9acSAndroid Build Coastguard Worker {
317*1c60b9acSAndroid Build Coastguard Worker 	DBusError e;
318*1c60b9acSAndroid Build Coastguard Worker 
319*1c60b9acSAndroid Build Coastguard Worker         dbus_error_init(&e);
320*1c60b9acSAndroid Build Coastguard Worker 
321*1c60b9acSAndroid Build Coastguard Worker 	if (!lws_dbus_server_listen(&ctx_listener, ads, &e, new_conn)) {
322*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: failed\n", __func__);
323*1c60b9acSAndroid Build Coastguard Worker 		dbus_error_free(&e);
324*1c60b9acSAndroid Build Coastguard Worker 
325*1c60b9acSAndroid Build Coastguard Worker 		return 1;
326*1c60b9acSAndroid Build Coastguard Worker 	}
327*1c60b9acSAndroid Build Coastguard Worker 
328*1c60b9acSAndroid Build Coastguard Worker 	return 0;
329*1c60b9acSAndroid Build Coastguard Worker }
330*1c60b9acSAndroid Build Coastguard Worker 
331*1c60b9acSAndroid Build Coastguard Worker static int
create_dbus_server_conn(struct lws_dbus_ctx * ctx,DBusBusType type)332*1c60b9acSAndroid Build Coastguard Worker create_dbus_server_conn(struct lws_dbus_ctx *ctx, DBusBusType type)
333*1c60b9acSAndroid Build Coastguard Worker {
334*1c60b9acSAndroid Build Coastguard Worker 	DBusError err;
335*1c60b9acSAndroid Build Coastguard Worker 	int rv;
336*1c60b9acSAndroid Build Coastguard Worker 
337*1c60b9acSAndroid Build Coastguard Worker         dbus_error_init(&err);
338*1c60b9acSAndroid Build Coastguard Worker 
339*1c60b9acSAndroid Build Coastguard Worker 	/* connect to the daemon bus */
340*1c60b9acSAndroid Build Coastguard Worker 	ctx->conn = dbus_bus_get(type, &err);
341*1c60b9acSAndroid Build Coastguard Worker 	if (!ctx->conn) {
342*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: Failed to get a session DBus connection: %s\n",
343*1c60b9acSAndroid Build Coastguard Worker 			 __func__, err.message);
344*1c60b9acSAndroid Build Coastguard Worker 		goto fail;
345*1c60b9acSAndroid Build Coastguard Worker 	}
346*1c60b9acSAndroid Build Coastguard Worker 
347*1c60b9acSAndroid Build Coastguard Worker 	/*
348*1c60b9acSAndroid Build Coastguard Worker 	 * by default dbus will call exit() when this connection closes...
349*1c60b9acSAndroid Build Coastguard Worker 	 * we have to shut down other things cleanly, so disable that
350*1c60b9acSAndroid Build Coastguard Worker 	 */
351*1c60b9acSAndroid Build Coastguard Worker 	dbus_connection_set_exit_on_disconnect(ctx->conn, 0);
352*1c60b9acSAndroid Build Coastguard Worker 
353*1c60b9acSAndroid Build Coastguard Worker 	rv = dbus_bus_request_name(ctx->conn, THIS_BUSNAME,
354*1c60b9acSAndroid Build Coastguard Worker 				   DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
355*1c60b9acSAndroid Build Coastguard Worker 	if (rv != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
356*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: Failed to request name on bus: %s\n",
357*1c60b9acSAndroid Build Coastguard Worker 			 __func__, err.message);
358*1c60b9acSAndroid Build Coastguard Worker 		goto fail;
359*1c60b9acSAndroid Build Coastguard Worker 	}
360*1c60b9acSAndroid Build Coastguard Worker 
361*1c60b9acSAndroid Build Coastguard Worker 	if (!dbus_connection_register_object_path(ctx->conn, THIS_OBJECT,
362*1c60b9acSAndroid Build Coastguard Worker 						  &server_vtable, NULL)) {
363*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: Failed to register object path for TestObject\n",
364*1c60b9acSAndroid Build Coastguard Worker 			 __func__);
365*1c60b9acSAndroid Build Coastguard Worker 		dbus_bus_release_name(ctx->conn, THIS_BUSNAME, &err);
366*1c60b9acSAndroid Build Coastguard Worker 		goto fail;
367*1c60b9acSAndroid Build Coastguard Worker 	}
368*1c60b9acSAndroid Build Coastguard Worker 
369*1c60b9acSAndroid Build Coastguard Worker 	/*
370*1c60b9acSAndroid Build Coastguard Worker 	 * This is the part that binds the connection to lws watcher and
371*1c60b9acSAndroid Build Coastguard Worker 	 * timeout handling provided by lws
372*1c60b9acSAndroid Build Coastguard Worker 	 */
373*1c60b9acSAndroid Build Coastguard Worker 
374*1c60b9acSAndroid Build Coastguard Worker 	if (lws_dbus_connection_setup(ctx, ctx->conn, cb_closing)) {
375*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: connection bind to lws failed\n", __func__);
376*1c60b9acSAndroid Build Coastguard Worker 		goto fail;
377*1c60b9acSAndroid Build Coastguard Worker 	}
378*1c60b9acSAndroid Build Coastguard Worker 
379*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: created OK\n", __func__);
380*1c60b9acSAndroid Build Coastguard Worker 
381*1c60b9acSAndroid Build Coastguard Worker 	return 0;
382*1c60b9acSAndroid Build Coastguard Worker 
383*1c60b9acSAndroid Build Coastguard Worker fail:
384*1c60b9acSAndroid Build Coastguard Worker 	dbus_error_free(&err);
385*1c60b9acSAndroid Build Coastguard Worker 
386*1c60b9acSAndroid Build Coastguard Worker 	return 1;
387*1c60b9acSAndroid Build Coastguard Worker }
388*1c60b9acSAndroid Build Coastguard Worker 
389*1c60b9acSAndroid Build Coastguard Worker /*
390*1c60b9acSAndroid Build Coastguard Worker  * Cleanly release the connection
391*1c60b9acSAndroid Build Coastguard Worker  */
392*1c60b9acSAndroid Build Coastguard Worker 
393*1c60b9acSAndroid Build Coastguard Worker static void
destroy_dbus_server_listener(struct lws_dbus_ctx * ctx)394*1c60b9acSAndroid Build Coastguard Worker destroy_dbus_server_listener(struct lws_dbus_ctx *ctx)
395*1c60b9acSAndroid Build Coastguard Worker {
396*1c60b9acSAndroid Build Coastguard Worker 	dbus_server_disconnect(ctx->dbs);
397*1c60b9acSAndroid Build Coastguard Worker 
398*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll_safe(struct lws_dll2 *, rdt, nx,
399*1c60b9acSAndroid Build Coastguard Worker 				   ctx->owner.head) {
400*1c60b9acSAndroid Build Coastguard Worker 		struct lws_dbus_ctx *r =
401*1c60b9acSAndroid Build Coastguard Worker 			lws_container_of(rdt, struct lws_dbus_ctx, next);
402*1c60b9acSAndroid Build Coastguard Worker 
403*1c60b9acSAndroid Build Coastguard Worker 		dbus_connection_close(r->conn);
404*1c60b9acSAndroid Build Coastguard Worker 		dbus_connection_unref(r->conn);
405*1c60b9acSAndroid Build Coastguard Worker 		free(r);
406*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll_safe(rdt, nx);
407*1c60b9acSAndroid Build Coastguard Worker 
408*1c60b9acSAndroid Build Coastguard Worker 	dbus_server_unref(ctx->dbs);
409*1c60b9acSAndroid Build Coastguard Worker }
410*1c60b9acSAndroid Build Coastguard Worker 
411*1c60b9acSAndroid Build Coastguard Worker /*
412*1c60b9acSAndroid Build Coastguard Worker  * DBUS can send messages outside the usual client-initiated RPC concept.
413*1c60b9acSAndroid Build Coastguard Worker  *
414*1c60b9acSAndroid Build Coastguard Worker  * You can receive them using a message filter.
415*1c60b9acSAndroid Build Coastguard Worker  */
416*1c60b9acSAndroid Build Coastguard Worker 
417*1c60b9acSAndroid Build Coastguard Worker static void
spam_connected_clients(struct lws_dbus_ctx * ctx)418*1c60b9acSAndroid Build Coastguard Worker spam_connected_clients(struct lws_dbus_ctx *ctx)
419*1c60b9acSAndroid Build Coastguard Worker {
420*1c60b9acSAndroid Build Coastguard Worker 
421*1c60b9acSAndroid Build Coastguard Worker 	/* send connected clients an unsolicited message */
422*1c60b9acSAndroid Build Coastguard Worker 
423*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll_safe(struct lws_dll2 *, rdt, nx,
424*1c60b9acSAndroid Build Coastguard Worker 				   ctx->owner.head) {
425*1c60b9acSAndroid Build Coastguard Worker 		struct lws_dbus_ctx *r =
426*1c60b9acSAndroid Build Coastguard Worker 			lws_container_of(rdt, struct lws_dbus_ctx, next);
427*1c60b9acSAndroid Build Coastguard Worker 
428*1c60b9acSAndroid Build Coastguard Worker 
429*1c60b9acSAndroid Build Coastguard Worker 		DBusMessage *msg;
430*1c60b9acSAndroid Build Coastguard Worker 		const char *payload = "Unsolicited message";
431*1c60b9acSAndroid Build Coastguard Worker 
432*1c60b9acSAndroid Build Coastguard Worker 		msg = dbus_message_new(DBUS_NUM_MESSAGE_TYPES + 1);
433*1c60b9acSAndroid Build Coastguard Worker 		if (!msg) {
434*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("%s: new message failed\n", __func__);
435*1c60b9acSAndroid Build Coastguard Worker 		}
436*1c60b9acSAndroid Build Coastguard Worker 
437*1c60b9acSAndroid Build Coastguard Worker 		dbus_message_append_args(msg, DBUS_TYPE_STRING, &payload,
438*1c60b9acSAndroid Build Coastguard Worker 						 DBUS_TYPE_INVALID);
439*1c60b9acSAndroid Build Coastguard Worker 		if (!dbus_connection_send(r->conn, msg, NULL)) {
440*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("%s: unable to send\n", __func__);
441*1c60b9acSAndroid Build Coastguard Worker 		}
442*1c60b9acSAndroid Build Coastguard Worker 
443*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("%s\n", __func__);
444*1c60b9acSAndroid Build Coastguard Worker 
445*1c60b9acSAndroid Build Coastguard Worker 		dbus_message_unref(msg);
446*1c60b9acSAndroid Build Coastguard Worker 
447*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll_safe(rdt, nx);
448*1c60b9acSAndroid Build Coastguard Worker 
449*1c60b9acSAndroid Build Coastguard Worker }
450*1c60b9acSAndroid Build Coastguard Worker 
451*1c60b9acSAndroid Build Coastguard Worker 
sigint_handler(int sig)452*1c60b9acSAndroid Build Coastguard Worker void sigint_handler(int sig)
453*1c60b9acSAndroid Build Coastguard Worker {
454*1c60b9acSAndroid Build Coastguard Worker 	interrupted = 1;
455*1c60b9acSAndroid Build Coastguard Worker }
456*1c60b9acSAndroid Build Coastguard Worker 
main(int argc,const char ** argv)457*1c60b9acSAndroid Build Coastguard Worker int main(int argc, const char **argv)
458*1c60b9acSAndroid Build Coastguard Worker {
459*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context_creation_info info;
460*1c60b9acSAndroid Build Coastguard Worker 	const char *p;
461*1c60b9acSAndroid Build Coastguard Worker 	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
462*1c60b9acSAndroid Build Coastguard Worker 			/* for LLL_ verbosity above NOTICE to be built into lws,
463*1c60b9acSAndroid Build Coastguard Worker 			 * lws must have been configured and built with
464*1c60b9acSAndroid Build Coastguard Worker 			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
465*1c60b9acSAndroid Build Coastguard Worker 			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
466*1c60b9acSAndroid Build Coastguard Worker 			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
467*1c60b9acSAndroid Build Coastguard Worker 			/* | LLL_DEBUG */ /* | LLL_THREAD */;
468*1c60b9acSAndroid Build Coastguard Worker 
469*1c60b9acSAndroid Build Coastguard Worker 	signal(SIGINT, sigint_handler);
470*1c60b9acSAndroid Build Coastguard Worker 
471*1c60b9acSAndroid Build Coastguard Worker 	if ((p = lws_cmdline_option(argc, argv, "-d")))
472*1c60b9acSAndroid Build Coastguard Worker 		logs = atoi(p);
473*1c60b9acSAndroid Build Coastguard Worker 
474*1c60b9acSAndroid Build Coastguard Worker 	lws_set_log_level(logs, NULL);
475*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("LWS minimal DBUS server\n");
476*1c60b9acSAndroid Build Coastguard Worker 
477*1c60b9acSAndroid Build Coastguard Worker 	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
478*1c60b9acSAndroid Build Coastguard Worker 	info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
479*1c60b9acSAndroid Build Coastguard Worker 	context = lws_create_context(&info);
480*1c60b9acSAndroid Build Coastguard Worker 	if (!context) {
481*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("lws init failed\n");
482*1c60b9acSAndroid Build Coastguard Worker 		return 1;
483*1c60b9acSAndroid Build Coastguard Worker 	}
484*1c60b9acSAndroid Build Coastguard Worker 
485*1c60b9acSAndroid Build Coastguard Worker 	info.options |=
486*1c60b9acSAndroid Build Coastguard Worker 		LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
487*1c60b9acSAndroid Build Coastguard Worker 
488*1c60b9acSAndroid Build Coastguard Worker 	dbus_ctx.tsi = 0;
489*1c60b9acSAndroid Build Coastguard Worker 	ctx_listener.tsi = 0;
490*1c60b9acSAndroid Build Coastguard Worker 	ctx_listener.vh = dbus_ctx.vh = lws_create_vhost(context, &info);
491*1c60b9acSAndroid Build Coastguard Worker 	if (!dbus_ctx.vh)
492*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
493*1c60b9acSAndroid Build Coastguard Worker 
494*1c60b9acSAndroid Build Coastguard Worker 	session = !!lws_cmdline_option(argc, argv, "--session");
495*1c60b9acSAndroid Build Coastguard Worker 
496*1c60b9acSAndroid Build Coastguard Worker 	if (session) {
497*1c60b9acSAndroid Build Coastguard Worker 		/* create the dbus connection, loosely bound to our lws vhost */
498*1c60b9acSAndroid Build Coastguard Worker 
499*1c60b9acSAndroid Build Coastguard Worker 		if (create_dbus_server_conn(&dbus_ctx, DBUS_BUS_SESSION))
500*1c60b9acSAndroid Build Coastguard Worker 			goto bail;
501*1c60b9acSAndroid Build Coastguard Worker 	} else {
502*1c60b9acSAndroid Build Coastguard Worker 		if (create_dbus_listener(THIS_LISTEN_PATH)) {
503*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("%s: create_dbus_listener failed\n", __func__);
504*1c60b9acSAndroid Build Coastguard Worker 			goto bail;
505*1c60b9acSAndroid Build Coastguard Worker 		}
506*1c60b9acSAndroid Build Coastguard Worker 	}
507*1c60b9acSAndroid Build Coastguard Worker 
508*1c60b9acSAndroid Build Coastguard Worker 	/* lws event loop (default poll one) */
509*1c60b9acSAndroid Build Coastguard Worker 
510*1c60b9acSAndroid Build Coastguard Worker 	while (n >= 0 && !interrupted) {
511*1c60b9acSAndroid Build Coastguard Worker 		if (!session)
512*1c60b9acSAndroid Build Coastguard Worker 			spam_connected_clients(&ctx_listener);
513*1c60b9acSAndroid Build Coastguard Worker 		n = lws_service(context, 0);
514*1c60b9acSAndroid Build Coastguard Worker 	}
515*1c60b9acSAndroid Build Coastguard Worker 
516*1c60b9acSAndroid Build Coastguard Worker 	if (session)
517*1c60b9acSAndroid Build Coastguard Worker 		destroy_dbus_server_conn(&dbus_ctx);
518*1c60b9acSAndroid Build Coastguard Worker 	else
519*1c60b9acSAndroid Build Coastguard Worker 		destroy_dbus_server_listener(&ctx_listener);
520*1c60b9acSAndroid Build Coastguard Worker 
521*1c60b9acSAndroid Build Coastguard Worker 	/* this is required for valgrind-cleanliness */
522*1c60b9acSAndroid Build Coastguard Worker 	dbus_shutdown();
523*1c60b9acSAndroid Build Coastguard Worker 	lws_context_destroy(context);
524*1c60b9acSAndroid Build Coastguard Worker 
525*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("Exiting cleanly\n");
526*1c60b9acSAndroid Build Coastguard Worker 
527*1c60b9acSAndroid Build Coastguard Worker 	return 0;
528*1c60b9acSAndroid Build Coastguard Worker 
529*1c60b9acSAndroid Build Coastguard Worker bail:
530*1c60b9acSAndroid Build Coastguard Worker 	lwsl_err("%s: failed to start\n", __func__);
531*1c60b9acSAndroid Build Coastguard Worker 
532*1c60b9acSAndroid Build Coastguard Worker 	lws_context_destroy(context);
533*1c60b9acSAndroid Build Coastguard Worker 
534*1c60b9acSAndroid Build Coastguard Worker 	return 1;
535*1c60b9acSAndroid Build Coastguard Worker }
536