Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 41 additions & 18 deletions Xposed.pm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use File::Tail;
use FindBin qw($Bin);
use POSIX qw(strftime);
use Term::ANSIColor;
use Archive::Zip qw(:ERROR_CODES :CONSTANTS);

our $cfg;
my $MAX_SUPPORTED_SDK = 23;
Expand Down Expand Up @@ -119,21 +120,30 @@ sub expand_targets($;$) {

my @result;
my %seen;
foreach (split(m/[\/ ]+/, $spec)) {
my ($pfspec, $sdkspec) = split(m/[: ]+/, $_, 2);
my @pflist = ($pfspec ne 'all' && $pfspec ne 'all+') ? split(m/[, ]/, $pfspec) : ('arm', 'x86', 'arm64', 'armv5');
if ($pfspec eq 'all+') {
push @pflist, 'host';
push @pflist, 'hostd';
$pfspec = 'all';
}
my @sdklist = ($sdkspec ne 'all') ? split(m/[, ]/, $sdkspec) : $cfg->Parameters('AospDir');
foreach my $sdk (@sdklist) {
foreach my $pf (@pflist) {
next if !check_target_sdk_platform($pf, $sdk, $pfspec eq 'all' || $sdkspec eq 'all');
next if $seen{"$pf/$sdk"}++;
push @result, { platform => $pf, sdk => $sdk };
print " SDK $sdk, platform $pf\n" if $print;
my ($pfspec, $sdkspec) = split(m/[: ]+/, $spec, 2);
my @pflist = ($pfspec ne 'bundle' && $pfspec ne 'all' && $pfspec ne 'all+') ? split(m/[, ]/, $pfspec) : ('arm', 'x86', 'arm64', 'armv5');
if ($pfspec eq 'all+') {
push @pflist, 'host';
push @pflist, 'hostd';
$pfspec = 'all';
}
my $bundle;
if ($pfspec eq 'bundle') {
$bundle = 1;
$pfspec = 'all';
} else {
$bundle = 0
}
my @sdklist = ($sdkspec ne 'all') ? split(m/[, ]/, $sdkspec) : $cfg->Parameters('AospDir');
foreach my $sdk (@sdklist) {
foreach my $pf (@pflist) {
next if !check_target_sdk_platform($pf, $sdk, $pfspec eq 'all' || $sdkspec eq 'all');
next if $seen{"$pf/$sdk"}++;
push @result, { platform => $pf, sdk => $sdk, bundle => $bundle };
if ($print) {
print " SDK $sdk, platform $pf";
print " (bundle)" if ($bundle);
print "\n";
}
}
}
Expand Down Expand Up @@ -186,7 +196,7 @@ sub get_version() {
# Returns the Xposed version number and the suffix to be used in file names
sub get_version_for_filename(;$) {
my $version = shift || get_version();
$version =~ m/^(\d+)(.*)/;
$version =~ m/^(\d+(?:\.\d+)?)(.*)/;
my ($version_num, $suffix) = ($1, $2);
if ($suffix) {
$suffix =~ s/[\s\/|*"?<:>%()]+/-/g;
Expand Down Expand Up @@ -241,10 +251,20 @@ sub get_collection_dir($$) {
return sprintf('%s/sdk%d/%s', $cfg->val('General', 'outdir'), $sdk, $platform);
}

# Determines the sdk directory where compiled files etc. are collected
sub get_bundle_dir($) {
my $sdk = shift;
return sprintf('%s/sdk%d', $cfg->val('General', 'outdir'), $sdk);
}

# Returns the directory to store symlinks to the ZIPs per versions
sub get_version_dir(;$) {
my ($version, $suffix) = get_version_for_filename(shift);
return sprintf('%s/versions/v%d%s', $cfg->val('General', 'outdir'), $version, $suffix);
if ($version =~ m/^\d+\./) {
return sprintf('%s/versions/v%.1f%s', $cfg->val('General', 'outdir'), $version, $suffix);
} else {
return sprintf('%s/versions/v%d%s', $cfg->val('General', 'outdir'), $version, $suffix);
}
}

# Determines the mode that has to be passed to the "lunch" command
Expand Down Expand Up @@ -354,7 +374,10 @@ sub sign_zip($) {
my $signed = $file . '.signed';
my $cmd = "java -jar $Bin/signapk.jar -w $Bin/signkey.x509.pem $Bin/signkey.pk8 $file $signed";
system("bash -c \"$cmd\"") == 0 || return 0;
rename($signed, $file);
# Re-zip the file to fix zip headers
my $zip = Archive::Zip->new($signed);
$zip->writeToFileNamed($file) == AZ_OK || return 0;
unlink $signed;
return 1;
}

Expand Down
151 changes: 129 additions & 22 deletions build.pl
Original file line number Diff line number Diff line change
Expand Up @@ -47,30 +47,37 @@ ()

# Determine build targets
my $target_spec = $opts{'t'} || '';
print_status("Expanding targets from '$target_spec'...", 0);
my @targets = Xposed::expand_targets($target_spec, 1);
if (!@targets) {
print_error('No valid targets specified');
usage(2);
}
print "\n";
foreach (split(m/[\/ ]+/, $target_spec)) {
print_status("Expanding targets from '$_'...", 0);
my @targets = Xposed::expand_targets($_, 1);
if (!@targets) {
print_error('No valid targets specified');
usage(2);
}
print "\n";

# Check whether flashing is possible
if ($opts{'f'} && $#targets != 0) {
print_error('Flashing is only supported for a single target!');
exit 1;
}
# Check whether flashing is possible
if ($opts{'f'} && $#targets != 0) {
print_error('Flashing is only supported for a single target!');
exit 1;
}

# Build the specified targets
foreach my $target (@targets) {
all_in_one($target->{'platform'}, $target->{'sdk'}, $target->{'bundle'}, !$opts{'v'}) || exit 1;
}

# Build the specified targets
foreach my $target (@targets) {
all_in_one($target->{'platform'}, $target->{'sdk'}, !$opts{'v'}) || exit 1;
bundle_zip($targets[0]->{'sdk'}) if ($targets[0]->{'bundle'})
}
} elsif ($action eq 'java') {
# Build XposedBridge.jar
build_java() || exit 1;
} elsif ($action eq 'prunelogs') {
# Remove old logs
prune_logs() || exit 1;
} elsif ($action eq 'uninstaller') {
# Build uninstaller
uninstaller_zip() || exit 1;
} else {
print_error("Unknown action specified: $action");
usage(2);
Expand All @@ -96,14 +103,19 @@ ($)
-v Verbose mode. Display the build log instead of redirecting it to a file.

Possible actions are:
build Builds the native executables and libraries.
java Builds the Java part (XposedBridge).
prunelogs Removes logs which are older than 24 hours.
build Builds the native executables and libraries.
java Builds the Java part (XposedBridge).
prunelogs Removes logs which are older than 24 hours.
uninstaller Create uninstaller ZIP file

Format of <targets> is: <platform>:<sdk>[/<platform2>:<sdk2>/...]
<platform> is a comma-separated list of: arm, x86, arm64 (and up to SDK 17, also armv5)
<sdk> is a comma-separated list of integers (e.g. 21 for Android 5.0)
Both platform and SDK accept the wildcard "all".
For platform, the "all" option will create seperate package for all platforms.
Platform also accepts wildcard "bundle".
The "bundle" option will create an all-in-one package for a certain SDK version.


Values for <steps> are provided as a comma-separated list of:
compile Compile executables and libraries.
Expand All @@ -113,6 +125,8 @@ ($)


Examples:
$0 -t bundle:23
(build an all-in-one package for SDK 23)
$0 -t arm:all/x86,arm64:21
(build ARM files for all SDKs, plus x86 and arm64 files for SDK 21)

Expand Down Expand Up @@ -140,9 +154,10 @@ ($)
}

# Performs all build steps for one platform/SDK combination
sub all_in_one($$;$) {
sub all_in_one($$$;$) {
my $platform = shift;
my $sdk = shift;
my $bundle = shift;
my $silent = shift || 0;

print_status("Processing SDK $sdk, platform $platform...", 0);
Expand All @@ -151,7 +166,7 @@ ($$;$)
if ($platform ne 'host' && $platform ne 'hostd') {
collect($platform, $sdk) || return 0;
create_xposed_prop($platform, $sdk, !$silent) || return 0;
create_zip($platform, $sdk) || return 0;
create_zip($platform, $sdk) if (!$bundle) || return $bundle;
}

print "\n\n";
Expand Down Expand Up @@ -356,7 +371,7 @@ ($$)
$zip->addFile("$outdir/java/XposedBridge.jar", 'system/framework/XposedBridge.jar') || return 0;
# TODO: We probably need different files for older releases
$zip->addTree($Bin . '/zipstatic/_all/', '') == AZ_OK || return 0;
$zip->addTree($Bin . '/zipstatic/' . $platform . '/', '') == AZ_OK || return 0;
$zip->addTree($Bin . '/zipstatic/single/', '') == AZ_OK || return 0;

# Set last modification time to "now"
my $now = time();
Expand All @@ -366,7 +381,12 @@ ($$)

# Write the ZIP file to disk
my ($version, $suffix) = Xposed::get_version_for_filename();
my $zipname = sprintf('xposed-v%d-sdk%d-%s%s.zip', $version, $sdk, $platform, $suffix);
my $zipname;
if ($version =~ m/^\d+\./) {
$zipname = sprintf('xposed-v%.1f-sdk%d-%s%s.zip', $version, $sdk, $platform, $suffix);
} else {
$zipname = sprintf('xposed-v%d-sdk%d-%s%s.zip', $version, $sdk, $platform, $suffix);
}
my $zippath = $coldir . '/' . $zipname;
print "$zippath\n";
$zip->writeToFileNamed($zippath) == AZ_OK || return 0;
Expand Down Expand Up @@ -404,6 +424,93 @@ ($$)
return 1;
}

# Create an all-in-one bundled flashable ZIP file with the compiled and some static files
sub bundle_zip($) {
my $sdk = shift;

should_perform_step('zip') || return 1;
print_status("Creating all-in-one bundled flashable ZIP file...", 1);

# Create a new ZIP file
my $zip = Archive::Zip->new();
my $outdir = $Xposed::cfg->val('General', 'outdir');
my $armdir = Xposed::get_collection_dir('arm', $sdk);
my $arm64dir = Xposed::get_collection_dir('arm64', $sdk);
my $x86dir = Xposed::get_collection_dir('x86', $sdk);
$zip->addTree($armdir . '/files/', 'arm/') == AZ_OK || return 0;
$zip->addTree($arm64dir . '/files/', 'arm64/') == AZ_OK || return 0;
$zip->addTree($x86dir . '/files/', 'x86/') == AZ_OK || return 0;
$zip->addDirectory('common/') || return 0;
$zip->addFile("$outdir/java/XposedBridge.jar", 'common/XposedBridge.jar') || return 0;
# TODO: We probably need different files for older releases
$zip->addTree($Bin . '/zipstatic/_all/', '') == AZ_OK || return 0;
$zip->addTree($Bin . '/zipstatic/bundle/', '') == AZ_OK || return 0;

# Set last modification time to "now"
my $now = time();
foreach my $member($zip->members()) {
$member->setLastModFileDateTimeFromUnix($now);
}

# Write the ZIP file to disk
my ($version, $suffix) = Xposed::get_version_for_filename();
my $zipname;
if ($version =~ m/^\d+\./) {
$zipname = sprintf('xposed-v%.1f-sdk%d%s.zip', $version, $sdk, $suffix);
} else {
$zipname = sprintf('xposed-v%d-sdk%d%s.zip', $version, $sdk, $suffix);
}
my $zippath = Xposed::get_bundle_dir($sdk) . '/' . $zipname;
print "$zippath\n";
$zip->writeToFileNamed($zippath) == AZ_OK || return 0;

Xposed::sign_zip($zippath);
Xposed::gpg_sign($zippath, $opts{'r'});

# Create a symlink in a version-specific directory for easier collection
my $versiondir = Xposed::get_version_dir();
my $versionlink = $versiondir . '/' . $zipname;
make_path($versiondir);
unlink($versionlink);
if (!symlink($zippath, $versionlink)) {
print_error("Could not create link $versionlink -> $zippath: $!");
}

print "\n\n";
print_status('Bundle ZIP Done!', 0);

return 1;
}

# Create a flashable ZIP file with the compiled and some static files
sub uninstaller_zip() {

print_status("Creating uninstaller ZIP file...", 1);

# Create a new ZIP file
my $zip = Archive::Zip->new();
my $outdir = $Xposed::cfg->val('General', 'outdir');
$zip->addTree($Bin . '/zipstatic/_uninstaller/', '') == AZ_OK || return 0;

# Set last modification time to "now"
my $now = time();
foreach my $member($zip->members()) {
$member->setLastModFileDateTimeFromUnix($now);
}

# Write the ZIP file to disk
my ($version, $suffix) = Xposed::get_version_for_filename();
my $zipname = sprintf('xposed-uninstaller%s.zip', $suffix);
my $zippath = $outdir . '/' . $zipname;
print "$zippath\n";
$zip->writeToFileNamed($zippath) == AZ_OK || return 0;

Xposed::sign_zip($zippath);
Xposed::gpg_sign($zippath, $opts{'r'});

return 1;
}

# Build XposedBridge.jar
sub build_java() {
print_status('Building the Java part...', 0);
Expand Down
Loading