Preliminary Android build support (#31086)

* Android build

* Fixes
* More fixes
  - Still failing in the linking step
* More work on getting linking working

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* android: use mozjs with ndk r25c. loads servo.org

more android build fixes.

* fix ./mach run for android and make it follow logs

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* add experimental logic for compositor pause/resume

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* pass DPI from android to simpleservo

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* ci: add android workflow

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* switch to ANDROID_SDK_ROOT and ANDROID_NDK_ROOT vars

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* upgrade gradle to 4.10.1

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* upgrade to gradle 5.1.1

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* upgrade to gradle 8 and agp 8

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* make compositing work again with external present

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* android: improve mach support for non-NixOS and CI

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* fix sampler compilation bug introduced in #30490

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* ci: add android build to main workflow

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* gradle: set MinSdk = targetSdk = 30

NDK requires we compile against the minSdk API level
which is 30 in our case.

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* add instructions for android in README.md

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* apk: move servosurface to servoview

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* apk: uncomment the mediasession callbacks on MainActivity

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* apk: fix crash on MainAtivity.onDestroy

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* apk: drop VR, arm 5 and unused code

This commit drops:
* support for google, oculusvr
* support for arm5 architecture

and also removes
* fakeld scripts
* unused java code

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* cleanup shell.nix

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* android: add FIXMEs for gstreamer code

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* apk: remove commented code and debug logs

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* cleanup ServoView.java

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* mach: comment call to download gstreamer deps for android

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* disable bluetooth for jniapi as blurdroid is broken

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* fixup! README.md

* fixup! remove change in Cargo.toml

* fixup! move shell variables together

* fixup! cleanup jniapi/Cargo.toml comments

* delete commented gstreamer related android code

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* remove unused config variable in servbuild

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* android: more cleanup

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* force no_static_freetype only for android

* use actions to manage sdk, ndk and java

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* rename embedder event names to be more clear.

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* link to startup crash issue

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* fix lint issues

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* upgrade env_logger to 0.10 with duplicate exception

libservo and android_logger can use env_logger 0.10
but quickcheck is still stuck on 0.8 and has not seen
any activity in the last 2 years. This commit adds
a duplicate exception until the quickcheck dependency
can be upgraded (or replaced)

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* android: fix comments

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* disable jemalloc on android

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* fixup! replace linux with android in cfg

---------

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Mukilan Thiyagarajan 2024-01-22 18:30:15 +05:30 committed by GitHub
parent 8e6bdb69b1
commit d7de206dbd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
58 changed files with 923 additions and 1382 deletions

View file

@ -9,9 +9,12 @@ publish = false
[lib]
path = "lib.rs"
[target.'cfg(not(windows))'.dependencies]
[target.'cfg(not(any(windows, target_os = "android")))'.dependencies]
jemallocator = { workspace = true }
jemalloc-sys = { workspace = true }
[target.'cfg(windows)'.dependencies]
winapi = { workspace = true, features = ["heapapi"] }
[target.'cfg(target_os = "android")'.dependencies]
libc = { workspace = true }

View file

@ -9,7 +9,7 @@ static ALLOC: Allocator = Allocator;
pub use crate::platform::*;
#[cfg(not(windows))]
#[cfg(not(any(windows, target_os = "android")))]
mod platform {
use std::os::raw::c_void;
@ -28,6 +28,21 @@ mod platform {
}
}
#[cfg(target_os = "android")]
mod platform {
pub use std::alloc::System as Allocator;
use std::os::raw::c_void;
/// Get the size of a heap block.
pub unsafe extern "C" fn usable_size(ptr: *const c_void) -> usize {
libc::malloc_usable_size(ptr)
}
pub mod libc_compat {
pub use libc::{free, malloc, realloc};
}
}
#[cfg(windows)]
mod platform {
pub use std::alloc::System as Allocator;

View file

@ -100,9 +100,9 @@ impl BackgroundHangMonitorRegister for HangMonitorRegister {
not(any(target_arch = "arm", target_arch = "aarch64"))
))]
let sampler = crate::sampler_linux::LinuxSampler::new();
#[cfg(all(
any(target_os = "android", target_os = "linux"),
any(target_arch = "arm", target_arch = "aarch64")
#[cfg(any(
target_os = "android",
all(target_os = "linux", any(target_arch = "arm", target_arch = "aarch64"))
))]
let sampler = crate::sampler::DummySampler::new();

View file

@ -22,6 +22,7 @@ servo_rand = { path = "../rand" }
uuid = { workspace = true }
[features]
default = ["bluetooth-test"]
native-bluetooth = ["blurz", "blurdroid", "blurmac", "bluetooth-test"]
bluetooth-test = ["blurmock"]

View file

@ -501,6 +501,33 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.shutdown_state = ShutdownState::FinishedShuttingDown;
}
/// The underlying native surface can be lost during servo's lifetime.
/// On Android, for example, this happens when the app is sent to background.
/// We need to unbind the surface so that we don't try to use it again.
pub fn invalidate_native_surface(&mut self) {
debug!("Invalidating native surface in compositor");
if let Err(e) = self.webrender_surfman.unbind_native_surface_from_context() {
warn!("Unbinding native surface from context failed ({:?})", e);
}
}
/// On Android, this function will be called when the app moves to foreground
/// and the system creates a new native surface that needs to bound to the current
/// context.
#[allow(unsafe_code)]
pub fn replace_native_surface(&mut self, native_widget: *mut c_void, coords: DeviceIntSize) {
debug!("Replacing native surface in compositor: {native_widget:?}");
let connection = self.webrender_surfman.connection();
let native_widget =
unsafe { connection.create_native_widget_from_ptr(native_widget, coords.to_untyped()) };
if let Err(e) = self
.webrender_surfman
.bind_native_surface_to_context(native_widget)
{
warn!("Binding native surface to context failed ({:?})", e);
}
}
fn handle_browser_message(&mut self, msg: CompositorMsg) -> bool {
match (msg, self.shutdown_state) {
(_, ShutdownState::FinishedShuttingDown) => {

View file

@ -10,6 +10,7 @@ use std::time::Duration;
use embedder_traits::{EmbedderProxy, EventLoopWaker};
use euclid::Scale;
use keyboard_types::KeyboardEvent;
use libc::c_void;
use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId, TraversalDirection};
use script_traits::{MediaSessionActionType, MouseButton, TouchEventType, TouchId, WheelDelta};
use servo_geometry::DeviceIndependentPixel;
@ -105,6 +106,14 @@ pub enum EmbedderEvent {
ChangeBrowserVisibility(TopLevelBrowsingContextId, bool),
/// Virtual keyboard was dismissed
IMEDismissed,
/// Sent on platforms like Android where the native widget surface can be
/// automatically destroyed by the system, for example when the app
/// is sent to background.
InvalidateNativeSurface,
/// Sent on platforms like Android where system recreates a new surface for
/// the native widget when it is brough back to foreground. This event
/// carries the pointer to the native widget and its new size.
ReplaceNativeSurface(*mut c_void, DeviceIntSize),
}
impl Debug for EmbedderEvent {
@ -139,6 +148,8 @@ impl Debug for EmbedderEvent {
EmbedderEvent::ChangeBrowserVisibility(..) => write!(f, "ChangeBrowserVisibility"),
EmbedderEvent::IMEDismissed => write!(f, "IMEDismissed"),
EmbedderEvent::ClearCache => write!(f, "ClearCache"),
EmbedderEvent::InvalidateNativeSurface => write!(f, "InvalidateNativeSurface"),
EmbedderEvent::ReplaceNativeSurface(..) => write!(f, "ReplaceNativeSurface"),
}
}
}

View file

@ -4,12 +4,13 @@
use std::path::Path;
use log::warn;
use ucd::{Codepoint, UnicodeBlock};
use super::xml::{Attribute, Node};
use crate::text::util::is_cjk;
lazy_static! {
lazy_static::lazy_static! {
static ref FONT_LIST: FontList = FontList::new();
}

View file

@ -23,6 +23,6 @@ task_info = { path = "../../support/rust-task_info" }
[target.'cfg(target_os = "linux")'.dependencies]
regex = { workspace = true }
[target.'cfg(not(target_os = "windows"))'.dependencies]
[target.'cfg(not(any(target_os = "windows", target_os = "android")))'.dependencies]
libc = { workspace = true }
jemalloc-sys = { workspace = true }

View file

@ -387,16 +387,16 @@ impl ReportsForest {
//---------------------------------------------------------------------------
mod system_reporter {
#[cfg(not(target_os = "windows"))]
#[cfg(not(any(target_os = "windows", target_os = "android")))]
use std::ffi::CString;
#[cfg(not(target_os = "windows"))]
#[cfg(not(any(target_os = "windows", target_os = "android")))]
use std::mem::size_of;
#[cfg(not(target_os = "windows"))]
#[cfg(not(any(target_os = "windows", target_os = "android")))]
use std::ptr::null_mut;
#[cfg(target_os = "linux")]
use libc::c_int;
#[cfg(not(target_os = "windows"))]
#[cfg(not(any(target_os = "windows", target_os = "android")))]
use libc::{c_void, size_t};
use profile_traits::mem::{Report, ReportKind, ReporterRequest};
use profile_traits::path;
@ -499,10 +499,10 @@ mod system_reporter {
None
}
#[cfg(not(target_os = "windows"))]
#[cfg(not(any(target_os = "windows", target_os = "android")))]
use jemalloc_sys::mallctl;
#[cfg(not(target_os = "windows"))]
#[cfg(not(any(target_os = "windows", target_os = "android")))]
fn jemalloc_stat(value_name: &str) -> Option<usize> {
// Before we request the measurement of interest, we first send an "epoch"
// request. Without that jemalloc gives cached statistics(!) which can be
@ -549,7 +549,7 @@ mod system_reporter {
Some(value as usize)
}
#[cfg(target_os = "windows")]
#[cfg(any(target_os = "windows", target_os = "android"))]
fn jemalloc_stat(_value_name: &str) -> Option<usize> {
None
}

View file

@ -503,7 +503,14 @@ where
EmbedderEvent::Resize => {
return self.compositor.on_resize_window_event();
},
EmbedderEvent::InvalidateNativeSurface => {
self.compositor.invalidate_native_surface();
},
EmbedderEvent::ReplaceNativeSurface(native_widget, coords) => {
self.compositor
.replace_native_surface(native_widget, coords);
self.compositor.composite();
},
EmbedderEvent::AllowNavigationResponse(pipeline_id, allowed) => {
let msg = ConstellationMsg::AllowNavigationResponse(pipeline_id, allowed);
if let Err(e) = self.constellation_chan.send(msg) {
@ -1091,6 +1098,9 @@ fn default_user_agent_string_for(agent: UserAgent) -> &'static str {
const DESKTOP_UA_STRING: &'static str =
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Servo/1.0 Firefox/111.0";
#[cfg(target_os = "android")]
const DESKTOP_UA_STRING: &'static str = "";
match agent {
UserAgent::Desktop => DESKTOP_UA_STRING,
UserAgent::Android => "Mozilla/5.0 (Android; Mobile; rv:109.0) Servo/1.0 Firefox/111.0",

View file

@ -216,4 +216,28 @@ impl WebrenderSurfman {
let ref context = self.0.context.borrow();
device.get_proc_address(context, name)
}
pub fn unbind_native_surface_from_context(&self) -> Result<(), Error> {
let device = self.0.device.borrow_mut();
let mut context = self.0.context.borrow_mut();
let mut surface = device.unbind_surface_from_context(&mut context)?.unwrap();
let _ = device.destroy_surface(&mut context, &mut surface)?;
Ok(())
}
pub fn bind_native_surface_to_context(&self, native_widget: NativeWidget) -> Result<(), Error> {
let mut device = self.0.device.borrow_mut();
let mut context = self.0.context.borrow_mut();
let surface_access = SurfaceAccess::GPUOnly;
let surface_type = SurfaceType::Widget { native_widget };
let surface = device.create_surface(&context, surface_access, surface_type)?;
device
.bind_surface_to_context(&mut context, surface)
.map_err(|(err, mut surface)| {
let _ = device.destroy_surface(&mut context, &mut surface);
err
})?;
device.make_context_current(&context)?;
Ok(())
}
}