コード例 #1
0
ファイル: Walker.java プロジェクト: safdariqbal/soot
  public void defaultCase(Node node) {
    if (node instanceof TQuotedName
        || node instanceof TFullIdentifier
        || node instanceof TIdentifier
        || node instanceof TStringConstant
        || node instanceof TIntegerConstant
        || node instanceof TFloatConstant
        || node instanceof TAtIdentifier) {

      if (debug) G.v().out.println("Default case -pushing token:" + ((Token) node).getText());
      String tokenString = ((Token) node).getText();
      if (node instanceof TStringConstant || node instanceof TQuotedName) {
        tokenString = tokenString.substring(1, tokenString.length() - 1);
      }

      if (node instanceof TIdentifier
          || node instanceof TFullIdentifier
          || node instanceof TQuotedName
          || node instanceof TStringConstant) {
        try {
          tokenString = StringTools.getUnEscapedStringOf(tokenString);

        } catch (RuntimeException e) {
          G.v().out.println(tokenString);
          throw e;
        }
      }

      mProductions.addLast(tokenString);
    }
  }
コード例 #2
0
ファイル: Scene.java プロジェクト: droidsec-cn/EC700-Epoch-2
  public void setMainClassFromOptions() {
    if (mainClass != null) return;
    if (Options.v().main_class() != null && Options.v().main_class().length() > 0) {
      setMainClass(getSootClass(Options.v().main_class()));
    } else {
      // try to infer a main class from the command line if none is given
      for (Iterator<String> classIter = Options.v().classes().iterator(); classIter.hasNext(); ) {
        SootClass c = getSootClass(classIter.next());
        if (c.declaresMethod(
            "main",
            Collections.<Type>singletonList(ArrayType.v(RefType.v("java.lang.String"), 1)),
            VoidType.v())) {
          G.v().out.println("No main class given. Inferred '" + c.getName() + "' as main class.");
          setMainClass(c);
          return;
        }
      }

      // try to infer a main class from the usual classpath if none is given
      for (Iterator<SootClass> classIter = getApplicationClasses().iterator();
          classIter.hasNext(); ) {
        SootClass c = (SootClass) classIter.next();
        if (c.declaresMethod(
            "main",
            Collections.<Type>singletonList(ArrayType.v(RefType.v("java.lang.String"), 1)),
            VoidType.v())) {
          G.v().out.println("No main class given. Inferred '" + c.getName() + "' as main class.");
          setMainClass(c);
          return;
        }
      }
    }
  }
コード例 #3
0
 private void analyzeLocal(SootMethod method, Value value) {
   Local l = (Local) value;
   boolean objIsThreadLocal = tloa.isObjectThreadLocal(l, method);
   if (objIsThreadLocal) {
     G.v().out.println("[lg.tlo] LOCAL " + l.toString() + " is thread-local in method " + method);
   } else {
     G.v().out.println("[lg.tlo] LOCAL " + l.toString() + " is thread-shared in method " + method);
   }
 }
コード例 #4
0
 private void analyzeField(SootMethod method, Value value) {
   FieldRef fr = (FieldRef) value;
   boolean fieldIsThreadLocal = tloa.isObjectThreadLocal(fr, method);
   if (fieldIsThreadLocal) {
     G.v().out.println("[lg.tlo] FIELD " + fr.toString() + " is thread-local in method " + method);
   } else {
     G.v()
         .out
         .println("[lg.tlo] FIELD " + fr.toString() + " is thread-shared in method " + method);
   }
 }
コード例 #5
0
  public StronglyConnectedComponentsBV(BitVector typeVariableList, TypeResolverBV resolver)
      throws TypeException {
    this.resolver = resolver;
    variables = typeVariableList;

    black = new TreeSet();
    finished = new LinkedList();

    for (BitSetIterator i = variables.iterator(); i.hasNext(); ) {
      TypeVariableBV var = resolver.typeVariableForId(i.next());

      if (!black.contains(var)) {
        black.add(var);
        dfsg_visit(var);
      }
    }

    black = new TreeSet();

    for (Iterator i = finished.iterator(); i.hasNext(); ) {
      TypeVariableBV var = (TypeVariableBV) i.next();

      if (!black.contains(var)) {
        current_tree = new LinkedList();
        forest.add(current_tree);
        black.add(var);
        dfsgt_visit(var);
      }
    }

    for (Iterator i = forest.iterator(); i.hasNext(); ) {
      LinkedList list = (LinkedList) i.next();
      TypeVariableBV previous = null;
      StringBuffer s = null;
      if (DEBUG) {
        s = new StringBuffer("scc:\n");
      }

      for (Iterator j = list.iterator(); j.hasNext(); ) {
        TypeVariableBV current = (TypeVariableBV) j.next();

        if (DEBUG) {
          s.append(" " + current + "\n");
        }

        if (previous == null) {
          previous = current;
        } else {
          try {
            previous = previous.union(current);
          } catch (TypeException e) {
            if (DEBUG) {
              G.v().out.println(s);
            }
            throw e;
          }
        }
      }
    }
  }
コード例 #6
0
ファイル: TypeNode.java プロジェクト: GeneBlue/JAADAS
  public TypeNode(int id, Type type) {
    this.id = id;
    this.type = type;

    if (DEBUG) {
      G.v().out.println("creating node " + this);
    }
  }
コード例 #7
0
ファイル: UnitGraph.java プロジェクト: safdariqbal/soot
 /**
  * Performs the work that is required to construct any sort of <tt>UnitGraph</tt>.
  *
  * @param body The body of the method for which to construct a control flow graph.
  */
 protected UnitGraph(Body body) {
   this.body = body;
   unitChain = body.getUnits();
   method = body.getMethod();
   if (Options.v().verbose())
     G.v()
         .out
         .println(
             "[" + method.getName() + "]     Constructing " + this.getClass().getName() + "...");
 }
コード例 #8
0
  /**
   * Traverse the statements in the given body, looking for aggregation possibilities; that is,
   * given a def d and a use u, d has no other uses, u has no other defs, collapse d and u.
   *
   * <p>option: only-stack-locals; if this is true, only aggregate variables starting with $
   */
  protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
    StmtBody body = (StmtBody) b;
    boolean onlyStackVars = PhaseOptions.getBoolean(options, "only-stack-locals");

    int aggregateCount = 1;

    if (Options.v().time()) Timers.v().aggregationTimer.start();
    boolean changed = false;

    Map<ValueBox, Zone> boxToZone =
        new HashMap<ValueBox, Zone>(body.getUnits().size() * 2 + 1, 0.7f);

    // Determine the zone of every box
    {
      Zonation zonation = new Zonation(body);

      for (Unit u : body.getUnits()) {
        Zone zone = zonation.getZoneOf(u);

        for (ValueBox box : u.getUseBoxes()) {
          boxToZone.put(box, zone);
        }

        for (ValueBox box : u.getDefBoxes()) {
          boxToZone.put(box, zone);
        }
      }
    }

    do {
      if (Options.v().verbose())
        G.v()
            .out
            .println(
                "["
                    + body.getMethod().getName()
                    + "] Aggregating iteration "
                    + aggregateCount
                    + "...");

      // body.printTo(new java.io.PrintWriter(G.v().out, true));

      changed = internalAggregate(body, boxToZone, onlyStackVars);

      aggregateCount++;
    } while (changed);

    if (Options.v().time()) Timers.v().aggregationTimer.end();
  }
コード例 #9
0
  protected void print_cfg(Body body) {
    DirectedGraph<Unit> graph = graphtype.buildGraph(body);
    DotGraph canvas = graphtype.drawGraph(drawer, graph, body);

    String methodname = body.getMethod().getSubSignature();
    String filename = soot.SourceLocator.v().getOutputDir();
    if (filename.length() > 0) {
      filename = filename + java.io.File.separator;
    }
    filename =
        filename + methodname.replace(java.io.File.separatorChar, '.') + DotGraph.DOT_EXTENSION;

    G.v().out.println("Generate dot file in " + filename);
    canvas.plot(filename);
  }
コード例 #10
0
 private static void usage() {
   G.v()
       .out
       .println(
           "Usage:\n"
               + "   java soot.util.CFGViewer [soot options] [CFGViewer options] [class[:method]]...\n\n"
               + "   CFGViewer options:\n"
               + "      (When specifying the value for an '=' option, you only\n"
               + "       need to type enough characters to specify the choice\n"
               + "       unambiguously, and case is ignored.)\n"
               + "\n"
               + "       --alt-classpath PATH :\n"
               + "                specifies the classpath from which to load classes\n"
               + "                that implement graph types whose names begin with 'Alt'.\n"
               + "       --graph={"
               + CFGGraphType.help(0, 70, "                ".length())
               + "} :\n"
               + "                show the specified type of graph.\n"
               + "                Defaults to "
               + defaultGraph
               + ".\n"
               + "       --ir={"
               + CFGIntermediateRep.help(0, 70, "                ".length())
               + "} :\n"
               + "                create the CFG from the specified intermediate\n"
               + "                representation. Defaults to "
               + defaultIR
               + ".\n"
               + "       --brief :\n"
               + "                label nodes with the unit or block index,\n"
               + "                instead of the text of their statements.\n"
               + "       --multipages :\n"
               + "                produce dot file output for multiple 8.5x11\" pages.\n"
               + "                By default, a single page is produced.\n"
               + "       --help :\n"
               + "                print this message.\n"
               + "\n"
               + "   Particularly relevant soot options (see \"soot --help\" for details):\n"
               + "       --soot-class-path PATH\n"
               + "       --show-exception-dests\n"
               + "       --throw-analysis {pedantic|unit}\n"
               + "       --omit-excepting-unit-edges\n"
               + "       --trim-cfgs\n");
 }
コード例 #11
0
ファイル: Scene.java プロジェクト: droidsec-cn/EC700-Epoch-2
  public void loadDynamicClasses() {
    dynamicClasses = new ArrayList<SootClass>();
    HashSet<String> dynClasses = new HashSet<String>();
    dynClasses.addAll(Options.v().dynamic_class());

    for (Iterator<String> pathIt = Options.v().dynamic_dir().iterator(); pathIt.hasNext(); ) {

      final String path = (String) pathIt.next();
      dynClasses.addAll(SourceLocator.v().getClassesUnder(path));
    }

    for (Iterator<String> pkgIt = Options.v().dynamic_package().iterator(); pkgIt.hasNext(); ) {

      final String pkg = (String) pkgIt.next();
      dynClasses.addAll(SourceLocator.v().classesInDynamicPackage(pkg));
    }

    for (String className : dynClasses) {

      dynamicClasses.add(loadClassAndSupport(className));
    }

    // remove non-concrete classes that may accidentally have been loaded
    for (Iterator<SootClass> iterator = dynamicClasses.iterator(); iterator.hasNext(); ) {
      SootClass c = iterator.next();
      if (!c.isConcrete()) {
        if (Options.v().verbose()) {
          G.v()
              .out
              .println(
                  "Warning: dynamic class "
                      + c.getName()
                      + " is abstract or an interface, and it will not be considered.");
        }
        iterator.remove();
      }
    }
  }
コード例 #12
0
  /**
   * Computes the analysis given a UnitGraph computed from a method body. It is recommended that a
   * ExceptionalUnitGraph (or similar) be provided for correct results in the case of exceptional
   * control flow.
   *
   * @param g a graph on which to compute the analysis.
   * @see ExceptionalUnitGraph
   */
  public SimpleLiveLocals(UnitGraph graph) {
    if (Options.v().time()) Timers.v().liveTimer.start();

    if (Options.v().verbose())
      G.v()
          .out
          .println(
              "["
                  + graph.getBody().getMethod().getName()
                  + "]     Constructing SimpleLiveLocals...");

    SimpleLiveLocalsAnalysis analysis = new SimpleLiveLocalsAnalysis(graph);

    if (Options.v().time()) Timers.v().livePostTimer.start();

    // Build unitToLocals map
    {
      unitToLocalsAfter = new HashMap<Unit, List>(graph.size() * 2 + 1, 0.7f);
      unitToLocalsBefore = new HashMap<Unit, List>(graph.size() * 2 + 1, 0.7f);

      Iterator unitIt = graph.iterator();

      while (unitIt.hasNext()) {
        Unit s = (Unit) unitIt.next();

        FlowSet set = (FlowSet) analysis.getFlowBefore(s);
        unitToLocalsBefore.put(s, Collections.unmodifiableList(set.toList()));

        set = (FlowSet) analysis.getFlowAfter(s);
        unitToLocalsAfter.put(s, Collections.unmodifiableList(set.toList()));
      }
    }

    if (Options.v().time()) Timers.v().livePostTimer.end();

    if (Options.v().time()) Timers.v().liveTimer.end();
  }
コード例 #13
0
  protected void internalTransform(String phaseName, Map options) {
    if (Options.v().verbose())
      G.v().out.println("Transforming all classes in the Scene to Shimple...");

    // *** FIXME: Add debug output to indicate which class/method is being shimplified.
    // *** FIXME: Is ShimpleTransformer the right solution?  The call graph may deem
    //            some classes unreachable.

    Iterator classesIt = Scene.v().getClasses().iterator();
    while (classesIt.hasNext()) {
      SootClass sClass = (SootClass) classesIt.next();
      if (sClass.isPhantom()) continue;

      Iterator methodsIt = sClass.getMethods().iterator();
      while (methodsIt.hasNext()) {
        SootMethod method = (SootMethod) methodsIt.next();
        if (!method.isConcrete()) continue;

        if (method.hasActiveBody()) {
          Body body = method.getActiveBody();
          ShimpleBody sBody = null;

          if (body instanceof ShimpleBody) {
            sBody = (ShimpleBody) body;
            if (!sBody.isSSA()) sBody.rebuild();
          } else {
            sBody = Shimple.v().newBody(body);
          }

          method.setActiveBody(sBody);
        } else {
          MethodSource ms = new ShimpleMethodSource(method.getSource());
          method.setSource(ms);
        }
      }
    }
  }
コード例 #14
0
ファイル: LineNumberAdder.java プロジェクト: GeneBlue/JAADAS
 public static LineNumberAdder v() {
   return G.v().soot_jimple_toolkits_annotation_LineNumberAdder();
 }
コード例 #15
0
ファイル: NullType.java プロジェクト: safdariqbal/soot
 public static NullType v() {
   return G.v().soot_NullType();
 }
コード例 #16
0
 public static ShimpleTransformer v() {
   return G.v().soot_shimple_ShimpleTransformer();
 }
コード例 #17
0
ファイル: Scene.java プロジェクト: droidsec-cn/EC700-Epoch-2
  public String defaultClassPath() {
    StringBuffer sb = new StringBuffer();
    if (System.getProperty("os.name").equals("Mac OS X")) {
      // in older Mac OS X versions, rt.jar was split into classes.jar and ui.jar
      sb.append(System.getProperty("java.home"));
      sb.append(File.separator);
      sb.append("..");
      sb.append(File.separator);
      sb.append("Classes");
      sb.append(File.separator);
      sb.append("classes.jar");

      sb.append(File.pathSeparator);
      sb.append(System.getProperty("java.home"));
      sb.append(File.separator);
      sb.append("..");
      sb.append(File.separator);
      sb.append("Classes");
      sb.append(File.separator);
      sb.append("ui.jar");
      sb.append(File.pathSeparator);
    }

    sb.append(System.getProperty("java.home"));
    sb.append(File.separator);
    sb.append("lib");
    sb.append(File.separator);
    sb.append("rt.jar");

    if (Options.v().whole_program() || Options.v().output_format() == Options.output_format_dava) {
      // add jce.jar, which is necessary for whole program mode
      // (java.security.Signature from rt.jar import javax.crypto.Cipher from jce.jar
      sb.append(
          File.pathSeparator
              + System.getProperty("java.home")
              + File.separator
              + "lib"
              + File.separator
              + "jce.jar");
    }

    String defaultClassPath = sb.toString();

    if (Options.v().src_prec() == Options.src_prec_apk) {
      // check that android.jar is not in classpath
      if (!defaultClassPath.contains("android.jar")) {
        String androidJars = Options.v().android_jars();
        String forceAndroidJar = Options.v().force_android_jar();
        if ((androidJars == null || androidJars.equals(""))
            && (forceAndroidJar == null || forceAndroidJar.equals(""))) {
          throw new RuntimeException(
              "You are analyzing an Android application but did not define android.jar. Options -android-jars or -force-android-jar should be used.");
        }

        String jarPath = "";
        if (forceAndroidJar != null && !forceAndroidJar.equals("")) {
          jarPath = forceAndroidJar;
        } else if (androidJars != null && !androidJars.equals("")) {
          List<String> classPathEntries =
              new LinkedList<String>(
                  Arrays.asList(Options.v().soot_classpath().split(File.pathSeparator)));
          classPathEntries.addAll(Options.v().process_dir());
          Set<String> targetApks = new HashSet<String>();
          for (String entry : classPathEntries) {
            if (entry.toLowerCase().endsWith(".apk")
                || entry
                    .toLowerCase()
                    .endsWith(".dex")) // on Windows, file names are case-insensitive
            targetApks.add(entry);
          }
          if (targetApks.size() == 0) throw new RuntimeException("no apk file given");
          else if (targetApks.size() > 1)
            throw new RuntimeException(
                "only one Android application can be analyzed when using option -android-jars.");
          jarPath = getAndroidJarPath(androidJars, (String) targetApks.toArray()[0]);
        }
        if (jarPath.equals("")) throw new RuntimeException("android.jar not found.");
        File f = new File(jarPath);
        if (!f.exists()) throw new RuntimeException("file '" + jarPath + "' does not exist!");
        else G.v().out.println("Using '" + jarPath + "' as android.jar");
        defaultClassPath = jarPath + File.pathSeparator + defaultClassPath;

      } else {
        G.v()
            .out
            .println(
                "warning: defaultClassPath contains android.jar! Options -android-jars and -force-android-jar are ignored!");
      }
    }

    return defaultClassPath;
  }
コード例 #18
0
 protected ReferenceVariable tempVariableImpl() {
   return pag.makeGlobalVarNode(
       new Pair("TempVar", new Integer(++G.v().SparkNativeHelper_tempVar)),
       RefType.v("java.lang.Object"));
 }
コード例 #19
0
ファイル: Scene.java プロジェクト: droidsec-cn/EC700-Epoch-2
 public static Scene v() {
   return G.v().soot_Scene();
 }
コード例 #20
0
  /**
   * This method pushes all newExpr down to be the stmt directly before every invoke of the init
   * only if they are in the types list
   */
  public void internalTransform(Body b, String phaseName, Map options) {
    JimpleBody body = (JimpleBody) b;

    if (Options.v().verbose())
      G.v().out.println("[" + body.getMethod().getName() + "] Folding Jimple constructors...");

    Chain units = body.getUnits();
    List<Unit> stmtList = new ArrayList<Unit>();
    stmtList.addAll(units);

    Iterator<Unit> it = stmtList.iterator();
    Iterator<Unit> nextStmtIt = stmtList.iterator();
    // start ahead one
    nextStmtIt.next();

    SmartLocalDefs localDefs = SmartLocalDefsPool.v().getSmartLocalDefsFor(body);
    UnitGraph graph = localDefs.getGraph();
    LocalUses localUses = new SimpleLocalUses(graph, localDefs);

    /* fold in NewExpr's with specialinvoke's */
    while (it.hasNext()) {
      Stmt s = (Stmt) it.next();

      if (!(s instanceof AssignStmt)) continue;

      /* this should be generalized to ArrayRefs */
      // only deal with stmts that are an local = newExpr
      Value lhs = ((AssignStmt) s).getLeftOp();
      if (!(lhs instanceof Local)) continue;

      Value rhs = ((AssignStmt) s).getRightOp();
      if (!(rhs instanceof NewExpr)) continue;

      // check if very next statement is invoke -->
      // this indicates there is no control flow between
      // new and invoke and should do nothing
      if (nextStmtIt.hasNext()) {
        Stmt next = (Stmt) nextStmtIt.next();
        if (next instanceof InvokeStmt) {
          InvokeStmt invoke = (InvokeStmt) next;

          if (invoke.getInvokeExpr() instanceof SpecialInvokeExpr) {
            SpecialInvokeExpr invokeExpr = (SpecialInvokeExpr) invoke.getInvokeExpr();
            if (invokeExpr.getBase() == lhs) {
              break;
            }
          }
        }
      }

      // check if new is in the types list - only process these
      if (!types.contains(((NewExpr) rhs).getType())) continue;

      List lu = localUses.getUsesOf(s);
      Iterator luIter = lu.iterator();
      boolean MadeNewInvokeExpr = false;

      while (luIter.hasNext()) {
        Unit use = ((UnitValueBoxPair) (luIter.next())).unit;
        if (!(use instanceof InvokeStmt)) continue;
        InvokeStmt is = (InvokeStmt) use;
        if (!(is.getInvokeExpr() instanceof SpecialInvokeExpr)
            || lhs != ((SpecialInvokeExpr) is.getInvokeExpr()).getBase()) continue;

        // make a new one here
        AssignStmt constructStmt =
            Jimple.v()
                .newAssignStmt(((DefinitionStmt) s).getLeftOp(), ((DefinitionStmt) s).getRightOp());
        constructStmt.setRightOp(Jimple.v().newNewExpr(((NewExpr) rhs).getBaseType()));
        MadeNewInvokeExpr = true;

        // redirect jumps
        use.redirectJumpsToThisTo(constructStmt);
        // insert new one here
        units.insertBefore(constructStmt, use);

        constructStmt.addTag(s.getTag("SourceLnPosTag"));
      }
      if (MadeNewInvokeExpr) {
        units.remove(s);
      }
    }
  }
コード例 #21
0
ファイル: Printer.java プロジェクト: safdariqbal/soot
 public static Printer v() {
   return G.v().soot_Printer();
 }
コード例 #22
0
 public static Integer1Type v() {
   return G.v().soot_jimple_toolkits_typing_fast_Integer1Type();
 }
コード例 #23
0
 public static Aggregator v() {
   return G.v().soot_jimple_toolkits_base_Aggregator();
 }
コード例 #24
0
 public static DumbPointerAnalysis v() {
   return G.v().soot_jimple_toolkits_pointer_DumbPointerAnalysis();
 }
コード例 #25
0
ファイル: ThrowableSet.java プロジェクト: safdariqbal/soot
 /**
  * Returns the single instance of <code>ThrowableSet.Manager</code>.
  *
  * @return Soot's <code>ThrowableSet.Manager</code>.
  */
 public static Manager v() {
   return G.v().soot_toolkits_exceptions_ThrowableSet_Manager();
 }
コード例 #26
0
 protected ReferenceVariable tempLocalVariableImpl(SootMethod method) {
   return pag.makeLocalVarNode(
       new Pair("TempVar", new Integer(++G.v().SparkNativeHelper_tempVar)),
       RefType.v("java.lang.Object"),
       method);
 }
コード例 #27
0
ファイル: Walker.java プロジェクト: safdariqbal/soot
 /*
   file =
   modifier* file_type class_name extends_clause? implements_clause? file_body;
 */
 public void inAFile(AFile node) {
   if (debug) G.v().out.println("reading class " + node.getClassName());
 }
コード例 #28
0
 public static DavaStaticBlockCleaner v() {
   return G.v().soot_dava_DavaStaticBlockCleaner();
 }
コード例 #29
0
ファイル: Scene.java プロジェクト: droidsec-cn/EC700-Epoch-2
  private int getTargetSDKVersion(String apkFile, String platformJARs) {
    // get AndroidManifest
    InputStream manifestIS = null;
    ZipFile archive = null;
    try {
      try {
        archive = new ZipFile(apkFile);
        for (Enumeration<? extends ZipEntry> entries = archive.entries();
            entries.hasMoreElements(); ) {
          ZipEntry entry = entries.nextElement();
          String entryName = entry.getName();
          // We are dealing with the Android manifest
          if (entryName.equals("AndroidManifest.xml")) {
            manifestIS = archive.getInputStream(entry);
            break;
          }
        }
      } catch (Exception e) {
        throw new RuntimeException("Error when looking for manifest in apk: " + e);
      }

      if (manifestIS == null) {
        G.v()
            .out
            .println(
                "Could not find sdk version in Android manifest! Using default: "
                    + defaultSdkVersion);
        return defaultSdkVersion;
      }

      // process AndroidManifest.xml
      int maxAPI = getMaxAPIAvailable(platformJARs);
      int sdkTargetVersion = -1;
      int minSdkVersion = -1;
      try {
        AXmlResourceParser parser = new AXmlResourceParser();
        parser.open(manifestIS);
        int depth = 0;
        loop:
        while (true) {
          int type = parser.next();
          switch (type) {
            case XmlPullParser.START_DOCUMENT:
              {
                break;
              }
            case XmlPullParser.END_DOCUMENT:
              break loop;
            case XmlPullParser.START_TAG:
              {
                depth++;
                String tagName = parser.getName();
                if (depth == 2 && tagName.equals("uses-sdk")) {
                  for (int i = 0; i != parser.getAttributeCount(); ++i) {
                    String attributeName = parser.getAttributeName(i);
                    String attributeValue = AXMLPrinter.getAttributeValue(parser, i);
                    if (attributeName.equals("targetSdkVersion")) {
                      sdkTargetVersion = Integer.parseInt(attributeValue);
                    } else if (attributeName.equals("minSdkVersion")) {
                      minSdkVersion = Integer.parseInt(attributeValue);
                    }
                  }
                }
                break;
              }
            case XmlPullParser.END_TAG:
              depth--;
              break;
            case XmlPullParser.TEXT:
              break;
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
      }

      int APIVersion = -1;
      if (sdkTargetVersion != -1) {
        if (sdkTargetVersion > maxAPI && minSdkVersion != -1 && minSdkVersion <= maxAPI) {
          G.v()
              .out
              .println(
                  "warning: Android API version '"
                      + sdkTargetVersion
                      + "' not available, using minApkVersion '"
                      + minSdkVersion
                      + "' instead");
          APIVersion = minSdkVersion;
        } else {
          APIVersion = sdkTargetVersion;
        }
      } else if (minSdkVersion != -1) {
        APIVersion = minSdkVersion;
      } else {
        G.v()
            .out
            .println(
                "Could not find sdk version in Android manifest! Using default: "
                    + defaultSdkVersion);
        APIVersion = defaultSdkVersion;
      }

      if (APIVersion <= 2) APIVersion = 3;
      return APIVersion;
    } finally {
      if (archive != null)
        try {
          archive.close();
        } catch (IOException e) {
          throw new RuntimeException("Error when looking for manifest in apk: " + e);
        }
    }
  }