summaryrefslogtreecommitdiff
path: root/src/plugins/preflighting.core/src/com/motorolamobility/preflighting/core/internal/utils/ApkUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/preflighting.core/src/com/motorolamobility/preflighting/core/internal/utils/ApkUtils.java')
-rw-r--r--src/plugins/preflighting.core/src/com/motorolamobility/preflighting/core/internal/utils/ApkUtils.java318
1 files changed, 318 insertions, 0 deletions
diff --git a/src/plugins/preflighting.core/src/com/motorolamobility/preflighting/core/internal/utils/ApkUtils.java b/src/plugins/preflighting.core/src/com/motorolamobility/preflighting/core/internal/utils/ApkUtils.java
new file mode 100644
index 0000000..6382ce0
--- /dev/null
+++ b/src/plugins/preflighting.core/src/com/motorolamobility/preflighting/core/internal/utils/ApkUtils.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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.motorolamobility.preflighting.core.internal.utils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.eclipse.core.runtime.Path;
+
+import com.motorolamobility.preflighting.core.exception.PreflightingToolException;
+import com.motorolamobility.preflighting.core.i18n.PreflightingCoreNLS;
+import com.motorolamobility.preflighting.core.logging.PreflightingLogger;
+import com.motorolamobility.preflighting.core.validation.ValidationManagerConfiguration;
+
+/**
+ * This class holds methods which deal with APK package.
+ */
+public final class ApkUtils
+{
+ public static final String APP_VALIDATOR_TEMP_DIR = "MotodevAppValidator";
+
+ private static final String JAVA_TEMP_DIR_PROPERTY = "java.io.tmpdir";
+
+ private static final String TEMP_DIR_PATH = System.getProperty(JAVA_TEMP_DIR_PROPERTY);
+
+ // Temp folder used for APK extracting
+ public static final File tmpAppValidatorFolder =
+ new File(TEMP_DIR_PATH, APP_VALIDATOR_TEMP_DIR);
+
+ private static final String RSA = ".rsa";
+
+ private static final String DSA = ".dsa";
+
+ public static final String APK_EXTENSION = ".apk";
+
+ public static final String ZIP_EXTENSION = ".zip";
+
+ private static final int BUFFER_SIZE = 1024;
+
+ /**
+ * Give an APK file, a tree directories and files are extracted,
+ * representing partially the project which generated the APK.
+ * <p>
+ * The files are created in a temporary directory.
+ *
+ * @param apkFile
+ * APK file which the project tree will be extracted from.
+ * @param sdkPath
+ * SDK path where the tools for extracting and interpreting the
+ * APK information will be used.
+ *
+ * @return A file object holding a tree of directories and files which
+ * represent partially the project which generated the APK.
+ *
+ * @throws PreflightingToolException
+ * Exception thrown when there are problems creating the files
+ * and directories structure.
+ */
+ public static File extractProjectFromAPK(File apkFile, String sdkPath)
+ throws PreflightingToolException
+ {
+ String apkName = apkFile.getName();
+
+ // Create a temp directory to contain all extracted packages, if needed
+ if (!tmpAppValidatorFolder.exists())
+ {
+
+ try
+ {
+ tmpAppValidatorFolder.mkdir();
+ }
+ catch (SecurityException se)
+ {
+ PreflightingLogger.error(ApkUtils.class,
+ "It was not possible to extract the android package.", se); //$NON-NLS-1$
+ throw new PreflightingToolException(
+ PreflightingCoreNLS.ApkUtils_ImpossibleExtractAndroidPackageMessage, se);
+ }
+ }
+
+ File tmpProjectFile;
+ try
+ {
+ tmpProjectFile = File.createTempFile(apkName, null, tmpAppValidatorFolder);
+ tmpProjectFile.delete();
+ tmpProjectFile.mkdir();
+ }
+ catch (IOException ioException)
+ {
+ PreflightingLogger.error(ApkUtils.class,
+ "It was not possible to extract the android package.", ioException); //$NON-NLS-1$
+ throw new PreflightingToolException(
+ PreflightingCoreNLS.ApkUtils_ImpossibleExtractAndroidPackageMessage,
+ ioException);
+ }
+
+ String extractionMode =
+ ValidationManagerConfiguration.getInstance().getProperty(
+ ValidationManagerConfiguration.ConfigProperties.APK_EXTRACTION_MODE
+ .getName());
+ if (extractionMode.equals(ValidationManagerConfiguration.ExtractionModes.APKTOOL_MODE
+ .getMode()))
+ {
+ ApktoolUtils.extractFilesFromApk(apkFile, tmpProjectFile);
+ }
+ else
+ {
+ AaptUtils.extractFilesFromAPK(apkFile, sdkPath, tmpProjectFile);
+ }
+
+ return tmpProjectFile;
+ }
+
+ /**
+ * Returns a handler to the temp directory used for extracting APKs.
+ *
+ * @return A handler to the temp directory.
+ */
+ public static File getAppValidatorTempApkFolder()
+ {
+ return tmpAppValidatorFolder;
+ }
+
+ /**
+ * Iterates over APK (jar entries) to populate
+ *
+ * @param projectFile
+ * @return
+ * @throws IOException
+ * @throws CertificateException
+ */
+ public static List<Certificate> populateCertificate(File projectFile) throws IOException,
+ CertificateException
+ {
+ List<Certificate> certList = new ArrayList<Certificate>();
+ JarFile jar = new JarFile(projectFile);
+ Enumeration<JarEntry> jarEntries = jar.entries();
+ while (jarEntries.hasMoreElements())
+ {
+ JarEntry entry = jarEntries.nextElement();
+ if (entry.getName().toLowerCase().contains(DSA)
+ || entry.getName().toLowerCase().contains(RSA))
+ {
+ certList.addAll(extractCertificate(jar, entry));
+ }
+ }
+ return certList;
+ }
+
+ /**
+ * Extracts certificate from APK
+ *
+ * @param jar
+ * @param entry
+ * rsa or dsa jar item
+ * @return
+ * @throws IOException
+ * I/O problem to read jar
+ * @throws CertificateException
+ * certificate has problems
+ */
+ private static List<Certificate> extractCertificate(JarFile jar, JarEntry entry)
+ throws IOException, CertificateException
+ {
+ List<Certificate> certList = new ArrayList<Certificate>();
+ InputStream inStream = null;
+ try
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ inStream = jar.getInputStream(entry);
+ Collection<? extends Certificate> c = cf.generateCertificates(inStream);
+ Iterator<? extends Certificate> i = c.iterator();
+ while (i.hasNext())
+ {
+ Certificate cert = i.next();
+ certList.add(cert);
+ }
+ }
+ finally
+ {
+ if (inStream != null)
+ {
+ inStream.close();
+ }
+ }
+ return certList;
+ }
+
+ /**
+ * Unzip zipFile and returns the directory created with its contents
+ * @param zipFile
+ * @return
+ * @throws PreflightingToolException
+ */
+ public static File unzip(File zipFile) throws PreflightingToolException
+ {
+ File tempExtractionDir = null;
+ ZipInputStream apkInputStream = null;
+ FileOutputStream apkOutputStream = null;
+
+ try
+ {
+ //crate MOTODEV temp folder
+ if (!tmpAppValidatorFolder.exists())
+ {
+ tmpAppValidatorFolder.mkdir();
+ }
+ //create extraction folder
+ tempExtractionDir = File.createTempFile(zipFile.getName(), null, tmpAppValidatorFolder);
+ tempExtractionDir.delete();
+ tempExtractionDir.mkdir();
+
+ //open zipFile stream
+ apkInputStream = new ZipInputStream(new FileInputStream(zipFile.getAbsolutePath()));
+ ZipEntry apkZipEntry = apkInputStream.getNextEntry();
+
+ byte[] buf = new byte[BUFFER_SIZE];
+ CRC32 crc = new CRC32();
+
+ //while there are apks inside zip file
+ while (apkZipEntry != null)
+ {
+ crc.reset();
+ if (apkZipEntry.getName().endsWith(APK_EXTENSION))
+ {
+ //file to be created (apk)
+ try
+ {
+ apkOutputStream =
+ new FileOutputStream(tempExtractionDir.getAbsolutePath()
+ + Path.SEPARATOR + apkZipEntry.getName());
+
+ int length = 0;
+ //creates apk and updates CRC during the process
+ while ((length = apkInputStream.read(buf, 0, BUFFER_SIZE)) > -1)
+ {
+ apkOutputStream.write(buf, 0, length);
+ crc.update(buf, 0, length);
+ }
+
+ //test if extraction went fine
+ if (crc.getValue() != apkZipEntry.getCrc())
+ {
+ throw new PreflightingToolException(PreflightingCoreNLS.bind(
+ PreflightingCoreNLS.ApkUtils_ZipExtractionFile,
+ apkZipEntry.getName()));
+ }
+ }
+ finally
+ {
+ if (apkOutputStream != null)
+ {
+ try
+ {
+ apkOutputStream.close();
+ }
+ catch (IOException e)
+ {
+ // do nothing
+ }
+ }
+ }
+ }
+ apkZipEntry = apkInputStream.getNextEntry();
+ }
+ }
+ catch (IOException ioe)
+ {
+ //error during extraction, abort validation
+ throw new PreflightingToolException(PreflightingCoreNLS.ApkUtils_ZipExtraction, ioe);
+ }
+ finally
+ {
+ try
+ {
+ if (apkInputStream != null)
+ {
+ apkInputStream.close();
+ }
+ }
+ catch (IOException e)
+ {
+ // do nothing
+ }
+ }
+
+ return tempExtractionDir;
+ }
+} \ No newline at end of file