• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.ant;
18 
19 import com.android.sdklib.internal.build.SignedJarBuilder;
20 import com.android.sdklib.internal.build.SignedJarBuilder.IZipEntryFilter;
21 
22 import org.apache.tools.ant.BuildException;
23 import org.apache.tools.ant.types.Path;
24 
25 import java.io.FileInputStream;
26 import java.io.FileNotFoundException;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.security.KeyStore;
30 import java.security.KeyStore.PrivateKeyEntry;
31 import java.security.cert.X509Certificate;
32 
33 /**
34  * Simple Task to sign an apk.
35  *
36  */
37 public class SignApkTask extends SingleInputOutputTask {
38 
39     private String mKeystore;
40     private String mStorepass;
41     private String mAlias;
42     private String mKeypass;
43 
setKeystore(Path keystore)44     public void setKeystore(Path keystore) {
45         mKeystore = TaskHelper.checkSinglePath("keystore", keystore);
46     }
47 
setStorepass(String storepass)48     public void setStorepass(String storepass) {
49         mStorepass = storepass;
50     }
51 
setAlias(String alias)52     public void setAlias(String alias) {
53         mAlias = alias;
54     }
55 
setKeypass(String keypass)56     public void setKeypass(String keypass) {
57         mKeypass = keypass;
58     }
59 
60     @Override
createOutput()61     protected void createOutput() throws BuildException {
62         PrivateKeyEntry key = loadKeyEntry(
63                 mKeystore, null, mStorepass.toCharArray(),
64                 mAlias, mKeypass.toCharArray());
65 
66         if (key == null) {
67             throw new BuildException(String.format("Signing key %s not found", mAlias));
68         }
69 
70         SignedJarBuilder mBuilder = null;
71         try {
72             mBuilder = new SignedJarBuilder(
73                     new FileOutputStream(getOutput(), false /* append */),
74                     key.getPrivateKey(), (X509Certificate) key.getCertificate());
75 
76             mBuilder.writeZip(new FileInputStream(getInput()), new NullZipFilter());
77 
78             mBuilder.close();
79         } catch (FileNotFoundException e) {
80             throw new BuildException(String.format("Keystore '%s' is not found!", mKeystore));
81         } catch (Exception e) {
82             throw new BuildException(e.getMessage());
83         } finally {
84             if (mBuilder != null) {
85                 mBuilder.cleanUp();
86             }
87         }
88     }
89 
90     /**
91      * Loads the debug key from the keystore.
92      * @param osKeyStorePath the OS path to the keystore.
93      * @param storeType an optional keystore type, or <code>null</code> if the default is to
94      * be used.
95      * @return <code>true</code> if success, <code>false</code> if the keystore does not exist.
96      */
loadKeyEntry(String osKeyStorePath, String storeType, char[] storePassword, String alias, char[] aliasPassword)97     private PrivateKeyEntry loadKeyEntry(String osKeyStorePath, String storeType,
98             char[] storePassword, String alias, char[] aliasPassword) {
99         FileInputStream fis = null;
100         try {
101             KeyStore keyStore = KeyStore.getInstance(
102                     storeType != null ? storeType : KeyStore.getDefaultType());
103             fis = new FileInputStream(osKeyStorePath);
104             keyStore.load(fis, storePassword);
105             return (KeyStore.PrivateKeyEntry)keyStore.getEntry(
106                     alias, new KeyStore.PasswordProtection(aliasPassword));
107         } catch (Exception e) {
108             String msg = e.getMessage();
109             String causeMsg = null;
110 
111             Throwable cause = e.getCause();
112             if (cause != null) {
113                 causeMsg = cause.getMessage();
114             }
115 
116             if (msg != null) {
117                 if (causeMsg == null) {
118                     throw new BuildException(msg);
119                 } else {
120                     throw new BuildException(msg + ": " + causeMsg);
121                 }
122             } else {
123                 if (causeMsg == null) {
124                     throw new BuildException(e);
125                 } else {
126                     throw new BuildException(causeMsg);
127                 }
128             }
129         } finally {
130             if (fis != null) {
131                 try {
132                     fis.close();
133                 } catch (IOException e) {
134                     // pass
135                 }
136             }
137         }
138     }
139 
140     private final static class NullZipFilter implements IZipEntryFilter {
141 
142         @Override
checkEntry(String archivePath)143         public boolean checkEntry(String archivePath) throws ZipAbortException {
144             return true;
145         }
146     }
147 }
148