2 // Copyright 2005 The Android Open Source Project
4 // Management of the simulated device.
7 // For compilers that support precompilation, include "wx/wx.h".
10 // Otherwise, include all standard headers
16 #include "DeviceManager.h"
18 #include "DeviceWindow.h"
19 #include "LogWindow.h"
20 #include "UserEvent.h"
21 #include "UserEventMessage.h"
23 #include "SimRuntime.h"
30 #if !defined(SIGKILL) // doesn't exist in MinGW
31 # if defined(SIGBREAK)
32 # define SIGKILL SIGBREAK // intended for Ctrl-Break
34 # define SIGKILL SIGABRT
42 DeviceManager::DeviceManager(void)
43 : mThread(NULL), mDisplay(NULL), mNumDisplays(0), mKeyMap(NULL),
46 //printf("--- DeviceManager constructor\n");
50 * Destructor. Snuff the thread if it's still kicking.
52 DeviceManager::~DeviceManager(void)
54 //printf("--- DeviceManager destructor\n");
56 if (mThread != NULL && mThread->IsRunning()) {
57 mThread->KillChildProcesses();
59 if (mThread != NULL) {
60 wxThread::ExitCode code;
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);
74 * Initialize the device configuration.
76 * "statusWindow" is where message boxes with failure messages go, usually
79 bool DeviceManager::Init(int numDisplays, wxWindow* statusWindow)
82 // fprintf(stderr, "ERROR: tried to Configure device while running\n");
85 assert(mDisplay == NULL);
86 assert(numDisplays > 0);
88 //if (mDisplay != NULL)
91 mDisplay = new Display[numDisplays];
92 mNumDisplays = numDisplays;
94 mpStatusWindow = statusWindow;
100 * Have we been initialized already?
102 bool DeviceManager::IsInitialized(void) const
104 return (mDisplay != NULL);
109 * Return the Nth display.
111 int DeviceManager::GetShmemKey(int displayIndex)
113 assert(displayIndex >= 0 && displayIndex < mNumDisplays);
114 return mDisplay[displayIndex].GetShmemKey();
119 * Define mapping between the device's display and a wxWidgets window.
121 bool DeviceManager::SetDisplayConfig(int displayIndex, wxWindow* window,
122 int width, int height, android::PixelFormat format, int refresh)
124 assert(displayIndex >= 0 && displayIndex < mNumDisplays);
126 if (!mDisplay[displayIndex].Create(displayIndex, window, width, height,
129 fprintf(stderr, "Sim: ERROR: unable to configure display %d\n",
133 printf("Sim: configured display %d (w=%d h=%d f=%d re=%d)\n",
134 displayIndex, width, height, format, refresh);
140 * Define the keyboard
142 bool DeviceManager::SetKeyboardConfig(const char *keymap) {
143 free((void*)mKeyMap);
144 mKeyMap = strdup(keymap);
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
154 void DeviceManager::WindowsClosing(void)
158 for (i = 0; i < mNumDisplays; i++)
159 mDisplay[i].Uncreate();
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.
166 bool DeviceManager::StartRuntime(void)
168 return DeviceManager::DeviceThread::LaunchProcess(mpStatusWindow);
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
176 bool DeviceManager::StartRuntime(android::Pipe* reader, android::Pipe* writer)
178 if (mThread != NULL) {
179 wxThread::ExitCode code;
181 if (mThread->IsRunning()) {
183 "Sim: ERROR: start requested, but thread running\n");
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);
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");
208 * Get the message stream. Returns NULL if it doesn't exist.
210 android::MessageStream* DeviceManager::GetStream(void)
213 fprintf(stderr, "Sim: ERROR: runtime thread not active\n");
217 assert(mThread != NULL);
218 android::MessageStream* pStream = mThread->GetStream();
219 assert(pStream != NULL);
221 if (!pStream->isReady()) {
222 fprintf(stderr, "Sim: NOTE: connection to runtime not ready\n");
230 * Stop the runtime, politely.
232 * We don't clean up the thread here, because it might not exit immediately.
234 bool DeviceManager::StopRuntime(void)
236 android::MessageStream* pStream = GetStream();
240 printf("Sim: Sending quit command\n");
242 android::Message msg;
243 msg.setCommand(android::Simulator::kCommandQuit, 0);
249 * Kill the runtime as efficiently as possible.
251 void DeviceManager::KillRuntime(void)
253 if (mThread != NULL && mThread->IsRunning())
254 mThread->KillChildProcesses();
259 * Check if the modified time is newer than mLastModified
261 bool DeviceManager::RefreshRuntime(void)
263 return (IsRunning() && mThread->IsRuntimeNew());
267 * Tells the device manager that the user does not want to update
270 void DeviceManager::UserCancelledRefresh(void)
272 mThread->UpdateLastModified();
277 * Send an event to the runtime.
279 * The events are defined in display_device.h.
281 void DeviceManager::SendKeyEvent(int32_t keyCode, bool down)
283 android::MessageStream* pStream = GetStream();
287 int event = down ? android::Simulator::kCommandKeyDown :
288 android::Simulator::kCommandKeyUp;
290 //printf("Sim: sending key-%s %d\n", down ? "down" : "up", keyCode);
292 android::Message msg;
293 msg.setCommand(event, keyCode);
298 * Send a "touch screen" event to the runtime.
300 * "mode" can be "down" (we're pressing), "up" (we're lifting our finger
303 void DeviceManager::SendTouchEvent(android::Simulator::TouchMode mode,
306 android::MessageStream* pStream = GetStream();
310 //printf("Sim: sending touch-%d x=%d y=%d\n", (int) mode, x, y);
312 android::Message msg;
313 msg.setCommandExt(android::Simulator::kCommandTouch, mode, x, y);
318 * The runtime has sent us a new frame of stuff to display.
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.
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.
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
335 void DeviceManager::ShowFrame(int displayIndex)
337 assert(displayIndex >= 0 && displayIndex < mNumDisplays);
339 // copy the data to local storage and convert
340 mDisplay[displayIndex].CopyFromShared();
342 // create a user event and send it to the window
343 UserEvent uev(0, (void*) displayIndex);
345 wxWindow* pEventWindow = mDisplay[displayIndex].GetWindow();
346 if (pEventWindow != NULL) {
347 //printf("runtime has image, passing up\n");
348 pEventWindow->AddPendingEvent(uev);
350 fprintf(stderr, "NOTE: runtime has image, display not available\n");
354 void DeviceManager::Vibrate(int vibrateOn)
356 ((MyApp*)wxTheApp)->Vibrate(vibrateOn);
360 * Get the display data from the specified display.
362 wxBitmap* DeviceManager::GetImageData(int displayIndex)
364 assert(displayIndex >= 0 && displayIndex < mNumDisplays);
365 return mDisplay[displayIndex].GetImageData();
369 * Send an event to all device windows
371 void 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);
383 * ===========================================================================
384 * DeviceManager::Display
385 * ===========================================================================
389 * Fill out the various interesting fields based on the parameters.
391 bool DeviceManager::Display::Create(int displayNum, wxWindow* window,
392 int width, int height, android::PixelFormat format, int refresh)
394 //printf("DeviceManager::Display constructor\n");
396 assert(window != NULL);
397 if (mImageData != NULL) {
398 assert(false); // no re-init
402 mDisplayNum = displayNum;
403 mDisplayWindow = window;
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))
415 //printf("--- CREATED shmem, key=0x%08x addr=%p\n",
416 // mShmemKey, mpShmem->getAddr());
418 mImageData = new unsigned char[width * height * 3];
419 if (mImageData == NULL)
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.
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.
434 void DeviceManager::Display::Uncreate(void)
436 wxMutexLocker locker(mImageDataLock);
438 //printf("--- Uncreate\n");
440 mDisplayWindow = NULL;
442 // the "locker" mutex keeps this from hosing CopyFromShared()
443 if (mpShmem != NULL) {
444 //printf("--- DELETING shmem, addr=%p\n", mpShmem->getAddr());
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.
454 void DeviceManager::Display::CopyFromShared(void)
456 wxMutexLocker locker(mImageDataLock);
458 if (mpShmem == NULL) {
459 //printf("Sim: SKIP CopyFromShared\n");
463 //printf("Display %d: copying data from %p to %p\n",
464 // mDisplayNum, mpShmem->getAddr(), mImageData);
466 /* data is always 24bpp RGB */
467 mpShmem->lock(); // avoid tearing
468 memcpy(mImageData, mpShmem->getAddr(), mWidth * mHeight * 3);
473 * Get the image data in the form of a newly-allocated bitmap.
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").
479 wxBitmap* DeviceManager::Display::GetImageData(void)
481 wxMutexLocker locker(mImageDataLock);
483 assert(mImageData != NULL);
485 //printf("HEY: creating tmpImage, w=%d h=%d data=%p\n",
486 // mWidth, mHeight, mImageData);
488 /* create a temporary wxImage; it does not own the data */
489 wxImage tmpImage(mWidth, mHeight, (unsigned char*) mImageData, true);
491 /* return a new bitmap with the converted-for-display data */
492 return new wxBitmap(tmpImage);
497 * ===========================================================================
498 * DeviceManager::DeviceThread
499 * ===========================================================================
503 * Some notes on process management under Linux/Mac OS X:
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.
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.
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.
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
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.
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
547 * Some notes on process management under Windows (Cygwin, MinGW):
549 * Signals cannot be caught or ignored under MinGW. All signals are fatal.
551 * Signals can be ignored under Cygwin, but not caught.
553 * Windows has some process group stuff (e.g. CREATE_NEW_PROCESS_GROUP flag
554 * and GenerateConsoleCtrlEvent()). Need to explore.
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.
565 * Convert a space-delimited string into an argument vector.
567 * "arg" is the current arg offset.
569 static int stringToArgv(char* mangle, const char** argv, int arg, int maxArgs)
573 while (*mangle != '\0') {
574 assert(arg < maxArgs);
576 argv[arg++] = mangle;
579 if (*mangle == ' ') {
590 * Launch the runtime process in its own terminal window. Start by setting
591 * up the argument vector to the runtime process.
593 * The last entry in the vector will be a NULL pointer.
595 * This is awkward and annoying because the wxWidgets strings are current
596 * configured for UNICODE.
598 /*static*/ bool DeviceManager::DeviceThread::LaunchProcess(wxWindow* statusWindow)
600 static const char* kLaunchWrapper = "launch-wrapper";
601 const int kMaxArgs = 64;
605 wxString debuggerExe;
606 wxString debuggerScript;
607 wxString valgrinderExe;
608 wxString launchWrapperExe;
609 wxString launchWrapperArgs;
610 wxString javaAppName;
617 bool doDebug, doValgrind, doCheckJni, doEnableSound, doEnableFakeCamera;
618 const char** argv = NULL;
620 wxCharBuffer runtimeExeTmp;
621 wxCharBuffer debuggerExeTmp;
622 wxCharBuffer debuggerScriptTmp;
623 wxCharBuffer javaAppNameTmp;
624 wxCharBuffer valgrinderExeTmp;
625 wxCharBuffer termCmdTmp;
626 wxCharBuffer launchWrapperExeTmp;
627 wxCharBuffer launchWrapperArgsTmp;
629 pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
630 if (pPrefs == NULL) {
631 errMsg = wxT("Preferences were not loaded.");
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.
640 * TODO: remove this in favor of system properties
643 // TODO: restore this
645 pPrefs->GetBool("check-jni", &doCheckJni);
649 pPrefs->GetString("ld-assume-kernel", /*ref*/ tmpStr);
650 if (tmpStr.IsEmpty()) {
651 unsetenv("LD_ASSUME_KERNEL");
653 setenv("LD_ASSUME_KERNEL", tmpStr.ToAscii(), 1);
656 doEnableSound = false;
657 pPrefs->GetBool("enable-sound", &doEnableSound);
659 setenv("ANDROIDSOUND", "1", 1);
661 doEnableFakeCamera = false;
662 pPrefs->GetBool("enable-fake-camera", &doEnableFakeCamera);
663 if (doEnableFakeCamera)
664 setenv("ANDROIDFAKECAMERA", "1", 1);
667 * Set the Dalvik bootstrap class path. Normally this is set by "init".
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",
674 * Figure out where the "runtime" binary lives.
676 runtimeExe = ((MyApp*)wxTheApp)->GetRuntimeExe();
677 assert(!runtimeExe.IsEmpty());
679 //UpdateLastModified();
684 argv = new const char*[kMaxArgs];
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.
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.
700 pPrefs->GetString("launch-command", /*ref*/ termCmd);
701 if (termCmd.IsEmpty()) {
702 fprintf(stderr, "Sim: WARNING: launch-command is empty\n");
704 termCmdTmp = termCmd.ToAscii();
705 char* mangle = strdup(termCmdTmp);
706 arg = stringToArgv(mangle, argv, arg, kMaxArgs);
710 * The "launch-wrapper" binary lives in the same place as the runtime.
711 * This sets up LD_PRELOAD and some other environment variables.
715 charIdx = runtimeExe.Find('/', true);
717 launchWrapperExe = wxString::FromAscii(kLaunchWrapper);
719 launchWrapperExe = runtimeExe.Mid(0, charIdx+1);
720 launchWrapperExe.Append(wxString::FromAscii(kLaunchWrapper));
722 printf("Sim launch wrapper: %s\n", (const char*)launchWrapperExe.ToAscii());
724 argv[arg++] = launchWrapperExeTmp = launchWrapperExe.ToAscii();
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);
735 * If we're launching under GDB or valgrind, set that up.
737 doDebug = doValgrind = false;
738 pPrefs->GetBool("debug", &doDebug);
739 if (((MyApp*)wxTheApp)->GetDebuggerOption()) {
742 debuggerScript = ((MyApp*)wxTheApp)->GetDebuggerScript();
744 pPrefs->GetBool("valgrind", &doValgrind);
745 if (doDebug || doValgrind) {
747 pPrefs->GetString("debugger", /*ref*/ debuggerExe);
748 pPrefs->GetString("valgrinder", /*ref*/ valgrinderExe);
750 // check for empty or undefined preferences
751 if (doDebug && debuggerExe.IsEmpty()) {
752 errMsg = wxT("Debugger not defined.");
755 if (doValgrind && valgrinderExe.IsEmpty()) {
756 errMsg = wxT("Valgrinder not defined.");
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
769 //mTerminalFollowsChild = true; // interactive
770 argv[arg++] = "--db-attach=yes";
774 argv[arg++] = debuggerExeTmp = debuggerExe.ToAscii();
775 if (!debuggerScript.IsEmpty()) {
777 argv[arg++] = debuggerScriptTmp = debuggerScript.ToAscii();
779 argv[arg++] = runtimeExeTmp = runtimeExe.ToAscii();
780 argv[arg++] = "--args";
788 argv[arg++] = runtimeExeTmp = (const char*) runtimeExe.ToAscii();
790 javaAppName = ((MyApp*)wxTheApp)->GetAutoRunApp();
791 if (javaAppName.IsEmpty()) {
792 if (!pPrefs->GetString("java-app-name", /*ref*/ javaAppName)) {
793 javaAppName = wxT("");
797 if (!javaAppName.IsEmpty())
800 argv[arg++] = javaAppNameTmp = (const char*) javaAppName.ToAscii();
803 if (pPrefs->GetDouble("gamma", &dval) && dval != 1.0) {
804 snprintf(gammaVal, sizeof(gammaVal), "%.3f", dval);
806 argv[arg++] = gammaVal;
812 assert(arg <= kMaxArgs);
816 for (int i = 0; i < arg; i++)
817 printf(" %d: '%s'\n", i, argv[i]);
821 execvp(argv[0], (char* const*) argv);
822 fprintf(stderr, "execvp '%s' failed: %s\n", argv[0], strerror(errno));
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.
834 tmpStr = wxT("=== launched ");
835 tmpStr += runtimeExe;
836 LogWindow::PostLogMsg(tmpStr);
838 assert(errMsg.IsEmpty());
841 if (!errMsg.IsEmpty()) {
842 assert(result == false);
844 UserEventMessage* pUem = new UserEventMessage;
845 pUem->CreateErrorMessage(errMsg);
847 UserEvent uev(0, (void*) pUem);
849 assert(statusWindow != NULL);
850 statusWindow->AddPendingEvent(uev);
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
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.
864 void* DeviceManager::DeviceThread::Entry(void)
866 //android::MessageStream stream;
867 android::Message msg;
869 char statusBuf[64] = "(no status)";
872 /* print this so we can make sense of log messages */
873 LOG(LOG_DEBUG, "", "Sim: device management thread starting (pid=%d)\n",
876 assert(mReader != NULL && mWriter != NULL);
879 * Tell the main thread that we're running. If something fails here,
880 * we'll send them a "stopped running" immediately afterward.
883 UserEventMessage* pUem = new UserEventMessage;
884 pUem->CreateRuntimeStarted();
886 UserEvent uev(0, (void*) pUem);
888 assert(mpStatusWindow != NULL);
889 mpStatusWindow->AddPendingEvent(uev);
891 LogWindow::PostLogMsg(
892 "==============================================================");
893 LogWindow::PostLogMsg("=== runtime starting");
896 * Establish contact with runtime.
898 if (!mStream.init(mReader, mWriter, true)) {
899 errMsg = wxT("ERROR: Unable to establish communication with runtime.\n");
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.
908 msg.setCommand(android::Simulator::kCommandNewPGroup, true);
911 printf("Sim: Sending hardware configuration\n");
914 * Send display config.
916 * Right now we're just shipping a big binary blob over.
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];
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();
933 msg.setRaw((const unsigned char*)buf, sizeof(buf),
934 android::Message::kCleanupNoDelete);
938 * Send other hardware config.
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").
947 msg.setConfig("keycharmap", mpDeviceManager->GetKeyMap());
953 msg.setCommand(android::Simulator::kCommandConfigDone, 0);
957 * Sit forever, waiting for messages from the runtime process.
960 if (!mStream.recv(&msg, true)) {
962 * The read failed. This usually means the child has died.
964 printf("Sim: runtime process has probably died\n");
968 if (msg.getType() == android::Message::kTypeCommand) {
971 if (!msg.getCommand(&cmd, &arg)) {
972 fprintf(stderr, "Sim: Warning: failed unpacking command\n");
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;
982 case android::Simulator::kCommandRuntimeReady:
983 // sim is up and running, do late init
985 case android::Simulator::kCommandUpdateDisplay:
986 // new frame of graphics is ready
987 //printf("RCVD display update %d\n", arg);
988 mpDeviceManager->ShowFrame(arg);
990 case android::Simulator::kCommandVibrate:
991 // vibrator on or off
992 //printf("RCVD vibrator update %d\n", arg);
993 mpDeviceManager->Vibrate(arg);
996 printf("Sim: got unknown command %d/%d\n", cmd, arg);
1000 } else if (msg.getType() == android::Message::kTypeLogBundle) {
1001 android_LogBundle bundle;
1003 if (!msg.getLogBundle(&bundle)) {
1004 fprintf(stderr, "Sim: Warning: failed unpacking logBundle\n");
1007 LogWindow::PostLogMsg(&bundle);
1010 printf("Sim: got unknown message type=%d\n", msg.getType());
1017 printf("Sim: DeviceManager thread preparing to exit\n");
1019 /* kill the comm channel; should encourage runtime to die */
1023 mReader = mWriter = NULL;
1026 * We never really did get a "friendly death" working, so just slam
1027 * the thing if we have the process group.
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);
1035 if (!errMsg.IsEmpty()) {
1036 UserEventMessage* pUem = new UserEventMessage;
1037 pUem->CreateErrorMessage(errMsg);
1039 UserEvent uev(0, (void*) pUem);
1040 mpStatusWindow->AddPendingEvent(uev);
1043 /* notify the main window that the runtime has stopped */
1045 UserEventMessage* pUem = new UserEventMessage;
1046 pUem->CreateRuntimeStopped();
1048 UserEvent uev(0, (void*) pUem);
1049 mpStatusWindow->AddPendingEvent(uev);
1052 /* show exit status in log file */
1054 exitMsg.Printf(wxT("=== runtime exiting - %s"), statusBuf);
1055 LogWindow::PostLogMsg(exitMsg);
1056 LogWindow::PostLogMsg(
1057 "==============================================================\n");
1060 * Reset system properties for future runs.
1064 return (void*) result;
1069 * Wait for a little bit to see if the thread will exit.
1071 * "delay" is in 0.1s increments.
1073 void DeviceManager::DeviceThread::WaitForDeath(int delay)
1075 const int kDelayUnit = 100000;
1078 for (i = 0; i < delay; i++) {
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.
1091 void DeviceManager::DeviceThread::KillChildProcesses(void)
1093 if (!this->IsRunning())
1096 /* clear "slow exit" flag -- we're forcefully killing this thing */
1097 //this->mSlowExit = false;
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.
1107 * For now, we just hope for the best. FIX this someday.
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.
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);
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.
1130 if (this->IsRunning()) {
1131 printf("Sim: killing comm channel\n");
1135 mReader = mWriter = NULL;
1140 * At this point it's possible that our DeviceThread is just wedged.
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.
1147 if (this->IsRunning()) {
1148 fprintf(stderr, "Sim: WARNING: killing runtime thread (%ld)\n",
1157 if (this->IsRunning()) {
1158 fprintf(stderr, "Sim: thread won't die!\n");
1164 * Configure system properties for the simulated device.
1166 * Property requests can arrive *before* the full connection to the
1167 * simulator is established, so we want to reset these during cleanup.
1169 void DeviceManager::DeviceThread::ResetProperties(void)
1171 wxWindow* mainFrame = ((MyApp*)wxTheApp)->GetMainFrame();
1172 PropertyServer* props = ((MainFrame*)mainFrame)->GetPropertyServer();
1174 props->ClearProperties();
1175 props->SetDefaultProperties();
1181 * Return true if the executable found is newer than
1182 * what is currently running
1184 bool DeviceManager::DeviceThread::IsRuntimeNew(void)
1186 if (mLastModified == 0) {
1188 * Haven't called UpdateLastModified yet, or called it but
1189 * couldn't stat() the executable.
1195 if (stat(mRuntimeExe.ToAscii(), &status) == 0) {
1196 return (status.st_mtime > mLastModified);
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));
1206 * Updates mLastModified to reflect the current executables mtime
1208 void DeviceManager::DeviceThread::UpdateLastModified(void)
1211 if (stat(mRuntimeExe.ToAscii(), &status) == 0) {
1212 mLastModified = status.st_mtime;
1214 fprintf(stderr, "Sim: unable to stat '%s': %s\n",
1215 (const char*) mRuntimeExe.ToAscii(), strerror(errno));