/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.motorola.studio.android.emulator.logic.stop; import static com.motorola.studio.android.common.log.StudioLogger.error; import static com.motorola.studio.android.common.log.StudioLogger.info; import static com.motorola.studio.android.common.log.StudioLogger.warn; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.osgi.util.NLS; import org.eclipse.sequoyah.vnc.protocol.PluginProtocolActionDelegate; import org.eclipse.sequoyah.vnc.protocol.lib.ProtocolHandle; import org.eclipse.sequoyah.vnc.vncviewer.registry.VNCProtocolRegistry; import com.motorola.studio.android.common.utilities.EclipseUtils; import com.motorola.studio.android.emulator.i18n.EmulatorNLS; import com.motorola.studio.android.emulator.logic.AndroidLogicUtils; import com.motorola.studio.android.emulator.logic.IAndroidLogicInstance; /** * DESCRIPTION: * This class contains the business layer of the Android * Emulator stop procedure * * RESPONSIBILITY: * Stop any Android Emulator * * COLABORATORS: * None. * * USAGE: * Use the public method to stop a Android Emulator */ public class AndroidEmulatorStopper { private static Lock lock = new ReentrantReadWriteLock().writeLock(); private static final int MAX_LOCK_ATTEMPTS = 20; /** * Stops this instance, removing its viewer from Android Emulator View * * @param instance The device instance * @param force If true do not ask the user if he/she wants to proceed * @param monitor A progress monitor that will show the disposal * action progress at UI * * @return True if the instance was stopped; false if the user chose not to stop it */ public static boolean stopInstance(final IAndroidLogicInstance instance, boolean force, boolean kill, IProgressMonitor monitor) { if (instance == null) { error("Could not stop the protocol because the provided instance is null"); return false; } boolean canProceed = true; // decision whether to actually stop or not comes from user if (!force) { canProceed = EclipseUtils.showQuestionDialog(EmulatorNLS.GEN_Question, NLS.bind( EmulatorNLS.QUESTION_AndroidEmulatorStopper_StopEmulatorQuestion, instance.getName())); } if (canProceed) { int attempts = 0; boolean locked = lock.tryLock(); while (!locked && (attempts < MAX_LOCK_ATTEMPTS)) { try { Thread.sleep(125); } catch (InterruptedException e) { //Do nothing! } locked = lock.tryLock(); attempts++; } if (locked) { if (monitor == null) { monitor = new NullProgressMonitor(); } try { info("Stopping the Android Emulator instance"); monitor .beginTask(EmulatorNLS.MON_AndroidEmulatorStopper_DisposingInstance, 200); monitor.setTaskName(EmulatorNLS.MON_AndroidEmulatorStopper_DisposingInstance); // Try to stop the protocol. // // This is not critical to the stop instance procedure, but it is // desirable because the TmL's methods may do some cleanup // before returning. The loop below tries to stop for some time (and // give enough time for cleanup as well), but if TmL does not finish // in an acceptable time, the stop instance procedure continues try { info("Trying to stop the protocol"); // Try to implement a TmL independent code ProtocolHandle handle = instance.getProtocolHandle(); if (handle != null) { PluginProtocolActionDelegate.requestStopProtocol(handle); while (PluginProtocolActionDelegate.isProtocolRunning(handle)) { Thread.sleep(250); } VNCProtocolRegistry.getInstance().unregister(handle); info("Protocol stopped"); } } catch (Exception e) { error("There was an error while trying to stop the protocol"); } // Try to implement a TmL independent code instance.setProtocolHandle(null); monitor.worked(100); monitor.setTaskName(EmulatorNLS.MON_AndroidEmulatorStopper_StopVm); if (kill) { AndroidLogicUtils.kill(instance); } info("Stopped the Android Emulator instance"); } finally { monitor.done(); try { lock.unlock(); } catch (Exception e) { warn("The thread that is releasing the lock is not the one which has it."); } } } else { canProceed = false; } } return canProceed; } }