public interface ApkSignerEngine extends Closeable
The engine is stateful and thus cannot be used for signing multiple APKs. However, once the engine signed an APK, the engine can be used to re-sign the APK after it has been modified. This may be more efficient than signing the APK using a new instance of the engine. See Incremental Operation.
In the engine's operating model, a signed APK is produced as follows.
The input APK may contain JAR entries which, depending on the engine's configuration, may or
may not be output (e.g., existing signatures may need to be preserved or stripped) or which the
engine will overwrite as part of signing. The engine thus offers inputJarEntry(String)
which tells the client whether the input JAR entry needs to be output. This avoids the need for
the client to hard-code the aspects of APK signing which determine which parts of input must be
ignored. Similarly, the engine offers inputApkSigningBlock(DataSource)
to help the
client avoid dealing with preserving or stripping APK Signature Scheme v2 signature of the input
APK.
To use the engine to sign an input APK (or a collection of JAR entries), follow these steps:
inputApkSigningBlock(DataSource)
.inputJarEntry(String)
to determine
whether this entry should be output. The engine may request to inspect the entry.outputJarEntry(String)
which may request to
inspect the entry.outputJarEntries()
which may request
that additional JAR entries are output. These entries comprise the output APK's JAR
signature.outputZipSections(DataSource, DataSource, DataSource)
which may request that
an APK Signature Block is inserted before the ZIP Central Directory. The block contains the
output APK's APK Signature Scheme v2 signature.outputDone()
to signal that the APK was output in full. The engine will
confirm that the output APK is signed.close()
to signal that the engine will no longer be used. This lets the
engine free any resources it no longer needs.
Some invocations of the engine may provide the client with a task to perform. The client is expected to perform all requested tasks before proceeding to the next stage of signing. See documentation of each method about the deadlines for performing the tasks requested by the method.
To use the engine in incremental mode, keep notifying the engine of changes to the APK through
inputApkSigningBlock(DataSource)
, inputJarEntry(String)
,
inputJarEntryRemoved(String)
, outputJarEntry(String)
,
and outputJarEntryRemoved(String)
, perform the tasks requested by the engine through
these methods, and, when a new signed APK is desired, run through steps 5 onwards to re-sign the
APK.
input...
methods are
not invoked. In this mode, the engine has less control over output because it cannot request that
some JAR entries are not output. Nevertheless, the engine will attempt to make the output APK
signed and will report an error if cannot do so.Modifier and Type | Interface and Description |
---|---|
static class |
ApkSignerEngine.InputJarEntryInstructions
Instructions about how to handle an input APK's JAR entry.
|
static interface |
ApkSignerEngine.InspectJarEntryRequest
Request to inspect the specified JAR entry.
|
static interface |
ApkSignerEngine.OutputApkSigningBlockRequest
Request to add the specified APK Signing Block to the output APK.
|
static interface |
ApkSignerEngine.OutputJarSignatureRequest
Request to add JAR signature (aka v1 signature) to the output APK.
|
Modifier and Type | Method and Description |
---|---|
void |
close()
Indicates to this engine that it will no longer be used.
|
void |
inputApkSigningBlock(DataSource apkSigningBlock)
Indicates to this engine that the input APK contains the provided APK Signing Block.
|
ApkSignerEngine.InputJarEntryInstructions |
inputJarEntry(String entryName)
Indicates to this engine that the specified JAR entry was encountered in the input APK.
|
ApkSignerEngine.InputJarEntryInstructions.OutputPolicy |
inputJarEntryRemoved(String entryName)
Indicates to this engine that the specified JAR entry was removed from the input.
|
void |
outputDone()
Indicates to this engine that the signed APK was output.
|
ApkSignerEngine.OutputJarSignatureRequest |
outputJarEntries()
Indicates to this engine that all JAR entries have been output.
|
ApkSignerEngine.InspectJarEntryRequest |
outputJarEntry(String entryName)
Indicates to this engine that the specified JAR entry was output.
|
void |
outputJarEntryRemoved(String entryName)
Indicates to this engine that the specified JAR entry was removed from the output.
|
ApkSignerEngine.OutputApkSigningBlockRequest |
outputZipSections(DataSource zipEntries,
DataSource zipCentralDirectory,
DataSource zipEocd)
Indicates to this engine that the ZIP sections comprising the output APK have been output.
|
void inputApkSigningBlock(DataSource apkSigningBlock) throws IOException, ApkFormatException, IllegalStateException
apkSigningBlock
- APK signing block of the input APK. The provided data source is
guaranteed to not be used by the engine after this method terminates.IOException
- if an I/O error occurs while reading the APK Signing BlockApkFormatException
- if the APK Signing Block is malformedIllegalStateException
- if this engine is closedApkSignerEngine.InputJarEntryInstructions inputJarEntry(String entryName) throws IllegalStateException
When an input entry is updated/changed, it's OK to not invoke
inputJarEntryRemoved(String)
before invoking this method.
IllegalStateException
- if this engine is closedApkSignerEngine.InspectJarEntryRequest outputJarEntry(String entryName) throws IllegalStateException
It is unnecessary to invoke this method for entries added to output by this engine (e.g.,
requested by outputJarEntries()
) provided the entries were output with exactly the
data requested by the engine.
When an already output entry is updated/changed, it's OK to not invoke
outputJarEntryRemoved(String)
before invoking this method.
null
if the engine does not need to inspect
the entry. The request must be fulfilled before outputJarEntries()
is
invoked.IllegalStateException
- if this engine is closedApkSignerEngine.InputJarEntryInstructions.OutputPolicy inputJarEntryRemoved(String entryName) throws IllegalStateException
inputJarEntry(String)
hasn't been invoked.IllegalStateException
- if this engine is closedvoid outputJarEntryRemoved(String entryName) throws IllegalStateException
outputJarEntry(String)
hasn't been invoked.IllegalStateException
- if this engine is closedApkSignerEngine.OutputJarSignatureRequest outputJarEntries() throws ApkFormatException, NoSuchAlgorithmException, InvalidKeyException, SignatureException, IllegalStateException
null
if there is no need to add
a JAR signature. The request will contain additional JAR entries to be output. The
request must be fulfilled before
outputZipSections(DataSource, DataSource, DataSource)
is invoked.ApkFormatException
- if the APK is malformed in a way which is preventing this engine
from producing a valid signature. For example, if the engine uses the provided
META-INF/MANIFEST.MF
as a template and the file is malformed.NoSuchAlgorithmException
- if a signature could not be generated because a required
cryptographic algorithm implementation is missingInvalidKeyException
- if a signature could not be generated because a signing key is
not suitable for generating the signatureSignatureException
- if an error occurred while generating a signatureIllegalStateException
- if there are unfulfilled requests, such as to inspect some JAR
entries, or if the engine is closedApkSignerEngine.OutputApkSigningBlockRequest outputZipSections(DataSource zipEntries, DataSource zipCentralDirectory, DataSource zipEocd) throws IOException, ApkFormatException, NoSuchAlgorithmException, InvalidKeyException, SignatureException, IllegalStateException
The provided data sources are guaranteed to not be used by the engine after this method terminates.
zipEntries
- the section of ZIP archive containing Local File Header records and data of
the ZIP entries. In a well-formed archive, this section starts at the start of the
archive and extends all the way to the ZIP Central Directory.zipCentralDirectory
- ZIP Central Directory sectionzipEocd
- ZIP End of Central Directory (EoCD) recordnull
if the output must
not contain an APK Signing Block. The request must be fulfilled before
outputDone()
is invoked.IOException
- if an I/O error occurs while reading the provided ZIP sectionsApkFormatException
- if the provided APK is malformed in a way which prevents this
engine from producing a valid signature. For example, if the APK Signing Block
provided to the engine is malformed.NoSuchAlgorithmException
- if a signature could not be generated because a required
cryptographic algorithm implementation is missingInvalidKeyException
- if a signature could not be generated because a signing key is
not suitable for generating the signatureSignatureException
- if an error occurred while generating a signatureIllegalStateException
- if there are unfulfilled requests, such as to inspect some JAR
entries or to output JAR signature, or if the engine is closedvoid outputDone() throws IllegalStateException
This does not change the output APK. The method helps the client confirm that the current output is signed.
IllegalStateException
- if there are unfulfilled requests, such as to inspect some JAR
entries or to output signatures, or if the engine is closedvoid close()
This does not change the output APK. For example, if the output APK is not yet fully signed, it will remain so after this method terminates.
close
in interface AutoCloseable
close
in interface Closeable
Copyright © 2016. All rights reserved.