39#include <sys/eventfd.h>
60static const char *
const devstate_name[] = {
74static bool worker_thread_p (
void);
75bool worker_bailing_out (
void);
76static devstate_t worker_get_mtp_device_state (
void);
77static void worker_unmount_mtp_device (
void);
78static bool worker_mount_mtp_device (
void);
79static bool worker_mode_is_mtp_mode (
const char *mode);
80static bool worker_is_mtpd_running (
void);
81static bool worker_mtpd_running_p (
void *aptr);
82static bool worker_mtpd_stopped_p (
void *aptr);
83static bool worker_stop_mtpd (
void);
84static bool worker_start_mtpd (
void);
85static bool worker_switch_to_charging (
void);
88void worker_clear_kernel_module (
void);
92static const char *worker_get_activated_mode_locked(
void);
93static bool worker_set_activated_mode_locked(
const char *mode);
94static const char *worker_get_requested_mode_locked(
void);
95static bool worker_set_requested_mode_locked(
const char *mode);
96void worker_request_hardware_mode (
const char *mode);
97void worker_clear_hardware_mode (
void);
98static void worker_execute (
void);
99static void worker_switch_to_mode (
const char *mode);
100static guint worker_add_iowatch (
int fd,
bool close_on_unref, GIOCondition cnd, GIOFunc io_cb, gpointer aptr);
101static void *worker_thread_cb (
void *aptr);
102static gboolean worker_notify_cb (GIOChannel *chn, GIOCondition cnd, gpointer data);
103static bool worker_start_thread (
void);
104static void worker_stop_thread (
void);
105static void worker_delete_eventfd (
void);
106static bool worker_create_eventfd (
void);
107bool worker_init (
void);
108void worker_quit (
void);
109void worker_wakeup (
void);
110static void worker_notify (
void);
116static pthread_t worker_thread_id = 0;
118static pthread_mutex_t worker_mutex = PTHREAD_MUTEX_INITIALIZER;
125static volatile bool worker_bailout_requested =
false;
132static volatile bool worker_bailout_handled =
false;
134#define WORKER_LOCKED_ENTER do {\
135 if( pthread_mutex_lock(&worker_mutex) != 0 ) { \
136 log_crit("WORKER LOCK FAILED");\
137 _exit(EXIT_FAILURE);\
141#define WORKER_LOCKED_LEAVE do {\
142 if( pthread_mutex_unlock(&worker_mutex) != 0 ) { \
143 log_crit("WORKER UNLOCK FAILED");\
144 _exit(EXIT_FAILURE);\
155 LOG_REGISTER_CONTEXT;
157 return worker_thread_id && worker_thread_id == pthread_self();
161worker_bailing_out(
void)
163 LOG_REGISTER_CONTEXT;
166 return (worker_thread_p() &&
167 worker_bailout_requested &&
168 !worker_bailout_handled);
193worker_get_mtp_device_state(
void)
195 LOG_REGISTER_CONTEXT;
199 if( access(
"/dev/mtp/ep0", F_OK) == 0 )
201 else if( errno == ENOENT )
204 log_warning(
"/dev/mtp/ep0: %m");
206 log_debug(
"mtp device state = %s", devstate_name[state]);
213worker_unmount_mtp_device(
void)
215 LOG_REGISTER_CONTEXT;
218 log_debug(
"unmounting mtp device");
219 common_system(
"/bin/umount /dev/mtp");
231worker_mount_mtp_device(
void)
233 LOG_REGISTER_CONTEXT;
235 bool mounted =
false;
239 log_err(
"mtp device already mounted");
244 if( mkdir(
"/dev/mtp", 0755) == -1 && errno != EEXIST ) {
245 log_err(
"failed to create /dev/mtp directory: %m");
253 if( uid == UID_UNKNOWN )
256 struct passwd *pw = getpwuid(uid);
264 snprintf(cmd,
sizeof cmd,
265 "/bin/mount -o mode=0770,uid=0,gid=%u -t functionfs mtp /dev/mtp",
268 log_debug(
"mounting mtp device");
269 if( common_system(cmd) != 0 )
274 log_err(
"mtp control not mounted");
298static unsigned worker_mtp_start_delay = 120 * 1000;
306static unsigned worker_mtp_stop_delay = 15 * 1000;
314static bool worker_mtp_service_started =
false;
316static bool worker_mode_is_mtp_mode(
const char *mode)
318 LOG_REGISTER_CONTEXT;
320 return mode && !strcmp(mode,
"mtp_mode");
323static bool worker_is_mtpd_running(
void)
325 LOG_REGISTER_CONTEXT;
332 static const char *
const lut[] = {
342 for(
size_t i = 0; lut[i]; ++i ) {
343 if( access(lut[i], F_OK) == -1 ) {
353worker_mtpd_running_p(
void *aptr)
355 LOG_REGISTER_CONTEXT;
358 return worker_is_mtpd_running();
362worker_mtpd_stopped_p(
void *aptr)
364 LOG_REGISTER_CONTEXT;
367 return !worker_is_mtpd_running();
371worker_stop_mtpd(
void)
373 LOG_REGISTER_CONTEXT;
377 if( !worker_mtp_service_started && worker_mtpd_stopped_p(0) ) {
378 log_debug(
"mtp daemon is not running");
382 int rc = common_system(
"systemctl-user stop buteo-mtp.service");
384 log_warning(
"failed to stop mtp daemon; exit code = %d", rc);
389 worker_mtp_service_started =
false;
391 if( common_wait(worker_mtp_stop_delay, worker_mtpd_stopped_p, 0) != WAIT_READY ) {
392 log_warning(
"failed to stop mtp daemon; giving up");
396 log_debug(
"mtp daemon has stopped");
406worker_start_mtpd(
void)
408 LOG_REGISTER_CONTEXT;
412 if( worker_mtpd_running_p(0) ) {
413 log_debug(
"mtp daemon is running");
418 worker_mtp_service_started =
true;
420 int rc = common_system(
"systemctl-user start buteo-mtp.service");
422 log_warning(
"failed to start mtp daemon; exit code = %d", rc);
426 if( common_wait(worker_mtp_start_delay, worker_mtpd_running_p, 0) != WAIT_READY ) {
427 log_warning(
"failed to start mtp daemon; giving up");
431 log_debug(
"mtp daemon has started");
440static bool worker_switch_to_charging(
void)
442 LOG_REGISTER_CONTEXT;
446 if( android_set_charging_mode() )
449 if( configfs_set_charging_mode() )
452 if( modules_in_use() ) {
458 log_err(
"switch to charging mode failed");
470static char *worker_kernel_module = NULL;
479 LOG_REGISTER_CONTEXT;
481 return worker_kernel_module ?: MODULE_NONE;
491 LOG_REGISTER_CONTEXT;
496 module = MODULE_NONE;
500 log_debug(
"current module: %s -> %s", current, module);
502 if( !g_strcmp0(current, module) )
508 free(worker_kernel_module), worker_kernel_module = 0;
513 if( g_strcmp0(module, MODULE_NONE) )
514 worker_kernel_module = strdup(module);
522void worker_clear_kernel_module(
void)
524 LOG_REGISTER_CONTEXT;
526 free(worker_kernel_module), worker_kernel_module = 0;
544 LOG_REGISTER_CONTEXT;
546 return worker_mode_data;
557 LOG_REGISTER_CONTEXT;
576 LOG_REGISTER_CONTEXT;
596static gchar *worker_requested_mode = NULL;
598static gchar *worker_activated_mode = NULL;
601worker_get_activated_mode_locked(
void)
603 LOG_REGISTER_CONTEXT;
609worker_set_activated_mode_locked(
const char *mode)
611 LOG_REGISTER_CONTEXT;
613 bool changed =
false;
614 const char *prev = worker_get_activated_mode_locked();
616 if( !g_strcmp0(prev, mode) )
619 log_debug(
"activated_mode: %s -> %s", prev, mode);
620 g_free(worker_activated_mode),
621 worker_activated_mode = g_strdup(mode);
629worker_get_requested_mode_locked(
void)
631 LOG_REGISTER_CONTEXT;
637worker_set_requested_mode_locked(
const char *mode)
639 LOG_REGISTER_CONTEXT;
641 bool changed =
false;
642 const char *prev = worker_get_requested_mode_locked();
644 if( !g_strcmp0(prev, mode) )
647 log_debug(
"requested_mode: %s -> %s", prev, mode);
648 g_free(worker_requested_mode),
649 worker_requested_mode = g_strdup(mode);
656void worker_request_hardware_mode(
const char *mode)
658 LOG_REGISTER_CONTEXT;
662 if( !worker_set_requested_mode_locked(mode) )
672void worker_clear_hardware_mode(
void)
674 LOG_REGISTER_CONTEXT;
677 g_free(worker_requested_mode), worker_requested_mode = 0;
684 LOG_REGISTER_CONTEXT;
688 const char *activated = worker_get_activated_mode_locked();
689 const char *requested = worker_get_requested_mode_locked();
690 const char *activate = common_map_mode_to_hardware(requested);
692 log_debug(
"activated = %s", activated);
693 log_debug(
"requested = %s", requested);
694 log_debug(
"activate = %s", activate);
696 bool changed = g_strcmp0(activated, activate) != 0;
697 gchar *mode = g_strdup(activate);
702 worker_switch_to_mode(mode);
716worker_switch_to_mode(
const char *mode)
718 LOG_REGISTER_CONTEXT;
720 const char *
override = 0;
725 log_debug(
"Cleaning up previous mode");
734 worker_unmount_mtp_device();
737 modesetting_leave_dynamic_mode();
746 log_debug(
"Setting %s\n", mode);
760 log_warning(
"Policy does not allow mode: %s", mode);
765 log_debug(
"Matching mode %s found.\n", mode);
773 if( worker_mode_is_mtp_mode(mode) && configfs_in_use() ) {
774 if( !worker_mount_mtp_device() )
776 if( !worker_start_mtpd() )
783 if( !modesetting_enter_dynamic_mode() )
789 if( worker_mode_is_mtp_mode(mode) && !configfs_in_use() ) {
790 if( !worker_mount_mtp_device() )
792 if( !worker_start_mtpd() )
799 log_warning(
"Matching mode %s was not found.", mode);
802 worker_bailout_handled =
true;
806 log_debug(
"Cleaning up failed mode switch");
808 modesetting_leave_dynamic_mode();
820 const char *requested = worker_get_requested_mode_locked();
826 log_warning(
"mode setting failed, try %s",
override);
829 if( worker_switch_to_charging() )
832 log_crit(
"failed to activate charging, all bets are off");
841 log_warning(
"mode setting failed, fallback to %s",
override);
848 worker_set_requested_mode_locked(
override);
849 override = common_map_mode_to_hardware(
override);
850 worker_set_activated_mode_locked(
override);
853 worker_set_activated_mode_locked(mode);
869static int worker_req_evfd = -1;
872static int worker_rsp_evfd = -1;
875static guint worker_rsp_wid = 0;
878worker_add_iowatch(
int fd,
bool close_on_unref,
879 GIOCondition cnd, GIOFunc io_cb, gpointer aptr)
881 LOG_REGISTER_CONTEXT;
886 if( !(chn = g_io_channel_unix_new(fd)) )
889 g_io_channel_set_close_on_unref(chn, close_on_unref);
891 cnd |= G_IO_ERR | G_IO_HUP | G_IO_NVAL;
893 if( !(wid = g_io_add_watch(chn, cnd, io_cb, aptr)) )
897 if( chn != 0 ) g_io_channel_unref(chn);
903static void *worker_thread_cb(
void *aptr)
905 LOG_REGISTER_CONTEXT;
910 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
911 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
916 sigaddset(&ss, SIGINT);
917 sigaddset(&ss, SIGTERM);
918 pthread_sigmask(SIG_BLOCK, &ss, 0);
923 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
925 int rc = read(worker_req_evfd, &cnt,
sizeof cnt);
926 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
929 if( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK )
935 if( rc !=
sizeof cnt )
939 worker_bailout_requested =
false;
940 worker_bailout_handled =
false;
950worker_notify_cb(GIOChannel *chn, GIOCondition cnd, gpointer data)
952 LOG_REGISTER_CONTEXT;
956 gboolean keep_going = FALSE;
958 if( !worker_rsp_wid )
961 int fd = g_io_channel_unix_get_fd(chn);
969 if( !(cnd & G_IO_IN) )
974 int rc = read(fd, &cnt,
sizeof cnt);
977 log_err(
"unexpected eof");
982 if( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK )
985 log_err(
"read error: %m");
989 if( rc !=
sizeof cnt )
994 const char *mode = worker_get_requested_mode_locked();
995 gchar *work = g_strdup(mode);
998 control_mode_switched(work);
1009 log_crit(
"worker notifications disabled");
1016worker_start_thread(
void)
1018 LOG_REGISTER_CONTEXT;
1021 int err = pthread_create(&worker_thread_id, 0, worker_thread_cb, 0);
1023 worker_thread_id = 0;
1024 log_err(
"failed to start worker thread");
1028 log_debug(
"worker thread started");
1035worker_stop_thread(
void)
1037 LOG_REGISTER_CONTEXT;
1039 if( !worker_thread_id )
1042 log_debug(
"stopping worker thread");
1043 int err = pthread_cancel(worker_thread_id);
1045 log_err(
"failed to cancel worker thread");
1048 log_debug(
"waiting for worker thread to exit ...");
1050 struct timespec tmo = { 0, 0};
1051 clock_gettime(CLOCK_REALTIME, &tmo);
1053 err = pthread_timedjoin_np(worker_thread_id, &ret, &tmo);
1055 log_err(
"worker thread did not exit");
1058 log_debug(
"worker thread terminated");
1059 worker_thread_id = 0;
1063 if( worker_thread_id ) {
1065 _exit(EXIT_FAILURE);
1073worker_delete_eventfd(
void)
1075 LOG_REGISTER_CONTEXT;
1077 if( worker_req_evfd != -1 )
1078 close(worker_req_evfd), worker_req_evfd = -1;
1080 if( worker_rsp_wid )
1081 g_source_remove(worker_rsp_wid), worker_rsp_wid = 0;
1083 if( worker_rsp_evfd != -1 )
1084 close(worker_rsp_evfd), worker_req_evfd = -1;
1088worker_create_eventfd(
void)
1090 LOG_REGISTER_CONTEXT;
1096 if( (worker_rsp_evfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) == -1 )
1099 worker_rsp_wid = worker_add_iowatch(worker_rsp_evfd,
false, G_IO_IN,
1100 worker_notify_cb, 0);
1101 if( !worker_rsp_wid )
1106 if( (worker_req_evfd = eventfd(0, EFD_CLOEXEC)) == -1 )
1119 LOG_REGISTER_CONTEXT;
1123 if( !worker_create_eventfd() )
1126 if( !worker_start_thread() )
1141 LOG_REGISTER_CONTEXT;
1143 worker_stop_thread();
1144 worker_delete_eventfd();
1153 LOG_REGISTER_CONTEXT;
1155 worker_bailout_requested =
true;
1158 if( write(worker_req_evfd, &cnt,
sizeof cnt) == -1 ) {
1159 log_err(
"failed to signal requested: %m");
1166 LOG_REGISTER_CONTEXT;
1169 if( write(worker_rsp_evfd, &cnt,
sizeof cnt) == -1 ) {
1170 log_err(
"failed to signal handled: %m");
void appsync_switch_configuration(void)
void modedata_free(modedata_t *self)
modedata_t * modedata_copy(const modedata_t *that)
#define MODE_CHARGING_FALLBACK
int modules_load_module(const char *module)
int modules_unload_module(const char *module)
bool worker_set_kernel_module(const char *module)
modedata_t * worker_dup_usb_mode_data(void)
const modedata_t * worker_get_usb_mode_data(void)
void worker_set_usb_mode_data(const modedata_t *data)
const char * worker_get_kernel_module(void)
modedata_t * usbmoded_dup_modedata(const char *modename)
bool usbmoded_can_export(void)
uid_t usbmoded_get_current_user(void)