private static AndroidSdk doInstall(
      Launcher launcher, BuildListener listener, String androidSdkHome)
      throws SdkInstallationException, IOException, InterruptedException {
    // We should install the SDK on the current build machine
    Node node = Computer.currentComputer().getNode();

    // Install the SDK if required
    String androidHome;
    try {
      androidHome = installBasicSdk(listener, node).getRemote();
    } catch (IOException e) {
      throw new SdkInstallationException(Messages.SDK_DOWNLOAD_FAILED(), e);
    } catch (SdkUnavailableException e) {
      throw new SdkInstallationException(Messages.SDK_DOWNLOAD_FAILED(), e);
    }

    // Check whether we need to install the SDK components
    if (!isSdkInstallComplete(node, androidHome)) {
      PrintStream logger = listener.getLogger();
      log(logger, Messages.INSTALLING_REQUIRED_COMPONENTS());
      AndroidSdk sdk = new AndroidSdk(androidHome, androidSdkHome);
      installComponent(logger, launcher, sdk, "platform-tool", "tool");

      // If we made it this far, confirm completion by writing our our metadata file
      getInstallationInfoFilename(node).write(String.valueOf(SDK_VERSION), "UTF-8");

      // As this SDK will not be used manually, opt out of the stats gathering;
      // this also prevents the opt-in dialog from popping up during execution
      optOutOfSdkStatistics(launcher, listener, androidSdkHome);
    }

    // Create an SDK object now that all the components exist
    return Utils.getAndroidSdk(launcher, androidHome, androidSdkHome);
  }
 private static boolean isPlatformInstalled(
     PrintStream logger, Launcher launcher, AndroidSdk sdk, String platform)
     throws IOException, InterruptedException {
   ByteArrayOutputStream targetList = new ByteArrayOutputStream();
   // Preferably we'd use the "--compact" flag here, but it wasn't added until r12
   Utils.runAndroidTool(launcher, targetList, logger, sdk, Tool.ANDROID, "list target", null);
   return targetList.toString().contains('"' + platform + '"');
 }
  /**
   * Determines whether a snapshot image has already been created for this emulator.
   *
   * @throws IOException If execution of the emulator command fails.
   * @throws InterruptedException If execution of the emulator command is interrupted.
   */
  public boolean hasExistingSnapshot(Launcher launcher, AndroidSdk androidSdk)
      throws IOException, InterruptedException {
    final PrintStream logger = launcher.getListener().getLogger();

    // List available snapshots for this emulator
    ByteArrayOutputStream listOutput = new ByteArrayOutputStream();
    String args = String.format("-snapshot-list -no-window -avd %s", getAvdName());
    Utils.runAndroidTool(launcher, listOutput, logger, androidSdk, Tool.EMULATOR, args, null);

    // Check whether a Jenkins snapshot was listed in the output
    return Pattern.compile(Constants.REGEX_SNAPSHOT).matcher(listOutput.toString()).find();
  }
  /**
   * Installs the given SDK component(s) into the given installation.
   *
   * @param logger Logs things.
   * @param launcher Used to launch tasks on the remote node.
   * @param sdk Root of the SDK installation to install components for.
   * @param components Name of the component(s) to install.
   */
  private static void installComponent(
      PrintStream logger, Launcher launcher, AndroidSdk sdk, String... components)
      throws IOException, InterruptedException {
    String proxySettings = getProxySettings();

    String list = StringUtils.join(components, ',');
    log(logger, Messages.INSTALLING_SDK_COMPONENTS(list.toString()));
    String all = sdk.getSdkToolsVersion() < 17 ? "-o" : "-a";
    String upgradeArgs = String.format("update sdk -u %s %s -t %s", all, proxySettings, list);

    Utils.runAndroidTool(launcher, logger, logger, sdk, Tool.ANDROID, upgradeArgs, null);
  }
    private boolean createSdCard(File homeDir) {
      // Build command: mksdcard 32M /home/foo/.android/avd/whatever.avd/sdcard.img
      ArgumentListBuilder builder =
          Utils.getToolCommand(androidSdk, !Functions.isWindows(), Tool.MKSDCARD, null);
      builder.add(sdCardSize);
      builder.add(new File(getAvdDirectory(homeDir), "sdcard.img"));

      // Run!
      try {
        ProcessBuilder procBuilder = new ProcessBuilder(builder.toList());
        if (androidSdkHome != null) {
          procBuilder.environment().put("ANDROID_SDK_HOME", androidSdkHome);
        }
        procBuilder.start().waitFor();
      } catch (InterruptedException ex) {
        return false;
      } catch (IOException ex) {
        return false;
      }

      return true;
    }
    public Void call() throws Exception {
      if (logger == null) {
        logger = listener.getLogger();
      }

      final File homeDir = Utils.getHomeDirectory(androidSdkHome);
      final File androidDir = new File(homeDir, ".android");
      androidDir.mkdirs();

      File configFile = new File(androidDir, "ddms.cfg");
      PrintWriter out;
      try {
        out = new PrintWriter(configFile);
        out.println("pingOptIn=false");
        out.flush();
        out.close();
      } catch (FileNotFoundException e) {
        log(logger, "Failed to automatically opt out of SDK statistics gathering.", e);
      }

      return null;
    }
    public Boolean call() throws Exception {
      if (logger == null) {
        logger = listener.getLogger();
      }

      // Check whether the AVD exists
      final File homeDir = Utils.getHomeDirectory(androidSdkHome);
      final File avdDirectory = getAvdDirectory(homeDir);
      final boolean emulatorExists = avdDirectory.exists();
      if (!emulatorExists) {
        AndroidEmulator.log(logger, Messages.AVD_DIRECTORY_NOT_FOUND(avdDirectory));
        return false;
      }

      // Recursively delete the contents
      new FilePath(avdDirectory).deleteRecursive();

      // Delete the metadata file
      getAvdMetadataFile().delete();

      // Success!
      return true;
    }
    public Void call() throws IOException {
      if (logger == null) {
        logger = listener.getLogger();
      }

      final File homeDir = Utils.getHomeDirectory(androidSdkHome);

      // Parse the AVD's config
      Map<String, String> configValues;
      configValues = parseAvdConfigFile(homeDir);

      // Insert any hardware properties we want to override
      AndroidEmulator.log(logger, Messages.SETTING_HARDWARE_PROPERTIES());
      for (HardwareProperty prop : hardwareProperties) {
        AndroidEmulator.log(logger, String.format("%s: %s", prop.key, prop.value), true);
        configValues.put(prop.key, prop.value);
      }

      // Update config file
      writeAvdConfigFile(homeDir, configValues);

      return null;
    }
  /**
   * Downloads and extracts the basic Android SDK on a given Node, if it hasn't already been done.
   *
   * @param node Node to install the SDK on.
   * @return Path where the SDK is installed, regardless of whether it was installed right now.
   * @throws SdkUnavailableException If the Android SDK is not available on this platform.
   */
  private static FilePath installBasicSdk(final BuildListener listener, Node node)
      throws SdkUnavailableException, IOException, InterruptedException {
    // Locate where the SDK should be installed to on this node
    final FilePath installDir = Utils.getSdkInstallDirectory(node);

    // Get the OS-specific download URL for the SDK
    AndroidInstaller installer = AndroidInstaller.fromNode(node);
    final URL downloadUrl = installer.getUrl(SDK_VERSION);

    // Download the SDK, if required
    boolean wasNowInstalled =
        installDir.act(
            new FileCallable<Boolean>() {
              public Boolean invoke(File f, VirtualChannel channel)
                  throws InterruptedException, IOException {
                String msg = Messages.DOWNLOADING_SDK_FROM(downloadUrl);
                return installDir.installIfNecessaryFrom(downloadUrl, listener, msg);
              }

              private static final long serialVersionUID = 1L;
            });

    if (wasNowInstalled) {
      // If the SDK was required, pull files up from the intermediate directory
      installDir.listDirectories().get(0).moveAllChildrenTo(installDir);

      // Java's ZipEntry doesn't preserve the executable bit...
      if (installer == AndroidInstaller.MAC_OS_X) {
        setPermissions(installDir.child("tools"));
      }

      // Success!
      log(listener.getLogger(), Messages.BASE_SDK_INSTALLED());
    }

    return installDir;
  }
 /**
  * Sends a user command to the running emulator via its telnet interface.<br>
  * Execution will be cancelled if it takes longer than timeout ms.
  *
  * @param command The command to execute on the emulator's telnet interface.
  * @param timeout The command's timeout, in ms.
  * @return Whether sending the command succeeded.
  */
 public boolean sendCommand(final String command, int timeout) {
   return Utils.sendEmulatorCommand(launcher, logger(), userPort, command, timeout);
 }
 /**
  * Generates a ready-to-use ProcStarter for one of the Android SDK tools, based on the current
  * context.
  *
  * @param tool The Android tool to run.
  * @param args Any extra arguments for the command.
  * @return A ready ProcStarter
  * @throws IOException
  * @throws InterruptedException
  */
 public ProcStarter getToolProcStarter(Tool tool, String args)
     throws IOException, InterruptedException {
   return getProcStarter(Utils.getToolCommand(sdk, launcher.isUnix(), tool, args));
 }
 /**
  * Generates a ready-to-use ArgumentListBuilder for one of the Android SDK tools, based on the
  * current context.
  *
  * @param tool The Android tool to run.
  * @param args Any extra arguments for the command.
  * @return Arguments including the full path to the SDK and any extra Windows stuff required.
  */
 public ArgumentListBuilder getToolCommand(Tool tool, String args) {
   return Utils.getToolCommand(sdk, launcher.isUnix(), tool, args);
 }
    public Boolean call() throws AndroidEmulatorException {
      if (logger == null) {
        logger = listener.getLogger();
      }

      final File homeDir = Utils.getHomeDirectory(androidSdk.getSdkHome());
      final File avdDirectory = getAvdDirectory(homeDir);
      final boolean emulatorExists = getAvdConfigFile(homeDir).exists();

      // Can't do anything if a named emulator doesn't exist
      if (isNamedEmulator() && !emulatorExists) {
        throw new EmulatorDiscoveryException(Messages.AVD_DOES_NOT_EXIST(avdName, avdDirectory));
      }

      // Check whether AVD needs to be created
      boolean createSdCard = false;
      boolean createSnapshot = false;
      File snapshotsFile = new File(getAvdDirectory(homeDir), "snapshots.img");
      if (emulatorExists) {
        // AVD exists: check whether there's anything still to be set up
        File sdCardFile = new File(getAvdDirectory(homeDir), "sdcard.img");
        boolean sdCardRequired = getSdCardSize() != null;

        // Check if anything needs to be done for snapshot-enabled builds
        if (shouldUseSnapshots() && androidSdk.supportsSnapshots()) {
          if (!snapshotsFile.exists()) {
            createSnapshot = true;
          }

          // We should ensure that we start out with a clean SD card for the build
          if (sdCardRequired && sdCardFile.exists()) {
            sdCardFile.delete();
          }
        }

        // Flag that we need to generate an SD card, if there isn't one existing
        if (sdCardRequired && !sdCardFile.exists()) {
          createSdCard = true;
        }

        // If everything is ready, then return
        if (!createSdCard && !createSnapshot) {
          return true;
        }
      } else {
        AndroidEmulator.log(logger, Messages.CREATING_AVD(avdDirectory));
      }

      // We can't continue if we don't know where to find emulator images or tools
      if (!androidSdk.hasKnownRoot()) {
        throw new EmulatorCreationException(Messages.SDK_NOT_SPECIFIED());
      }
      final File sdkRoot = new File(androidSdk.getSdkRoot());
      if (!sdkRoot.exists()) {
        throw new EmulatorCreationException(Messages.SDK_NOT_FOUND(androidSdk.getSdkRoot()));
      }

      // If we need to initialise snapshot support for an existing emulator, do so
      if (createSnapshot) {
        // Copy the snapshots file into place
        File snapshotDir = new File(sdkRoot, "tools/lib/emulator");
        Util.copyFile(new File(snapshotDir, "snapshots.img"), snapshotsFile);

        // Update the AVD config file mark snapshots as enabled
        Map<String, String> configValues;
        try {
          configValues = parseAvdConfigFile(homeDir);
          configValues.put("snapshot.present", "true");
          writeAvdConfigFile(homeDir, configValues);
        } catch (IOException e) {
          throw new EmulatorCreationException(Messages.AVD_CONFIG_NOT_READABLE(), e);
        }
      }

      // If we need create an SD card for an existing emulator, do so
      if (createSdCard) {
        AndroidEmulator.log(logger, Messages.ADDING_SD_CARD(sdCardSize, getAvdName()));
        if (!createSdCard(homeDir)) {
          throw new EmulatorCreationException(Messages.SD_CARD_CREATION_FAILED());
        }

        // Update the AVD config file
        Map<String, String> configValues;
        try {
          configValues = parseAvdConfigFile(homeDir);
          configValues.put("sdcard.size", sdCardSize);
          writeAvdConfigFile(homeDir, configValues);
        } catch (IOException e) {
          throw new EmulatorCreationException(Messages.AVD_CONFIG_NOT_READABLE(), e);
        }
      }

      // Return if everything is now ready for use
      if (emulatorExists) {
        return true;
      }

      // Build up basic arguments to `android` command
      final StringBuilder args = new StringBuilder(100);
      args.append("create avd ");

      // Overwrite any existing files
      args.append("-f ");

      // Initialise snapshot support, regardless of whether we will actually use it
      if (androidSdk.supportsSnapshots()) {
        args.append("-a ");
      }

      if (sdCardSize != null) {
        args.append("-c ");
        args.append(sdCardSize);
        args.append(" ");
      }
      args.append("-s ");
      args.append(screenResolution.getSkinName());
      args.append(" -n ");
      args.append(getAvdName());
      boolean isUnix = !Functions.isWindows();
      ArgumentListBuilder builder =
          Utils.getToolCommand(androidSdk, isUnix, Tool.ANDROID, args.toString());

      // Tack on quoted platform name at the end, since it can be anything
      builder.add("-t");
      builder.add(osVersion.getTargetName());

      if (targetAbi != null) {
        builder.add("--abi");
        builder.add(targetAbi);
      }

      // Log command line used, for info
      AndroidEmulator.log(logger, builder.toStringWithQuote());

      // Run!
      boolean avdCreated = false;
      final Process process;
      try {
        ProcessBuilder procBuilder = new ProcessBuilder(builder.toList());
        if (androidSdk.hasKnownHome()) {
          procBuilder.environment().put("ANDROID_SDK_HOME", androidSdk.getSdkHome());
        }
        process = procBuilder.start();
      } catch (IOException ex) {
        throw new EmulatorCreationException(Messages.AVD_CREATION_FAILED());
      }

      // Redirect process's stderr to a stream, for logging purposes
      ByteArrayOutputStream stderr = new ByteArrayOutputStream();
      ByteArrayOutputStream stdout = new ByteArrayOutputStream();
      new StreamCopyThread("", process.getErrorStream(), stderr).start();

      // Command may prompt us whether we want to further customise the AVD.
      // Just "press" Enter to continue with the selected target's defaults.
      try {
        boolean processAlive = true;

        // Block until the command outputs something (or process ends)
        final PushbackInputStream in = new PushbackInputStream(process.getInputStream(), 10);
        int len = in.read();
        if (len == -1) {
          // Check whether the process has exited badly, as sometimes no output is valid.
          // e.g. When creating an AVD with Google APIs, no user input is requested.
          if (process.waitFor() != 0) {
            AndroidEmulator.log(logger, Messages.AVD_CREATION_FAILED());
            AndroidEmulator.log(logger, stderr.toString(), true);
            throw new EmulatorCreationException(Messages.AVD_CREATION_FAILED());
          }
          processAlive = false;
        }
        in.unread(len);

        // Write CRLF, if required
        if (processAlive) {
          final OutputStream stream = process.getOutputStream();
          stream.write('\r');
          stream.write('\n');
          stream.flush();
          stream.close();
        }

        // read the rest of stdout (for debugging purposes)
        Util.copyStream(in, stdout);
        in.close();

        // Wait for happy ending
        if (process.waitFor() == 0) {
          // Do a sanity check to ensure the AVD was really created
          avdCreated = getAvdConfigFile(homeDir).exists();
        }

      } catch (IOException e) {
        throw new EmulatorCreationException(Messages.AVD_CREATION_ABORTED(), e);
      } catch (InterruptedException e) {
        throw new EmulatorCreationException(Messages.AVD_CREATION_INTERRUPTED(), e);
      } finally {
        process.destroy();
      }

      // For reasons unknown, the return code may not be correctly reported on Windows.
      // So check whether stderr contains failure info (useful for other platforms too).
      String errOutput = stderr.toString();
      String output = stdout.toString();
      if (errOutput.contains("list targets")) {
        AndroidEmulator.log(logger, Messages.INVALID_AVD_TARGET(osVersion.getTargetName()));
        avdCreated = false;
        errOutput = null;
      } else if (errOutput.contains("more than one ABI")) {
        AndroidEmulator.log(
            logger, Messages.MORE_THAN_ONE_ABI(osVersion.getTargetName(), output), true);
        avdCreated = false;
        errOutput = null;
      }

      // Check everything went ok
      if (!avdCreated) {
        if (errOutput != null && errOutput.length() != 0) {
          AndroidEmulator.log(logger, stderr.toString(), true);
        }
        throw new EmulatorCreationException(Messages.AVD_CREATION_FAILED());
      }

      // Done!
      return false;
    }
 private Map<String, String> parseAvdConfigFile(File homeDir) throws IOException {
   File configFile = getAvdConfigFile(homeDir);
   return Utils.parseConfigFile(configFile);
 }
 public File getAvdMetadataFile() {
   final File homeDir = Utils.getHomeDirectory(androidSdkHome);
   return new File(getAvdHome(homeDir), getAvdName() + ".ini");
 }
 /** Gets the path of our installation metadata file for the given node. */
 private static final FilePath getInstallationInfoFilename(Node node) {
   return Utils.getSdkInstallDirectory(node).child(SDK_INFO_FILENAME);
 }