/* * PSXperia Converter Tool - Logging * Copyright (C) 2011 Yifan Lu (http://yifan.lu/) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.yifanlu.PSXperiaTool; import com.android.sdklib.internal.build.SignedJarBuilder; import java.io.*; import java.security.*; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Arrays; public class ApkBuilder { private static final String ALIAS = "signPSXperia"; private static final char[] KEYSTORE_PASSWORD = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; private static final char[] ALIAS_PASSWORD = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; public static final String VERSION = "0.3 Beta 2"; private File mInputDir; private File mOutputApk; public ApkBuilder(File inputDir, File outputApk){ this.mInputDir = inputDir; this.mOutputApk = outputApk; } public void buildApk() throws IOException, InterruptedException, GeneralSecurityException, SignedJarBuilder.IZipEntryFilter.ZipAbortException { String os = System.getProperty("os.name"); Logger.verbose("Your OS: %s", os); File aaptTool; if(os.equals("Mac OS X")) aaptTool = new File("./aapt-osx"); else if(os.startsWith("Windows")) aaptTool = new File("./aapt-windows.exe"); else if(os.equals("Linux")) aaptTool = new File("./aapt-linux"); else { Logger.warning("Does not understand OS name '%s', assuming to be Linux", os); aaptTool = new File("./aapt-linux"); } InputStream in = PSXperiaTool.class.getResourceAsStream("/resources/" + aaptTool.getName()); Logger.verbose("Extracting %s", aaptTool.getPath()); writeStreamToFile(in, aaptTool); in.close(); aaptTool.setExecutable(true); File androidFrameworkJar = new File("./android-framework.jar"); Logger.verbose("Extracting %s", androidFrameworkJar.getPath()); in = PSXperiaTool.class.getResourceAsStream("/resources/android-framework.jar"); writeStreamToFile(in, androidFrameworkJar); in.close(); File tempApk = new File(mOutputApk.getPath() + ".unsigned"); String[] cmd = new String[12]; cmd[0] = (aaptTool.getPath()); cmd[1] = ("package"); cmd[2] = ("-f"); cmd[3] = ("-F"); cmd[4] = (tempApk.getPath()); cmd[5] = ("-S"); cmd[6] = ((new File(mInputDir, "/res")).getPath()); cmd[7] = ("-M"); cmd[8] = ((new File(mInputDir, "/assets/AndroidManifest.xml")).getPath()); cmd[9] = ("-I"); cmd[10] = (androidFrameworkJar.getPath()); cmd[11] = (mInputDir.getPath()); Logger.debug("Running command: " + Arrays.toString(cmd).replaceAll("\\,", "")); runCmdWithOutput(cmd); Logger.info("Signing apk %s to %s", tempApk.getPath(), mOutputApk.getPath()); signApk(tempApk); Logger.verbose("Cleaning up signing stuff."); tempApk.delete(); androidFrameworkJar.delete(); aaptTool.delete(); } private void writeStreamToFile(InputStream in, File outFile) throws IOException { Logger.verbose("Writing to: %s", outFile.getPath()); FileOutputStream out = new FileOutputStream(outFile); byte[] buffer = new byte[1024]; int n; while((n = in.read(buffer)) != -1){ out.write(buffer, 0, n); } out.close(); } public static void runCmdWithOutput(String[] cmd) throws IOException, InterruptedException { Process ps = Runtime.getRuntime().exec(cmd); BufferedReader in = new BufferedReader(new InputStreamReader(ps.getErrorStream())); String line; while ((line = in.readLine()) != null) { Logger.debug(line); } in.close(); if (ps.waitFor() != 0) { throw new IOException("Executable did not return without error."); } } private void signApk(File unsignedApk) throws IOException, GeneralSecurityException, SignedJarBuilder.IZipEntryFilter.ZipAbortException { FileInputStream in = new FileInputStream(unsignedApk); FileOutputStream out = new FileOutputStream(mOutputApk); KeyStore ks = getKeyStore(); PrivateKey key = (PrivateKey)ks.getKey(ALIAS, ALIAS_PASSWORD); X509Certificate cert = (X509Certificate)ks.getCertificate(ALIAS); SignedJarBuilder builder = new SignedJarBuilder(out, key, cert); builder.writeZip(in, null); builder.close(); out.close(); in.close(); } private KeyStore getKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream is = PSXperiaTool.class.getResourceAsStream("/resources/signApk.keystore"); ks.load(is, KEYSTORE_PASSWORD); return ks; } }