com.github.promeg.configchecker.Main.java Source code

Java tutorial

Introduction

Here is the source code for com.github.promeg.configchecker.Main.java

Source

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.promeg.configchecker;

import org.apache.commons.io.IOUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

public class Main {

    String mAndroidJar;
    String mFlavor;
    String mBuildType;

    public static void main(String[] args) {
        Main main = new Main();
        main.run(args);
    }

    void run(String[] args) {

        try {
            String[] inputFileNames = parseArgs(args);
            for (String fileName : collectFileNames(inputFileNames)) {
                System.out.println("Processing " + fileName);
                List<String> dexFiles = openInputFiles(fileName);
                new DexChecker(mAndroidJar, dexFiles, mFlavor, mBuildType).run();
            }
        } catch (ConfigCheckFailException exp) {
            exp.printStackTrace();
            System.exit(3);
        } catch (UsageException ue) {
            usage();
            System.exit(2);
        } catch (IOException ioe) {
            if (ioe.getMessage() != null) {
                System.err.println("Failed: " + ioe);
            }
            System.exit(1);
        }
    }

    /**
     * Opens an input file, which could be a .dex or a .jar/.apk with a
     * classes.dex inside.  If the latter, we extract the contents to a
     * temporary file.
     */
    List<String> openInputFiles(String fileName) throws IOException {
        List<String> dexFiles = new ArrayList<String>();

        openInputFileAsZip(fileName, dexFiles);
        if (dexFiles.size() == 0) {
            File inputFile = new File(fileName);
            dexFiles.add(inputFile.getAbsolutePath());
        }

        return dexFiles;
    }

    /**
     * Tries to open an input file as a Zip archive (jar/apk) with a
     * "classes.dex" inside.
     */
    void openInputFileAsZip(String fileName, List<String> dexFiles) throws IOException {
        ZipFile zipFile;

        // Try it as a zip file.
        try {
            zipFile = new ZipFile(fileName);
        } catch (FileNotFoundException fnfe) {
            // not found, no point in retrying as non-zip.
            System.err.println("Unable to open '" + fileName + "': " + fnfe.getMessage());
            throw fnfe;
        } catch (ZipException ze) {
            // not a zip
            return;
        }

        // Open and add all files matching "classes.*\.dex" in the zip file.
        for (ZipEntry entry : Collections.list(zipFile.entries())) {
            if (entry.getName().matches("classes.*\\.dex")) {
                dexFiles.add(openDexFile(zipFile, entry).getAbsolutePath());
            }
        }

        zipFile.close();
    }

    File openDexFile(ZipFile zipFile, ZipEntry entry) throws IOException {
        // We know it's a zip; see if there's anything useful inside.  A
        // failure here results in some type of IOException (of which
        // ZipException is a subclass).
        InputStream zis = zipFile.getInputStream(entry);

        // Create a temp file to hold the DEX data, open it, and delete it
        // to ensure it doesn't hang around if we fail.
        File dexFile = File.createTempFile("dexdeps", ".dex");

        // Copy all data from input stream to output file.
        IOUtils.copy(zis, new FileOutputStream(dexFile));

        return dexFile;
    }

    private String[] parseArgs(String[] args) {
        int idx;

        for (idx = 0; idx < args.length; idx++) {
            String arg = args[idx];

            if (arg.equals("--") || !arg.startsWith("--")) {
                break;
            } else if (arg.startsWith("--androidjar=")) {
                mAndroidJar = arg.substring(arg.indexOf('=') + 1);
            } else if (arg.startsWith("--flavor=")) {
                mFlavor = arg.substring(arg.indexOf('=') + 1);
            } else if (arg.startsWith("--buildType=")) {
                mBuildType = arg.substring(arg.indexOf('=') + 1);
            } else {
                System.err.println("Unknown option '" + arg + "'");
                throw new UsageException();
            }
        }

        // We expect at least one more argument (file name).
        int fileCount = args.length - idx;
        if (fileCount != 1) {
            throw new UsageException();
        }
        String[] inputFileNames = new String[fileCount];
        System.arraycopy(args, idx, inputFileNames, 0, fileCount);

        if (mAndroidJar == null || mFlavor == null || mBuildType == null) {
            throw new UsageException();
        }
        return inputFileNames;
    }

    private void usage() {
        System.err.print("ApkConfigChecker: Check apk's config v1.0\n"
                + "Usage: apk-config-checker [args] <file.{dex,apk}>\n" + "Args(required):\n"
                + "  --androidjar={Path to sdk/platforms/android-{version}/androidjar.jar}\n"
                + "  --flavor={flavor name to check}\n" + "  --buildType={build type to check}\n");
    }

    /**
     * Checks if input files array contain directories and
     * adds it's contents to the file list if so.
     * Otherwise just adds a file to the list.
     *
     * @return a List of file names to process
     */
    private List<String> collectFileNames(String[] inputFileNames) {
        List<String> fileNames = new ArrayList<String>();
        for (String inputFileName : inputFileNames) {
            File file = new File(inputFileName);
            if (file.isDirectory()) {
                throw new IllegalArgumentException("Only support file input(dex or apk).");
            } else {
                fileNames.add(inputFileName);
            }
        }
        return fileNames;
    }

    private static class UsageException extends RuntimeException {
    }
}