1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.motorola.studio.android.emulator.logic; 17 18 import static com.motorola.studio.android.common.log.StudioLogger.error; 19 import static com.motorola.studio.android.common.log.StudioLogger.info; 20 21 import java.io.IOException; 22 import java.util.Collection; 23 import java.util.LinkedList; 24 25 import org.eclipse.core.runtime.IProgressMonitor; 26 import org.eclipse.core.runtime.IStatus; 27 import org.eclipse.core.runtime.Status; 28 import org.eclipse.core.runtime.jobs.IJobChangeListener; 29 import org.eclipse.core.runtime.jobs.IJobManager; 30 import org.eclipse.core.runtime.jobs.ISchedulingRule; 31 import org.eclipse.core.runtime.jobs.Job; 32 33 import com.motorola.studio.android.adt.DDMSFacade; 34 import com.motorola.studio.android.adt.ISerialNumbered; 35 import com.motorola.studio.android.common.exception.AndroidException; 36 import com.motorola.studio.android.emulator.EmulatorPlugin; 37 import com.motorola.studio.android.emulator.core.exception.InstanceStartException; 38 import com.motorola.studio.android.emulator.core.exception.StartCancelledException; 39 import com.motorola.studio.android.emulator.core.exception.StartTimeoutException; 40 import com.motorola.studio.android.emulator.core.model.IAndroidEmulatorInstance; 41 42 /** 43 * This class contains the logic to start the VNC server on the given Emulator. 44 */ 45 public final class StartVncServerLogic implements IAndroidLogic 46 { 47 public static final String VNC_SERVER_JOB_PREFIX = "VNC Server - "; 48 49 public static final Object VNC_SERVER_JOB_FAMILY = new Object(); 50 51 /** 52 * Sequence of commands that must be executed on the emulator to start the VNC server 53 */ 54 private final Collection<String> remoteCommands = new LinkedList<String>(); 55 56 /** 57 * Collection of listeners for the job executing the VNC server. 58 */ 59 private final Collection<IJobChangeListener> listeners = new LinkedList<IJobChangeListener>(); 60 61 /** 62 * Executes the logic to start the vnc server. 63 */ 64 public void execute(final IAndroidLogicInstance instance, int timeout, 65 final IProgressMonitor monitor) throws InstanceStartException, StartTimeoutException, 66 StartCancelledException, IOException 67 { 68 cancelCurrentVncServerJobs(instance); 69 70 // Creates and starts a job that will keep running as long as the VNC server is up on that Emulator instance. 71 // add listeners that will receive notifications about the Job life-cycle. 72 VncServerJob vncServerJob = new VncServerJob(instance, getRemoteCommands()); 73 for (IJobChangeListener vncServerListener : listeners) 74 { 75 vncServerJob.addJobChangeListener(vncServerListener); 76 } 77 vncServerJob.schedule(); 78 79 } 80 81 /** 82 * Cancel any VncServerJob that is currently running the VNC server on the given emulator instance. 83 * @param instance, the emulator instances where VNC server execution must be canceled. 84 **/ 85 public static void cancelCurrentVncServerJobs(IAndroidEmulatorInstance instance) 86 { 87 // stop the previous VNC Server job for this instance if any... 88 IJobManager manager = Job.getJobManager(); 89 Job[] allVncJobs = manager.find(StartVncServerLogic.VNC_SERVER_JOB_FAMILY); 90 if (allVncJobs.length > 0) 91 { 92 for (Job job : allVncJobs) 93 { 94 if (job.getName().equals( 95 StartVncServerLogic.VNC_SERVER_JOB_PREFIX + instance.getName())) 96 { 97 info("Cancel execution of the VNC Server on " + instance); 98 job.cancel(); 99 } 100 } 101 } 102 } 103 104 /** 105 * Add job listener to receive state-change notifications from the job that runs the VNC Server. 106 * @param vncServerListener job listener that willl receive state change notifications from the VNC Serever job. 107 */ 108 public void addVncServerJobListener(IJobChangeListener vncServerListener) 109 { 110 listeners.add(vncServerListener); 111 } 112 113 /** 114 * Add a command to be executed in the process of starting the VNC Server on the Emulator. 115 * @param remoteCommand 116 */ 117 public void addRemoteCommand(String remoteCommand) 118 { 119 remoteCommands.add(remoteCommand); 120 } 121 122 /** 123 * Get the list of commands to be executed on the Emulator in order to start the VNC Server. 124 * @return the sequence of commands that must be executed on the Emulator to start the VNC Server. 125 */ 126 public Collection<String> getRemoteCommands() 127 { 128 return remoteCommands; 129 } 130 131 } 132 133 /** 134 * Job that executes the VNC Server. 135 * It will keep running as long as the VNC Server process is running on the Emulator. 136 */ 137 class VncServerJob extends Job implements ISchedulingRule 138 { 139 private String serialNumber; 140 141 /** 142 * Sequence of commands that must be executed on the emulator to start the VNC server 143 */ 144 private final Collection<String> remoteCommands; 145 146 /** 147 * Creates a new job to execute the VNC server on the given emulator instance. 148 * @param instance, emulator instance where the VNC server will be started. 149 * @param remoteCommands, sequence of commands that must be executed on the given emulator instance to start the VNC Server. 150 * @throws InstanceStartException 151 */ 152 public VncServerJob(IAndroidLogicInstance instance, Collection<String> remoteCommands) 153 throws InstanceStartException 154 { 155 super(StartVncServerLogic.VNC_SERVER_JOB_PREFIX + instance.getName()); 156 157 this.serialNumber = ((ISerialNumbered) instance).getSerialNumber(); 158 159 try 160 { 161 AndroidLogicUtils.testDeviceStatus(serialNumber); 162 } 163 catch (AndroidException e) 164 { 165 throw new InstanceStartException(e.getMessage()); 166 } 167 168 this.remoteCommands = remoteCommands; 169 setSystem(true); 170 setRule(this); 171 } 172 173 /** 174 * @see org.eclipse.core.runtime.jobs.Job#run(IProgressMonitor) 175 */ 176 @Override 177 public IStatus run(IProgressMonitor monitor) 178 { 179 IStatus status = Status.OK_STATUS; 180 try 181 { 182 info("Executing VNC Server on " + serialNumber); 183 AndroidLogicUtils.testDeviceStatus(serialNumber); 184 DDMSFacade.execRemoteApp(serialNumber, remoteCommands, monitor); 185 186 if (monitor.isCanceled()) 187 { 188 status = Status.CANCEL_STATUS; 189 } 190 } 191 catch (Exception e) 192 { 193 String errorMessage = "Error while trying to run the VNC server on " + serialNumber; 194 error(errorMessage + " " + e.getMessage()); 195 status = new Status(IStatus.CANCEL, EmulatorPlugin.PLUGIN_ID, errorMessage, e); 196 } 197 198 info("Finished the execution of the VNC Server on " + serialNumber + " with status " 199 + status); 200 201 return status; 202 } 203 204 /** 205 * @see org.eclipse.core.runtime.jobs.Job#belongsTo(Object) 206 */ 207 @Override 208 public boolean belongsTo(Object family) 209 { 210 return StartVncServerLogic.VNC_SERVER_JOB_FAMILY.equals(family); 211 } 212 213 public boolean contains(ISchedulingRule rule) 214 { 215 boolean contains = false; 216 if (rule instanceof VncServerJob) 217 { 218 VncServerJob otherVncServerJob = (VncServerJob) rule; 219 contains = otherVncServerJob.serialNumber.equals(serialNumber); 220 } 221 222 return contains; 223 } 224 225 public boolean isConflicting(ISchedulingRule rule) 226 { 227 return contains(rule); 228 } 229 } 230