Merge lp:~ted/url-dispatcher/mediaplayer-app-helper-rtm into lp:url-dispatcher/rtm-14.09

Proposed by Ted Gould
Status: Rejected
Rejected by: Ted Gould
Proposed branch: lp:~ted/url-dispatcher/mediaplayer-app-helper-rtm
Merge into: lp:url-dispatcher/rtm-14.09
Diff against target: 436 lines (+286/-5)
11 files modified
CMakeLists.txt (+1/-0)
debian/control (+1/-0)
debian/url-dispatcher.install (+1/-0)
service/CMakeLists.txt (+2/-0)
service/dispatcher.c (+89/-5)
tests/CMakeLists.txt (+4/-0)
tests/manual (+17/-0)
tests/service-test.cc (+43/-0)
tests/ts-helper-test.sh.in (+12/-0)
trusted-session-helper/CMakeLists.txt (+13/-0)
trusted-session-helper/main.cpp (+103/-0)
To merge this branch: bzr merge lp:~ted/url-dispatcher/mediaplayer-app-helper-rtm
Reviewer Review Type Date Requested Status
Indicator Applet Developers Pending
Review via email: mp+246728@code.launchpad.net

Commit message

Add special handling for mediaplayer to call the helper instead of an app

To post a comment you must log in.

Unmerged revisions

103. By Ted Gould

Adding a manual test for working with the camera AND the dash

102. By Ted Gould

Checking the other parameters as well

101. By Ted Gould

Make the test check to ensure the PID is the correct one

100. By Ted Gould

Switching back to discovering the PID from the dbus message for the camera app

99. By Ted Gould

Make sure to pick up our new binary

98. By Ted Gould

Don't hardcode the utility being called

97. By Ted Gould

Setup a fork/exec relationship so we keep the Mir connection open

96. By Ted Gould

Getting the PID from Upstart

95. By Ted Gould

A test to ensure we call the helper correctly

94. By Ted Gould

Test setup

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-05-26 12:56:47 +0000
3+++ CMakeLists.txt 2015-01-16 16:37:34 +0000
4@@ -76,6 +76,7 @@
5 add_subdirectory(service)
6 add_subdirectory(liburl-dispatcher)
7 add_subdirectory(tools)
8+add_subdirectory(trusted-session-helper)
9
10 # testing & coverage
11 if (${enable_tests})
12
13=== modified file 'debian/control'
14--- debian/control 2014-08-20 18:41:41 +0000
15+++ debian/control 2015-01-16 16:37:34 +0000
16@@ -14,6 +14,7 @@
17 libglib2.0-dev,
18 libjson-glib-dev,
19 libgtest-dev,
20+ libmirclient-dev,
21 libsqlite3-dev,
22 libubuntu-app-launch2-dev (>= 0.3),
23 python3,
24
25=== modified file 'debian/url-dispatcher.install'
26--- debian/url-dispatcher.install 2013-06-28 16:35:12 +0000
27+++ debian/url-dispatcher.install 2015-01-16 16:37:34 +0000
28@@ -1,3 +1,4 @@
29 usr/lib/*/url-dispatcher
30+usr/lib/*/trusted-session-helper
31 usr/share/dbus-1
32 usr/share/upstart/sessions
33
34=== modified file 'service/CMakeLists.txt'
35--- service/CMakeLists.txt 2014-05-26 12:56:47 +0000
36+++ service/CMakeLists.txt 2015-01-16 16:37:34 +0000
37@@ -36,6 +36,8 @@
38 # Dispatcher Lib
39 ###########################
40
41+add_definitions(-DURL_DISPATCHER_TRUST_SESSION_HELPER="${CMAKE_INSTALL_FULL_LIBEXECDIR}/trusted-session-helper")
42+
43 add_library(dispatcher-lib STATIC
44 dispatcher.h
45 dispatcher.c)
46
47=== modified file 'service/dispatcher.c'
48--- service/dispatcher.c 2014-12-11 19:00:04 +0000
49+++ service/dispatcher.c 2015-01-16 16:37:34 +0000
50@@ -190,16 +190,90 @@
51 return TRUE;
52 }
53
54+/* React to getting the PID and start the media player helper */
55+static void
56+send_to_media_player_pid_cb (GObject * obj, GAsyncResult * res, gpointer user_data)
57+{
58+ gchar * url = (gchar *)user_data;
59+ GVariant * pid_tuple = NULL;
60+ GError * error = NULL;
61+
62+ pid_tuple = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
63+ if (error != NULL) {
64+ g_warning("Unable to get PID for media player with URL '%s': %s", url, error->message);
65+ g_free(url);
66+ g_error_free(error);
67+ return;
68+ }
69+
70+ guint32 pid = 0;
71+ g_variant_get(pid_tuple, "(u)", &pid);
72+ g_variant_unref(pid_tuple);
73+
74+ gchar * pidstr = g_strdup_printf("%d", pid);
75+
76+ static const gchar * helper = NULL;
77+
78+ if (helper == NULL) {
79+ helper = g_getenv("URL_DISPATCHER_TRUST_SESSION_HELPER");
80+ }
81+ if (helper == NULL) {
82+ helper = URL_DISPATCHER_TRUST_SESSION_HELPER;
83+ }
84+
85+ const gchar * argv[5] = {
86+ helper,
87+ pidstr,
88+ "mediaplayer-app", /* TODO: Discover this */
89+ url,
90+ NULL
91+ };
92+
93+ g_spawn_async(NULL,
94+ (gchar **)argv,
95+ NULL, /* envp */
96+ G_SPAWN_DEFAULT,
97+ NULL, /* child setup */
98+ NULL, /* user_data */
99+ NULL, /* child pid */
100+ &error);
101+
102+ g_free(pidstr);
103+
104+ if (error != NULL) {
105+ g_warning("Unable to start trusted session helper for '%s': %s", url, error->message);
106+ g_error_free(error);
107+ }
108+}
109+
110+gboolean
111+send_to_scope_helper (GDBusMethodInvocation * invocation, const gchar * url)
112+{
113+ const gchar * sender = g_dbus_method_invocation_get_sender(invocation);
114+ GDBusConnection * conn = g_dbus_method_invocation_get_connection(invocation);
115+
116+ g_dbus_connection_call(conn,
117+ "org.freedesktop.DBus",
118+ "/",
119+ "org.freedesktop.DBus",
120+ "GetConnectionUnixProcessID",
121+ g_variant_new("(s)", sender),
122+ G_VARIANT_TYPE("(u)"),
123+ G_DBUS_CALL_FLAGS_NONE,
124+ -1, /* timeout */
125+ NULL, /* cancellable */
126+ send_to_media_player_pid_cb,
127+ g_strdup(url));
128+
129+ return FALSE;
130+}
131+
132 /* Handles taking an application and an URL and sending them to Upstart */
133 gboolean
134 dispatcher_send_to_app (const gchar * app_id, const gchar * url)
135 {
136 g_debug("Emitting 'application-start' for APP_ID='%s' and URLS='%s'", app_id, url);
137
138- if (g_strcmp0(app_id, "unity8-dash") == 0) {
139- return send_to_dash(url);
140- }
141-
142 const gchar * urls[2] = {
143 url,
144 NULL
145@@ -276,7 +350,17 @@
146 }
147
148 /* We're cleared to continue */
149- dispatcher_send_to_app(appid, outurl);
150+ /* Handle special cases */
151+ if (g_strcmp0(appid, "unity8-dash") == 0) {
152+ send_to_dash(outurl);
153+ } else if (g_strcmp0(appid, "mediaplayer-app") == 0) {
154+ /* TODO: This should be more than mediaplayer-app in the future, but we're
155+ implementing that first and then we can expand it. */
156+ send_to_scope_helper(invocation, outurl);
157+ } else {
158+ dispatcher_send_to_app(appid, outurl);
159+ }
160+
161 g_free(appid);
162
163 g_dbus_method_invocation_return_value(invocation, NULL);
164
165=== modified file 'tests/CMakeLists.txt'
166--- tests/CMakeLists.txt 2014-09-22 15:20:40 +0000
167+++ tests/CMakeLists.txt 2015-01-16 16:37:34 +0000
168@@ -1,5 +1,6 @@
169
170 add_definitions ( -DCMAKE_BINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}" )
171+add_definitions ( -DURL_DISPATCHER_TRUST_SESSION_HELPER="${CMAKE_BINARY_DIR}/trusted-session-helper/trusted-session-helper" )
172
173 ###########################
174 # Click Database
175@@ -88,8 +89,11 @@
176 # service test
177 ###########################
178
179+configure_file ("ts-helper-test.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/ts-helper-test.sh" @ONLY)
180 add_definitions ( -DURL_DISPATCHER_SERVICE="${CMAKE_BINARY_DIR}/service/url-dispatcher" )
181 add_definitions ( -DXDG_DATA_DIRS="${CMAKE_CURRENT_SOURCE_DIR}/xdg-data" )
182+add_definitions ( -DTS_HELPER_TEST="${CMAKE_CURRENT_BINARY_DIR}/ts-helper-test.sh" )
183+add_definitions ( -DTS_HELPER_TEST_FILE="${CMAKE_CURRENT_BINARY_DIR}/ts-helper-test-ran" )
184
185 add_executable (service-test service-test.cc)
186 target_link_libraries (service-test
187
188=== modified file 'tests/manual'
189--- tests/manual 2014-02-05 04:57:41 +0000
190+++ tests/manual 2015-01-16 16:37:34 +0000
191@@ -25,3 +25,20 @@
192 <dd>The settings application should come to focus</dd>
193 <dd>The settings app should display the battery settings</dd>
194 </dl>
195+
196+Test-case url-dispatcher/mediaplayer-special-case
197+<dl>
198+ <dt>NOTE: Testing for a special case, should go away in the future</dt>
199+ <dt>Open the camera app</dt>
200+ <dt>Record a video of yourself singing "Mary had a little lamb"</dt>
201+ <dt>Open the camera roll</dt>
202+ <dt>Play the video you just recorded</dt>
203+ <dd>The video should start playing above the camera app</dd>
204+ <dd>When looking at the application switcher the video should be managed as the camera app</dd>
205+ <dt>Stop the video playing</dt>
206+ <dt>Navigate to the dash</dt>
207+ <dt>Switch to the My Videos scope</dt>
208+ <dt>Select and play the video you just recorded</dt>
209+ <dd>The video should start playing above the dash</dd>
210+ <dd>When looking at the application switcher the video should be managed as the dash</dd>
211+</dl>
212
213=== modified file 'tests/service-test.cc'
214--- tests/service-test.cc 2014-09-22 15:20:40 +0000
215+++ tests/service-test.cc 2015-01-16 16:37:34 +0000
216@@ -15,8 +15,10 @@
217 *
218 */
219
220+#include <string>
221
222 #include <gio/gio.h>
223+#include <glib/gstdio.h>
224 #include <gtest/gtest.h>
225 #include <liburl-dispatcher/url-dispatcher.h>
226 #include <libdbustest/dbus-test.h>
227@@ -38,6 +40,10 @@
228 g_setenv("UBUNTU_APP_LAUNCH_USE_SESSION", "1", TRUE);
229 g_setenv("URL_DISPATCHER_DISABLE_RECOVERABLE_ERROR", "1", TRUE);
230 g_setenv("XDG_DATA_DIRS", XDG_DATA_DIRS, TRUE);
231+ g_setenv("URL_DISPATCHER_TRUST_SESSION_HELPER", TS_HELPER_TEST, TRUE);
232+
233+ g_debug("Deleting TS helper file: '" TS_HELPER_TEST_FILE "'");
234+ g_unlink(TS_HELPER_TEST_FILE);
235
236 SetUpDb();
237
238@@ -113,6 +119,9 @@
239 }
240
241 TearDownDb();
242+
243+ g_unlink(TS_HELPER_TEST_FILE);
244+
245 return;
246 }
247
248@@ -128,6 +137,8 @@
249 time.tv_sec = 5;
250 url_db_set_file_motification_time(db, "/unity8-dash.url-dispatcher", &time);
251 url_db_insert_url(db, "/unity8-dash.url-dispatcher", "scope", NULL);
252+ url_db_set_file_motification_time(db, "/mediaplayer-app.url-dispatcher", &time);
253+ url_db_insert_url(db, "/mediaplayer-app.url-dispatcher", "video", NULL);
254 sqlite3_close(db);
255 }
256
257@@ -297,3 +308,35 @@
258 g_dbus_connection_signal_unsubscribe(bus, focus_signal);
259 g_clear_object(&bus);
260 }
261+
262+TEST_F(ServiceTest, MediaPlayerHelperTest) {
263+ EXPECT_FALSE(g_file_test(TS_HELPER_TEST_FILE, G_FILE_TEST_EXISTS));
264+
265+ GMainLoop * main = g_main_loop_new(NULL, FALSE);
266+
267+ /* Send a dummy URL */
268+ url_dispatch_send("dummy:///this/wont/work.mp4", simple_cb, main);
269+
270+ /* Give it some time to send and reply */
271+ g_main_loop_run(main);
272+
273+ EXPECT_FALSE(g_file_test(TS_HELPER_TEST_FILE, G_FILE_TEST_EXISTS));
274+
275+ /* Send an video URL */
276+ url_dispatch_send("video:///foo/bar/movie.mp4", simple_cb, main);
277+
278+ /* Give it some time to send and reply */
279+ g_main_loop_run(main);
280+ g_main_loop_unref(main);
281+
282+ g_usleep(0.2 * G_USEC_PER_SEC);
283+
284+ EXPECT_TRUE(g_file_test(TS_HELPER_TEST_FILE, G_FILE_TEST_EXISTS));
285+
286+ gchar * pidstr = NULL;
287+ gchar * getpidstr = g_strdup_printf("%d", getpid());
288+ EXPECT_TRUE(g_file_get_contents(TS_HELPER_TEST_FILE, &pidstr, NULL, NULL));
289+ EXPECT_STREQ(getpidstr, pidstr);
290+ g_free(getpidstr);
291+ g_free(pidstr);
292+}
293
294=== added file 'tests/ts-helper-test.sh.in'
295--- tests/ts-helper-test.sh.in 1970-01-01 00:00:00 +0000
296+++ tests/ts-helper-test.sh.in 2015-01-16 16:37:34 +0000
297@@ -0,0 +1,12 @@
298+#!/bin/bash
299+
300+if [ "$2" != "mediaplayer-app" ] ; then
301+ exit 1;
302+fi
303+
304+if [ "$3" != "video:///foo/bar/movie.mp4" ] ; then
305+ exit 1;
306+fi
307+
308+echo "TS Helper Touching: @CMAKE_CURRENT_BINARY_DIR@/ts-helper-test-ran"
309+echo -n $1 > @CMAKE_CURRENT_BINARY_DIR@/ts-helper-test-ran
310
311=== added directory 'trusted-session-helper'
312=== added file 'trusted-session-helper/CMakeLists.txt'
313--- trusted-session-helper/CMakeLists.txt 1970-01-01 00:00:00 +0000
314+++ trusted-session-helper/CMakeLists.txt 2015-01-16 16:37:34 +0000
315@@ -0,0 +1,13 @@
316+
317+find_package (PkgConfig REQUIRED)
318+pkg_check_modules (HELPER_DEPS REQUIRED
319+ glib-2.0
320+ mirclient)
321+include_directories (SYSTEM ${HELPER_DEPS_INCLUDE_DIRS})
322+
323+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -fPIE")
324+
325+add_executable(trusted-session-helper main.cpp)
326+target_link_libraries(trusted-session-helper ${HELPER_DEPS_LIBRARIES})
327+
328+install(TARGETS trusted-session-helper RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR})
329
330=== added file 'trusted-session-helper/main.cpp'
331--- trusted-session-helper/main.cpp 1970-01-01 00:00:00 +0000
332+++ trusted-session-helper/main.cpp 2015-01-16 16:37:34 +0000
333@@ -0,0 +1,103 @@
334+
335+#include <memory>
336+#include <string>
337+#include <iostream>
338+#include <cstdlib>
339+
340+extern "C" {
341+#include <unistd.h>
342+#include <fcntl.h>
343+#include <sys/wait.h>
344+
345+#include <glib.h>
346+#include <mir_toolkit/mir_connection.h>
347+#include <mir_toolkit/mir_prompt_session.h>
348+}
349+
350+int
351+main (int argc, char * argv[])
352+{
353+ if (argc != 4) {
354+ std::cerr << "Usage: " << argv[0] << " [parent pid] [appid] [url]" << std::endl;
355+ std::cerr << "TODO: AppID is currently just the binary to execute" << std::endl;
356+ return -1;
357+ }
358+
359+ pid_t pid = atoi(argv[1]);
360+ if (pid == 0) {
361+ std::cerr << "Invalid PID: " << argv[1] << std::endl;
362+ return -1;
363+ }
364+
365+ /* Connect to Mir */
366+ gchar* mirpath = g_build_filename(g_get_user_runtime_dir(), "mir_socket_trusted", NULL);
367+
368+ std::shared_ptr<MirConnection> connection = std::shared_ptr<MirConnection>(
369+ mir_connect_sync(mirpath, "url-dispatcher-trusted-session-helper"),
370+ [](MirConnection * connection)
371+ {
372+ if (connection != nullptr)
373+ {
374+ mir_connection_release(connection);
375+ }
376+ });
377+ g_free(mirpath);
378+
379+ if (connection == nullptr) {
380+ std::cerr << "Unable to connect to Mir" << std::endl;
381+ return -1;
382+ }
383+
384+ /* Setup the trusted prompt session */
385+ auto session = std::shared_ptr<MirPromptSession>(
386+ mir_connection_create_prompt_session_sync(connection.get(), pid, nullptr, nullptr),
387+ [](MirPromptSession * session)
388+ {
389+ if (session != nullptr)
390+ {
391+ mir_prompt_session_release_sync(session);
392+ }
393+ });
394+
395+ if (session == nullptr) {
396+ std::cerr << "Unable to make Mir Trusted Prompt session" << std::endl;
397+ return -1;
398+ }
399+
400+ int fd = 0;
401+ auto mirwait = mir_prompt_session_new_fds_for_prompt_providers(session.get(),
402+ 1,
403+ [](MirPromptSession * session, size_t count, int const * fdsin, void* context) -> void
404+ {
405+ g_debug("FDs %d Returned from Mir", count);
406+ if (count != 1) return;
407+ int * fd = reinterpret_cast<int *>(context);
408+ *fd = fdsin[0];
409+ },
410+ &fd);
411+
412+ mir_wait_for(mirwait);
413+
414+ if (fd == 0) {
415+ std::cerr << "Unable to get Mir socket" << std::endl;
416+ return -1;
417+ }
418+
419+ /* Ensure FD will get passed to an exec */
420+ fcntl(fd, F_SETFD, 0);
421+
422+ pid_t child = fork();
423+ if (child == 0) {
424+ std::string socketstr("fd://");
425+ socketstr += std::to_string(fd);
426+
427+ setenv("MIR_SOCKET", socketstr.c_str(), 1);
428+
429+ return execlp(argv[2], argv[2], argv[3]);
430+ }
431+
432+ int childstatus = 0;
433+ waitpid(child, &childstatus, 0);
434+
435+ return childstatus;
436+}

Subscribers

People subscribed via source and target branches