Initialize
[sdk/emulator/qemu.git] / tizen / src / emulator.c
1 /*
2  * Emulator
3  *
4  * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * DoHyung Hong <don.hong@samsung.com>
8  * SeokYeon Hwang <syeon.hwang@samsung.com>
9  * Hyunjun Son <hj79.son@samsung.com>
10  * SangJin Kim <sangjin3.kim@samsung.com>
11  * MunKyu Im <munkyu.im@samsung.com>
12  * KiTae Kim <kt920.kim@samsung.com>
13  * JinHyung Jo <jinhyung.jo@samsung.com>
14  * SungMin Ha <sungmin82.ha@samsung.com>
15  * JiHye Kim <jihye1128.kim@samsung.com>
16  * GiWoong Kim <giwoong.kim@samsung.com>
17  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
18  * DongKyun Yun <dk77.yun@samsung.com>
19  *
20  * This program is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU General Public License
22  * as published by the Free Software Foundation; either version 2
23  * of the License, or (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
33  *
34  * Contributors:
35  * - S-Core Co., Ltd
36  *
37  */
38
39
40 /**
41  * @file     emulator.c
42  * @brief    main implementation file of emulator for controling player screen, initialization function, etc.
43  * @mainpage emulator for ISE
44  * @section  INTRO
45  *   program module name: ISE emulator
46  *   emulator program can run both standalone and with ISE
47  */
48
49 #include "emulator.h"
50 #include "about_version.h"
51 #include "vl.h"
52 #include "sensor_server.h"
53 #include <assert.h>
54
55 /* changes for saving emulator state */
56 #ifdef __MINGW32__
57 #include <winsock2.h>
58 #else
59 #include <sys/socket.h>
60 #include <arpa/inet.h>
61 #endif
62 #include <stdlib.h>
63 #include <string.h>
64 #include <unistd.h>
65 #include <sys/stat.h>
66 #include <pthread.h>
67
68 #ifdef __linux__
69 #include <sys/ipc.h>
70 #include <sys/shm.h>
71 #include <sys/utsname.h>
72 #include <linux/version.h>
73 #elif _WIN32
74 #include <windows.h>
75 #endif
76
77 #include "opengl_server.h"
78 #include "sdb.h"
79 #include "nbd.h"
80 #include "debug_ch.h"
81
82 //DEFAULT_DEBUG_CHANNEL(tizen);
83 MULTI_DEBUG_CHANNEL(tizen, main);
84
85 #define RCVBUFSIZE 40
86 #define MAX_COMMANDS 5
87 #define MAX_LENGTH 24
88 #define MAX_TIME_STR 100
89
90 /* enable opengl_server thread */
91 #define ENABLE_OPENGL_SERVER
92
93 /* configuration : global variable for saving config file
94  * sysinfo : global variable for using in this program
95  * startup_option : global variable for loading emulator option
96  * */
97
98 CONFIGURATION configuration;
99 SYSINFO SYSTEMINFO;
100 STARTUP_OPTION startup_option;
101 PHONEMODELINFO *phone_info;
102 VIRTUALTARGETINFO virtual_target_info;
103 FILE *g_out_fp;
104 FILE *g_err_fp;
105
106 UIFLAG UISTATE = {
107     .last_index = -1,
108     .button_press_flag = -1,
109     .key_button_press_flag = 0,
110     .frame_buffer_ctrl = 0,
111     .scale = 1.0,
112     .current_mode = 0,
113     .config_flag = 0,
114     .PID_flag = 0,
115     .is_ei_run = FALSE,
116     .is_em_run = FALSE,
117     .is_gps_run = FALSE,
118     .is_compass_run = FALSE,
119     .is_screenshot_run = FALSE,
120     .sub_window_flag = FALSE,
121     .network_read_flag = FALSE,
122 };
123
124 int _emulator_condition = 0;
125 PHONEMODELINFO PHONE;
126 GtkWidget *g_main_window;
127
128 GtkWidget *pixmap_widget;
129 GtkWidget *fixed;
130 #ifdef __linux__
131 struct utsname host_uname_buf;
132 #endif
133
134 /* Widgets for savevm */
135 GtkWidget *savevm_window;
136 GtkProgressBar *savevm_progress;
137 GtkWidget *savevm_label;
138 int        vmstate=0;
139 int        vmsock=-1;
140 int        device_count = 0;
141 GIOChannel *channel=NULL;
142
143 int get_emulator_condition(void)
144 {
145     return _emulator_condition;
146 }
147
148 void set_emulator_condition(int state)
149 {
150     _emulator_condition = state;
151 }
152
153 struct _arglist {
154     char *argv[QEMUARGC];
155     int argc;
156 };
157
158 static arglist g_qemu_arglist = {{0,}, 0};
159 int tizen_base_port = 0;
160 void append_argvlist(arglist* al, const char *fmt, ...)
161 {
162     char buf[MAXBUF];
163     va_list va;
164
165     va_start(va, fmt);
166     vsnprintf(buf, sizeof buf, fmt, va);
167     va_end(va);
168     al->argv[al->argc++] = strdup(buf);
169     assert(al->argc < QEMUARGC);
170 }
171
172 #ifndef _WIN32
173 static GSList* emul_process_list = NULL; /**<linked list of running terminal*/
174 pthread_t unfsd_thread;
175 #else
176 DWORD unfsd_thread;
177 #endif
178
179 #ifdef ENABLE_OPENGL_SERVER
180 pthread_t thread_opengl_id;
181 #endif  /* ENABLE_OPENGL_SERVER */
182
183 #ifndef _WIN32
184
185 static pthread_mutex_t mutex_emul = PTHREAD_MUTEX_INITIALIZER;
186
187 void emulator_mutex_lock(void)
188 {
189     pthread_mutex_lock(&mutex_emul);
190 }
191
192 void emulator_mutex_unlock(void)
193 {
194     pthread_mutex_unlock(&mutex_emul);
195 }
196
197 static void emulator_mutex_init(void)
198 {
199 }
200
201 #else
202
203 static HANDLE mutex_emul;
204
205 void emulator_mutex_lock(void)
206 {
207     WaitForSingleObject(mutex_emul, INFINITE);
208 }
209
210 void emulator_mutex_unlock(void)
211 {
212     ReleaseMutex(mutex_emul);
213 }
214
215 static void emulator_mutex_init(void)
216 {
217     mutex_emul = CreateMutex(NULL, 0, NULL);
218 }
219
220 #endif
221
222 #ifndef _WIN32
223 /**
224  *     @brief  called when command window closed.
225  *     it registered with g_child_watch_add function when creating each process
226  *     @param  pid: pid of each process been created by emulator
227  *     @param  status: dummy
228  *     @param  data: dummy
229  *     @see    create_cmdwindow
230  */
231 static void emul_process_close_handle (GPid pid, gint status, gpointer data)
232 {
233     TRACE( "remove pid=%d\n", pid);
234     g_spawn_close_pid (pid);
235     emul_process_list = g_slist_remove(emul_process_list, (gpointer) pid);
236     TRACE( "remove complete pid=%d\n", pid);
237 }
238
239 /**
240   @brief  send SIGTERM to process
241   @param    data: pid of terminal
242   @user_data: dummy
243  */
244 static void emul_kill_process(gpointer data, gpointer user_data)
245 {
246     WARN( "kill terminal pid=%d\n", (int)data);
247     kill( (pid_t)(gpointer)data, SIGTERM);
248 }
249
250 /**
251   @brief    call emul_kill_process for all the node in emul_process_list
252  */
253 void emul_kill_all_process(void)
254 {
255     g_slist_foreach(emul_process_list, emul_kill_process, NULL);
256 }
257
258 /**
259   @brief  create a process
260   @param    data: command of starting process
261   @return success: TRUE
262  */
263 int emul_create_process(const gchar cmd[])
264 {
265     GPid pid = 0;
266     GError* error = NULL;
267     gchar **argv_fork;
268     gint argc_fork;
269     int ret = TRUE;
270
271
272     emulator_mutex_lock();
273
274     g_shell_parse_argv (cmd, &argc_fork, &argv_fork, NULL);
275
276     if (g_spawn_async_with_pipes ("./", argv_fork, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL, NULL, NULL, &error) == TRUE) {
277         emul_process_list = g_slist_append(emul_process_list, (gpointer)pid);
278         g_child_watch_add(pid, emul_process_close_handle, NULL);
279     }
280
281     else {
282         //  ERR( "Error in g_spawn_async\n");
283         ret = FALSE;
284     }
285
286     g_strfreev (argv_fork);
287
288     if (error) {
289         //g_error(error->message);
290         ret = FALSE;
291     }
292
293     TRACE("create PID = %d\n", pid);
294
295     emulator_mutex_unlock();
296
297     return ret;
298
299 }
300 #else
301 void emul_kill_all_process(void)
302 {
303
304 }
305 int emul_create_process(const gchar cmd[])
306 {
307     return TRUE;
308 }
309 #endif
310
311 #ifdef _WIN32
312 void socket_cleanup(void)
313 {
314     WSACleanup();
315 }
316 #endif
317
318 int socket_init(void)
319 {
320 #ifdef _WIN32
321     WSADATA Data;
322     int ret, err;
323
324     ret = WSAStartup(MAKEWORD(2,0), &Data);
325     if (ret != 0) {
326         err = WSAGetLastError();
327         fprintf(stderr, "WSAStartup: %d\n", err);
328         return -1;
329     }
330     atexit(socket_cleanup);
331 #endif
332     return 0;
333 }
334
335 void exit_emulator_post_process( void ) {
336
337     set_emulator_condition(EMUL_SHUTTING_DOWN);
338
339     free_dbi_file(&PHONE);
340
341     /* 1. emulator and driver destroy */
342     destroy_emulator();
343     INFO( "Emulator Stop: destroy emulator \n");
344
345     /* 2. destroy hash */
346     window_hash_destroy();
347
348     /* 3. quit SDL */
349     //  SDL_Quit();
350
351     /* 4. quit main */
352     gtk_main_quit();
353     INFO( "Emulator Stop: shutdown qemu system, gtk_main quit complete \n");
354
355     /* 5. Flush output */
356     fclose(stdout);
357     fclose(stderr);
358
359     /* 6. close fp which is opened when redirect_log() */
360
361     fclose(g_out_fp);
362     fclose(g_err_fp);
363     INFO( "Close fp which is opened when redirect_log()\n");
364
365 #ifdef ENABLE_OPENGL_SERVER
366     pthread_cancel(thread_opengl_id);
367     INFO( "opengl_server thread is quited.\n");
368 #endif  /* ENABLE_OPENGL_SERVER */
369
370 }
371
372 #if 0
373 static int send_info_to_emuld(char *send_buf, int buf_size)
374 {
375     int   s;
376
377     s = tcp_socket_outgoing("127.0.0.1", (uint16_t)(get_sdb_base_port() + SDB_TCP_EMULD_INDEX));
378     if (s < 0) {
379         TRACE( "can't create socket to talk to the sdb forwarding session \n");
380         TRACE( "[127.0.0.1:%d/tcp] connect fail (%d:%s)\n"
381                 , get_sdb_base_port() + SDB_TCP_EMULD_INDEX
382                 , errno, strerror(errno)
383              );
384         return -1;
385     }
386
387     socket_send(s, "system\n\n\n\n", 10);
388     socket_send(s, &buf_size, 4);
389     socket_send(s, send_buf, buf_size);
390
391     INFO( "send(size: %d) te 127.0.0.1:%d/tcp \n"
392             , buf_size, get_sdb_base_port() + SDB_TCP_EMULD_INDEX);
393
394 #ifdef _WIN32
395     closesocket(s);
396 #else
397     close(s);
398 #endif
399
400     return 1;
401 }
402 #endif
403
404 #if 0
405 static void *graceful_shutdown_ftn(void* arg)
406 {
407     int i;
408
409     INFO("send command shutdown to emuld \n");
410     send_info_to_emuld("shutdown", 8);
411
412     /* wait 7 seconds */
413     INFO("wait 7 seconds \n");
414     for(i=0; i<7; i++){
415 #ifdef _WIN32
416         Sleep(1000);
417 #else
418         usleep(1000000);
419 #endif
420     }
421
422     INFO("qemu_system_shutdown_request call \n");
423     qemu_system_shutdown_request();
424
425     return 0;
426 }
427 #endif // #if 0
428
429 /**
430  * @brief    destroy emulator
431  * @param    widget
432  * @param    gpointer
433  * @date     Nov 20. 2008
434  */
435 void exit_emulator(void)
436 {
437
438 #if 1 /* graceful shutdown */
439
440     /* 1st way : long press => power key */
441     ps2kbd_put_keycode( 103 & 0x7f );
442 #ifdef _WIN32
443     Sleep( 1.6 * 1000 ); // 1.6 seconds
444 #else
445     usleep( 1.6 * 1000 * 1000 ); // 1.6 seconds
446 #endif
447     ps2kbd_put_keycode( 103 | 0x80 );
448     // If user selects 'Yes' in Power off poup, 'qemu_system_shutdown_request' in vl.c is supposed to be called.
449
450 #if 0
451     /* 2nd way : send command shutdown to emuld in guest image */
452     pthread_t thread_id;
453     if (pthread_create(&thread_id, NULL, graceful_shutdown_ftn, NULL) != 0) {
454         ERR("pthread_create fail \n");
455         qemu_system_shutdown_request();
456     }
457 #endif
458
459 #else
460
461     /* 1. emulator and driver destroy */
462
463     destroy_emulator();
464
465     INFO( "Emulator Stop: destroy emulator \n");
466
467     /* 2. destroy hash */
468
469     window_hash_destroy();
470
471     /* 3. quit SDL */
472
473     //  SDL_Quit();
474
475     /* 4. shutdown qemu system */
476
477     qemu_system_shutdown_request();
478
479     /* 5. quit main */
480
481     gtk_main_quit();
482     INFO( "Emulator Stop: shutdown qemu system, gtk_main quit complete \n");
483
484 #ifdef ENABLE_OPENGL_SERVER
485     pthread_cancel(thread_opengl_id);
486     INFO( "opengl_server thread is quited.\n");
487 #endif  /* ENABLE_OPENGL_SERVER */
488
489     exit(0);
490
491 #endif /* graceful shutdown */
492
493 }
494
495 #ifdef _WIN32
496 /**
497   @brief  enumerates display monitors
498   @param dwData: host screen resolution
499   @return success: TRUE
500  */
501 static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
502 {
503     RECT *pHostScreen;
504     MONITORINFO mi;
505     mi.cbSize = sizeof(MONITORINFO);
506     GetMonitorInfo(hMonitor, &mi);
507
508     pHostScreen = (RECT *)dwData;
509     pHostScreen->left = MIN(lprcMonitor->left, pHostScreen->left);
510     pHostScreen->top = MIN(lprcMonitor->top, pHostScreen->top);
511     pHostScreen->right = MAX(lprcMonitor->right, pHostScreen->right);
512     pHostScreen->bottom = MAX(lprcMonitor->bottom,pHostScreen->bottom);
513
514     return TRUE;
515 }
516 #endif
517
518 static void construct_main_window(void)
519 {
520
521     gchar emul_img_dir[512] = {0,};
522     gchar *name;
523     const gchar *skin;
524     GdkBitmap *SkinMask = NULL;
525     GtkWidget *popup_menu = NULL;
526     GtkWidget *sdl_widget = NULL;
527
528     UISTATE.current_mode = 0;
529
530     /* 1. create main_window without border */
531
532     g_main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
533     add_window (g_main_window, EMULATOR_ID);
534 #if GTK_CHECK_VERSION(2,20,0)
535     gtk_widget_set_can_focus(g_main_window,TRUE);
536 #else
537     GTK_WIDGET_SET_FLAGS(g_main_window, GTK_CAN_FOCUS);
538 #endif
539     GdkColor color;
540     color.red = color.green = color.blue = 0x8888;
541     gtk_widget_modify_bg(g_main_window, GTK_STATE_NORMAL, &color);
542     INFO("sets the emulator window background color (%x, %x, %x)\n", color.red, color.green, color.blue);
543
544     gtk_window_set_decorated (GTK_WINDOW (g_main_window), FALSE);
545
546     /* 2.1 emulator taskbar icon image */
547
548     skin = get_skin_path();
549     if (skin == NULL) {
550         ERR( "getting skin path is failed!!\n");
551         exit (1);
552     }
553 #ifdef _WIN32
554     OSVERSIONINFO osvi;
555     ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
556     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
557     GetVersionEx(&osvi);
558
559     if ((osvi.dwMajorVersion >= 6) && (osvi.dwMinorVersion >= 1))
560         sprintf(emul_img_dir, "%s/icons/Emulator.ico", skin);
561     else
562         sprintf(emul_img_dir, "%s/icons/Emulator_20x20.png", skin);
563
564 #else /* _WIN32 */
565     sprintf(emul_img_dir, "%s/icons/Emulator.ico", skin);
566 #endif/* _WIN32 */
567
568     if (g_file_test(emul_img_dir, G_FILE_TEST_EXISTS) == FALSE) {
569         ERR( "emulator icon directory %s doesn't exist!!\n", emul_img_dir);
570     }
571     gtk_window_set_icon_from_file(GTK_WINDOW(g_main_window), emul_img_dir, NULL);
572
573
574     /* 2.2 emulator taskbar name */
575
576     name = g_strdup_printf("emulator-%d", get_sdb_base_port());
577     gtk_window_set_title (GTK_WINDOW (g_main_window), name);
578     g_free(name);
579
580     /* 3. skin load */
581
582     if (load_skin_image(&PHONE) < 0) {
583         ERR( "emulator skin image is not loaded.\n");
584         exit(1);
585     }
586
587     /* 4. skin mask process */
588
589     pixmap_widget = gtk_image_new_from_pixbuf (PHONE.mode_SkinImg[UISTATE.current_mode].pPixImg);
590     gdk_pixbuf_render_pixmap_and_mask (PHONE.mode_SkinImg[UISTATE.current_mode].pPixImg, NULL, &SkinMask, 1);
591     gtk_widget_shape_combine_mask (g_main_window, SkinMask, 0, 0);
592     INFO("sets a shape for emulator window\n");
593
594     if (SkinMask != NULL) {
595         g_object_unref (SkinMask);
596     }
597
598     /* 5. emulator container */
599
600     fixed = gtk_fixed_new ();
601     if (!qemu_widget_new(&sdl_widget)) {
602         ERR( "sdl_widget is failed!!\n");
603         exit(1);
604     }
605
606     gtk_fixed_put (GTK_FIXED (fixed), pixmap_widget, 0, 0);
607     gtk_fixed_put (GTK_FIXED (fixed), sdl_widget, PHONE.mode[UISTATE.current_mode].lcd_list[0].lcd_region.x,
608             PHONE.mode[UISTATE.current_mode].lcd_list[0].lcd_region.y);
609     gtk_container_add (GTK_CONTAINER (g_main_window), fixed);
610
611 #ifdef __linux__
612     if (strcmp(host_uname_buf.release, "2.6.35-22-generic") == 0) { // for ubuntu 10.10 resize window bug
613         gtk_window_resize (GTK_WINDOW(g_main_window),
614             PHONE.mode_SkinImg[0].nImgHeight, PHONE.mode_SkinImg[0].nImgHeight);
615     }
616 #endif
617
618     /* 6. emulator start position */
619     UISTATE.scale = ((float)get_config_type(SYSTEMINFO.virtual_target_info_file, EMULATOR_GROUP, SCALE_KEY)) / 100;
620     if (UISTATE.scale <= 0 || UISTATE.scale > 1.0) {
621         UISTATE.scale = 1.0;
622     }
623     TRACE("scale = %f\n", UISTATE.scale);
624
625 #ifdef _WIN32
626     RECT host_screen;
627     int emulator_w, emulator_h;
628     int range;
629
630     emulator_w = emulator_h = 0;
631     ZeroMemory(&host_screen, sizeof(RECT));
632     EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&host_screen);
633
634     if (host_screen.left < 0) {
635         int shift = host_screen.left * -1;
636         host_screen.left += shift;
637         host_screen.right += shift;
638     }
639     if (host_screen.top < 0) {
640         int shift = host_screen.top * -1;
641         host_screen.top += shift;
642         host_screen.bottom += shift;
643     }
644
645     emulator_w = PHONE.mode_SkinImg[UISTATE.current_mode].nImgWidth * UISTATE.scale;
646     emulator_h = PHONE.mode_SkinImg[UISTATE.current_mode].nImgHeight * UISTATE.scale;
647
648     // position correction of x
649     range = host_screen.left - emulator_w;
650     if (configuration.main_x <= range)
651     {
652         INFO("configuration.main_x=%d is out of monitor range. (%d ~ %d)\n",
653                 configuration.main_x, range, host_screen.right);
654         configuration.main_x = host_screen.left;
655     }
656     else if (configuration.main_x >= host_screen.right)
657     {
658         INFO("configuration.main_x=%d is out of monitor range. (%d ~ %d)\n",
659                 configuration.main_x, range, host_screen.right);
660         configuration.main_x = host_screen.right - emulator_w;
661     }
662
663     // position correction of y
664     range = host_screen.top - emulator_h;
665     if (configuration.main_y <= range)
666     {
667         INFO("configuration.main_y=%d is out of monitor range. (%d ~ %d)\n",
668                 configuration.main_x, range, host_screen.bottom);
669         configuration.main_y = host_screen.top;
670     }
671     else if (configuration.main_y >= host_screen.bottom)
672     {
673         INFO("configuration.main_y=%d is out of monitor range. (%d ~ %d)\n",
674                 configuration.main_x, range, host_screen.bottom);
675         configuration.main_y = host_screen.bottom - emulator_h;
676     }
677 #endif
678
679     gtk_window_move (GTK_WINDOW (g_main_window), configuration.main_x, configuration.main_y);
680     INFO("emulator window is moved (%d, %d)\n", configuration.main_x, configuration.main_y);
681
682     /* 7. create popup menu */
683     create_popup_menu (&popup_menu, &PHONE, &configuration);
684     INFO("popup menu is created\n");
685
686     /* 8. Signal connect */
687
688     g_signal_connect (G_OBJECT(g_main_window), "motion_notify_event", G_CALLBACK(motion_notify_event_handler), NULL);
689     g_signal_connect (G_OBJECT(g_main_window), "button_press_event", G_CALLBACK(motion_notify_event_handler), NULL);
690     g_signal_connect (G_OBJECT(g_main_window), "button_release_event", G_CALLBACK(motion_notify_event_handler), NULL);
691     g_signal_connect (G_OBJECT(g_main_window), "key_press_event", G_CALLBACK(key_event_handler), NULL);
692     g_signal_connect (G_OBJECT(g_main_window), "key_release_event", G_CALLBACK(key_event_handler), NULL);
693     g_signal_connect (G_OBJECT(g_main_window), "delete-event", G_CALLBACK(exit_emulator), NULL);
694     g_signal_connect (G_OBJECT(g_main_window), "configure_event", G_CALLBACK(configure_event), NULL);
695
696     gtk_widget_set_has_tooltip(g_main_window, TRUE);
697     g_signal_connect (G_OBJECT(g_main_window), "query-tooltip", G_CALLBACK(query_tooltip_event), NULL);
698
699     gtk_widget_set_events (g_main_window, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK |
700             GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);// | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
701
702     /* 9. widget show all */
703
704     gtk_window_set_keep_above(GTK_WINDOW (g_main_window), configuration.always_on_top);
705     gtk_widget_show_all (g_main_window);
706     gtk_widget_queue_resize (g_main_window);
707
708     if (UISTATE.scale != 1.0) {
709         scale_event_callback(&PHONE, UISTATE.current_mode);
710     }
711 }
712
713 static void* run_gtk_main(void* arg)
714 {
715     /* 10. gtk main start */
716     init_sensor_server();
717     gtk_main();
718
719     return NULL;
720 }
721
722 #ifdef _WIN32
723 static void* construct_main_window_and_run_gtk_main(void* arg)
724 {
725     construct_main_window();
726     init_sensor_server();
727     gtk_main();
728     return NULL;
729 }
730 #endif
731
732
733
734 /**
735  * @brief    init startup structure
736  * @return   success  0,  fail    -1
737  * @date     Nov 3. 2008
738  * */
739
740 static void init_startup_option(void)
741 {
742     memset(&(startup_option), 0x00, sizeof(startup_option));
743     startup_option.run_level = 5;
744     startup_option.mountPort = 1301;
745     startup_option.telnet_port = 1201;
746     startup_option.ssh_port = 1202;
747     if(ENABLE_MULTI)
748     {
749         while(check_port(LOCALHOST, startup_option.mountPort) == 0)
750             startup_option.mountPort++;
751     }
752
753     startup_option.no_dump = FALSE;
754     startup_option.vtm = "default";
755 }
756
757
758 /**
759  * @brief    startup option
760  *           kill application and load kernel driver
761  *
762  * @return   success  0,  fail    -1
763  * @date     May 18. 2009
764  * */
765
766 static int startup_option_parser(int *argc, char ***argv)
767 {
768     /* 1. Goption handling */
769
770     gboolean version = FALSE;
771     GOptionContext *context = NULL;
772     GError *error = NULL;
773     char timeinfo[256] = { 0, };
774     struct tm *tm_time;
775     struct timeval tval;
776     char string[MAXBUF];
777     FILE *fp = NULL;
778     char *info_file;
779     char *arch = getenv(EMULATOR_ARCH);
780     const gchar *exec_path = get_exec_path();
781     if(!arch) /* for stand alone */
782     {
783         char *binary = g_path_get_basename(exec_path);
784         if(strstr(binary, EMULATOR_X86))
785             arch = g_strdup_printf(X86);
786         else if(strstr(binary, EMULATOR_ARM))
787             arch = g_strdup_printf(ARM);
788         else
789         {
790             ERR( "binary setting failed\n");
791             exit(1);
792         }
793         free(binary);
794     }
795
796     GOptionEntry options[] = {
797         {"disk", 0, 0, G_OPTION_ARG_STRING, &startup_option.disk, "Disk image path", "\"disk path\""},
798         {"vtm", 0, 0, G_OPTION_ARG_STRING, &startup_option.vtm, "Virtual target image file", "\"*.x86 or *.arm\""},
799         {"run-level", 0, 0, G_OPTION_ARG_INT, &startup_option.run_level, "Run level", "5"},
800         {"version", 0, 0, G_OPTION_ARG_NONE, &version, "Version info", NULL},
801         {"Port", 0, 0, G_OPTION_ARG_INT, &startup_option.mountPort, "Port for NFS mounting", "\"default is 1301\""},
802         {"ssh-port", 0, 0, G_OPTION_ARG_INT, &startup_option.ssh_port, "Port for ssh to guest", NULL},
803         {"telnet-port", 0, 0, G_OPTION_ARG_INT, &startup_option.telnet_port, "Port for telnet to guest", NULL},
804         {"no-dump", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &startup_option.no_dump, "Disable dump feature", NULL},
805         {NULL}
806     };
807
808     /* 2. Goption parsing */
809
810     context = g_option_context_new ("- Tizen SDK Emulator");
811     g_option_context_set_help_enabled(context, FALSE);
812     g_option_context_add_main_entries (context, options, NULL);
813     g_option_context_add_group (context, gtk_get_option_group (TRUE));
814
815     if (!g_option_context_parse (context, argc, argv, &error)) {
816         fprintf(stderr, "%s: option parsing failed\n", (*argv)[0]);
817         exit (1);
818     }
819
820     /* 3. starting info */
821     gettimeofday(&tval, NULL);
822     tm_time = localtime(&(tval.tv_sec));
823     strftime(timeinfo, sizeof(timeinfo), "%Y/%m/%d %H:%M:%S", tm_time);
824     INFO("=========INFO START========\n");
825     INFO("Current time : %s\n", timeinfo);
826     INFO("SDK version : %s(%s), Build date : %s\n", build_version, build_git, build_date);
827 #ifdef __linux__
828     INFO("Qemu build machine linux kernel version : (%d, %d, %d)\n",
829         LINUX_VERSION_CODE >> 16, (LINUX_VERSION_CODE >> 8) & 0xff , LINUX_VERSION_CODE & 0xff);
830
831         if (uname(&host_uname_buf) == 0) {
832         INFO("Host uname : %s %s %s %s %s\n", host_uname_buf.sysname, host_uname_buf.nodename,
833             host_uname_buf.release, host_uname_buf.version, host_uname_buf.machine);
834         }
835 #endif
836
837     INFO("Host sdl version : (%d, %d, %d)\n", SDL_Linked_Version()->major, SDL_Linked_Version()->minor, SDL_Linked_Version()->patch);
838
839     char *virtual_target_path = get_virtual_target_path(startup_option.vtm);
840     info_file = g_strdup_printf("%sconfig.ini", virtual_target_path);
841     if( (fp = fopen(info_file, "r")) == NULL )
842     {
843         ERR("can't open %s", info_file);
844         exit(1);
845     }
846
847     if (!startup_option.vtm)
848         startup_option.vtm = g_strdup_printf("default");
849     startup_option.disk = g_strdup_printf("%semulimg-%s.%s",virtual_target_path, startup_option.vtm, arch);
850     INFO("target name : %s, disk path : %s\n", startup_option.vtm, startup_option.disk);
851
852     INFO("\n");
853     while(fgets(string, MAXBUF, fp)!=NULL)
854         INFO("%s", string);
855     dbg_printf("\n");
856     INFO("=========INFO END========\n");
857
858     fclose(fp);
859     free(virtual_target_path);
860     free(info_file);
861
862     return 0;
863 }
864
865
866 /**
867  * @brief    init structure
868  * @return   success  0,  fail    -1
869  * @date     Nov 3. 2008
870  * */
871
872 static int init_structure(void)
873 {
874
875     /* 3. make startup option structure */
876
877     init_startup_option();
878
879     return 0;
880 }
881
882
883 /**
884  * @brief   init emulator
885  * @param argc  number of argument
886  * @param argv  argument vector
887  * @return  void
888  * @date    4. 14. 2008
889  * */
890
891 static void init_emulator(int *argc, char ***argv)
892 {
893     /* 1. thread_init */
894
895     emulator_mutex_init();
896 #ifndef _WIN32
897     g_thread_init(NULL);
898     XInitThreads();
899 #endif
900
901     /* 3. gtk_init */
902
903     gtk_init (argc, argv);
904
905     /* 4. structure init */
906
907     init_structure();
908
909     /* 5. make hash init */
910
911     window_hash_init ();
912 }
913
914
915 /**
916  * @brief    function to load config parsed to qemu option
917  * @return   success  0,  fail    -1
918  * @date     Apr 22. 2009
919  * */
920
921 static int load_config_passed_to_qemu (arglist* al, int argc, char **argv)
922 {
923     int i;
924
925     /* 1. load configuration and show option window */
926
927     if (load_config_file(&SYSTEMINFO) < 0) {
928         ERR( "load configuration file error!!\n");
929         return -1;
930     }
931
932     TRACE( "load config file complete\n");
933
934
935
936     if (determine_skin(&virtual_target_info, &configuration) < 0) {
937         ERR( "invalid skin file\n");
938         return -1;
939     }
940
941     /* 2. skin parse dbi file and fill the structure */
942
943     if (skin_parser(configuration.skin_path, &PHONE) < 0) {
944         ERR( "skin parse error\n");
945         return -1;
946     }
947
948     TRACE( "skin parse complete\n");
949
950     /* 3. parsed to qemu startup option when ok clicked */
951
952     qemu_option_set_to_config(al);
953
954     /*
955      * note: g_option_context_parse modifies argc and argv
956      * Append args after -- to QEMU command line
957      */
958     if (argc > 2 && !strcmp(argv[1], "--")) {
959         for (i=2; i<argc; i++) {
960             /* if snapshot boot set then skip -loadvm snapshot option */
961             if(configuration.qemu_configuration.save_emulator_state == 0 && strcmp(argv[i],"-loadvm") == 0){
962                 i++;    // skip snapshot id
963             }
964             else append_argvlist(al, "%s", argv[i]);
965         }
966     }
967
968     return 0;
969 }
970
971 #ifndef _WIN32
972 static void emul_prepare_process(void)
973 {
974     gchar cmd[256] = "";
975
976     /* start the vmodem*/
977     if(qemu_arch_is_arm()) {
978         const char* target_path = get_target_path();
979
980         if(configuration.qemu_configuration.diskimg_type)
981             sprintf (cmd, "/opt/tizen_sdk/simulator/vmodem_arm");
982         else
983             sprintf (cmd, "%s/usr/bin/vmodem_arm", target_path);
984
985         if(emul_create_process(cmd) == FALSE)
986             fprintf(stderr, "create vmodem failed\n");
987     }
988
989     /* start serial console */
990     if(configuration.qemu_configuration.serial_console_command_type == 1 &&
991             configuration.qemu_configuration.telnet_type == 1) {
992         sprintf(cmd, "%s", configuration.qemu_configuration.serial_console_command);
993
994         if(emul_create_process(cmd) == FALSE)
995             fprintf(stderr, "create serial console failed\n");
996     }
997 }
998 #endif
999
1000 int make_shdmem()
1001 {
1002     char *virtual_target_path = NULL;
1003     virtual_target_path = get_virtual_target_path(startup_option.vtm);
1004     tizen_base_port = get_sdb_base_port();
1005 #ifndef _WIN32
1006     int shmid;
1007     char *shared_memory;
1008     shmid = shmget((key_t)tizen_base_port, MAXPATH, 0666|IPC_CREAT);
1009     if (shmid == -1)
1010     {
1011         ERR("shmget failed");
1012         return -1;
1013     }
1014     shared_memory = shmat(shmid, (char*)0x00, 0);
1015     if (shared_memory == (void *)-1)
1016     {
1017         ERR("shmat failed");
1018         return -1;
1019     }
1020     sprintf(shared_memory, "%s", virtual_target_path);
1021     INFO( "shared memory key: %d value: %s\n", tizen_base_port, (char*)shared_memory);
1022 #else
1023     HANDLE hMapFile;
1024     char* pBuf;
1025     char* port_in_use;
1026     char *shared_memory;
1027     shared_memory = g_strdup_printf("%s", virtual_target_path);
1028     port_in_use =  g_strdup_printf("%d", tizen_base_port);
1029     hMapFile = CreateFileMapping(
1030                  INVALID_HANDLE_VALUE,    // use paging file
1031                  NULL,                    // default security
1032                  PAGE_READWRITE,          // read/write access
1033                  0,                       // maximum object size (high-order DWORD)
1034                  50,                // maximum object size (low-order DWORD)
1035                  port_in_use);                 // name of mapping object
1036     if (hMapFile == NULL)
1037     {
1038         ERR("Could not create file mapping object (%d).\n", GetLastError());
1039         return -1;
1040     }
1041     pBuf = MapViewOfFile(hMapFile,   // handle to map object
1042                         FILE_MAP_ALL_ACCESS, // read/write permission
1043                         0,
1044                         0,
1045                         50);
1046
1047     if (pBuf == NULL)
1048     {
1049         ERR("Could not map view of file (%d).\n", GetLastError());
1050         CloseHandle(hMapFile);
1051         return -1;
1052     }
1053
1054     CopyMemory((PVOID)pBuf, shared_memory, strlen(shared_memory));
1055     free(port_in_use);
1056     free(shared_memory);
1057 #endif
1058     free(virtual_target_path);
1059     return 0;
1060 }
1061
1062
1063 static void redirect_log(void)
1064 {
1065     static char logfile[256] = { 0, };
1066
1067     strcpy(logfile, get_virtual_target_log_path(startup_option.vtm));
1068     strcat(logfile, EMUL_LOGFILE);
1069
1070     g_out_fp = freopen(logfile, "a+", stdout);
1071     if (g_out_fp ==NULL) {
1072         fprintf(stderr, "log file open error\n");
1073     }
1074
1075     g_err_fp = freopen(logfile, "a+", stderr);
1076     if (g_err_fp ==NULL) {
1077         fprintf(stderr, "log file open error\n");
1078     }
1079
1080     setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
1081     setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
1082
1083 }
1084
1085 /**
1086  * @brief    function to create emulator
1087  * @param argc        number of argument
1088  * @param argv        argument vector
1089  *
1090  * @return   success  0,  fail    -1
1091  * @date     Apr 22. 2009
1092  * */
1093
1094 int main(int argc, char** argv)
1095 {
1096     //int sensor_port = SENSOR_PORT;
1097     int i, r;
1098     pthread_t thread_gtk_id;
1099
1100     init_emulator(&argc, &argv);
1101
1102     startup_option_parser(&argc, &argv);
1103
1104     /* redirect stderr, stdout to log file */
1105
1106     redirect_log();
1107
1108     /* initailize socket for windows */
1109
1110     socket_init();
1111
1112     /* make shared memory not for launching multiple instance of one target */
1113     make_shdmem();
1114     INFO("created a shared memory\n");
1115
1116     /* option parsed and pass to qemu option */
1117
1118     r = load_config_passed_to_qemu(&g_qemu_arglist, argc, argv);
1119     if (r < 0) {
1120         ERR( "option parsed and pass to qemu option error!!\n");
1121         return -1;
1122     }
1123     INFO("Arguments : ");
1124     for(i=0; i<g_qemu_arglist.argc; i++){
1125         dbg_printf_nonewline("%s ", g_qemu_arglist.argv[i]);
1126     }
1127     dbg_printf("\n");
1128
1129     /* signal handler */
1130
1131     register_sig_handler();
1132
1133 #ifndef _WIN32
1134     construct_main_window();
1135
1136     /* create gtk thread  */
1137     if (pthread_create(&thread_gtk_id, NULL, run_gtk_main, NULL) != 0) {
1138         ERR( "error creating gtk_id thread!!\n");
1139         return -1;
1140     }
1141 #else /* _WIN32 */
1142     /* if _WIN32, window creation and gtk main must be run in a thread */
1143     if (pthread_create(&thread_gtk_id, NULL, construct_main_window_and_run_gtk_main, NULL) != 0) {
1144         ERR( "error creating gtk_id thread!!\n");
1145         return -1;
1146     }
1147 #endif
1148     INFO("run_gtk_main\n");
1149
1150 #ifdef ENABLE_OPENGL_SERVER
1151     /* create OPENGL server thread */
1152     if (pthread_create(&thread_opengl_id, NULL, init_opengl_server, NULL) != 0) {
1153         ERR( "error creating opengl_id thread!!");
1154         return -1;
1155     }
1156 #endif  /* ENABLE_OPENGL_SERVER */
1157
1158     /* create serial console and vmodem, and other processes */
1159 #ifndef _WIN32
1160     emul_prepare_process();
1161 #endif
1162
1163     qemu_main(g_qemu_arglist.argc, g_qemu_arglist.argv, NULL);
1164
1165     return 0;
1166 }
1167
1168 gboolean  update_progress_bar(GIOChannel *channel, GIOCondition condition, gpointer data)
1169 {
1170     unsigned int len = 0;
1171     GIOError error;
1172     GIOStatus status;
1173     gchar *recvbuffer;
1174     time_t rawtime;
1175     struct tm *timeinfo;
1176     char time_str[MAX_TIME_STR];
1177     char telnet_commands[MAX_COMMANDS][MAX_LENGTH] = {
1178         "read", //dummy command for local use
1179         "delvm snapshot\r",
1180         "read", //dummy command for local use
1181         "savevm snapshot\r",
1182         "read", //dummy command for local use
1183     };
1184
1185     if((condition==G_IO_IN) && !(vmstate%2))
1186     {
1187         status = g_io_channel_read_line(channel, &recvbuffer, NULL, NULL, NULL);
1188         if(status!=G_IO_STATUS_NORMAL)
1189         {
1190             printf("recv() failed or connection closed prematurely %d\n", status);
1191             vmstate = -1;
1192             g_io_channel_unref (channel);
1193             g_io_channel_shutdown(channel, TRUE, NULL);
1194             return FALSE;
1195         }
1196         else
1197         {
1198             char *ptr = NULL;
1199             if((ptr = strstr(recvbuffer, "Completed="))!=NULL)
1200             {
1201                 ptr[18]='\0';
1202                 gdouble fraction = atof(ptr+10);
1203                 gtk_progress_bar_set_fraction(savevm_progress,fraction);
1204             }
1205             else if (strstr(recvbuffer, "SaveVM Complete"))
1206             {
1207                 gtk_progress_bar_set_fraction(savevm_progress,1);
1208                 gtk_progress_bar_set_text(savevm_progress,"Save State Successful");
1209                 gtk_label_set_text(GTK_LABEL(savevm_label), "Please close this dialog");
1210                 g_free(recvbuffer);
1211                 g_io_channel_shutdown(channel, TRUE, NULL);
1212                 g_io_channel_unref (channel);
1213                 vmstate = 0;
1214                 rawtime = time(NULL);
1215                 timeinfo = localtime(&rawtime);
1216                 strftime(time_str, MAX_TIME_STR, "%Y-%m-%d %H:%M:%S", timeinfo);
1217                 printf("%s\n", time_str);
1218
1219                 virtual_target_info.snapshot_saved = 1;
1220                 snprintf(virtual_target_info.snapshot_saved_date, MAXBUF, "%s", time_str);
1221                 set_config_type(SYSTEMINFO.virtual_target_info_file, ETC_GROUP, SNAPSHOT_SAVED_KEY, virtual_target_info.snapshot_saved);
1222                 set_config_value(SYSTEMINFO.virtual_target_info_file, ETC_GROUP, SNAPSHOT_SAVED_DATE_KEY, virtual_target_info.snapshot_saved_date);
1223
1224                 return FALSE;
1225             }
1226
1227             g_free(recvbuffer);
1228
1229             if(vmstate<(MAX_COMMANDS-1))
1230                 vmstate++;
1231
1232             return TRUE;
1233         }
1234     }
1235
1236     if(vmstate%2)
1237     {
1238         error = g_io_channel_write(channel,telnet_commands[vmstate],\
1239                 strlen(telnet_commands[vmstate]), \
1240                 &len);
1241         if(error!=G_IO_ERROR_NONE)
1242         {
1243             g_io_channel_unref (channel);
1244             g_io_channel_shutdown(channel, TRUE, NULL);
1245             vmstate = -1;
1246             printf("send() failed or connection closed prematurely %d\n", G_IO_ERROR_UNKNOWN);
1247             return FALSE;
1248         }
1249         else
1250         {
1251             if(vmstate<MAX_COMMANDS)
1252                 vmstate++;
1253             return TRUE;
1254         }
1255     }
1256
1257     if(((condition==G_IO_ERR) || (condition==G_IO_HUP))&&(vmstate<=(MAX_COMMANDS-1)))
1258     {
1259         g_io_channel_unref (channel);
1260         g_io_channel_shutdown(channel, TRUE, NULL);
1261         close(vmsock);
1262         vmstate = 0;
1263         return FALSE;
1264     }
1265     return TRUE;
1266 }
1267
1268 void save_emulator_state(void)
1269 {
1270     /* Connect to the monitor console */
1271     struct sockaddr_in server;
1272     unsigned short server_port = 9000;
1273     char *server_ip = "127.0.0.1";
1274
1275
1276     /* build the UI */
1277     GtkBuilder *builder = gtk_builder_new();
1278     char full_glade_path[256];
1279     sprintf(full_glade_path, "%s/savevm.glade", get_root_path());
1280     gtk_builder_add_from_file(builder, full_glade_path, NULL);
1281
1282     //get objects from the UI
1283     savevm_window = (GtkWidget *)gtk_builder_get_object(builder, "savevm_window");
1284     savevm_progress = (GtkProgressBar *)gtk_builder_get_object(builder, "savevm_progress");
1285     savevm_label = (GtkWidget *)gtk_builder_get_object(builder, "savevm_label");
1286     gtk_progress_bar_set_text(savevm_progress,"Saving State in progress...");
1287     //gtk_builder_connect_signals(builder, NULL);
1288     gtk_widget_show(savevm_window);
1289
1290     if ((vmsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
1291     {
1292         printf("socket() failed\n");
1293         return ;
1294     }
1295     memset(&server, 0, sizeof(server));
1296     server.sin_family      = AF_INET;
1297     server.sin_addr.s_addr = inet_addr(server_ip);
1298     server.sin_port        = htons(server_port);
1299     if (connect(vmsock, (struct sockaddr *) &server, sizeof(server)) < 0)
1300     {
1301         printf("connect() failed\n");
1302         close(vmsock);
1303         return ;
1304     }
1305
1306     channel=g_io_channel_unix_new(vmsock);
1307     if(channel==NULL)
1308     {
1309         printf("gnet_tcp_socket_get_io_channel() failed\n");
1310         close(vmsock);
1311         return ;
1312     }
1313     //g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
1314
1315     guint sourceid = g_io_add_watch(channel, G_IO_IN|G_IO_ERR|G_IO_HUP, \
1316             update_progress_bar, NULL);
1317
1318     if(sourceid<=0)
1319     {
1320         printf("g_io_add_watch() failed\n");
1321         g_io_channel_unref(channel);
1322         close(vmsock);
1323         return ;
1324     }
1325     printf("Added to gmain loop = %d\n", sourceid);
1326 }