38 #include <sys/types.h>
39 #include <sys/eventfd.h>
59 static const char *
const devstate_name[] = {
73 static bool worker_thread_p (
void);
74 bool worker_bailing_out (
void);
75 static devstate_t worker_get_mtp_device_state (
void);
76 static void worker_unmount_mtp_device (
void);
77 static bool worker_mount_mtp_device (
void);
78 static bool worker_mode_is_mtp_mode (
const char *mode);
79 static bool worker_is_mtpd_running (
void);
80 static bool worker_mtpd_running_p (
void *aptr);
81 static bool worker_mtpd_stopped_p (
void *aptr);
82 static bool worker_stop_mtpd (
void);
83 static bool worker_start_mtpd (
void);
84 static bool worker_switch_to_charging (
void);
87 void worker_clear_kernel_module (
void);
91 static const char *worker_get_activated_mode_locked(
void);
92 static bool worker_set_activated_mode_locked(
const char *mode);
93 static const char *worker_get_requested_mode_locked(
void);
94 static bool worker_set_requested_mode_locked(
const char *mode);
95 void worker_request_hardware_mode (
const char *mode);
96 void worker_clear_hardware_mode (
void);
97 static void worker_execute (
void);
98 static void worker_switch_to_mode (
const char *mode);
99 static guint worker_add_iowatch (
int fd,
bool close_on_unref, GIOCondition cnd, GIOFunc io_cb, gpointer aptr);
100 static void *worker_thread_cb (
void *aptr);
101 static gboolean worker_notify_cb (GIOChannel *chn, GIOCondition cnd, gpointer data);
102 static bool worker_start_thread (
void);
103 static void worker_stop_thread (
void);
104 static void worker_delete_eventfd (
void);
105 static bool worker_create_eventfd (
void);
106 bool worker_init (
void);
107 void worker_quit (
void);
108 void worker_wakeup (
void);
109 static void worker_notify (
void);
115 static pthread_t worker_thread_id = 0;
117 static pthread_mutex_t worker_mutex = PTHREAD_MUTEX_INITIALIZER;
124 static volatile bool worker_bailout_requested =
false;
131 static volatile bool worker_bailout_handled =
false;
133 #define WORKER_LOCKED_ENTER do {\
134 if( pthread_mutex_lock(&worker_mutex) != 0 ) { \
135 log_crit("WORKER LOCK FAILED");\
136 _exit(EXIT_FAILURE);\
140 #define WORKER_LOCKED_LEAVE do {\
141 if( pthread_mutex_unlock(&worker_mutex) != 0 ) { \
142 log_crit("WORKER UNLOCK FAILED");\
143 _exit(EXIT_FAILURE);\
152 worker_thread_p(
void)
154 LOG_REGISTER_CONTEXT;
156 return worker_thread_id && worker_thread_id == pthread_self();
160 worker_bailing_out(
void)
162 LOG_REGISTER_CONTEXT;
165 return (worker_thread_p() &&
166 worker_bailout_requested &&
167 !worker_bailout_handled);
192 worker_get_mtp_device_state(
void)
194 LOG_REGISTER_CONTEXT;
198 if( access(
"/dev/mtp/ep0", F_OK) == 0 )
200 else if( errno == ENOENT )
203 log_warning(
"/dev/mtp/ep0: %m");
205 log_debug(
"mtp device state = %s", devstate_name[state]);
212 worker_unmount_mtp_device(
void)
214 LOG_REGISTER_CONTEXT;
217 log_debug(
"unmounting mtp device");
218 common_system(
"/bin/umount /dev/mtp");
230 worker_mount_mtp_device(
void)
232 LOG_REGISTER_CONTEXT;
234 bool mounted =
false;
238 log_err(
"mtp device already mounted");
243 if( mkdir(
"/dev/mtp", 0755) == -1 && errno != EEXIST ) {
244 log_err(
"failed to create /dev/mtp directory: %m");
252 if( uid == UID_UNKNOWN )
255 struct passwd *pw = getpwuid(uid);
263 snprintf(cmd,
sizeof cmd,
264 "/bin/mount -o mode=0770,uid=0,gid=%u -t functionfs mtp /dev/mtp",
267 log_debug(
"mounting mtp device");
268 if( common_system(cmd) != 0 )
273 log_err(
"mtp control not mounted");
297 static unsigned worker_mtp_start_delay = 120 * 1000;
305 static unsigned worker_mtp_stop_delay = 15 * 1000;
313 static bool worker_mtp_service_started =
false;
315 static bool worker_mode_is_mtp_mode(
const char *mode)
317 LOG_REGISTER_CONTEXT;
319 return mode && !strcmp(mode,
"mtp_mode");
322 static bool worker_is_mtpd_running(
void)
324 LOG_REGISTER_CONTEXT;
331 static const char *
const lut[] = {
341 for(
size_t i = 0; lut[i]; ++i ) {
342 if( access(lut[i], F_OK) == -1 ) {
352 worker_mtpd_running_p(
void *aptr)
354 LOG_REGISTER_CONTEXT;
357 return worker_is_mtpd_running();
361 worker_mtpd_stopped_p(
void *aptr)
363 LOG_REGISTER_CONTEXT;
366 return !worker_is_mtpd_running();
370 worker_stop_mtpd(
void)
372 LOG_REGISTER_CONTEXT;
376 if( !worker_mtp_service_started && worker_mtpd_stopped_p(0) ) {
377 log_debug(
"mtp daemon is not running");
381 int rc = common_system(
"systemctl-user stop buteo-mtp.service");
383 log_warning(
"failed to stop mtp daemon; exit code = %d", rc);
388 worker_mtp_service_started =
false;
390 if( common_wait(worker_mtp_stop_delay, worker_mtpd_stopped_p, 0) != WAIT_READY ) {
391 log_warning(
"failed to stop mtp daemon; giving up");
395 log_debug(
"mtp daemon has stopped");
405 worker_start_mtpd(
void)
407 LOG_REGISTER_CONTEXT;
411 if( worker_mtpd_running_p(0) ) {
412 log_debug(
"mtp daemon is running");
417 worker_mtp_service_started =
true;
419 int rc = common_system(
"systemctl-user start buteo-mtp.service");
421 log_warning(
"failed to start mtp daemon; exit code = %d", rc);
425 if( common_wait(worker_mtp_start_delay, worker_mtpd_running_p, 0) != WAIT_READY ) {
426 log_warning(
"failed to start mtp daemon; giving up");
430 log_debug(
"mtp daemon has started");
439 static bool worker_switch_to_charging(
void)
441 LOG_REGISTER_CONTEXT;
445 if( android_set_charging_mode() )
448 if( configfs_set_charging_mode() )
451 if( modules_in_use() ) {
457 log_err(
"switch to charging mode failed");
469 static char *worker_kernel_module = NULL;
478 LOG_REGISTER_CONTEXT;
480 return worker_kernel_module ?: MODULE_NONE;
490 LOG_REGISTER_CONTEXT;
495 module = MODULE_NONE;
499 log_debug(
"current module: %s -> %s", current, module);
501 if( !g_strcmp0(current, module) )
507 free(worker_kernel_module), worker_kernel_module = 0;
512 if( g_strcmp0(module, MODULE_NONE) )
513 worker_kernel_module = strdup(module);
521 void worker_clear_kernel_module(
void)
523 LOG_REGISTER_CONTEXT;
525 free(worker_kernel_module), worker_kernel_module = 0;
543 LOG_REGISTER_CONTEXT;
545 return worker_mode_data;
556 LOG_REGISTER_CONTEXT;
575 LOG_REGISTER_CONTEXT;
595 static gchar *worker_requested_mode = NULL;
597 static gchar *worker_activated_mode = NULL;
600 worker_get_activated_mode_locked(
void)
602 LOG_REGISTER_CONTEXT;
608 worker_set_activated_mode_locked(
const char *mode)
610 LOG_REGISTER_CONTEXT;
612 bool changed =
false;
613 const char *prev = worker_get_activated_mode_locked();
615 if( !g_strcmp0(prev, mode) )
618 log_debug(
"activated_mode: %s -> %s", prev, mode);
619 g_free(worker_activated_mode),
620 worker_activated_mode = g_strdup(mode);
628 worker_get_requested_mode_locked(
void)
630 LOG_REGISTER_CONTEXT;
636 worker_set_requested_mode_locked(
const char *mode)
638 LOG_REGISTER_CONTEXT;
640 bool changed =
false;
641 const char *prev = worker_get_requested_mode_locked();
643 if( !g_strcmp0(prev, mode) )
646 log_debug(
"requested_mode: %s -> %s", prev, mode);
647 g_free(worker_requested_mode),
648 worker_requested_mode = g_strdup(mode);
655 void worker_request_hardware_mode(
const char *mode)
657 LOG_REGISTER_CONTEXT;
661 if( !worker_set_requested_mode_locked(mode) )
671 void worker_clear_hardware_mode(
void)
673 LOG_REGISTER_CONTEXT;
676 g_free(worker_requested_mode), worker_requested_mode = 0;
683 LOG_REGISTER_CONTEXT;
687 const char *activated = worker_get_activated_mode_locked();
688 const char *requested = worker_get_requested_mode_locked();
689 const char *activate = common_map_mode_to_hardware(requested);
691 log_debug(
"activated = %s", activated);
692 log_debug(
"requested = %s", requested);
693 log_debug(
"activate = %s", activate);
695 bool changed = g_strcmp0(activated, activate) != 0;
696 gchar *mode = g_strdup(activate);
701 worker_switch_to_mode(mode);
715 worker_switch_to_mode(
const char *mode)
717 LOG_REGISTER_CONTEXT;
719 const char *
override = 0;
724 log_debug(
"Cleaning up previous mode");
733 worker_unmount_mtp_device();
736 modesetting_leave_dynamic_mode();
745 log_debug(
"Setting %s\n", mode);
759 log_warning(
"Policy does not allow mode: %s", mode);
764 log_debug(
"Matching mode %s found.\n", mode);
772 if( worker_mode_is_mtp_mode(mode) && configfs_in_use() ) {
773 if( !worker_mount_mtp_device() )
775 if( !worker_start_mtpd() )
782 if( !modesetting_enter_dynamic_mode() )
788 if( worker_mode_is_mtp_mode(mode) && !configfs_in_use() ) {
789 if( !worker_mount_mtp_device() )
791 if( !worker_start_mtpd() )
798 log_warning(
"Matching mode %s was not found.", mode);
801 worker_bailout_handled =
true;
805 log_debug(
"Cleaning up failed mode switch");
807 modesetting_leave_dynamic_mode();
819 const char *requested = worker_get_requested_mode_locked();
825 log_warning(
"mode setting failed, try %s",
override);
828 if( worker_switch_to_charging() )
831 log_crit(
"failed to activate charging, all bets are off");
840 log_warning(
"mode setting failed, fallback to %s",
override);
847 worker_set_requested_mode_locked(
override);
848 override = common_map_mode_to_hardware(
override);
849 worker_set_activated_mode_locked(
override);
852 worker_set_activated_mode_locked(mode);
868 static int worker_req_evfd = -1;
871 static int worker_rsp_evfd = -1;
874 static guint worker_rsp_wid = 0;
877 worker_add_iowatch(
int fd,
bool close_on_unref,
878 GIOCondition cnd, GIOFunc io_cb, gpointer aptr)
880 LOG_REGISTER_CONTEXT;
885 if( !(chn = g_io_channel_unix_new(fd)) )
888 g_io_channel_set_close_on_unref(chn, close_on_unref);
890 cnd |= G_IO_ERR | G_IO_HUP | G_IO_NVAL;
892 if( !(wid = g_io_add_watch(chn, cnd, io_cb, aptr)) )
896 if( chn != 0 ) g_io_channel_unref(chn);
902 static void *worker_thread_cb(
void *aptr)
904 LOG_REGISTER_CONTEXT;
909 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
910 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
915 sigaddset(&ss, SIGINT);
916 sigaddset(&ss, SIGTERM);
917 pthread_sigmask(SIG_BLOCK, &ss, 0);
922 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
924 int rc = read(worker_req_evfd, &cnt,
sizeof cnt);
925 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
928 if( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK )
934 if( rc !=
sizeof cnt )
938 worker_bailout_requested =
false;
939 worker_bailout_handled =
false;
949 worker_notify_cb(GIOChannel *chn, GIOCondition cnd, gpointer data)
951 LOG_REGISTER_CONTEXT;
955 gboolean keep_going = FALSE;
957 if( !worker_rsp_wid )
960 int fd = g_io_channel_unix_get_fd(chn);
968 if( !(cnd & G_IO_IN) )
973 int rc = read(fd, &cnt,
sizeof cnt);
976 log_err(
"unexpected eof");
981 if( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK )
984 log_err(
"read error: %m");
988 if( rc !=
sizeof cnt )
993 const char *mode = worker_get_requested_mode_locked();
994 gchar *work = g_strdup(mode);
997 control_mode_switched(work);
1008 log_crit(
"worker notifications disabled");
1015 worker_start_thread(
void)
1017 LOG_REGISTER_CONTEXT;
1020 int err = pthread_create(&worker_thread_id, 0, worker_thread_cb, 0);
1022 worker_thread_id = 0;
1023 log_err(
"failed to start worker thread");
1027 log_debug(
"worker thread started");
1034 worker_stop_thread(
void)
1036 LOG_REGISTER_CONTEXT;
1038 if( !worker_thread_id )
1041 log_debug(
"stopping worker thread");
1042 int err = pthread_cancel(worker_thread_id);
1044 log_err(
"failed to cancel worker thread");
1047 log_debug(
"waiting for worker thread to exit ...");
1049 struct timespec tmo = { 0, 0};
1050 clock_gettime(CLOCK_REALTIME, &tmo);
1052 err = pthread_timedjoin_np(worker_thread_id, &ret, &tmo);
1054 log_err(
"worker thread did not exit");
1057 log_debug(
"worker thread terminated");
1058 worker_thread_id = 0;
1062 if( worker_thread_id ) {
1064 _exit(EXIT_FAILURE);
1072 worker_delete_eventfd(
void)
1074 LOG_REGISTER_CONTEXT;
1076 if( worker_req_evfd != -1 )
1077 close(worker_req_evfd), worker_req_evfd = -1;
1079 if( worker_rsp_wid )
1080 g_source_remove(worker_rsp_wid), worker_rsp_wid = 0;
1082 if( worker_rsp_evfd != -1 )
1083 close(worker_rsp_evfd), worker_req_evfd = -1;
1087 worker_create_eventfd(
void)
1089 LOG_REGISTER_CONTEXT;
1095 if( (worker_rsp_evfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) == -1 )
1098 worker_rsp_wid = worker_add_iowatch(worker_rsp_evfd,
false, G_IO_IN,
1099 worker_notify_cb, 0);
1100 if( !worker_rsp_wid )
1105 if( (worker_req_evfd = eventfd(0, EFD_CLOEXEC)) == -1 )
1118 LOG_REGISTER_CONTEXT;
1122 if( !worker_create_eventfd() )
1125 if( !worker_start_thread() )
1140 LOG_REGISTER_CONTEXT;
1142 worker_stop_thread();
1143 worker_delete_eventfd();
1152 LOG_REGISTER_CONTEXT;
1154 worker_bailout_requested =
true;
1157 if( write(worker_req_evfd, &cnt,
sizeof cnt) == -1 ) {
1158 log_err(
"failed to signal requested: %m");
1165 LOG_REGISTER_CONTEXT;
1168 if( write(worker_rsp_evfd, &cnt,
sizeof cnt) == -1 ) {
1169 log_err(
"failed to signal handled: %m");