a2aa7e020ef5df9715168193584d1b5023d03796
[platform/core/connectivity/mtp-responder.git] / src / mtp_event_handler.c
1 /*
2  * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <signal.h>
20 #include <vconf.h>
21 #include <vconf-keys.h>
22 #include <glib.h>
23 #include "mtp_event_handler.h"
24 #include "mtp_cmd_handler.h"
25 #include "mtp_util.h"
26 #include "mtp_thread.h"
27 #include "mtp_init.h"
28 #include "mtp_usb_driver.h"
29 #include "mtp_transport.h"
30 #include "mtp_media_info.h"
31
32 /*
33  * GLOBAL AND EXTERN VARIABLES
34  */
35 extern mtp_mgr_t g_mtp_mgr;
36 pthread_t g_eh_thrd;    /* event handler thread */
37 mtp_int32 g_pipefd[2];
38
39 /*
40  * STATIC VARIABLES
41  */
42 static mtp_mgr_t *g_mgr = &g_mtp_mgr;
43
44 /*
45  * STATIC FUNCTIONS
46  */
47 static mtp_bool __process_event_request(mtp_event_t *evt);
48 static void *__thread_event_handler(void *arg);
49 static mtp_bool __send_events_from_device_to_pc(mtp_dword store_id,
50                 mtp_uint16 ptp_event, mtp_uint32 param1, mtp_uint32 param2);
51 static void __handle_usb_notification(keynode_t *key, void *data);
52 static void __handle_usb_mode_notification(keynode_t *key, void *data);
53 static mtp_bool __send_start_event_to_eh_thread(void);
54
55 /*
56  * FUNCTIONS
57  */
58 /* LCOV_EXCL_START */
59 mtp_bool _eh_register_notification_callbacks(void)
60 {
61         mtp_int32 ret;
62         phone_status_t val = 0;
63
64         /* For FFS transport we rely on ep0 events */
65         if (_transport_get_type() == MTP_TRANSPORT_FFS) {
66                 DBG("Using FFS transport, assuming established connection");
67                 _util_set_local_usb_status(MTP_PHONE_USB_DISCONNECTED);
68                 _util_set_local_usbmode_status(1);
69         } else {
70                 DBG("Using legacy transport, registering vconf notifier");
71                 _util_get_usb_status(&val);
72                 _util_set_local_usb_status(val);
73                 ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_USB_STATUS,
74                                 __handle_usb_notification, NULL);
75                 if (ret < 0) {
76                         ERR("vconf_notify_key_changed(%s) Fail", VCONFKEY_SYSMAN_USB_STATUS);
77                         return FALSE;
78                 }
79
80                 _util_get_usbmode_status(&val);
81                 _util_set_local_usbmode_status(val);
82                 ret = vconf_notify_key_changed(VCONFKEY_USB_CUR_MODE,
83                                 __handle_usb_mode_notification, NULL);
84                 if (ret < 0) {
85                         ERR("vconf_notify_key_changed(%s) Fail", VCONFKEY_USB_CUR_MODE);
86                         return FALSE;
87                 }
88         }
89
90         _util_get_lock_status(&val);
91         _util_set_local_lock_status(val);
92         _util_get_mmc_status(&val);
93         _util_set_local_mmc_status(val);
94
95         DBG("Phone status: USB = [%d] MMC = [%d] USB_MODE = [%d] LOCK_STATUS = [%d]\n",
96                         _util_get_local_usb_status(), _util_get_local_mmc_status(),
97                         _util_get_local_usbmode_status(), _util_get_local_lock_status());
98         return TRUE;
99 }
100
101 mtp_bool _eh_handle_usb_events(mtp_uint32 type)
102 {
103         mtp_state_t state = MTP_STATE_STOPPED;
104         mtp_int32 res = 0;
105         /* Prevent repeated USB insert/remove mal-function */
106         static mtp_int32 is_usb_inserted = 0;
107         static mtp_int32 is_usb_removed = 0;
108
109         state = _transport_get_mtp_operation_state();
110
111         switch (type) {
112         case USB_INSERTED:
113                 if (is_usb_inserted == 1) {
114                         ERR("USB is already connected");
115                         return TRUE;
116                 }
117
118                 /* check USB connection state */
119                 if (_transport_get_type() != MTP_TRANSPORT_FFS &&
120                                 MTP_PHONE_USB_DISCONNECTED == _util_get_local_usb_status()) {
121                         ERR("USB is disconnected. So just return.");
122                         return FALSE;
123                 }
124                 is_usb_inserted = 1;
125
126                 _transport_set_usb_discon_state(FALSE);
127                 _transport_set_cancel_initialization(FALSE);
128
129                 if (state == MTP_STATE_INITIALIZING) {
130                         ERR("MTP is already being initialized");
131                         break;
132                 }
133
134                 res = pipe(g_pipefd);
135                 if (res < 0) {
136                         ERR("pipe() Fail");
137                         _util_print_error();
138                         return FALSE;
139                 }
140
141                 res = _util_thread_create(&g_eh_thrd,
142                                 "Mtp Event Request Handler", PTHREAD_CREATE_JOINABLE,
143                                 __thread_event_handler, NULL);
144                 if (FALSE == res) {
145                         ERR("_util_thread_create() Fail");
146                         return FALSE;
147                 }
148
149                 __send_start_event_to_eh_thread();
150
151                 break;
152
153         case USB_REMOVED:
154                 if (is_usb_removed == 1) {
155                         ERR("USB is already removed");
156                         return TRUE;
157                 }
158
159                 is_usb_removed = 1;
160                 DBG("USB is disconnected");
161
162                 _transport_set_usb_discon_state(TRUE);
163                 _transport_set_cancel_initialization(TRUE);
164
165                 /* cancel all transaction */
166                 _transport_set_control_event(PTP_EVENTCODE_CANCELTRANSACTION);
167
168                 _transport_usb_finalize();
169                 _transport_set_mtp_operation_state(MTP_STATE_STOPPED);
170
171                 /*
172                  * Temp file should be deleted after usb usb read/write threads
173                  * are terminated. Because data receive thread tries to
174                  * write the temp file until sink thread is terminated.
175                  */
176                 if (g_mgr->ftemp_st.filepath != NULL &&
177                                 (access(g_mgr->ftemp_st.filepath, F_OK) == 0)) {
178                         DBG("USB disconnected but temp file is remaind.\
179                                         It will be deleted.");
180
181                         if (g_mgr->ftemp_st.fhandle != NULL) {
182                                 DBG("handle is found. At first close file");
183                                 _util_file_close(g_mgr->ftemp_st.fhandle);
184                                 g_mgr->ftemp_st.fhandle = NULL;
185                         }
186                         if (remove(g_mgr->ftemp_st.filepath) < 0) {
187                                 ERR_SECURE("remove(%s) Fail", g_mgr->ftemp_st.filepath);
188                                 _util_print_error();
189                         }
190                         g_free(g_mgr->ftemp_st.filepath);
191                         g_mgr->ftemp_st.filepath = NULL;
192                 }
193
194                 _mtp_deinit();
195                 _device_uninstall_storage(MTP_ADDREM_AUTO);
196                 _eh_send_event_req_to_eh_thread(EVENT_CLOSE, 1, 0, NULL);
197                 break;
198
199         default:
200                 ERR("can be ignored notify [0x%x]\n", type);
201                 break;
202         }
203         return TRUE;
204 }
205
206 static mtp_bool __process_event_request(mtp_event_t *evt)
207 {
208         retv_if(evt == NULL, FALSE);
209
210         switch (evt->action) {
211         case EVENT_CANCEL_INITIALIZATION:
212                 DBG("EVENT_CANCEL_INITIALIZATION entered.");
213                 _device_uninstall_storage(MTP_ADDREM_AUTO);
214                 break;
215
216         case EVENT_START_MAIN_OP:
217                 DBG("EVENT_START_MAIN_OP entered.");
218
219                 /* start MTP */
220                 _transport_set_cancel_initialization(FALSE);
221                 _transport_set_mtp_operation_state(MTP_STATE_INITIALIZING);
222
223                 _mtp_init(evt->param1);
224                 _transport_set_mtp_operation_state(MTP_STATE_READY_SERVICE);
225                 if (FALSE == _transport_init_interfaces(_receive_mq_data_cb)) {
226                         ERR("USB init fail");
227                         kill(getpid(), SIGTERM);
228                         break;
229                 }
230                 _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE);
231                 break;
232
233         case EVENT_USB_REMOVED:
234                 _util_flush_db();
235                 _eh_handle_usb_events(USB_REMOVED);
236                 break;
237
238         case EVENT_OBJECT_ADDED:
239                 __send_events_from_device_to_pc(0, PTP_EVENTCODE_OBJECTADDED,
240                                 evt->param1, 0);
241                 break;
242
243         case EVENT_OBJECT_REMOVED:
244                 __send_events_from_device_to_pc(0,
245                                 PTP_EVENTCODE_OBJECTREMOVED, evt->param1, 0);
246                 break;
247
248         case EVENT_OBJECT_PROP_CHANGED:
249                 __send_events_from_device_to_pc(0,
250                                 MTP_EVENTCODE_OBJECTPROPCHANGED, evt->param1,
251                                 evt->param2);
252                 break;
253
254         case EVENT_CLOSE:
255                 break;
256
257         default:
258                 ERR("Unknown action");
259                 break;
260         }
261         return TRUE;
262 }
263
264 static void *__thread_event_handler(void *arg)
265 {
266         DBG("__thread_event_handler is started ");
267
268         mtp_int32 flag = 1;
269         mtp_event_t evt;
270
271         while (flag) {
272                 mtp_int32 status = 0;
273                 status = read(g_pipefd[0], &evt, sizeof(mtp_event_t));
274                 if ((status == -1) && errno == EINTR) {
275                         ERR("read() Fail");
276                         continue;
277                 }
278
279                 __process_event_request(&evt);
280
281                 if (evt.action == EVENT_CLOSE) {
282                         /* USB removed, terminate the thread */
283                         flag = 0;
284                 }
285         }
286
287         DBG("Event handler terminated");
288         close(g_pipefd[0]);
289         close(g_pipefd[1]);
290         mtp_end_event();
291
292         _util_thread_exit("__thread_event_handler thread is over.");
293         return NULL;
294 }
295
296 static mtp_bool __send_events_from_device_to_pc(mtp_dword store_id,
297                 mtp_uint16 ptp_event, mtp_uint32 param1, mtp_uint32 param2)
298 {
299         cmd_container_t event = { 0, };
300
301         memset(&event, 0, sizeof(cmd_container_t));
302
303         switch (ptp_event) {
304         case PTP_EVENTCODE_STOREADDED:
305                 DBG("case PTP_EVENTCODE_STOREADDED:");
306                 DBG("store_id [0x%lu]\n", store_id);
307                 _hdlr_init_event_container(&event, PTP_EVENTCODE_STOREADDED, 0,
308                                 store_id, 0);
309                 break;
310
311         case PTP_EVENTCODE_STOREREMOVED:
312                 DBG("case PTP_EVENTCODE_STOREREMOVED");
313                 DBG("store_id [0x%lu]\n", store_id);
314                 _hdlr_init_event_container(&event,
315                                 PTP_EVENTCODE_STOREREMOVED, 0, store_id, 0);
316                 break;
317
318         case PTP_EVENTCODE_OBJECTADDED:
319                 DBG("case PTP_EVENTCODE_OBJECTADDED");
320                 DBG("param1 : [0x%x]\n", param1);
321                 _hdlr_init_event_container(&event, PTP_EVENTCODE_OBJECTADDED,
322                                 0, param1, 0);
323                 break;
324
325         case PTP_EVENTCODE_OBJECTREMOVED:
326                 DBG("case PTP_EVENTCODE_OBJECTREMOVED");
327                 DBG("param1 [0x%x]\n", param1);
328                 _hdlr_init_event_container(&event, PTP_EVENTCODE_OBJECTREMOVED,
329                                 0, param1 , 0);
330                 break;
331
332         case MTP_EVENTCODE_OBJECTPROPCHANGED:
333                 DBG("case MTP_EVENTCODE_OBJECTPROPCHANGED");
334                 DBG("param1 [0x%x]\n", param1);
335                 DBG("param2 [0x%x]\n", param2);
336                 _hdlr_init_event_container_with_param(&event,
337                                 MTP_EVENTCODE_OBJECTPROPCHANGED, 0, param1 , param2);
338                 break;
339
340         default:
341                 DBG("Event not supported");
342                 return FALSE;
343         }
344
345         return _hdlr_send_event_container(&event);
346 }
347
348 static void __handle_usb_notification(keynode_t *key, void *data)
349 {
350         phone_status_t val = MTP_PHONE_USB_DISCONNECTED;
351         mtp_int32 intval = VCONFKEY_SYSMAN_USB_DISCONNECTED;
352
353         ret_if(key == NULL);
354
355         intval = vconf_keynode_get_int(key);
356         if (-1 == intval) {
357                 ERR("vconf_keynode_get_int() Fail");
358                 return;
359         }
360
361         if (VCONFKEY_SYSMAN_USB_DISCONNECTED == intval) {
362                 DBG("USB Disconnected");
363                 _util_set_local_usb_status(val);
364                 mtp_end_event();
365                 return;
366         }
367
368         val = MTP_PHONE_USB_CONNECTED;
369         _util_set_local_usb_status(val);
370         DBG("USB Connected. Just return.");
371         return;
372 }
373
374 static void __handle_usb_mode_notification(keynode_t *key, void *data)
375 {
376         phone_status_t val = MTP_PHONE_USB_MODE_OTHER;
377
378         ret_if(key == NULL);
379
380         val = vconf_keynode_get_int(key);
381
382         _util_set_local_usbmode_status(val);
383         return;
384 }
385
386 void _handle_lock_status_notification(keynode_t *key, void *data)
387 {
388         phone_status_t previous_val = MTP_PHONE_LOCK_ON;
389         phone_status_t current_val = MTP_PHONE_LOCK_ON;
390
391         previous_val = _util_get_local_lock_status();
392         _util_get_lock_status(&current_val);
393
394         if (previous_val == current_val)
395                 return;
396
397         _util_set_local_lock_status(current_val);
398
399         if (MTP_PHONE_LOCK_OFF == current_val) {
400                 _device_install_storage(MTP_ADDREM_INTERNAL);
401                 __send_events_from_device_to_pc(MTP_INTERNAL_STORE_ID,
402                                 PTP_EVENTCODE_STOREADDED, 0, 0);
403
404                 _util_media_content_connect();
405         } else if (MTP_PHONE_LOCK_ON == current_val) {
406                 _device_uninstall_storage(MTP_ADDREM_INTERNAL);
407
408                 __send_events_from_device_to_pc(MTP_INTERNAL_STORE_ID,
409                                 PTP_EVENTCODE_STOREREMOVED, 0, 0);
410
411                 _util_media_content_disconnect();
412         }
413
414         return;
415 }
416
417 void _handle_mmc_notification(keynode_t *key, void *data)
418 {
419         phone_status_t val = MTP_PHONE_MMC_NONE;
420
421         _util_get_mmc_status(&val);
422         _util_set_local_mmc_status(val);
423
424         if (MTP_PHONE_MMC_INSERTED == val) {
425                 _device_install_storage(MTP_ADDREM_EXTERNAL);
426                 __send_events_from_device_to_pc(MTP_EXTERNAL_STORE_ID,
427                                 PTP_EVENTCODE_STOREADDED, 0, 0);
428
429         } else if (MTP_PHONE_MMC_NONE == val) {
430                 _device_uninstall_storage(MTP_ADDREM_EXTERNAL);
431
432                 __send_events_from_device_to_pc(MTP_EXTERNAL_STORE_ID,
433                                 PTP_EVENTCODE_STOREREMOVED, 0, 0);
434         }
435
436         return;
437 }
438
439 void _eh_deregister_notification_callbacks(void)
440 {
441         vconf_ignore_key_changed(VCONFKEY_SYSMAN_USB_STATUS,
442                         __handle_usb_notification);
443         vconf_ignore_key_changed(VCONFKEY_USB_CUR_MODE,
444                         __handle_usb_mode_notification);
445
446         return;
447 }
448
449 void _eh_send_event_req_to_eh_thread(event_code_t action, mtp_ulong param1,
450                 mtp_ulong param2, void *param3)
451 {
452         mtp_event_t event = { 0 };
453         mtp_int32 status;
454
455         event.action = action;
456         event.param1 = param1;
457         event.param2 = param2;
458         event.param3 = (mtp_ulong)param3;
459
460         DBG("action[%d], param1[%ld], param2[%ld]\n", action, param1, param2);
461
462         status = write(g_pipefd[1], &event, sizeof(mtp_event_t));
463         if (status == -1 || errno == EINTR) {
464                 ERR("Event write over pipe Fail, status = [%d], pipefd = [%d], errno [%d]\n",
465                                 status, g_pipefd[1], errno);
466         }
467         return;
468 }
469
470 static mtp_bool __send_start_event_to_eh_thread(void)
471 {
472         mtp_event_t event;
473         mtp_int32 status;
474
475         event.action = EVENT_START_MAIN_OP;
476         event.param1 = (mtp_ulong) MTP_ADDREM_AUTO;
477         event.param2 = 0;
478         event.param3 = 0;
479
480         DBG("Action : START MTP OPERATION");
481
482         status = write(g_pipefd[1], &event, sizeof(mtp_event_t));
483         if (status == -1 || errno == EINTR) {
484                 ERR("Event write over pipe Fail, status= [%d],pipefd = [%d], errno [%d]\n",
485                                 status, g_pipefd[1], errno);
486                 return FALSE;
487         }
488
489         return TRUE;
490 }
491 /* LCOV_EXCL_STOP */