pub struct Engine { /* private fields */ }Expand description
Engine over one APK.
Implementations§
Source§impl Engine
impl Engine
Sourcepub fn call_graph(&self, q: &CallQuery) -> Result<CallTree>
pub fn call_graph(&self, q: &CallQuery) -> Result<CallTree>
Callers or callees of a method, depth levels deep, as a tree.
The roots are every overload of method declared by class (or the
exact signature) that some DEX references; an unknown method is an
error. Each method is expanded once, at its shallowest occurrence;
other occurrences are marked repeated.
§Errors
EngineError::Query for an inconsistent query (from on a callees
walk), a root method no DEX references or a condition no method
matches; EngineError::Apk when the APK cannot be opened.
Sourcepub fn call_graph_cancellable(
&self,
q: &CallQuery,
cancel: &AtomicBool,
) -> Result<CallTree>
pub fn call_graph_cancellable( &self, q: &CallQuery, cancel: &AtomicBool, ) -> Result<CallTree>
Engine::call_graph that stops, with ApkError::Cancelled, once
cancel is raised.
§Errors
As Engine::call_graph, plus the cancellation.
Source§impl Engine
impl Engine
Sourcepub fn scan_classes(
&self,
prefix: Option<&str>,
progress: impl Fn(usize, usize) + Sync,
) -> Result<Vec<EntryClasses>>
pub fn scan_classes( &self, prefix: Option<&str>, progress: impl Fn(usize, usize) + Sync, ) -> Result<Vec<EntryClasses>>
Enumerate the classes of every root DEX entry whose descriptor starts
with prefix (a Dalvik descriptor prefix, used as is).
Entries are read in parallel, largest first; the result follows the
central-directory order, and each entry’s logical DEXes and classes
keep their file order. progress(done, total) runs after each entry.
Problems are reported per entry / DEX, never as a failure of the call;
only an unreadable APK fails it.
§Errors
EngineError::Apk when the APK cannot be opened.
Sourcepub fn list_classes(&self, prefix: Option<&str>) -> Result<Vec<ClassListing>>
pub fn list_classes(&self, prefix: Option<&str>) -> Result<Vec<ClassListing>>
Every class of the APK, optionally restricted to a package / class
prefix (com.poc, com/poc or Lcom/poc), in DEX order. Strict: the
first unreadable entry, unparsable DEX or bad class_def fails the call.
§Errors
EngineError::Query for an empty prefix, the error of the first
entry that cannot be read, and EngineError::BadDex for the first
bad DEX or class_def (DexClasses::check).
Source§impl Engine
impl Engine
Sourcepub fn matching_methods(
&self,
queries: &[Query],
cancel: &AtomicBool,
) -> Result<MatchingMethods>
pub fn matching_methods( &self, queries: &[Query], cancel: &AtomicBool, ) -> Result<MatchingMethods>
The signatures (Lcls;->name(params)ret) of the methods whose code
matches each query, all queries in one pass.
§Errors
EngineError::Query for a class relation query (it matches classes,
not code) or when some DEX entry could not be searched (a partial set
would silently drop methods), plus the errors of
Engine::find_refs.
Source§impl Engine
impl Engine
Sourcepub fn hierarchy(&self, q: &HierarchyQuery) -> Result<HierarchyTree>
pub fn hierarchy(&self, q: &HierarchyQuery) -> Result<HierarchyTree>
Transitive subclasses / implementers (or supertypes) of a class, as a
tree, with the classes defining method marked.
§Errors
EngineError::Query when no DEX defines or references the class,
EngineError::Smali for a malformed method signature, and
EngineError::Apk when the APK cannot be opened.
Sourcepub fn hierarchy_cancellable(
&self,
q: &HierarchyQuery,
cancel: &AtomicBool,
) -> Result<HierarchyTree>
pub fn hierarchy_cancellable( &self, q: &HierarchyQuery, cancel: &AtomicBool, ) -> Result<HierarchyTree>
Engine::hierarchy that stops, with ApkError::Cancelled, once
cancel is raised.
§Errors
As Engine::hierarchy, plus the cancellation.
Source§impl Engine
impl Engine
Sourcepub fn manifest_summary(&self) -> Result<ManifestSummary>
pub fn manifest_summary(&self) -> Result<ManifestSummary>
Parse AndroidManifest.xml (and the XML resources it points at) into
a ManifestSummary.
§Errors
EngineError::Apk when the APK or manifest
cannot be read, EngineError::Arsc when
resources.arsc is malformed, and
EngineError::Axml when the manifest is not
valid binary XML. Referenced XML resources that fail are
ManifestSummary::warnings instead.
Source§impl Engine
impl Engine
Sourcepub fn with_name_mappings(
self,
mappings: impl Into<Arc<NameMappings>>,
) -> Engine
pub fn with_name_mappings( self, mappings: impl Into<Arc<NameMappings>>, ) -> Engine
Show the names of mappings in decompiled source (typically read
from the user’s mapping.txt with NameMappings::from_proguard_file).
Shared, since one mapping file serves many engines.
Sourcepub fn name_mappings(&self) -> &NameMappings
pub fn name_mappings(&self) -> &NameMappings
The names this program’s classes and members go by in decompiled
output: the set given to Engine::with_name_mappings, or the
identity (empty) when there is none, in which case every class and
member keeps its own name (backends still escape names their language
cannot spell). Narrow it to a request with NameMappings::restricted_to.
Source§impl Engine
impl Engine
Sourcepub fn prebuild(&self) -> Result<PrebuildReport>
pub fn prebuild(&self) -> Result<PrebuildReport>
Build (or map from L2) the locator tables of every DEX entry the caches hold, so the first query of each kind skips its table builds. Blocks until done; meant for a background thread after a warm open. Does nothing without a memory cache (the tables would be dropped).
§Errors
EngineError::Apk when the APK cannot be
opened. A DEX that fails to parse or build tables is skipped (its
queries report the error later).
§Panics
When a worker thread panics (a bug); the panic is propagated.
Sourcepub fn cancel_prebuild(&self)
pub fn cancel_prebuild(&self)
Stop a running Engine::prebuild (and any later one) and wait for
its workers to finish the table they are on.
§Panics
When the prebuild’s state mutex is poisoned (a prebuild thread panicked while holding it).
Source§impl Engine
impl Engine
Sourcepub fn resources(&self) -> Result<Option<Arc<ResTable>>>
pub fn resources(&self) -> Result<Option<Arc<ResTable>>>
The APK’s resource table, parsed once per APK version and kept for
later calls. None when the APK has no resources.arsc.
§Errors
EngineError::Apk when the APK or the table cannot be read,
EngineError::Arsc when the table is malformed.
Sourcepub fn release_resources(&self)
pub fn release_resources(&self)
Forget the parsed resource table (and its name index); the next resource query parses it again (about a millisecond even for a large app).
Sourcepub fn xml(&self, path: &str) -> Result<String>
pub fn xml(&self, path: &str) -> Result<String>
Decode a binary XML file of the APK (res/xml/..., a layout, the
manifest), naming references and app attributes from the resource table.
§Errors
EngineError::Query when the APK has no entry path, the errors of
Engine::resources, and EngineError::Axml when the entry is not
valid binary XML.
Sourcepub fn manifest_xml_resolved(&self) -> Result<String>
pub fn manifest_xml_resolved(&self) -> Result<String>
Sourcepub fn dump_resources(&self, f: impl FnMut(ResourceRow)) -> Result<()>
pub fn dump_resources(&self, f: impl FnMut(ResourceRow)) -> Result<()>
Call f with every value of every resource, in id order (one row per
resource and configuration).
§Errors
EngineError::Query when the APK has no resources.arsc, and the errors of
Engine::resources.
Sourcepub fn resource(&self, query: &str) -> Result<Vec<ResourceRow>>
pub fn resource(&self, query: &str) -> Result<Vec<ResourceRow>>
Every configuration’s value of the resource query: an id
(0x7f0d0001) or a name (string/app_name, @pkg:type/name).
§Errors
EngineError::Query when the APK has no resources.arsc or no resource
query, and the errors of Engine::resources.
Sourcepub fn resolve_resource(
&self,
query: &str,
config: Option<&Config>,
) -> Result<(Vec<String>, ResourceRow)>
pub fn resolve_resource( &self, query: &str, config: Option<&Config>, ) -> Result<(Vec<String>, ResourceRow)>
Resolve the reference chain of query for a device described by
config (default: Config::any_device). Returns the rendered
chain (@string/a -> @string/b) and the final value.
§Errors
EngineError::Query when the APK has no resources.arsc, no resource
query, or a chain that cannot be resolved (no value for the
configuration, a dangling or cyclic reference), and the errors of
Engine::resources.
§Panics
Never: a resolved chain always starts with the queried id.
Sourcepub fn search_resources(
&self,
pattern: &str,
literal: bool,
field: ResourceField,
limit: usize,
) -> Result<(Vec<ResourceRow>, usize)>
pub fn search_resources( &self, pattern: &str, literal: bool, field: ResourceField, limit: usize, ) -> Result<(Vec<ResourceRow>, usize)>
Resources whose name and/or string value matches the regex pattern
(a plain substring when literal), one row per matching configuration
value (names: one row per configuration). At most limit rows; the
second value is the total number of matches.
§Errors
EngineError::Query for an invalid regex or an APK without
resources.arsc, and the errors of Engine::resources.
Source§impl Engine
impl Engine
Sourcepub fn annotate_resource_ids(&self, smali: &str) -> String
pub fn annotate_resource_ids(&self, smali: &str) -> String
Name the resource ids of smali: a const (or .array-data element)
whose literal is a resource of this APK gets # @type/name appended,
e.g. const v0, 0x7f0b001c # @layout/activity_main. Unchanged when
the APK has no (readable) resource table: names are a convenience,
never a reason for the class itself to fail.
Source§impl Engine
impl Engine
Sourcepub fn find_refs_rules(
&self,
rules: &[Query],
opts: FindOptions,
cancel: &AtomicBool,
sink: &mut dyn FnMut(usize, RefBatch),
) -> Result<RefSummary>
pub fn find_refs_rules( &self, rules: &[Query], opts: FindOptions, cancel: &AtomicBool, sink: &mut dyn FnMut(usize, RefBatch), ) -> Result<RefSummary>
Several queries in one pass: each DEX is loaded once and scanned once
per index kind for all of them. sink gets (rule index, batch),
one batch per rule and entry, entries in completion order.
Each rule shares L3 with Engine::find_refs_opts: rules an earlier
run left there are replayed, only the others are searched, and each of
those is kept under its own key.
§Errors
As Engine::find_refs, for the first invalid rule.
§Panics
Never: results are only recorded for L3 when a disk cache is in use.
Sourcepub fn search_target_entry_rules(
&self,
target: &SearchTarget,
entry: &Entry,
rules: &[&CompiledQuery],
aggregate: bool,
cancel: &AtomicBool,
) -> Vec<RefBatch>
pub fn search_target_entry_rules( &self, target: &SearchTarget, entry: &Entry, rules: &[&CompiledQuery], aggregate: bool, cancel: &AtomicBool, ) -> Vec<RefBatch>
Engine::search_target_entry for a rule set: one batch per rule.
Source§impl Engine
impl Engine
Sourcepub fn cached_refs(
&self,
target: &SearchTarget,
query: &Query,
aggregate: bool,
) -> Option<Vec<RefBatch>>
pub fn cached_refs( &self, target: &SearchTarget, query: &Query, aggregate: bool, ) -> Option<Vec<RefBatch>>
The rows an earlier search of query on this APK left in L3: what
Engine::find_refs_with replays, so the one-APK and the sweep paths
share results.
Sourcepub fn store_refs(&self, query: &Query, aggregate: bool, batches: &[RefBatch])
pub fn store_refs(&self, query: &Query, aggregate: bool, batches: &[RefBatch])
Keep the batches of a complete search of query on this APK in L3
(not when one failed, see Engine::cached_refs).
§Panics
Never: it returns early unless a disk cache with L3 is in use.
Sourcepub fn search_target_entry_dedup(
&self,
target: &SearchTarget,
entry: &Entry,
query: &CompiledQuery,
aggregate: bool,
cancel: &AtomicBool,
claim: &Claim,
) -> RefBatch
pub fn search_target_entry_dedup( &self, target: &SearchTarget, entry: &Entry, query: &CompiledQuery, aggregate: bool, cancel: &AtomicBool, claim: &Claim, ) -> RefBatch
Engine::search_target_entry for an entry claimed in a
DexDedup: a leading entry is searched and its rows offered to the
entries that follow it; a following one reuses them when its bytes
hash the same.
§Panics
Never: a search of one query yields exactly one batch.
Sourcepub fn search_target_entry_rules_dedup(
&self,
target: &SearchTarget,
entry: &Entry,
rules: &[&CompiledQuery],
aggregate: bool,
cancel: &AtomicBool,
claim: &Claim,
) -> Vec<RefBatch>
pub fn search_target_entry_rules_dedup( &self, target: &SearchTarget, entry: &Entry, rules: &[&CompiledQuery], aggregate: bool, cancel: &AtomicBool, claim: &Claim, ) -> Vec<RefBatch>
Engine::search_target_entry_rules for an entry claimed with
DexDedup::claim_rules for these rules.
Source§impl Engine
impl Engine
Sourcepub fn new(apk_path: impl AsRef<Path>) -> Engine
pub fn new(apk_path: impl AsRef<Path>) -> Engine
An engine over apk_path: an APK, a jar, a bare DEX file, or a
program of several read as one (a directory, or paths joined with
,; see Apk::open).
Sourcepub fn with_limits(self, limits: Limits) -> Engine
pub fn with_limits(self, limits: Limits) -> Engine
Refuse entries that inflate past limits (zip bombs).
Sourcepub fn with_threads(self, threads: impl Into<Threads>) -> Engine
pub fn with_threads(self, threads: impl Into<Threads>) -> Engine
Use threads worker threads per search (or pick them automatically).
Sourcepub fn with_debug(self, debug: bool) -> Engine
pub fn with_debug(self, debug: bool) -> Engine
Log timings and cache decisions of each query through the logger.
Sourcepub fn with_logger(
self,
logger: impl Fn(&str) + Send + Sync + 'static,
) -> Engine
pub fn with_logger( self, logger: impl Fn(&str) + Send + Sync + 'static, ) -> Engine
Route debug output somewhere other than stdout.
Sourcepub fn with_cache(self, config: CacheConfig) -> Engine
pub fn with_cache(self, config: CacheConfig) -> Engine
Enable caching of inflated entries. A disk cache whose directory holds foreign files is dropped with a warning through the logger (set it first), instead of every write failing silently in the background.
Use cache (shared with other engines) instead of a private one.
Sourcepub fn cache_stats(&self) -> CacheStats
pub fn cache_stats(&self) -> CacheStats
Cache activity of this engine so far.
Sourcepub fn resident_bytes(&self) -> usize
pub fn resident_bytes(&self) -> usize
Heap this engine holds outside the memory cache, roughly: the class
graph and the parsed resource table it keeps for later calls. A host
keeping many engines counts it against its memory budget
(SharedCache::set_reserved).
Sourcepub fn memory_cache_bytes(&self) -> usize
pub fn memory_cache_bytes(&self) -> usize
Bytes currently charged to the in-memory cache: entry bytes plus the locator tables built for them.
Sourcepub fn release_memory_cache(&self) -> usize
pub fn release_memory_cache(&self) -> usize
Drop this APK’s entries from the in-memory cache (shared or not), and its parsed resource table, and return the DEX bytes released; queries still holding them keep them alive.
Sourcepub fn memory_cache_mapped_bytes(&self) -> usize
pub fn memory_cache_mapped_bytes(&self) -> usize
Entry bytes of the in-memory cache that are mapped from the disk cache (file-backed pages the OS can reclaim) rather than held on the heap.
Sourcepub fn memory_cache_mapped_table_bytes(&self) -> usize
pub fn memory_cache_mapped_table_bytes(&self) -> usize
Bytes of the in-memory cache’s locator tables that are viewed in L2 files (file-backed pages shared with other processes) rather than held on the heap.
Sourcepub fn flush_cache_writes(&self)
pub fn flush_cache_writes(&self)
Block until every queued disk-cache write has been renamed into place.
Sourcepub fn close_cache_writes(&self)
pub fn close_cache_writes(&self)
Engine::flush_cache_writes for process exit: also stops queueing,
so a worker still holding the engine cannot start a writer thread that
exiting would kill mid-write. Run on drop.
Sourcepub fn open(&self) -> Result<Apk>
pub fn open(&self) -> Result<Apk>
Open the APK, or reuse the one opened last while Apk::version_of
finds the same files, sizes and times.
§Errors
EngineError::Apk when the APK cannot be opened or its central
directory read.
Sourcepub fn resolve_path(apk_path: &Path, base: &Path) -> PathBuf
pub fn resolve_path(apk_path: &Path, base: &Path) -> PathBuf
apk_path (what Engine::new takes) with relative paths resolved
against base, each path of a program on its own.
Sourcepub fn can_open(apk_path: &Path) -> bool
pub fn can_open(apk_path: &Path) -> bool
Whether apk_path opens: a readable file, or a program with code.
Sourcepub fn program_notes(&self) -> Vec<String>
pub fn program_notes(&self) -> Vec<String>
One line per archive of a program left out of its code (no root DEX,
e.g. a jar deodexed into oat/, or not a zip); none for one file.
Sourcepub fn search_target(&self) -> Result<SearchTarget>
pub fn search_target(&self) -> Result<SearchTarget>
Open the APK and list its DEX entries for
Engine::search_target_entry.
§Errors
EngineError::Apk when the APK cannot be opened or its central
directory read.
Sourcepub fn search_target_entry(
&self,
target: &SearchTarget,
entry: &Entry,
query: &CompiledQuery,
aggregate: bool,
cancel: &AtomicBool,
) -> RefBatch
pub fn search_target_entry( &self, target: &SearchTarget, entry: &Entry, query: &CompiledQuery, aggregate: bool, cancel: &AtomicBool, ) -> RefBatch
Search one entry of target (what Engine::find_refs_with runs per
entry), through this engine’s caches.
Sourcepub fn dex_entries(&self) -> Result<Vec<Entry>>
pub fn dex_entries(&self) -> Result<Vec<Entry>>
Root-level DEX entries, smallest compressed first.
§Errors
EngineError::Apk when the APK cannot be opened or its central
directory read.
Sourcepub fn apk_key(&self, apk: &Apk) -> Option<ApkKey>
pub fn apk_key(&self, apk: &Apk) -> Option<ApkKey>
Cache key for apk when caching is enabled. Hashing the central
directory is done once per APK version; later calls only stat.
Sourcepub fn entry_bytes(
&self,
apk: &Apk,
key: Option<&ApkKey>,
entry: &Entry,
) -> Result<DexBytes>
pub fn entry_bytes( &self, apk: &Apk, key: Option<&ApkKey>, entry: &Entry, ) -> Result<DexBytes>
Inflated bytes of entry, through the caches when enabled. Stored
entries are copied only when an in-memory cache wants to keep them.
§Errors
EngineError::Apk when the entry cannot be read or inflated, or
inflates past the InflateLimits.
Sourcepub fn get_class_dex(&self, descriptor: &str) -> Result<Option<ClassHit>>
pub fn get_class_dex(&self, descriptor: &str) -> Result<Option<ClassHit>>
Find the DEX that defines descriptor (Lcom/poc/Main;).
DEX entries are inflated in parallel, smallest first. Entries that are not cached are first streamed only as far as their id tables and string data to answer the probe cheaply; only a hit is inflated fully.
A class several DEX files define resolves as a class loader would:
the first archive of a program, then classes.dex, classes2.dex,
and so on. Once a DEX defines it, DEX files after it are no
longer read; workers still inflating one at that moment finish on
their own in the background. A program reads every archive, to name
the others that define the class too (ClassHit::also_defined_in).
A class no DEX defines is Ok(None).
§Errors
EngineError::Apk when the APK cannot be opened, and the error of a
DEX that failed to read or parse when no other DEX defines the class.
Sourcepub fn get_class_dex_cancellable(
&self,
descriptor: &str,
cancel: &AtomicBool,
) -> Result<Option<ClassHit>>
pub fn get_class_dex_cancellable( &self, descriptor: &str, cancel: &AtomicBool, ) -> Result<Option<ClassHit>>
Engine::get_class_dex that stops, with ApkError::Cancelled, once
cancel is raised.
§Errors
As Engine::get_class_dex, plus the cancellation.
Sourcepub fn get_class(&self, descriptor: &str) -> Result<ClassSource>
pub fn get_class(&self, descriptor: &str) -> Result<ClassSource>
Locate, rebuild and disassemble a class.
§Errors
EngineError::ClassNotFound when no DEX defines it, the errors of
Engine::get_class_dex, and EngineError::Rebuild /
EngineError::Smali when the class cannot be rendered at all (a class
the rebuild cannot represent is disassembled from the original DEX
instead, with a ClassSource::warning).
Sourcepub fn get_class_with(
&self,
descriptor: &str,
opts: SmaliOptions,
) -> Result<ClassSource>
pub fn get_class_with( &self, descriptor: &str, opts: SmaliOptions, ) -> Result<ClassSource>
Sourcepub fn get_class_method(
&self,
descriptor: &str,
opts: SmaliOptions,
method: Option<&str>,
) -> Result<ClassSource>
pub fn get_class_method( &self, descriptor: &str, opts: SmaliOptions, method: Option<&str>, ) -> Result<ClassSource>
Engine::get_class_with that renders only the method whose
name(params)ret is method (no fields) when one is given. A malformed
signature is rejected before the APK is read; a class without such a
method is an error. The rebuilt DEX still holds the whole class.
§Errors
As Engine::get_class, plus EngineError::Smali for a malformed
method or one the class does not have.
Sourcepub fn get_class_method_cancellable(
&self,
descriptor: &str,
opts: SmaliOptions,
method: Option<&str>,
cancel: &AtomicBool,
) -> Result<ClassSource>
pub fn get_class_method_cancellable( &self, descriptor: &str, opts: SmaliOptions, method: Option<&str>, cancel: &AtomicBool, ) -> Result<ClassSource>
Engine::get_class_method that stops looking for the class, with
ApkError::Cancelled, once cancel is raised.
§Errors
As Engine::get_class_method, plus the cancellation.
Sourcepub fn find_refs(
&self,
query: &Query,
sink: impl FnMut(RefBatch),
) -> Result<RefSummary>
pub fn find_refs( &self, query: &Query, sink: impl FnMut(RefBatch), ) -> Result<RefSummary>
Search every DEX entry for references. sink receives one batch per
entry in completion order. Returns a summary once all entries finish.
A query that finds no row as written is searched again with its names
read as decompiled Java / Kotlin source spells DEX names
(names::denormalize_query); RefSummary::notes says so when that
finds rows.
§Errors
EngineError::Query / EngineError::Find for an invalid query,
and EngineError::Apk when the APK cannot be opened. A DEX entry that
fails to load or search does not fail the run: its batch carries the
error in RefBatch::error.
Sourcepub fn find_refs_with(
&self,
query: &Query,
aggregate: bool,
cancel: &AtomicBool,
sink: &mut dyn FnMut(RefBatch),
) -> Result<RefSummary>
pub fn find_refs_with( &self, query: &Query, aggregate: bool, cancel: &AtomicBool, sink: &mut dyn FnMut(RefBatch), ) -> Result<RefSummary>
find_refs with control over aggregation and cancellation. An invalid
pattern is reported once, up front, instead of once per DEX.
§Errors
Sourcepub fn find_refs_opts(
&self,
query: &Query,
opts: FindOptions,
cancel: &AtomicBool,
sink: &mut dyn FnMut(RefBatch),
) -> Result<RefSummary>
pub fn find_refs_opts( &self, query: &Query, opts: FindOptions, cancel: &AtomicBool, sink: &mut dyn FnMut(RefBatch), ) -> Result<RefSummary>
Sourcepub fn find_refs_text(
&self,
query: &Query,
cancel: &AtomicBool,
sink: &mut dyn FnMut(RefBatch),
) -> Result<RefSummary>
pub fn find_refs_text( &self, query: &Query, cancel: &AtomicBool, sink: &mut dyn FnMut(RefBatch), ) -> Result<RefSummary>
The rows of Engine::find_refs (one per method, no context) as
text: each batch holds them in RefBatch::text, exactly the
RefResult::lines find_refs would give, with no structured rows.
A broad query renders and replays much faster this way.
§Errors
Sourcepub fn fill_context(
&self,
rows: &mut [RefResult],
ctx: RefContext,
) -> Result<Vec<String>>
pub fn fill_context( &self, rows: &mut [RefResult], ctx: RefContext, ) -> Result<Vec<String>>
Fill the context of rows an earlier Engine::find_refs returned
(typically one page of them): only their DEX files are loaded, from
the cache when it holds them. Returns the entries that failed to load.
§Errors
EngineError::Apk when the APK cannot be opened or its central
directory read.
Sourcepub fn manifest_xml(&self) -> Result<String>
pub fn manifest_xml(&self) -> Result<String>
Decode AndroidManifest.xml.
§Errors
EngineError::Apk when the APK or the manifest entry cannot be read,
EngineError::Axml when the manifest is not valid binary XML.