Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   package hudson.plugins.android_emulator;
   
   
   import  hudson.EnvVars;
   import  hudson.Extension;
   import  hudson.FilePath;
   import  hudson.Launcher;
   import  hudson.Proc;
   import  hudson.Util;
  import  hudson.Launcher.ProcStarter;
  import  hudson.model.AbstractBuild;
  import  hudson.model.AbstractProject;
  import  hudson.model.BuildListener;
  import  hudson.model.Computer;
  import  hudson.model.Hudson;
  import  hudson.model.Result;
  import  hudson.model.TaskListener;
  import  hudson.tasks.BuildWrapper;
  import  hudson.tasks.BuildWrapperDescriptor;
  import  hudson.util.ArgumentListBuilder;
  import  hudson.util.FormValidation;
  
  import java.io.File;
  import java.net.Socket;
  import java.util.Map;
  
  
  import  org.jvnet.hudson.plugins.port_allocator.PortAllocationManager;
  
  public class AndroidEmulator extends BuildWrapper implements Serializable {
  
      private static final long serialVersionUID = 1L;

    
Duration by which the emulator should start being available via adb.
  
      private static final int ADB_CONNECT_TIMEOUT_MS = 60 * 1000;

    
Duration by which emulator booting should normally complete.
  
      private static final int BOOT_COMPLETE_TIMEOUT_MS = 120 * 1000;
  
      private DescriptorImpl descriptor;
  
      private final String avdName;
      private final String osVersion;
      private final String screenDensity;
      private final String screenResolution;
      private final String deviceLocale;
      private final String sdCardSize;
      private final boolean wipeData;
      private final boolean showWindow;
      private final String commandLineOptions;
      private final int startupDelay;
  
      public AndroidEmulator(String avdNameString osVersionString screenDensity,
              String screenResolutionString deviceLocaleString sdCardSizeboolean wipeData,
              boolean showWindowString commandLineOptionsint startupDelay) {
          this. = avdName;
          this. = osVersion;
          this. = screenDensity;
          this. = screenResolution;
          this. = deviceLocale;
          this. = sdCardSize;
          this. = wipeData;
          this. = showWindow;
          this. = commandLineOptions;
          this. = Math.abs(startupDelay);
      }
  
      public boolean getUseNamedEmulator() {
          return  != null;
      }
  
      public String getOsVersion() {
          return ;
      }
  
      public String getAvdName() {
          return ;
      }
  
      public String getScreenDensity() {
          return ;
      }
  
     public String getScreenResolution() {
         return ;
     }
 
     public String getDeviceLocale() {
         return ;
     }
 
     public String getSdCardSize() {
         return ;
     }
 
     public boolean shouldWipeData() {
         return ;
     }
 
     public boolean shouldShowWindow() {
         return ;
     }
 
     public String getCommandLineOptions() {
         return ;
     }
 
     public int getStartupDelay() {
         return ;
     }
 
     @Override
     @SuppressWarnings("unchecked")
     public Environment setUp(AbstractBuild buildfinal Launcher launcher, BuildListener listener)
             throws IOExceptionInterruptedException {
         final PrintStream logger = listener.getLogger();
         if ( == null) {
              = Hudson.getInstance().getDescriptorByType(DescriptorImpl.class);
         }
 
         // Substitute environment and build variables into config
         final EnvVars localVars = Computer.currentComputer().getEnvironment();
         final EnvVars envVars = new EnvVars(localVars);
         envVars.putAll(build.getEnvironment(listener));
         final Map<StringStringbuildVars = build.getBuildVariables();
 
         // Device properties
         String avdName = expandVariables(envVarsbuildVarsthis.);
         String osVersion = expandVariables(envVarsbuildVarsthis.);
         String screenDensity = expandVariables(envVarsbuildVarsthis.);
         String screenResolution = expandVariables(envVarsbuildVarsthis.);
         String deviceLocale = expandVariables(envVarsbuildVarsthis.);
         String sdCardSize = expandVariables(envVarsbuildVarsthis.);
 
         // Emulator properties
         String commandLineOptions = expandVariables(envVarsbuildVarsthis.);
 
         // SDK location
         String androidHome = expandVariables(envVarsbuildVars.);
         androidHome = discoverAndroidHome(launcherlocalVarsandroidHome);
 
         // Despite the nice inline checks and warnings when the user is editing the config,
         // these are not binding, so the user may have saved invalid configuration.
         // Here we check whether or not it's worth proceeding based on the saved values.
         String configError = isConfigValid(avdNameosVersionscreenDensityscreenResolution,
                 deviceLocalesdCardSize);
         if (configError != null) {
             log(logger, Messages.ERROR_MISCONFIGURED(configError));
             build.setResult(Result.NOT_BUILT);
             return null;
         }
 
         // Confirm that tools are available on PATH
         AndroidSdk androidSdk = new AndroidSdk(androidHome);
         if (androidHome == null) {
             if (!validateAndroidToolsInPath(launcher)) {
                 log(logger, Messages.SDK_TOOLS_NOT_FOUND());
                 build.setResult(Result.NOT_BUILT);
                 return null;
             }
         } else {
             // Determine SDK type, if tools aren't on the PATH
             boolean usesPlatformTools = sdkUsesPlatformTools(launcherandroidSdk);
             androidSdk.setUsesPlatformTools(usesPlatformTools);
         }
 
         // Ok, everything looks good.. let's go
         String displayHome = androidSdk.hasKnownRoot() ? androidSdk.getSdkRoot() : Messages.USING_PATH();
         log(logger, Messages.USING_SDK(displayHome));
         EmulatorConfig emuConfig = EmulatorConfig.create(avdNameosVersionscreenDensity,
                 screenResolutiondeviceLocalesdCardSizecommandLineOptions);
 
         return doSetUp(buildlauncherlistenerandroidSdkemuConfig);
     }
 
     private Environment doSetUp(final AbstractBuild<?, ?> buildfinal Launcher launcher,
             final BuildListener listenerfinal AndroidSdk androidSdkfinal EmulatorConfig emuConfig)
                 throws IOExceptionInterruptedException {
         final PrintStream logger = listener.getLogger();
         final boolean isUnix = launcher.isUnix();
 
         // First ensure that emulator exists
         final Computer computer = Computer.currentComputer();
         final boolean emulatorAlreadyExists;
         try {
             Callable<BooleanAndroidEmulatorExceptiontask = emuConfig.getEmulatorCreationTask(androidSdkisUnixlistener);
             emulatorAlreadyExists = launcher.getChannel().call(task);
         } catch (EmulatorDiscoveryException ex) {
             log(logger, Messages.CANNOT_START_EMULATOR(ex.getMessage()));
             build.setResult(Result.FAILURE);
             return null;
         } catch (AndroidEmulatorException ex) {
             log(logger, Messages.COULD_NOT_CREATE_EMULATOR(ex.getMessage()));
             build.setResult(Result.NOT_BUILT);
             return null;
         }
 
         // Delay start up by the configured amount of time
         final int delaySecs = getStartupDelay();
         if (delaySecs > 0) {
             log(logger, Messages.DELAYING_START_UP(delaySecs));
             Thread.sleep(delaySecs * 1000);
         }
 
         // Use the Port Allocator plugin to reserve the two ports we need
         final PortAllocationManager portAllocator = PortAllocationManager.getManager(computer);
         final int userPort = portAllocator.allocateRandom(build, 0);
         final int adbPort = portAllocator.allocateRandom(build, 0);
 
         // Compile complete command for starting emulator
         final String avdArgs = emuConfig.getCommandArguments();
         String emulatorArgs = String.format("-ports %s,%s %s"userPortadbPortavdArgs);
         ArgumentListBuilder emulatorCmd = Utils.getToolCommand(androidSdkisUnix.emulatorArgs);
 
         // Start emulator process
         log(logger, Messages.STARTING_EMULATOR());
         if (emulatorAlreadyExists && emuConfig.shouldWipeData()) {
             log(logger, Messages.ERASING_EXISTING_EMULATOR_DATA());
         }
         final long bootTime = System.currentTimeMillis();
         final EnvVars buildEnvironment = build.getEnvironment(TaskListener.NULL);
         final ProcStarter procStarter = launcher.launch().stdout(logger).stderr(logger);
         final Proc emulatorProcess = procStarter.envs(buildEnvironment).cmds(emulatorCmd).start();
 
         // Wait for TCP socket to become available
         boolean socket = waitForSocket(launcheradbPort);
         if (!socket || !emulatorProcess.isAlive()) {
             log(logger, Messages.EMULATOR_DID_NOT_START());
             build.setResult(Result.NOT_BUILT);
             cleanUp(loggerportAllocatoremulatorProcessadbPortuserPort);
             return null;
         }
 
         // Notify adb of our existence
         final String adbConnectArgs = "connect localhost:"adbPort;
         ArgumentListBuilder adbConnectCmd = Utils.getToolCommand(androidSdkisUnix.adbConnectArgs);
         int result = procStarter.cmds(adbConnectCmd).stdout(new NullOutputStream()).start().join();
         if (result != 0) { // adb currently only ever returns 0!
             log(logger, Messages.CANNOT_CONNECT_TO_EMULATOR());
             build.setResult(Result.NOT_BUILT);
             cleanUp(loggerportAllocatoremulatorProcessadbPortuserPort);
             return null;
         }
 
         // Start dumping logs to disk
         final File artifactsDir = build.getArtifactsDir();
         final FilePath logcatFile = build.getWorkspace().createTempFile("logcat_"".log");
         final OutputStream logcatStream = logcatFile.write();
         final String logcatArgs = "-s localhost:"adbPort +" logcat -v time";
         ArgumentListBuilder logcatCmd = Utils.getToolCommand(androidSdkisUnix.logcatArgs);
         final Proc logWriter = procStarter.cmds(logcatCmd).stdout(logcatStream).stderr(new NullOutputStream()).start();
 
         // Monitor device for boot completion signal
         log(logger, Messages.WAITING_FOR_BOOT_COMPLETION());
         int bootTimeout = ;
         if (!emulatorAlreadyExists || emuConfig.shouldWipeData()) {
             bootTimeout *= 4;
         }
         boolean bootSucceeded = waitForBootCompletion(loggerlauncherandroidSdkadbPortbootTimeout);
         if (!bootSucceeded) {
             log(logger, Messages.BOOT_COMPLETION_TIMED_OUT(bootTimeout / 1000));
             build.setResult(Result.NOT_BUILT);
             cleanUp(loggerlauncherandroidSdkportAllocatoremulatorProcess,
                     adbPortuserPortlogWriterlogcatFilelogcatStreamartifactsDir);
             return null;
         }
 
         // Unlock emulator by pressing the Menu key once, if required.
         // Upon first boot (and when the data is wiped) the emulator is already unlocked
         if (emulatorAlreadyExists && !) {
             // Even if the emulator has started, we generally need to wait longer before the lock
             // screen is up and ready to accept key presses.
             // The delay here is a function of boot time, i.e. relative to the slowness of the host
             final long bootDuration = System.currentTimeMillis() - bootTime;
             Thread.sleep(bootDuration / 4);
 
             log(logger, Messages.UNLOCKING_SCREEN());
             final String keyEventArgs = String.format("-s localhost:%d shell input keyevent %%d"adbPort);
             final String menuArgs = String.format(keyEventArgs, 82);
             ArgumentListBuilder menuCmd = Utils.getToolCommand(androidSdkisUnix.menuArgs);
             procStarter.cmds(menuCmd).start().join();
 
             // If a named emulator already existed, it may not have been booted yet, so the screen
             // wouldn't be locked.  In this case, after pressing Menu, we press Back to compensate
             if (emuConfig.isNamedEmulator()) {
                 final String backArgs = String.format(keyEventArgs, 4);
                 ArgumentListBuilder backCmd = Utils.getToolCommand(androidSdkisUnix.backArgs);
                 procStarter.cmds(backCmd).start().join();
             }
         }
 
         // Done!
         final long bootCompleteTime = System.currentTimeMillis();
         log(logger, Messages.EMULATOR_IS_READY((bootCompleteTime - bootTime) / 1000));
 
         // Return wrapped environment
         return new Environment() {
             @Override
             public void buildEnvVars(Map<StringStringenv) {
                 env.put("ANDROID_AVD_DEVICE""localhost:"adbPort);
                 env.put("ANDROID_AVD_ADB_PORT", Integer.toString(adbPort));
                 env.put("ANDROID_AVD_USER_PORT", Integer.toString(userPort));
                 env.put("ANDROID_AVD_NAME"emuConfig.getAvdName());
                 if (!emuConfig.isNamedEmulator()) {
                     env.put("ANDROID_AVD_OS"emuConfig.getOsVersion().toString());
                     env.put("ANDROID_AVD_DENSITY"emuConfig.getScreenDensity().toString());
                     env.put("ANDROID_AVD_RESOLUTION"emuConfig.getScreenResolution().toString());
                     env.put("ANDROID_AVD_SKIN"emuConfig.getScreenResolution().getSkinName());
                     env.put("ANDROID_AVD_LOCALE"emuConfig.getDeviceLocale());
                 }
             }
 
             @Override
             @SuppressWarnings("unchecked")
             public boolean tearDown(AbstractBuild build, BuildListener listener)
                     throws IOExceptionInterruptedException {
                 cleanUp(loggerlauncherandroidSdkportAllocatoremulatorProcess,
                         adbPortuserPortlogWriterlogcatFilelogcatStreamartifactsDir);
 
                 return true;
             }
         };
     }

    
Helper method for writing to the build log in a consistent manner.
 
     synchronized static void log(final PrintStream loggerfinal String message) {
         log(loggermessagefalse);
     }

    
Helper method for writing to the build log in a consistent manner.
 
     synchronized static void log(final PrintStream loggerString messageboolean indent) {
         if (indent) {
             message = '\t' + message.replace("\n""\n\t");
         } else {
             logger.print("[android] ");
         }
         logger.println(message);
     }

    
Called when this wrapper needs to exit, so we need to clean up some processes etc.

Parameters:
logger The build logger.
portAllocator The port allocator used.
emulatorProcess The Android emulator process.
adbPort The ADB port used by the emulator.
userPort The user port used by the emulator.
 
     private void cleanUp(PrintStream logger, PortAllocationManager portAllocator,
             Proc emulatorProcessint adbPortint userPortthrows IOExceptionInterruptedException {
         cleanUp(loggernullnullportAllocatoremulatorProcessadbPortuserPortnullnullnullnull);
     }

    
Called when this wrapper needs to exit, so we need to clean up some processes etc.

Parameters:
logger The build logger.
launcher The launcher for the remote node.
androidSdk The Android SDK being used.
portAllocator The port allocator used.
emulatorProcess The Android emulator process.
adbPort The ADB port used by the emulator.
userPort The user port used by the emulator.
logcatProcess The adb logcat process.
logcatFile The file the logcat output is being written to.
logcatStream The stream the logcat output is being written to.
artifactsDir The directory where build artifacts should go.
 
     private void cleanUp(PrintStream logger, Launcher launcherAndroidSdk androidSdk,
             PortAllocationManager portAllocator, Proc emulatorProcessint adbPort,
             int userPort, Proc logcatProcess, FilePath logcatFile,
             OutputStream logcatStreamFile artifactsDir)
                 throws IOExceptionInterruptedException {
         // FIXME: Sometimes on Windows neither the emulator.exe nor the adb.exe processes die.
         //        Launcher.kill(EnvVars) does not appear to help either.
         //        This is (a) inconsistent; (b) very annoying.
 
         // Disconnect emulator from adb, if it's running
         if (launcher != null) {
             final String args = "disconnect localhost:"adbPort;
             ArgumentListBuilder adbDisconnectCmd = Utils.getToolCommand(androidSdklauncher.isUnix(), .args);
             final ProcStarter procStarter = launcher.launch().stderr(logger);
             procStarter.cmds(adbDisconnectCmd).stdout(new NullOutputStream()).start().join();
         }
 
         // Stop emulator process
         log(logger, Messages.STOPPING_EMULATOR());
         if (logcatProcess != null) {
             sendEmulatorCommand(launcherloggeruserPort"kill");
             if (logcatProcess.isAlive()) {
                 logcatProcess.kill();
             }
             logcatStream.close();
 
             // Archive the logs
             if (logcatFile.length() != 0) {
                 log(logger, Messages.ARCHIVING_LOG());
                 logcatFile.copyTo(new FilePath(artifactsDir).child("logcat.txt"));
             }
             logcatFile.delete();
         }
 
         // Ensure the process is dead and free up the TCP ports
         if (emulatorProcess.isAlive()) {
             emulatorProcess.kill();
         }
         portAllocator.free(adbPort);
         portAllocator.free(userPort);
     }

    
Expands the variable in the given string to its value in the environment variables available to this build. The Hudson-specific build variables for this build are then substituted.

Parameters:
envVars Map of the environment variables.
buildVars Map of the build-specific variables.
token The token which may or may not contain variables in the format ${foo}.
Returns:
The given token, with applicable variable expansions done.
 
     private String expandVariables(EnvVars envVarsMap<String,StringbuildVars,
             String token) {
         String result = Util.fixEmptyAndTrim(token);
         if (result != null) {
             result = Util.replaceMacro(Util.replaceMacro(resultenvVars), buildVars);
         }
         return result;
     }

    
Validates this instance's configuration.

Returns:
A human-readable error message, or null if the config is valid.
 
     private String isConfigValid(String avdNameString osVersionString screenDensity,
             String screenResolutionString deviceLocaleString sdCardSize) {
         if (getUseNamedEmulator()) {
             ValidationResult result = .doCheckAvdName(avdNamefalse);
             if (result.isFatal()) {
                 return result.getMessage();
             }
         } else {
             ValidationResult result = .doCheckOsVersion(osVersionfalse);
             if (result.isFatal()) {
                 return result.getMessage();
             }
             result = .doCheckScreenDensity(screenDensityfalse);
             if (result.isFatal()) {
                 return result.getMessage();
             }
             result = .doCheckScreenResolution(screenResolutionnullfalse);
             if (result.isFatal()) {
                 return result.getMessage();
             }
             result = .doCheckDeviceLocale(deviceLocalefalse);
             if (result.isFatal()) {
                 return result.getMessage();
             }
             result = .doCheckSdCardSize(sdCardSizefalse);
             if (result.isFatal()) {
                 return result.getMessage();
             }
         }
 
         return null;
     }

    
Tries to validate the given Android SDK root directory; otherwise tries to locate a copy of the SDK by checking for common environment variables.

Parameters:
launcher The launcher for the remote node.
envVars Environment variables for the build.
androidHome The (variable-expanded) SDK root given in global config.
Returns:
Either a discovered SDK path or, if all else fails, the given androidHome value.
 
     private String discoverAndroidHome(final Launcher launcherfinal EnvVars envVars,
             final String androidHome) {
         Callable<StringInterruptedExceptiontask = new Callable<StringInterruptedException>() {
             public String call() throws InterruptedException {
                 // Verify existence of provided value
                 if (validateHomeDir(androidHome)) {
                     return androidHome;
                 }
 
                 // Check for common environment variables
                 String[] keys = { "ANDROID_SDK_ROOT""ANDROID_SDK_HOME",
                                   "ANDROID_HOME""ANDROID_SDK" };
                 for (String key : keys) {
                     String home = envVars.get(key);
                     if (validateHomeDir(home)) {
                         return home;
                     }
                 }
 
                 // Give up
                 return null;
             }
 
             private boolean validateHomeDir(String dir) {
                 if (Util.fixEmptyAndTrim(dir) == null) {
                     return false;
                 }
                 return !.doCheckAndroidHome(new File(dir), false).isFatal();
             }
 
             private static final long serialVersionUID = 1L;
         };
 
         String result = androidHome;
         try {
             result = launcher.getChannel().call(task);
         } catch (InterruptedException e) {
             // Ignore; will return default value
         } catch (IOException e) {
             // Ignore; will return default value
         }
         return result;
     }

    
Validates whether the required SDK tools can be found on the PATH.

Parameters:
launcher The launcher for the remote node.
Returns:
true if all the required tools are available.
 
     private boolean validateAndroidToolsInPath(Launcher launcher) {
         final boolean isUnix = launcher.isUnix();
 
         Callable<BooleanIOExceptiontask = new Callable<BooleanIOException>() {
             public Boolean call() throws IOException {
                 // Get list of required tools when working from PATH
                 Tool[] tools = { .. };
 
                 // Examine each directory specified by the PATH environment variable.
                 int toolCount = 0;
                 String[] paths = System.getenv("PATH").split(.);
                 for (String path : paths) {
                     File toolsDirectory = new File(path);
                     if (toolsDirectory.isDirectory()) {
                         for (Tool tool : tools) {
                             String executable = tool.getExecutable(isUnix);
                             if (new File(toolsDirectoryexecutable).exists()) {
                                 toolCount++;
                             }
                         }
                     }
                     if (toolCount == tools.length) {
                         return true;
                     }
                 }
 
                 return false;
             }
             private static final long serialVersionUID = 1L;
         };
 
         try {
             return launcher.getChannel().call(task);
         } catch (IOException e) {
             // Ignore
         } catch (InterruptedException e) {
             // Ignore
         }
         return false;
     }

    
Determines where platform tools are stored for the given SDK instance.

Parameters:
launcher The launcher for the remote node.
androidHome The SDK we are going to use.
 
     private boolean sdkUsesPlatformTools(Launcher launcherfinal AndroidSdk androidSdk) {
         Callable<BooleanIOExceptiontask = new Callable<BooleanIOException>() {
             public Boolean call() throws IOException {
                 File toolsDirectory = new File(androidSdk.getSdkRoot(), "platform-tools");
                 return toolsDirectory.isDirectory();
             }
             private static final long serialVersionUID = 1L;
         };
 
         try {
             return launcher.getChannel().call(task);
         } catch (IOException e) {
             // Ignore
         } catch (InterruptedException e) {
             // Ignore
         }
 
         return false;
     }

    
Waits for a socket on the remote machine's localhost to become available, or times out.

Parameters:
launcher The launcher for the remote node.
port The port to try and connect to.
timeout How long to keep trying (in milliseconds) before giving up.
Returns:
true if the socket was available, false if we timed-out.
 
     private boolean waitForSocket(Launcher launcherint portint timeout) {
         try {
             LocalPortOpenTask task = new LocalPortOpenTask(porttimeout);
             return launcher.getChannel().call(task);
         } catch (InterruptedException ex) {
             // Ignore
         } catch (IOException e) {
             // Ignore
         }
 
         return false;
     }

    
Checks whether the emulator running on the given port has finished booting yet, or times out.

Parameters:
logger The build logger.
launcher The launcher for the remote node.
androidHome The Android SDK root.
port The emulator's ADB port.
timeout How long to keep trying (in milliseconds) before giving up.
Returns:
true if the emulator has booted, false if we timed-out.
 
     private boolean waitForBootCompletion(final PrintStream loggerfinal Launcher launcher,
             final AndroidSdk androidSdkfinal int portfinal int timeout) {
         long start = System.currentTimeMillis();
         int sleep = timeout / (int) Math.sqrt(timeout / 1000);
 
         final String serialNo = "localhost:"port;
         final String args = "-s "serialNo +" shell getprop dev.bootcomplete";
         ArgumentListBuilder cmd = Utils.getToolCommand(androidSdklauncher.isUnix(), .args);
 
         try {
             while (System.currentTimeMillis() < start + timeout) {
                 ByteArrayOutputStream stream = new ByteArrayOutputStream(4);
 
                 // Run "getprop"
                 launcher.launch().cmds(cmd).stdout(stream).start().join();
 
                 // Check output
                 String result = stream.toString().trim();
                 if (result.equals("1")) {
                     return true;
                 }
 
                 // Otherwise continue...
                 Thread.sleep(sleep);
             }
         } catch (InterruptedException ex) {
             log(logger, Messages.INTERRUPTED_DURING_BOOT_COMPLETION());
         } catch (IOException ex) {
             log(logger, Messages.COULD_NOT_CHECK_BOOT_COMPLETION());
             ex.printStackTrace(logger);
         }
 
         return false;
     }

    
Sends a user command to the running emulator via its telnet interface.

Parameters:
logger The build logger.
launcher The launcher for the remote node.
port The emulator's telnet port.
command The command to execute on the emulator's telnet interface.
Returns:
Whether sending the command succeeded.
 
     private boolean sendEmulatorCommand(final Launcher launcherfinal PrintStream logger,
             final int portfinal String command) {
         Callable<BooleanIOExceptiontask = new Callable<BooleanIOException>() {
             @Override
             public Boolean call() throws IOException {
                 Socket socket = null;
                 BufferedReader in = null;
                 PrintWriter out = null;
                 try {
                     socket = new Socket("127.0.0.1"port);
                     out = new PrintWriter(socket.getOutputStream(), true);
                     in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                     if (in.readLine() == null) {
                         return false;
                     }
 
                     out.write(command);
                     out.write("\r\n");
                 } finally {
                     try {
                         out.close();
                         in.close();
                         socket.close();
                     } catch (Exception e) {
                         // Buh
                     }
                 }
 
                 return true;
             }
 
             private static final long serialVersionUID = 1L;
         };
 
         boolean result = false;
         try {
             result = launcher.getChannel().call(task);
         } catch (Exception e) {
             log(logger, String.format("Failed to execute emulator command '%s': %s"commande));
         }
 
         return result;
     }
 
     @Extension(ordinal=-100) // Negative ordinal makes us execute after other wrappers (i.e. Xvnc)
     public static final class DescriptorImpl extends BuildWrapperDescriptor implements Serializable {
 
         private static final long serialVersionUID = 1L;
 
         // From hudson.Util.VARIABLE
         private static final String VARIABLE_REGEX = "\\$([A-Za-z0-9_]+|\\{[A-Za-z0-9_]+\\}|\\$)";

        
The Android SDK home directory. Can include variables, e.g. ${ANDROID_HOME}.

If null, we will just assume the required commands are on the PATH.

 
         public String androidHome;
 
         public DescriptorImpl() {
             super(AndroidEmulator.class);
             load();
         }
 
         @Override
         public String getDisplayName() {
             return Messages.JOB_DESCRIPTION();
         }
 
         @Override
         public boolean configure(StaplerRequest reqJSONObject jsonthrows FormException {
             req.bindParameters(this"android-emulator.");
             save();
             return true;
         }
 
         @Override
         public BuildWrapper newInstance(StaplerRequest reqJSONObject formDatathrows FormException {
             String avdName = null;
             String osVersion = null;
             String screenDensity = null;
             String screenResolution = null;
             String deviceLocale = null;
             String sdCardSize = null;
             boolean wipeData = false;
             boolean showWindow = true;
             String commandLineOptions = null;
             int startupDelay = 0;
 
             JSONObject emulatorData = formData.getJSONObject("useNamed");
             String useNamedValue = emulatorData.getString("value");
             if (Boolean.parseBoolean(useNamedValue)) {
                 avdName = Util.fixEmptyAndTrim(emulatorData.getString("avdName"));
             } else {
                 osVersion = Util.fixEmptyAndTrim(emulatorData.getString("osVersion"));
                 screenDensity = Util.fixEmptyAndTrim(emulatorData.getString("screenDensity"));
                 screenResolution = Util.fixEmptyAndTrim(emulatorData.getString("screenResolution"));
                 deviceLocale = Util.fixEmptyAndTrim(emulatorData.getString("deviceLocale"));
                 sdCardSize = Util.fixEmptyAndTrim(emulatorData.getString("sdCardSize"));
                 if (sdCardSize != null) {
                     sdCardSize = sdCardSize.toUpperCase().replaceAll("[ B]""");
                 }
             }
             wipeData = formData.getBoolean("wipeData");
             showWindow = formData.getBoolean("showWindow");
             commandLineOptions = formData.getString("commandLineOptions");
             try {
                 startupDelay = Integer.parseInt(formData.getString("startupDelay"));
             } catch (NumberFormatException e) {}
 
             return new AndroidEmulator(avdNameosVersionscreenDensityscreenResolution,
                     deviceLocalesdCardSizewipeDatashowWindowcommandLineOptionsstartupDelay);
         }
 
         @Override
         public String getHelpFile() {
             return "/plugin/android-emulator/help-buildConfig.html";
         }
 
         @Override
         public boolean isApplicable(AbstractProject<?, ?> item) {
             return true;
         }

        
Used in config.jelly: Lists the OS versions available.
 
         public AndroidPlatform[] getAndroidVersions() {
            return .;
         }

        
Used in config.jelly: Lists the screen densities available.
 
         public ScreenDensity[] getDeviceDensities() {
             return .;
         }

        
Used in config.jelly: Lists the screen resolutions available.
 
         public ScreenResolution[] getDeviceResolutions() {
             return .;
         }

        
Used in config.jelly: Lists the locales available.
 
         public String[] getEmulatorLocales() {
             return .;
         }
 
         public FormValidation doCheckAvdName(@QueryParameter String value) {
             return doCheckAvdName(valuetrue).getFormValidation();
         }
 
         private ValidationResult doCheckAvdName(String avdNameboolean allowVariables) {
             if (avdName == null || avdName.equals("")) {
                 return ValidationResult.error(Messages.AVD_NAME_REQUIRED());
             }
             String regex = .;
             if (allowVariables) {
                 regex = "((". +")*(" +")*)+";
             }
             if (!avdName.matches(regex)) {
                 return ValidationResult.error(Messages.INVALID_AVD_NAME());
             }
 
             return ValidationResult.ok();
 
         }
 
         public FormValidation doCheckOsVersion(@QueryParameter String value) {
             return doCheckOsVersion(valuetrue).getFormValidation();
         }
 
         private ValidationResult doCheckOsVersion(String osVersionboolean allowVariables) {
             if (osVersion == null || osVersion.equals("")) {
                 return ValidationResult.error(Messages.OS_VERSION_REQUIRED());
             }
             if (!allowVariables && osVersion.matches()) {
                 return ValidationResult.error(Messages.INVALID_OS_VERSION());
             }
 
             return ValidationResult.ok();
         }
 
         public FormValidation doCheckScreenDensity(@QueryParameter String value) {
             return doCheckScreenDensity(valuetrue).getFormValidation();
         }
 
         private ValidationResult doCheckScreenDensity(String densityboolean allowVariables) {
             if (density == null || density.equals("")) {
                 return ValidationResult.error(Messages.SCREEN_DENSITY_REQUIRED());
             }
             String regex = .;
             if (allowVariables) {
                 regex += "|";
             }
             if (!density.matches(regex)) {
                 return ValidationResult.error(Messages.SCREEN_DENSITY_NOT_NUMERIC());
             }
 
             return ValidationResult.ok();
         }
 
         public FormValidation doCheckScreenResolution(@QueryParameter String value,
                 @QueryParameter String density) {
             return doCheckScreenResolution(valuedensitytrue).getFormValidation();
         }
 
         private ValidationResult doCheckScreenResolution(String resolutionString density,
                 boolean allowVariables) {
             if (resolution == null || resolution.equals("")) {
                 return ValidationResult.error(Messages.SCREEN_RESOLUTION_REQUIRED());
             }
             String regex = .;
             if (allowVariables) {
                 regex += "|";
             }
             if (!resolution.matches(regex)) {
                 return ValidationResult.error(Messages.INVALID_RESOLUTION_FORMAT());
             }
 
             // Check for shenanigans
             ScreenResolution resolutionValue = ScreenResolution.valueOf(resolution);
             ScreenDensity densityValue = ScreenDensity.valueOf(density);
             if (resolutionValue != null && densityValue != null
                     && !resolutionValue.isCustomResolution() && !densityValue.isCustomDensity()) {
                 boolean densityFound = false;
                 for (ScreenDensity okDensity : resolutionValue.getApplicableDensities()) {
                     if (okDensity.equals(densityValue)) {
                         densityFound = true;
                         break;
                     }
                 }
                 if (!densityFound) {
                     return ValidationResult.warning(Messages.SUSPECT_RESOLUTION(resolutiondensityValue));
                 }
             }
 
             return ValidationResult.ok();
         }
 
         public FormValidation doCheckDeviceLocale(@QueryParameter String value) {
             return doCheckDeviceLocale(valuetrue).getFormValidation();
         }
 
         private ValidationResult doCheckDeviceLocale(String localeboolean allowVariables) {
             if (locale == null || locale.equals("")) {
                 return ValidationResult.warning(Messages.DEFAULT_LOCALE_WARNING(.));
             }
             String regex = .;
             if (allowVariables) {
                 regex += "|";
             }
             if (!locale.matches(regex)) {
                 return ValidationResult.error(Messages.LOCALE_FORMAT_WARNING());
             }
 
             return ValidationResult.ok();
         }
 
         public FormValidation doCheckSdCardSize(@QueryParameter String value) {
             return doCheckSdCardSize(valuetrue).getFormValidation();
         }
 
         private ValidationResult doCheckSdCardSize(String sdCardSizeboolean allowVariables) {
             if (sdCardSize == null || sdCardSize.equals("")) {
                 // No value, no SD card is created
                 return ValidationResult.ok();
             }
             String regex = .;
             if (allowVariables) {
                 regex += "|";
             }
             if (!sdCardSize.matches(regex)) {
                 return ValidationResult.error(Messages.INVALID_SD_CARD_SIZE());
             }
 
             // Validate size of SD card: New AVD requires at least 9MB
             Matcher matcher = Pattern.compile(.).matcher(sdCardSize);
             if (matcher.matches()) {
                 long bytes = Long.parseLong(matcher.group(1));
                 if (matcher.group(2).toUpperCase().equals("M")) {
                     // Convert to KB
                     bytes *= 1024;
                 }
                 bytes *= 1024L;
                 if (bytes < (9 * 1024 * 1024)) {
                     return ValidationResult.error(Messages.SD_CARD_SIZE_TOO_SMALL());
                 }
             }
 
             return ValidationResult.ok();
         }
 
         public FormValidation doCheckAndroidHome(@QueryParameter File value) {
             return doCheckAndroidHome(valuetrue).getFormValidation();
         }
 
         private ValidationResult doCheckAndroidHome(File sdkRootboolean fromWebConfig) {
             // This can be used to check the existence of a file on the server, so needs to be protected
             if (fromWebConfig && !Hudson.getInstance().hasPermission(Hudson.ADMINISTER)) {
                 return ValidationResult.ok();
             }
 
             // Check the utter basics
             if (fromWebConfig && (sdkRoot == null || sdkRoot.getPath().equals(""))) {
                 return ValidationResult.ok();
             }
             if (!sdkRoot.isDirectory()) {
                 if (fromWebConfig && sdkRoot.getPath().matches(".*(" +").*")) {
                     return ValidationResult.ok();
                 }
                 return ValidationResult.error(Messages.INVALID_DIRECTORY());
             }
 
             // We'll be using items from the tools and platforms directories.
             // Ignore that "platform-tools" may also be required for newer SDKs,
             // as we'll check for the presence of the individual tools in a moment
             final String[] sdkDirectories = { "tools""platforms" };
             for (String dirName : sdkDirectories) {
                 File dir = new File(sdkRootdirName);
                 if (!dir.exists() || !dir.isDirectory()) {
                    return ValidationResult.error(Messages.INVALID_SDK_DIRECTORY());
                }
            }
            // Search the possible tool directories to ensure the tools exist
            int toolsFound = 0;
            final String[] toolDirectories = { "tools""platform-tools" };
            for (String dir : toolDirectories) {
                File toolsDir = new File(sdkRootdir);
                if (!toolsDir.isDirectory()) {
                    continue;
                }
                for (String executable : Tool.getAllExecutableVariants()) {
                    File toolPath = new File(toolsDirexecutable);
                    if (toolPath.exists() && toolPath.isFile()) {
                        toolsFound++;
                    }
                }
            }
            if (toolsFound < Tool.values().length) {
                return ValidationResult.errorWithMarkup(Messages.REQUIRED_SDK_TOOLS_NOT_FOUND());
            }
            // Give the user a nice warning (not error) if they've not downloaded any platforms yet
            File platformsDir = new File(sdkRoot"platforms");
            if (platformsDir.list().length == 0) {
                return ValidationResult.warning(Messages.SDK_PLATFORMS_EMPTY());
            }
            return ValidationResult.ok();
        }
    }

    
Task that will block until it can either connect to a port on localhost, or it times-out.
    private static final class LocalPortOpenTask implements Callable<BooleanInterruptedException> {
        private static final long serialVersionUID = 1L;
        private final int port;
        private final int timeout;

        

Parameters:
port The local TCP port to attempt to connect to.
timeout How long to keep trying (in milliseconds) before giving up.
        public LocalPortOpenTask(int portint timeout) {
            this. = port;
            this. = timeout;
        }
        public Boolean call() throws InterruptedException {
            final long start = System.currentTimeMillis();
            while (System.currentTimeMillis() < start + ) {
                try {
                    Socket socket = new Socket("127.0.0.1");
                    socket.getOutputStream();
                    socket.close();
                    return true;
                } catch (IOException ex) {
                    // Ignore
                }
                Thread.sleep(1000);
            }
            return false;
        }
    }

    
The Java equivalent of /dev/null.
    private static final class NullOutputStream extends OutputStream {
        @Override
        public void write(int bthrows IOException {
            // La la la
        }
        @Override
        public void write(byte[] bthrows IOException {
            // I can't hear you
        }
        @Override
        public void write(byte[] bint offint lenthrows IOException {
            // Nope, still can't hear you
        }
    }
New to GrepCode? Check out our FAQ X