Ladybird: Make Android build work again, and tidy up files

We don't need the extra gradle files in our sources, the Qt CMake
integration will generate suitable ones for us.

Make sure that assets is always a folder, so that we can get the proper
layout for the ladybird-assets.tar.gz and CMake doesn't create a gzip
file with the name "assets".

Fix up the AndroidPlatform file and make sure it's linked into all the
applications that need it. Also make sure to copy all the application
shared libraries into the ladybird APK so that when we make them into
proper Services, the libs are already there.
This commit is contained in:
Andrew Kaster 2023-07-19 10:27:16 -06:00 committed by Andrew Kaster
parent 7de4fb2947
commit e02b2a7b9a
Notes: sideshowbarker 2024-07-17 03:25:24 +09:00
10 changed files with 58 additions and 137 deletions

View file

@ -10,9 +10,10 @@
#include <AK/ScopeGuard.h>
#include <LibArchive/Tar.h>
#include <LibArchive/TarStream.h>
#include <LibCompress/Gzip.h>
#include <LibCore/Directory.h>
#include <LibCore/FileStream.h>
#include <LibCore/System.h>
#include <LibFileSystem/FileSystem.h>
#include <LibMain/Main.h>
#include <QCoreApplication>
@ -31,7 +32,7 @@ extern DeprecatedString s_serenity_resource_root;
void android_platform_init();
static void extract_ladybird_resources();
static ErrorOr<void> extract_tar_archive(DeprecatedString archive_file, DeprecatedString output_directory);
static ErrorOr<void> extract_tar_archive(String archive_file, DeprecatedString output_directory);
void android_platform_init()
{
@ -53,31 +54,25 @@ void extract_ladybird_resources()
if (file_or_error.is_error()) {
qDebug() << "Unable to open test file file as expected, extracting asssets...";
MUST(extract_tar_archive(DeprecatedString::formatted("{}/ladybird-assets.tar", s_serenity_resource_root), s_serenity_resource_root));
MUST(extract_tar_archive(MUST(String::formatted("{}/ladybird-assets.tar", s_serenity_resource_root)), s_serenity_resource_root));
} else {
qDebug() << "Opened app-browser.png test file, good to go!";
qDebug() << "Hopefully no developer changed the asset files and expected them to be re-extracted!";
}
}
ErrorOr<void> extract_tar_archive(DeprecatedString archive_file, DeprecatedString output_directory)
ErrorOr<void> extract_tar_archive(String archive_file, DeprecatedString output_directory)
{
constexpr size_t buffer_size = 4096;
auto file = TRY(Core::DeprecatedFile::open(archive_file, Core::OpenMode::ReadOnly));
auto file = TRY(Core::InputBufferedFile::create(TRY(Core::File::open(archive_file, Core::File::OpenMode::Read))));
DeprecatedString old_pwd = TRY(Core::System::getcwd());
TRY(Core::System::chdir(output_directory));
ScopeGuard go_back = [&old_pwd] { MUST(Core::System::chdir(old_pwd)); };
Core::InputFileStream file_stream(file);
Archive::TarInputStream tar_stream(file_stream);
if (!tar_stream.valid()) {
qDebug() << "the provided file is not a well-formatted ustar file";
return Error::from_errno(EINVAL);
}
auto tar_stream = TRY(Archive::TarInputStream::construct(make<Compress::GzipCompressor>(move(file))));
HashMap<DeprecatedString, DeprecatedString> global_overrides;
HashMap<DeprecatedString, DeprecatedString> local_overrides;
@ -96,14 +91,14 @@ ErrorOr<void> extract_tar_archive(DeprecatedString archive_file, DeprecatedStrin
return {};
};
for (; !tar_stream.finished(); tar_stream.advance()) {
Archive::TarFileHeader const& header = tar_stream.header();
while (!tar_stream->finished()) {
Archive::TarFileHeader const& header = tar_stream->header();
// Handle meta-entries earlier to avoid consuming the file content stream.
if (header.content_is_like_extended_header()) {
switch (header.type_flag()) {
case Archive::TarFileType::GlobalExtendedHeader: {
TRY(tar_stream.for_each_extended_header([&](StringView key, StringView value) {
TRY(tar_stream->for_each_extended_header([&](StringView key, StringView value) {
if (value.length() == 0)
global_overrides.remove(key);
else
@ -112,7 +107,7 @@ ErrorOr<void> extract_tar_archive(DeprecatedString archive_file, DeprecatedStrin
break;
}
case Archive::TarFileType::ExtendedHeader: {
TRY(tar_stream.for_each_extended_header([&](StringView key, StringView value) {
TRY(tar_stream->for_each_extended_header([&](StringView key, StringView value) {
local_overrides.set(key, value);
}));
break;
@ -122,10 +117,11 @@ ErrorOr<void> extract_tar_archive(DeprecatedString archive_file, DeprecatedStrin
VERIFY_NOT_REACHED();
}
TRY(tar_stream->advance());
continue;
}
Archive::TarFileStream file_stream = tar_stream.file_contents();
Archive::TarFileStream file_stream = tar_stream->file_contents();
// Handle other header types that don't just have an effect on extraction.
switch (header.type_flag()) {
@ -133,12 +129,14 @@ ErrorOr<void> extract_tar_archive(DeprecatedString archive_file, DeprecatedStrin
StringBuilder long_name;
Array<u8, buffer_size> buffer;
size_t bytes_read;
while ((bytes_read = file_stream.read(buffer)) > 0)
long_name.append(reinterpret_cast<char*>(buffer.data()), bytes_read);
while (!file_stream.is_eof()) {
auto slice = TRY(file_stream.read_some(buffer));
long_name.append(reinterpret_cast<char*>(slice.data()), slice.size());
}
local_overrides.set("path", long_name.to_deprecated_string());
TRY(tar_stream->advance());
continue;
}
default:
@ -151,20 +149,22 @@ ErrorOr<void> extract_tar_archive(DeprecatedString archive_file, DeprecatedStrin
path = path.prepend(header.prefix());
DeprecatedString filename = get_override("path"sv).value_or(path.string());
DeprecatedString absolute_path = Core::DeprecatedFile::absolute_path(filename);
DeprecatedString absolute_path = TRY(FileSystem::absolute_path(filename)).to_deprecated_string();
auto parent_path = LexicalPath(absolute_path).parent();
auto header_mode = TRY(header.mode());
switch (header.type_flag()) {
case Archive::TarFileType::NormalFile:
case Archive::TarFileType::AlternateNormalFile: {
MUST(Core::Directory::create(parent_path, Core::Directory::CreateDirectories::Yes));
int fd = TRY(Core::System::open(absolute_path, O_CREAT | O_WRONLY, header.mode()));
int fd = TRY(Core::System::open(absolute_path, O_CREAT | O_WRONLY, header_mode));
Array<u8, buffer_size> buffer;
size_t bytes_read;
while ((bytes_read = file_stream.read(buffer)) > 0)
TRY(Core::System::write(fd, buffer.span().slice(0, bytes_read)));
while (!file_stream.is_eof()) {
auto slice = TRY(file_stream.read_some(buffer));
TRY(Core::System::write(fd, slice));
}
TRY(Core::System::close(fd));
break;
@ -178,9 +178,9 @@ ErrorOr<void> extract_tar_archive(DeprecatedString archive_file, DeprecatedStrin
case Archive::TarFileType::Directory: {
MUST(Core::Directory::create(parent_path, Core::Directory::CreateDirectories::Yes));
auto result_or_error = Core::System::mkdir(absolute_path, header.mode());
auto result_or_error = Core::System::mkdir(absolute_path, header_mode);
if (result_or_error.is_error() && result_or_error.error().code() != EEXIST)
return result_or_error.error();
return result_or_error.release_error();
break;
}
default:
@ -191,8 +191,8 @@ ErrorOr<void> extract_tar_archive(DeprecatedString archive_file, DeprecatedStrin
// Non-global headers should be cleared after every file.
local_overrides.clear();
}
file_stream.close();
TRY(tar_stream->advance());
}
return {};
}

View file

@ -97,9 +97,7 @@ set(SOURCES
main.cpp
)
qt_add_executable(ladybird ${SOURCES}
MANUAL_FINALIZATION
)
qt_add_executable(ladybird ${SOURCES})
target_link_libraries(ladybird PRIVATE Qt::Core Qt::Gui Qt::Network Qt::Widgets LibCore LibFileSystem LibGfx LibGUI LibIPC LibJS LibMain LibWeb LibWebView LibSQL)
target_include_directories(ladybird PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
@ -128,6 +126,7 @@ set_target_properties(ladybird PROPERTIES
if (ANDROID)
include(cmake/AndroidExtras.cmake)
link_android_libs(headless-browser)
endif()
add_custom_target(run${LADYBIRD_CUSTOM_TARGET_SUFFIX}
@ -141,8 +140,6 @@ add_custom_target(debug${LADYBIRD_CUSTOM_TARGET_SUFFIX}
USES_TERMINAL
)
qt_finalize_executable(ladybird)
add_subdirectory(SQLServer)
add_subdirectory(WebContent)
add_subdirectory(WebDriver)

View file

@ -28,3 +28,6 @@ qt_add_executable(WebContent ${WEBCONTENT_SOURCES})
target_include_directories(WebContent PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/)
target_include_directories(WebContent PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..)
target_link_libraries(WebContent PRIVATE Qt::Core Qt::Gui Qt::Network Qt::Multimedia LibAudio LibCore LibFileSystem LibGfx LibIPC LibJS LibMain LibWeb LibWebSocket)
if (ANDROID)
link_android_libs(WebContent)
endif()

View file

@ -17,3 +17,6 @@ target_include_directories(WebDriver PRIVATE ${SERENITY_SOURCE_DIR}/Userland)
target_include_directories(WebDriver PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services)
target_link_libraries(WebDriver PRIVATE Qt::Core Qt::Network LibCore LibFileSystem LibGfx LibIPC LibJS LibMain LibWeb LibWebSocket)
add_dependencies(WebDriver headless-browser)
if (ANDROID)
link_android_libs(WebDriver)
endif()

View file

@ -14,8 +14,5 @@
<meta-data android:name="android.app.extract_android_style" android:value="minimal"/>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
</manifest>

View file

View file

@ -1,81 +0,0 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.2'
}
}
repositories {
google()
mavenCentral()
}
apply plugin: 'com.android.application'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}
android {
/*******************************************************
* The following variables:
* - androidBuildToolsVersion,
* - androidCompileSdkVersion
* - qtAndroidDir - holds the path to qt android files
* needed to build any Qt application
* on Android.
*
* are defined in gradle.properties file. This file is
* updated by QtCreator and androiddeployqt tools.
* Changing them manually might break the compilation!
*******************************************************/
compileSdkVersion androidCompileSdkVersion.toInteger()
buildToolsVersion androidBuildToolsVersion
ndkVersion androidNdkVersion
// Extract native libraries from the APK
packagingOptions.jniLibs.useLegacyPackaging true
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = [qtAndroidDir + '/src', 'src', 'java']
aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl']
res.srcDirs = [qtAndroidDir + '/res', 'res']
resources.srcDirs = ['resources']
renderscript.srcDirs = ['src']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
}
tasks.withType(JavaCompile) {
options.incremental = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
abortOnError false
}
// Do not compress Qt binary resources file
aaptOptions {
noCompress 'rcc'
}
defaultConfig {
resConfig "en"
minSdkVersion qtMinSdkVersion
targetSdkVersion qtTargetSdkVersion
ndk.abiFilters = qtTargetAbiList.split(",")
}
}

View file

@ -1,14 +0,0 @@
# Project-wide Gradle settings.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2500m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# Enable building projects in parallel
org.gradle.parallel=true
# Gradle caching allows reusing the build artifacts from a previous
# build with the same inputs. However, over time, the cache size will
# grow. Uncomment the following line to enable it.
#org.gradle.caching=true

View file

@ -13,8 +13,12 @@ set_property(TARGET ladybird APPEND PROPERTY
#
# Android-specific sources and libs
#
target_sources(ladybird PRIVATE AndroidPlatform.cpp)
target_link_libraries(ladybird PRIVATE LibCompress LibArchive)
add_library(android_init STATIC AndroidPlatform.cpp)
target_link_libraries(android_init PUBLIC Qt::Core Qt::Gui Qt::Network LibCompress LibArchive LibFileSystem)
macro(link_android_libs target)
target_link_libraries(${target} PRIVATE android_init)
endmacro()
#
# NDK and Qt don't ship OpenSSL for Android
@ -27,7 +31,13 @@ FetchContent_Declare(android_openssl
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(android_openssl)
set_property(TARGET ladybird APPEND PROPERTY QT_ANDROID_EXTRA_LIBS ${ANDROID_EXTRA_LIBS})
link_android_libs(ladybird)
target_link_libraries(ladybird PRIVATE Qt::Network)
set_property(TARGET ladybird APPEND PROPERTY QT_ANDROID_EXTRA_LIBS ${ANDROID_EXTRA_LIBS}
"${CMAKE_CURRENT_BINARY_DIR}/WebContent/libWebContent_${ANDROID_ABI}.so"
"${CMAKE_CURRENT_BINARY_DIR}/SQLServer/libSQLServer_${ANDROID_ABI}.so"
"${CMAKE_CURRENT_BINARY_DIR}/WebDriver/libWebDriver_${ANDROID_ABI}.so"
)
#
# Copy resources into tarball for inclusion in /assets of APK
@ -60,6 +70,6 @@ add_custom_target(copy-content-filters
"asset-bundle/res/ladybird/BrowserContentFilters.txt"
)
add_dependencies(archive-assets copy-autoplay-allowlist copy-content-filters)
add_custom_target(copy-assets COMMAND ${CMAKE_COMMAND} -E copy_if_different ladybird-assets.tar.gz "${CMAKE_SOURCE_DIR}/android/assets")
add_custom_target(copy-assets COMMAND ${CMAKE_COMMAND} -E copy_if_different ladybird-assets.tar.gz "${CMAKE_SOURCE_DIR}/android/assets/")
add_dependencies(copy-assets archive-assets)
add_dependencies(ladybird copy-assets)

View file

@ -6,7 +6,13 @@ set(package ladybird)
set(ladybird_applications ladybird SQLServer WebContent WebDriver headless-browser)
install(TARGETS ${ladybird_applications}
set(app_install_targets ${ladybird_applications})
if (ANDROID)
# androiddeployqt will get confused with duplicate resources if we install every app
set(app_install_targets ladybird)
endif()
install(TARGETS ${app_install_targets}
EXPORT ladybirdTargets
RUNTIME
COMPONENT ladybird_Runtime