blob: c387d3a267bdc13dc8ec95790b972fdc130f21f2 [file] [log] [blame]
The Android Open Source Project52d4c302009-03-03 19:29:09 -08001//
2// Copyright 2005 The Android Open Source Project
3//
4// Management of the simulated device.
5//
6
7// For compilers that support precompilation, include "wx/wx.h".
8#include "wx/wxprec.h"
9
10// Otherwise, include all standard headers
11#ifndef WX_PRECOMP
12# include "wx/wx.h"
13#endif
14#include "wx/image.h"
15
16#include "DeviceManager.h"
17#include "MyApp.h"
18#include "DeviceWindow.h"
19#include "LogWindow.h"
20#include "UserEvent.h"
21#include "UserEventMessage.h"
22
23#include "SimRuntime.h"
24#include "utils.h"
25
26#include <unistd.h>
27#include <signal.h>
28#include <errno.h>
29
30#if !defined(SIGKILL) // doesn't exist in MinGW
31# if defined(SIGBREAK)
32# define SIGKILL SIGBREAK // intended for Ctrl-Break
33# else
34# define SIGKILL SIGABRT
35# endif
36#endif
37
38
39/*
40 * Constructor.
41 */
42DeviceManager::DeviceManager(void)
43 : mThread(NULL), mDisplay(NULL), mNumDisplays(0), mKeyMap(NULL),
44 mpStatusWindow(NULL)
45{
46 //printf("--- DeviceManager constructor\n");
47}
48
49/*
50 * Destructor. Snuff the thread if it's still kicking.
51 */
52DeviceManager::~DeviceManager(void)
53{
54 //printf("--- DeviceManager destructor\n");
55
56 if (mThread != NULL && mThread->IsRunning()) {
57 mThread->KillChildProcesses();
58 }
59 if (mThread != NULL) {
60 wxThread::ExitCode code;
61
62 printf("Sim: Waiting for old runtime thread..."); fflush(stdout);
63 code = mThread->Wait(); // join the old thread
64 printf("done (code=%ld)\n", (long) code);
65 }
66 delete mThread;
67 mThread = NULL;
68
69 delete[] mDisplay;
70 free((void*)mKeyMap);
71}
72
73/*
74 * Initialize the device configuration.
75 *
76 * "statusWindow" is where message boxes with failure messages go, usually
77 * the main frame.
78 */
79bool DeviceManager::Init(int numDisplays, wxWindow* statusWindow)
80{
81 //if (IsRunning()) {
82 // fprintf(stderr, "ERROR: tried to Configure device while running\n");
83 // return false;
84 //}
85 assert(mDisplay == NULL);
86 assert(numDisplays > 0);
87
88 //if (mDisplay != NULL)
89 // delete[] mDisplay;
90
91 mDisplay = new Display[numDisplays];
92 mNumDisplays = numDisplays;
93
94 mpStatusWindow = statusWindow;
95
96 return true;
97}
98
99/*
100 * Have we been initialized already?
101 */
102bool DeviceManager::IsInitialized(void) const
103{
104 return (mDisplay != NULL);
105}
106
107#if 0
108/*
109 * Return the Nth display.
110 */
111int DeviceManager::GetShmemKey(int displayIndex)
112{
113 assert(displayIndex >= 0 && displayIndex < mNumDisplays);
114 return mDisplay[displayIndex].GetShmemKey();
115}
116#endif
117
118/*
119 * Define mapping between the device's display and a wxWidgets window.
120 */
121bool DeviceManager::SetDisplayConfig(int displayIndex, wxWindow* window,
122 int width, int height, android::PixelFormat format, int refresh)
123{
124 assert(displayIndex >= 0 && displayIndex < mNumDisplays);
125
126 if (!mDisplay[displayIndex].Create(displayIndex, window, width, height,
127 format, refresh))
128 {
129 fprintf(stderr, "Sim: ERROR: unable to configure display %d\n",
130 displayIndex);
131 return false;
132 } else {
133 printf("Sim: configured display %d (w=%d h=%d f=%d re=%d)\n",
134 displayIndex, width, height, format, refresh);
135 return true;
136 }
137}
138
139/*
140 * Define the keyboard
141 */
142bool DeviceManager::SetKeyboardConfig(const char *keymap) {
143 free((void*)mKeyMap);
144 mKeyMap = strdup(keymap);
145 return true;
146}
147
148/*
149 * Called before the phone window dialog destroys itself. The goal here
150 * is to prevent the runtime thread from trying to draw after the phone
151 * window has closed for business but before the device manager destructor
152 * gets called.
153 */
154void DeviceManager::WindowsClosing(void)
155{
156 int i;
157
158 for (i = 0; i < mNumDisplays; i++)
159 mDisplay[i].Uncreate();
160}
161
162/*
163 * Launch a new runtime process. If there is an existing device manager
164 * thread, we assume that it is in the process of shutting down.
165 */
166bool DeviceManager::StartRuntime(void)
167{
168 return DeviceManager::DeviceThread::LaunchProcess(mpStatusWindow);
169}
170
171/*
172 * Start the runtime management thread when a runtime connects to us. If
173 * there is an existing thread, we assume that it is in the process of
174 * shutting down.
175 */
176bool DeviceManager::StartRuntime(android::Pipe* reader, android::Pipe* writer)
177{
178 if (mThread != NULL) {
179 wxThread::ExitCode code;
180
181 if (mThread->IsRunning()) {
182 fprintf(stderr,
183 "Sim: ERROR: start requested, but thread running\n");
184 return false;
185 }
186
187 // clean up old thread
188 printf("Sim: Waiting for old runtime thread..."); fflush(stdout);
189 code = mThread->Wait(); // join the old thread
190 printf("done (code=%ld)\n", (long) code);
191
192 delete mThread;
193 mThread = NULL;
194 }
195
196 assert(mpStatusWindow != NULL);
197 mThread = new DeviceThread(this, mpStatusWindow, reader, writer);
198 if (mThread->Create() != wxTHREAD_NO_ERROR) {
199 fprintf(stderr, "Sim: ERROR: can't create thread\n");
200 return false;
201 }
202 mThread->Run();
203
204 return true;
205}
206
207/*
208 * Get the message stream. Returns NULL if it doesn't exist.
209 */
210android::MessageStream* DeviceManager::GetStream(void)
211{
212 if (!IsRunning()) {
213 fprintf(stderr, "Sim: ERROR: runtime thread not active\n");
214 return NULL;
215 }
216
217 assert(mThread != NULL);
218 android::MessageStream* pStream = mThread->GetStream();
219 assert(pStream != NULL);
220
221 if (!pStream->isReady()) {
222 fprintf(stderr, "Sim: NOTE: connection to runtime not ready\n");
223 return NULL;
224 }
225
226 return pStream;
227}
228
229/*
230 * Stop the runtime, politely.
231 *
232 * We don't clean up the thread here, because it might not exit immediately.
233 */
234bool DeviceManager::StopRuntime(void)
235{
236 android::MessageStream* pStream = GetStream();
237 if (pStream == NULL)
238 return false;
239
240 printf("Sim: Sending quit command\n");
241
242 android::Message msg;
243 msg.setCommand(android::Simulator::kCommandQuit, 0);
244 pStream->send(&msg);
245 return true;
246}
247
248/*
249 * Kill the runtime as efficiently as possible.
250 */
251void DeviceManager::KillRuntime(void)
252{
253 if (mThread != NULL && mThread->IsRunning())
254 mThread->KillChildProcesses();
255}
256
257#if 0
258/*
259 * Check if the modified time is newer than mLastModified
260 */
261bool DeviceManager::RefreshRuntime(void)
262{
263 return (IsRunning() && mThread->IsRuntimeNew());
264}
265
266/*
267 * Tells the device manager that the user does not want to update
268 * the runtime
269 */
270void DeviceManager::UserCancelledRefresh(void)
271{
272 mThread->UpdateLastModified();
273}
274#endif
275
276/*
277 * Send an event to the runtime.
278 *
279 * The events are defined in display_device.h.
280 */
Jeff Brownfd606bc2010-07-13 16:14:54 -0700281void DeviceManager::SendKeyEvent(int32_t keyCode, bool down)
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800282{
283 android::MessageStream* pStream = GetStream();
284 if (pStream == NULL)
285 return;
286
287 int event = down ? android::Simulator::kCommandKeyDown :
288 android::Simulator::kCommandKeyUp;
289
290 //printf("Sim: sending key-%s %d\n", down ? "down" : "up", keyCode);
291
292 android::Message msg;
293 msg.setCommand(event, keyCode);
294 pStream->send(&msg);
295}
296
297/*
298 * Send a "touch screen" event to the runtime.
299 *
300 * "mode" can be "down" (we're pressing), "up" (we're lifting our finger
301 * off) or "drag".
302 */
303void DeviceManager::SendTouchEvent(android::Simulator::TouchMode mode,
304 int x, int y)
305{
306 android::MessageStream* pStream = GetStream();
307 if (pStream == NULL)
308 return;
309
310 //printf("Sim: sending touch-%d x=%d y=%d\n", (int) mode, x, y);
311
312 android::Message msg;
313 msg.setCommandExt(android::Simulator::kCommandTouch, mode, x, y);
314 pStream->send(&msg);
315}
316
317/*
318 * The runtime has sent us a new frame of stuff to display.
319 *
320 * NOTE: we're still in the runtime management thread. We have to pass the
321 * bitmap through AddPendingEvent to get it over to the main thread.
322 *
323 * We have to make a copy of the data from the runtime; the easiest
324 * way to do that is to convert it to a bitmap here. However, X11 gets
325 * all worked up about calls being made from multiple threads, so we're
326 * better off just copying it into a buffer.
327 *
328 * Because we're decoupled from the runtime, there is a chance that we
329 * could drop frames. Buffering them up is probably worse, since it
330 * creates the possibility that we could stall and run out of memory.
331 * We could save a copy by handing the runtime a pointer to our buffer,
332 * but then we'd have to mutex the runtime against the simulator window
333 * Paint function.
334 */
335void DeviceManager::ShowFrame(int displayIndex)
336{
337 assert(displayIndex >= 0 && displayIndex < mNumDisplays);
338
339 // copy the data to local storage and convert
340 mDisplay[displayIndex].CopyFromShared();
341
342 // create a user event and send it to the window
343 UserEvent uev(0, (void*) displayIndex);
344
345 wxWindow* pEventWindow = mDisplay[displayIndex].GetWindow();
346 if (pEventWindow != NULL) {
347 //printf("runtime has image, passing up\n");
348 pEventWindow->AddPendingEvent(uev);
349 } else {
350 fprintf(stderr, "NOTE: runtime has image, display not available\n");
351 }
352}
353
354void DeviceManager::Vibrate(int vibrateOn)
355{
356 ((MyApp*)wxTheApp)->Vibrate(vibrateOn);
357}
358
359/*
360 * Get the display data from the specified display.
361 */
362wxBitmap* DeviceManager::GetImageData(int displayIndex)
363{
364 assert(displayIndex >= 0 && displayIndex < mNumDisplays);
365 return mDisplay[displayIndex].GetImageData();
366}
367
368/*
369 * Send an event to all device windows
370 */
371void DeviceManager::BroadcastEvent(UserEvent& userEvent) {
372 int numDisplays = GetNumDisplays();
373 for (int i = 0; i < numDisplays; i++) {
374 wxWindow* pEventWindow = mDisplay[i].GetWindow();
375 if (pEventWindow != NULL) {
376 pEventWindow->AddPendingEvent(userEvent);
377 }
378 }
379}
380
381
382/*
383 * ===========================================================================
384 * DeviceManager::Display
385 * ===========================================================================
386 */
387
388/*
389 * Fill out the various interesting fields based on the parameters.
390 */
391bool DeviceManager::Display::Create(int displayNum, wxWindow* window,
392 int width, int height, android::PixelFormat format, int refresh)
393{
394 //printf("DeviceManager::Display constructor\n");
395
396 assert(window != NULL);
397 if (mImageData != NULL) {
398 assert(false); // no re-init
399 return false;
400 }
401
402 mDisplayNum = displayNum;
403 mDisplayWindow = window;
404 mWidth = width;
405 mHeight = height;
406 mFormat = format;
407 mRefresh = refresh;
408
409 // use a fixed key for now
410 mShmemKey = GenerateKey(displayNum);
411 // allocate 24bpp for now
412 mpShmem = new android::Shmem;
413 if (!mpShmem->create(mShmemKey, width * height * 3, true))
414 return false;
415 //printf("--- CREATED shmem, key=0x%08x addr=%p\n",
416 // mShmemKey, mpShmem->getAddr());
417
418 mImageData = new unsigned char[width * height * 3];
419 if (mImageData == NULL)
420 return false;
421
422 return true;
423}
424
425/*
426 * The UI components are starting to shut down. We need to do away with
427 * our wxWindow pointer so that the runtime management thread doesn't try
428 * to send it display update events.
429 *
430 * We also need to let go of our side of the shared memory, because a
431 * new DeviceManager may get started up before our destructor gets called,
432 * and we may be re-using the key.
433 */
434void DeviceManager::Display::Uncreate(void)
435{
436 wxMutexLocker locker(mImageDataLock);
437
438 //printf("--- Uncreate\n");
439
440 mDisplayWindow = NULL;
441
442 // the "locker" mutex keeps this from hosing CopyFromShared()
443 if (mpShmem != NULL) {
444 //printf("--- DELETING shmem, addr=%p\n", mpShmem->getAddr());
445 delete mpShmem;
446 mpShmem = NULL;
447 }
448}
449
450/*
451 * Make a local copy of the image data. The UI grabs this data from a
452 * different thread, so we have to mutex it.
453 */
454void DeviceManager::Display::CopyFromShared(void)
455{
456 wxMutexLocker locker(mImageDataLock);
457
458 if (mpShmem == NULL) {
459 //printf("Sim: SKIP CopyFromShared\n");
460 return;
461 }
462
463 //printf("Display %d: copying data from %p to %p\n",
464 // mDisplayNum, mpShmem->getAddr(), mImageData);
465
466 /* data is always 24bpp RGB */
467 mpShmem->lock(); // avoid tearing
468 memcpy(mImageData, mpShmem->getAddr(), mWidth * mHeight * 3);
469 mpShmem->unlock();
470}
471
472/*
473 * Get the image data in the form of a newly-allocated bitmap.
474 *
475 * This MUST be called from the UI thread. Creating wxBitmaps in the
476 * runtime management thread will cause X11 failures (e.g.
477 * "Xlib: unexpected async reply").
478 */
479wxBitmap* DeviceManager::Display::GetImageData(void)
480{
481 wxMutexLocker locker(mImageDataLock);
482
483 assert(mImageData != NULL);
484
485 //printf("HEY: creating tmpImage, w=%d h=%d data=%p\n",
486 // mWidth, mHeight, mImageData);
487
488 /* create a temporary wxImage; it does not own the data */
489 wxImage tmpImage(mWidth, mHeight, (unsigned char*) mImageData, true);
490
491 /* return a new bitmap with the converted-for-display data */
492 return new wxBitmap(tmpImage);
493}
494
495
496/*
497 * ===========================================================================
498 * DeviceManager::DeviceThread
499 * ===========================================================================
500 */
501
502/*
503 * Some notes on process management under Linux/Mac OS X:
504 *
505 * We want to put the runtime into its own process group. That way we
506 * can send SIGKILL to the entire group to guarantee that we kill it and
507 * all of its children. Simply killing the sim's direct descendant doesn't
508 * do what we want. If it's a debugger, we will just orphan the runtime
509 * without killing it. Even if the runtime is our child, the children of
510 * the runtime might outlive it.
511 *
512 * We want to be able to run the child under GDB or Valgrind, both
513 * of which take input from the tty. They need to be in the "foreground"
514 * process group. We might be debugging or valgrinding the simulator,
515 * or operating in a command-line-only "headless" mode, so in that case
516 * the sim front-end should actually be in the foreground group.
517 *
518 * Putting the runtime in the background group means it can't read input
519 * from the tty (not an issue) and will generate SIGTTOU signals when it
520 * writes output to the tty (easy to ignore). The trick, then, is to
521 * have the simulator and gdb/valgrind in the foreground pgrp while the
522 * runtime itself is in a different group. This group needs to be known
523 * to the simulator so that it can send signals to the appropriate place.
524 *
525 * The solution is to have the runtime process change its process group
526 * after it starts but before it creates any new processes, and then send
527 * the process group ID back to the simulator. The sim can then send
528 * signals to the pgrp to ensure that we don't end up with zombies. Any
529 * "pre-launch" processes, like GDB, stay in the sim's pgrp. This also
530 * allows a consistent API for platforms that don't have fork/exec
531 * (e.g. MinGW).
532 *
533 * This doesn't help us with interactive valgrind (e.g. --db-attach=yes),
534 * because valgrind is an LD_PRELOAD shared library rather than a
535 * separate process. For that, we actually need to use termios(3) to
536 * change the terminal's pgrp, or the interactive stuff just doesn't work.
537 * We don't want to do that every time or attempting to debug the simulator
538 * front-end will have difficulties.
539 *
540 * Making this even more entertaining is the fact that the simulator
541 * front-end could itself be launched in the background. It's essential
542 * that we be careful about assigning a process group to the foreground,
543 * and that we don't restore ourselves unless we were in the foreground to
544 * begin with.
545 *
546 *
547 * Some notes on process management under Windows (Cygwin, MinGW):
548 *
549 * Signals cannot be caught or ignored under MinGW. All signals are fatal.
550 *
551 * Signals can be ignored under Cygwin, but not caught.
552 *
553 * Windows has some process group stuff (e.g. CREATE_NEW_PROCESS_GROUP flag
554 * and GenerateConsoleCtrlEvent()). Need to explore.
555 *
556 *
557 * UPDATE: we've abandoned Mac OS and MinGW, so we now launch the runtime in
558 * a separate xterm. This avoids all tty work on our side. We still need
559 * to learn the pgrp from the child during the initial communication
560 * handshake so we can do necessary cleanup.
561 */
562
563
564/*
565 * Convert a space-delimited string into an argument vector.
566 *
567 * "arg" is the current arg offset.
568 */
569static int stringToArgv(char* mangle, const char** argv, int arg, int maxArgs)
570{
571 bool first = true;
572
573 while (*mangle != '\0') {
574 assert(arg < maxArgs);
575 if (first) {
576 argv[arg++] = mangle;
577 first = false;
578 }
579 if (*mangle == ' ') {
580 *mangle = '\0';
581 first = true;
582 }
583 mangle++;
584 }
585
586 return arg;
587}
588
589/*
590 * Launch the runtime process in its own terminal window. Start by setting
591 * up the argument vector to the runtime process.
592 *
593 * The last entry in the vector will be a NULL pointer.
594 *
595 * This is awkward and annoying because the wxWidgets strings are current
596 * configured for UNICODE.
597 */
598/*static*/ bool DeviceManager::DeviceThread::LaunchProcess(wxWindow* statusWindow)
599{
600 static const char* kLaunchWrapper = "launch-wrapper";
601 const int kMaxArgs = 64;
602 Preferences* pPrefs;
603 wxString errMsg;
604 wxString runtimeExe;
605 wxString debuggerExe;
606 wxString debuggerScript;
607 wxString valgrinderExe;
608 wxString launchWrapperExe;
609 wxString launchWrapperArgs;
610 wxString javaAppName;
611 wxString termCmd;
612 wxString tmpStr;
613 char gammaVal[8];
614 //bool bval;
615 double dval;
616 bool result = false;
617 bool doDebug, doValgrind, doCheckJni, doEnableSound, doEnableFakeCamera;
618 const char** argv = NULL;
619 int arg;
620 wxCharBuffer runtimeExeTmp;
621 wxCharBuffer debuggerExeTmp;
622 wxCharBuffer debuggerScriptTmp;
623 wxCharBuffer javaAppNameTmp;
624 wxCharBuffer valgrinderExeTmp;
625 wxCharBuffer termCmdTmp;
626 wxCharBuffer launchWrapperExeTmp;
627 wxCharBuffer launchWrapperArgsTmp;
628
629 pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
630 if (pPrefs == NULL) {
631 errMsg = wxT("Preferences were not loaded.");
632 goto bail;
633 }
634
635 /*
636 * Set environment variables. This stuff should be passed through as
637 * arguments, but the runtime binary currently has a disconnect
638 * between main() and the VM initilization.
639 *
640 * TODO: remove this in favor of system properties
641 */
642#if 0
643 // TODO: restore this
644 doCheckJni = false;
645 pPrefs->GetBool("check-jni", &doCheckJni);
646#endif
647
648 tmpStr.Empty();
649 pPrefs->GetString("ld-assume-kernel", /*ref*/ tmpStr);
650 if (tmpStr.IsEmpty()) {
651 unsetenv("LD_ASSUME_KERNEL");
652 } else {
653 setenv("LD_ASSUME_KERNEL", tmpStr.ToAscii(), 1);
654 }
655
656 doEnableSound = false;
657 pPrefs->GetBool("enable-sound", &doEnableSound);
658 if (doEnableSound)
659 setenv("ANDROIDSOUND", "1", 1);
660
661 doEnableFakeCamera = false;
662 pPrefs->GetBool("enable-fake-camera", &doEnableFakeCamera);
663 if (doEnableFakeCamera)
664 setenv("ANDROIDFAKECAMERA", "1", 1);
665
666 /*
667 * Set the Dalvik bootstrap class path. Normally this is set by "init".
668 */
669 setenv("BOOTCLASSPATH",
670 "/system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar",
671 1);
672
673 /*
674 * Figure out where the "runtime" binary lives.
675 */
676 runtimeExe = ((MyApp*)wxTheApp)->GetRuntimeExe();
677 assert(!runtimeExe.IsEmpty());
678
679 //UpdateLastModified();
680
681 /*
682 * Initialize argv.
683 */
684 argv = new const char*[kMaxArgs];
685 if (argv == NULL)
686 goto bail;
687 arg = 0;
688
689 /*
690 * We want to launch the runtime in its own terminal window so we don't
691 * have to fight over who gets access to the controlling tty. We allow
692 * the user to specify the command they want to use to perform the
693 * launch. Here we cut it into pieces for argv.
694 *
695 * To make life easier here, we require that the launch command be
696 * all one piece, i.e. it's not "xterm -e <stuff> -geom blah" with our
697 * stuff in the middle.
698 */
699 termCmd.Empty();
700 pPrefs->GetString("launch-command", /*ref*/ termCmd);
701 if (termCmd.IsEmpty()) {
702 fprintf(stderr, "Sim: WARNING: launch-command is empty\n");
703 } else {
704 termCmdTmp = termCmd.ToAscii();
705 char* mangle = strdup(termCmdTmp);
706 arg = stringToArgv(mangle, argv, arg, kMaxArgs);
707 }
708
709 /*
710 * The "launch-wrapper" binary lives in the same place as the runtime.
711 * This sets up LD_PRELOAD and some other environment variables.
712 */
713 int charIdx;
714
715 charIdx = runtimeExe.Find('/', true);
716 if (charIdx == -1) {
717 launchWrapperExe = wxString::FromAscii(kLaunchWrapper);
718 } else {
719 launchWrapperExe = runtimeExe.Mid(0, charIdx+1);
720 launchWrapperExe.Append(wxString::FromAscii(kLaunchWrapper));
721 }
722 printf("Sim launch wrapper: %s\n", (const char*)launchWrapperExe.ToAscii());
723
724 argv[arg++] = launchWrapperExeTmp = launchWrapperExe.ToAscii();
725
726 launchWrapperArgs.Empty();
727 pPrefs->GetString("launch-wrapper-args", /*ref*/ launchWrapperArgs);
728 if (!launchWrapperArgs.IsEmpty()) {
729 launchWrapperArgsTmp = launchWrapperArgs.ToAscii();
730 char* mangle = strdup(launchWrapperArgsTmp);
731 arg = stringToArgv(mangle, argv, arg, kMaxArgs);
732 }
733
734 /*
735 * If we're launching under GDB or valgrind, set that up.
736 */
737 doDebug = doValgrind = false;
738 pPrefs->GetBool("debug", &doDebug);
739 if (((MyApp*)wxTheApp)->GetDebuggerOption()) {
740 doDebug = true;
741 }
742 debuggerScript = ((MyApp*)wxTheApp)->GetDebuggerScript();
743
744 pPrefs->GetBool("valgrind", &doValgrind);
745 if (doDebug || doValgrind) {
746
747 pPrefs->GetString("debugger", /*ref*/ debuggerExe);
748 pPrefs->GetString("valgrinder", /*ref*/ valgrinderExe);
749
750 // check for empty or undefined preferences
751 if (doDebug && debuggerExe.IsEmpty()) {
752 errMsg = wxT("Debugger not defined.");
753 goto bail;
754 }
755 if (doValgrind && valgrinderExe.IsEmpty()) {
756 errMsg = wxT("Valgrinder not defined.");
757 goto bail;
758 }
759
760 if (doValgrind) {
761 argv[arg++] = valgrinderExeTmp = valgrinderExe.ToAscii();
762 //argv[arg++] = "--tool=callgrind";
763 argv[arg++] = "--tool=memcheck";
764 argv[arg++] = "--leak-check=yes"; // check for leaks too
765 argv[arg++] = "--leak-resolution=med"; // increase from 2 to 4
766 argv[arg++] = "--num-callers=8"; // reduce from 12 to 8
767 //argv[arg++] = "--show-reachable=yes"; // show still-reachable
768 if (doDebug) {
769 //mTerminalFollowsChild = true; // interactive
770 argv[arg++] = "--db-attach=yes";
771 }
772 //mSlowExit = true;
773 } else /*doDebug*/ {
774 argv[arg++] = debuggerExeTmp = debuggerExe.ToAscii();
775 if (!debuggerScript.IsEmpty()) {
776 argv[arg++] = "-x";
777 argv[arg++] = debuggerScriptTmp = debuggerScript.ToAscii();
778 }
779 argv[arg++] = runtimeExeTmp = runtimeExe.ToAscii();
780 argv[arg++] = "--args";
781 }
782 }
783
784 /*
785 * Get runtime args.
786 */
787
788 argv[arg++] = runtimeExeTmp = (const char*) runtimeExe.ToAscii();
789
790 javaAppName = ((MyApp*)wxTheApp)->GetAutoRunApp();
791 if (javaAppName.IsEmpty()) {
792 if (!pPrefs->GetString("java-app-name", /*ref*/ javaAppName)) {
793 javaAppName = wxT("");
794 }
795 }
796
797 if (!javaAppName.IsEmpty())
798 {
799 argv[arg++] = "-j";
800 argv[arg++] = javaAppNameTmp = (const char*) javaAppName.ToAscii();
801 }
802
803 if (pPrefs->GetDouble("gamma", &dval) && dval != 1.0) {
804 snprintf(gammaVal, sizeof(gammaVal), "%.3f", dval);
805 argv[arg++] = "-g";
806 argv[arg++] = gammaVal;
807 }
808
809 /* finish arg set */
810 argv[arg++] = NULL;
811
812 assert(arg <= kMaxArgs);
813
814#if 1
815 printf("ARGS:\n");
816 for (int i = 0; i < arg; i++)
817 printf(" %d: '%s'\n", i, argv[i]);
818#endif
819
820 if (fork() == 0) {
821 execvp(argv[0], (char* const*) argv);
822 fprintf(stderr, "execvp '%s' failed: %s\n", argv[0], strerror(errno));
823 exit(1);
824 }
825
826 /*
827 * We assume success; if it didn't succeed we'll just sort of hang
828 * out waiting for a connection. There are ways to fix this (create
829 * a non-close-on-exec pipe and watch to see if the other side closes),
830 * but at this stage it's not worthwhile.
831 */
832 result = true;
833
834 tmpStr = wxT("=== launched ");
835 tmpStr += runtimeExe;
836 LogWindow::PostLogMsg(tmpStr);
837
838 assert(errMsg.IsEmpty());
839
840bail:
841 if (!errMsg.IsEmpty()) {
842 assert(result == false);
843
844 UserEventMessage* pUem = new UserEventMessage;
845 pUem->CreateErrorMessage(errMsg);
846
847 UserEvent uev(0, (void*) pUem);
848
849 assert(statusWindow != NULL);
850 statusWindow->AddPendingEvent(uev);
851 }
852 delete[] argv;
853 return result;
854}
855
856/*
857 * This is the entry point for the device thread. The thread launches the
858 * runtime process and monitors it. When the runtime exits, the thread
859 * exits.
860 *
861 * Because this isn't running in the UI thread, any user interaction has
862 * to be channeled through "user events" to the appropriate window.
863 */
864void* DeviceManager::DeviceThread::Entry(void)
865{
866 //android::MessageStream stream;
867 android::Message msg;
868 wxString errMsg;
869 char statusBuf[64] = "(no status)";
870 int result = 1;
871
872 /* print this so we can make sense of log messages */
873 LOG(LOG_DEBUG, "", "Sim: device management thread starting (pid=%d)\n",
874 getpid());
875
876 assert(mReader != NULL && mWriter != NULL);
877
878 /*
879 * Tell the main thread that we're running. If something fails here,
880 * we'll send them a "stopped running" immediately afterward.
881 */
882 {
883 UserEventMessage* pUem = new UserEventMessage;
884 pUem->CreateRuntimeStarted();
885
886 UserEvent uev(0, (void*) pUem);
887
888 assert(mpStatusWindow != NULL);
889 mpStatusWindow->AddPendingEvent(uev);
890 }
891 LogWindow::PostLogMsg(
892 "==============================================================");
893 LogWindow::PostLogMsg("=== runtime starting");
894
895 /*
896 * Establish contact with runtime.
897 */
898 if (!mStream.init(mReader, mWriter, true)) {
899 errMsg = wxT("ERROR: Unable to establish communication with runtime.\n");
900 goto bail;
901 }
902
903 /*
904 * Tell the runtime to put itself into a new process group and set
905 * itself up as the foreground process. The latter is only really
906 * necessary to make valgrind+gdb work.
907 */
908 msg.setCommand(android::Simulator::kCommandNewPGroup, true);
909 mStream.send(&msg);
910
911 printf("Sim: Sending hardware configuration\n");
912
913 /*
914 * Send display config.
915 *
916 * Right now we're just shipping a big binary blob over.
917 */
918 assert(android::Simulator::kValuesPerDisplay >= 5);
919 int buf[1 + 1 + mpDeviceManager->GetNumDisplays() *
920 android::Simulator::kValuesPerDisplay];
921 buf[0] = android::Simulator::kDisplayConfigMagic;
922 buf[1] = mpDeviceManager->GetNumDisplays();
923 for (int i = 0; i < mpDeviceManager->GetNumDisplays(); i++) {
924 DeviceManager::Display* pDisplay = mpDeviceManager->GetDisplay(i);
925 int* pBuf = &buf[2 + android::Simulator::kValuesPerDisplay * i];
926
927 pBuf[0] = pDisplay->GetWidth();
928 pBuf[1] = pDisplay->GetHeight();
929 pBuf[2] = pDisplay->GetFormat();
930 pBuf[3] = pDisplay->GetRefresh();
931 pBuf[4] = pDisplay->GetShmemKey();
932 }
933 msg.setRaw((const unsigned char*)buf, sizeof(buf),
934 android::Message::kCleanupNoDelete);
935 mStream.send(&msg);
936
937 /*
938 * Send other hardware config.
939 *
940 * Examples:
941 * - Available input devices.
942 * - Set of buttons on device.
943 * - External devices (Bluetooth, etc).
944 * - Initial mode (e.g. "flipped open" vs. "flipped closed").
945 */
946
947 msg.setConfig("keycharmap", mpDeviceManager->GetKeyMap());
948 mStream.send(&msg);
949
950 /*
951 * Done with config.
952 */
953 msg.setCommand(android::Simulator::kCommandConfigDone, 0);
954 mStream.send(&msg);
955
956 /*
957 * Sit forever, waiting for messages from the runtime process.
958 */
959 while (1) {
960 if (!mStream.recv(&msg, true)) {
961 /*
962 * The read failed. This usually means the child has died.
963 */
964 printf("Sim: runtime process has probably died\n");
965 break;
966 }
967
968 if (msg.getType() == android::Message::kTypeCommand) {
969 int cmd, arg;
970
971 if (!msg.getCommand(&cmd, &arg)) {
972 fprintf(stderr, "Sim: Warning: failed unpacking command\n");
973 /* keep going? */
974 } else {
975 switch (cmd) {
976 case android::Simulator::kCommandNewPGroupCreated:
977 // runtime has moved into a separate process group
978 // (not expected for external)
979 printf("Sim: child says it's now in pgrp %d\n", arg);
980 mRuntimeProcessGroup = arg;
981 break;
982 case android::Simulator::kCommandRuntimeReady:
983 // sim is up and running, do late init
984 break;
985 case android::Simulator::kCommandUpdateDisplay:
986 // new frame of graphics is ready
987 //printf("RCVD display update %d\n", arg);
988 mpDeviceManager->ShowFrame(arg);
989 break;
990 case android::Simulator::kCommandVibrate:
991 // vibrator on or off
992 //printf("RCVD vibrator update %d\n", arg);
993 mpDeviceManager->Vibrate(arg);
994 break;
995 default:
996 printf("Sim: got unknown command %d/%d\n", cmd, arg);
997 break;
998 }
999 }
1000 } else if (msg.getType() == android::Message::kTypeLogBundle) {
1001 android_LogBundle bundle;
1002
1003 if (!msg.getLogBundle(&bundle)) {
1004 fprintf(stderr, "Sim: Warning: failed unpacking logBundle\n");
1005 /* keep going? */
1006 } else {
1007 LogWindow::PostLogMsg(&bundle);
1008 }
1009 } else {
1010 printf("Sim: got unknown message type=%d\n", msg.getType());
1011 }
1012 }
1013
1014 result = 0;
1015
1016bail:
1017 printf("Sim: DeviceManager thread preparing to exit\n");
1018
1019 /* kill the comm channel; should encourage runtime to die */
1020 mStream.close();
1021 delete mReader;
1022 delete mWriter;
1023 mReader = mWriter = NULL;
1024
1025 /*
1026 * We never really did get a "friendly death" working, so just slam
1027 * the thing if we have the process group.
1028 */
1029 if (mRuntimeProcessGroup != 0) {
1030 /* kill the group, not our immediate child */
1031 printf("Sim: killing pgrp %d\n", (int) mRuntimeProcessGroup);
1032 kill(-mRuntimeProcessGroup, 9);
1033 }
1034
1035 if (!errMsg.IsEmpty()) {
1036 UserEventMessage* pUem = new UserEventMessage;
1037 pUem->CreateErrorMessage(errMsg);
1038
1039 UserEvent uev(0, (void*) pUem);
1040 mpStatusWindow->AddPendingEvent(uev);
1041 }
1042
1043 /* notify the main window that the runtime has stopped */
1044 {
1045 UserEventMessage* pUem = new UserEventMessage;
1046 pUem->CreateRuntimeStopped();
1047
1048 UserEvent uev(0, (void*) pUem);
1049 mpStatusWindow->AddPendingEvent(uev);
1050 }
1051
1052 /* show exit status in log file */
1053 wxString exitMsg;
1054 exitMsg.Printf(wxT("=== runtime exiting - %s"), statusBuf);
1055 LogWindow::PostLogMsg(exitMsg);
1056 LogWindow::PostLogMsg(
1057 "==============================================================\n");
1058
1059 /*
1060 * Reset system properties for future runs.
1061 */
1062 ResetProperties();
1063
1064 return (void*) result;
1065}
1066
1067
1068/*
1069 * Wait for a little bit to see if the thread will exit.
1070 *
1071 * "delay" is in 0.1s increments.
1072 */
1073void DeviceManager::DeviceThread::WaitForDeath(int delay)
1074{
1075 const int kDelayUnit = 100000;
1076 int i;
1077
1078 for (i = 0; i < delay; i++) {
1079 if (!IsRunning())
1080 return;
1081 usleep(kDelayUnit);
1082 }
1083}
1084
1085
1086/*
1087 * Kill the runtime process. The goal is to cause our local runtime
1088 * management thread to exit. If it doesn't, this will kill the thread
1089 * before it returns.
1090 */
1091void DeviceManager::DeviceThread::KillChildProcesses(void)
1092{
1093 if (!this->IsRunning())
1094 return;
1095
1096 /* clear "slow exit" flag -- we're forcefully killing this thing */
1097 //this->mSlowExit = false;
1098
1099 /*
1100 * Use the ChildProcess object in the thread to send signals. There's
1101 * a risk that the DeviceThread will exit and destroy the object while
1102 * we're using it. Using a mutex here gets a little awkward because
1103 * we can't put it in DeviceThread. It's easier to make a copy of
1104 * ChildProcess and operate on the copy, but we have to do that very
1105 * carefully to avoid interfering with the communcation pipes.
1106 *
1107 * For now, we just hope for the best. FIX this someday.
1108 *
1109 * We broadcast to the process group, which will ordinarily kill
1110 * everything. If we're running with valgrind+GDB everything is in our
1111 * pgrp and we can't do the broadcast; if GDB alone, then only GDB is
1112 * in our pgrp, so the broadcast will hit everything except it. We
1113 * hit the group and then hit our child for good measure.
1114 */
1115 if (mRuntimeProcessGroup != 0) {
1116 /* kill the group, not our immediate child */
1117 printf("Sim: killing pgrp %d\n", (int) mRuntimeProcessGroup);
1118 kill(-mRuntimeProcessGroup, 9);
1119 WaitForDeath(15);
1120 }
1121
1122 /*
1123 * Close the communication channel. This should cause our thread
1124 * to snap out of its blocking read and the runtime thread to bail
1125 * out the next time it tries to interact with us. We should only
1126 * get here if somebody other than our direct descendant has the
1127 * comm channel open and our broadcast didn't work, which should
1128 * no longer be possible.
1129 */
1130 if (this->IsRunning()) {
1131 printf("Sim: killing comm channel\n");
1132 mStream.close();
1133 delete mReader;
1134 delete mWriter;
1135 mReader = mWriter = NULL;
1136 WaitForDeath(15);
1137 }
1138
1139 /*
1140 * At this point it's possible that our DeviceThread is just wedged.
1141 * Kill it.
1142 *
1143 * Using the thread Kill() function can orphan resources, including
1144 * locks and semaphores. There is some risk that the simulator will
1145 * be hosed after this.
1146 */
1147 if (this->IsRunning()) {
1148 fprintf(stderr, "Sim: WARNING: killing runtime thread (%ld)\n",
1149 (long) GetId());
1150 this->Kill();
1151 WaitForDeath(15);
1152 }
1153
1154 /*
1155 * Now I'm scared.
1156 */
1157 if (this->IsRunning()) {
1158 fprintf(stderr, "Sim: thread won't die!\n");
1159 }
1160}
1161
1162
1163/*
1164 * Configure system properties for the simulated device.
1165 *
1166 * Property requests can arrive *before* the full connection to the
1167 * simulator is established, so we want to reset these during cleanup.
1168 */
1169void DeviceManager::DeviceThread::ResetProperties(void)
1170{
1171 wxWindow* mainFrame = ((MyApp*)wxTheApp)->GetMainFrame();
1172 PropertyServer* props = ((MainFrame*)mainFrame)->GetPropertyServer();
1173
1174 props->ClearProperties();
1175 props->SetDefaultProperties();
1176}
1177
1178
1179#if 0
1180/*
1181 * Return true if the executable found is newer than
1182 * what is currently running
1183 */
1184bool DeviceManager::DeviceThread::IsRuntimeNew(void)
1185{
1186 if (mLastModified == 0) {
1187 /*
1188 * Haven't called UpdateLastModified yet, or called it but
1189 * couldn't stat() the executable.
1190 */
1191 return false;
1192 }
1193
1194 struct stat status;
1195 if (stat(mRuntimeExe.ToAscii(), &status) == 0) {
1196 return (status.st_mtime > mLastModified);
1197 } else {
1198 // doesn't exist, so it can't be newer
1199 fprintf(stderr, "Sim: unable to stat '%s': %s\n",
1200 (const char*) mRuntimeExe.ToAscii(), strerror(errno));
1201 return false;
1202 }
1203}
1204
1205/*
1206 * Updates mLastModified to reflect the current executables mtime
1207 */
1208void DeviceManager::DeviceThread::UpdateLastModified(void)
1209{
1210 struct stat status;
1211 if (stat(mRuntimeExe.ToAscii(), &status) == 0) {
1212 mLastModified = status.st_mtime;
1213 } else {
1214 fprintf(stderr, "Sim: unable to stat '%s': %s\n",
1215 (const char*) mRuntimeExe.ToAscii(), strerror(errno));
1216 mLastModified = 0;
1217 }
1218}
1219#endif
1220