Skip to content
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
29 changes: 14 additions & 15 deletions src/tasks/AndroidAppBuilder/ApkBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ public ApkBuilder(TaskLoggingHelper logger)
}
}
string abi;
AndroidProject? project = null;
if (IsNativeAOT)
{
abi = AndroidProject.DetermineAbi(runtimeIdentifier);
Expand Down Expand Up @@ -400,12 +401,12 @@ public ApkBuilder(TaskLoggingHelper logger)
}
File.WriteAllText(Path.Combine(OutputDir, monodroidSource), monodroidContent);

AndroidProject project = new AndroidProject("monodroid", runtimeIdentifier, AndroidNdk, logger);
project.GenerateCMake(OutputDir, MinApiLevel, StripDebugSymbols);
project.BuildCMake(OutputDir, StripDebugSymbols);
project = new AndroidProject("monodroid", runtimeIdentifier, AndroidNdk, logger);
project.GenerateCMake(OutputDir, MinApiLevel);
project.BuildCMake(OutputDir);
abi = project.Abi;

// TODO: https://github.com/dotnet/runtime/issues/115717

}

// 2. Compile Java files
Expand Down Expand Up @@ -486,7 +487,9 @@ public ApkBuilder(TaskLoggingHelper logger)

// 3. Generate APK

string debugModeArg = StripDebugSymbols ? string.Empty : "--debug-mode";
// Always keep the app debuggable to enable adb shell run-as access during test runs.
// Symbol stripping is done post-build via llvm-strip rather than by setting android:debuggable=false.
string debugModeArg = "--debug-mode";
string apkFile = Path.Combine(OutputDir, "bin", $"{ProjectName}.unaligned.apk");
Utils.RunProcess(logger, androidSdkHelper.AaptPath, $"package -f -m -F {apkFile} -A assets -M AndroidManifest.xml -I {androidJar} {debugModeArg}", workingDir: OutputDir);

Expand All @@ -501,15 +504,6 @@ public ApkBuilder(TaskLoggingHelper logger)
else
{
var excludedLibs = new HashSet<string> { "libmonodroid.so" };
if (IsCoreCLR)
{
if (StripDebugSymbols)
{
// exclude debugger support libs
excludedLibs.Add("libmscordbi.so");
excludedLibs.Add("libmscordaccore.so");
}
}
if (!StaticLinkedRuntime)
dynamicLibs.AddRange(Directory.GetFiles(AppDir, "*.so").Where(file => !excludedLibs.Contains(Path.GetFileName(file))));
}
Expand Down Expand Up @@ -554,8 +548,13 @@ public ApkBuilder(TaskLoggingHelper logger)
}
}

// NOTE: we can run android-strip tool from NDK to shrink native binaries here even more.
File.Copy(dynamicLib, Path.Combine(OutputDir, destRelative), true);
if (StripDebugSymbols)
{
if (project is null)
throw new InvalidOperationException("StripDebugSymbols is enabled, but no Android project is available to strip native libraries during APK packaging.");
project.StripBinaryInPlace(Path.Combine(OutputDir, destRelative));
}
Utils.RunProcess(logger, androidSdkHelper.AaptPath, $"add {apkFile} {NormalizePathToUnix(destRelative)}", workingDir: OutputDir);
}
Utils.RunProcess(logger, androidSdkHelper.AaptPath, $"add {apkFile} classes.dex", workingDir: OutputDir);
Expand Down
46 changes: 23 additions & 23 deletions src/tasks/MobileBuildTasks/Android/AndroidProject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public sealed class AndroidProject
private TaskLoggingHelper logger;

private string abi;
private string androidNdkPath;
private string androidToolchainPath;
private string projectName;
private string targetArchitecture;
Expand All @@ -33,6 +34,7 @@ public AndroidProject(string projectName, string runtimeIdentifier, TaskLoggingH

public AndroidProject(string projectName, string runtimeIdentifier, string androidNdkPath, TaskLoggingHelper logger)
{
this.androidNdkPath = androidNdkPath;
androidToolchainPath = Path.Combine(androidNdkPath, "build", "cmake", "android.toolchain.cmake").Replace('\\', '/');
abi = DetermineAbi(runtimeIdentifier);
targetArchitecture = GetTargetArchitecture(runtimeIdentifier);
Expand All @@ -50,49 +52,47 @@ public void Build(string workingDir, ClangBuildOptions buildOptions, bool stripD
Utils.RunProcess(logger, tools.ClangPath, workingDir: workingDir, args: clangArgs);
}

public void GenerateCMake(string workingDir, bool stripDebugSymbols)
public void GenerateCMake(string workingDir)
{
GenerateCMake(workingDir, DefaultMinApiLevel, stripDebugSymbols);
GenerateCMake(workingDir, DefaultMinApiLevel);
}

public void GenerateCMake(string workingDir, string apiLevel = DefaultMinApiLevel, bool stripDebugSymbols = false)
public void GenerateCMake(string workingDir, string apiLevel = DefaultMinApiLevel)
{
// force ninja generator on Windows, the VS generator causes issues with the built-in Android support in VS
var generator = Utils.IsWindows() ? "-G Ninja" : "";
string cmakeGenArgs = $"{generator} -DCMAKE_TOOLCHAIN_FILE={androidToolchainPath} -DANDROID_ABI=\"{Abi}\" -DANDROID_STL=none -DTARGETS_ANDROID=1 " +
$"-DANDROID_PLATFORM=android-{apiLevel} -B {projectName}";

if (stripDebugSymbols)
{
// Use "-s" to strip debug symbols, it complains it's unused but it works
cmakeGenArgs += " -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_C_FLAGS=\"-s -Wno-unused-command-line-argument\"";
}
else
{
cmakeGenArgs += " -DCMAKE_BUILD_TYPE=Debug";
}
// Always build with debug info; symbol stripping is done post-build via StripBinaryInPlace
cmakeGenArgs += " -DCMAKE_BUILD_TYPE=Debug";

Utils.RunProcess(logger, Cmake, workingDir: workingDir, args: cmakeGenArgs);
}

public string BuildCMake(string workingDir, bool stripDebugSymbols = false)
public string BuildCMake(string workingDir)
{
string cmakeBuildArgs = $"--build {projectName}";

if (stripDebugSymbols)
{
cmakeBuildArgs += " --config MinSizeRel";
}
else
{
cmakeBuildArgs += " --config Debug";
}
string cmakeBuildArgs = $"--build {projectName} --config Debug";

Utils.RunProcess(logger, Cmake, workingDir: workingDir, args: cmakeBuildArgs);

return Path.Combine(workingDir, projectName);
}

public void StripBinaryInPlace(string filePath)
{
string hostTag = GetHostOS() switch
{
"windows" => "windows-x86_64",
"osx" => "darwin-x86_64",
_ => "linux-x86_64"
};
string execExt = Utils.IsWindows() ? ".exe" : string.Empty;
string llvmStripPath = Path.Combine(androidNdkPath, "toolchains", "llvm", "prebuilt", hostTag, "bin", $"llvm-strip{execExt}");
logger.LogMessage(MessageImportance.High, $"Stripping debug symbols from {filePath}");
Utils.RunProcess(logger, llvmStripPath, args: $"--strip-debug \"{filePath}\"");
}

private static string BuildClangArgs(ClangBuildOptions buildOptions)
{
StringBuilder ret = new StringBuilder();
Expand Down
Loading