general stuff - we can't use ashmem (sailfish has it) because that was dropped from mainline kernels - android supports memfd these days, but that has to be enabled via prop sys.use_memfd - this is overwritten by android init system though - need to comment the override out it system/etc/init/hw/init.rc (can use overlayfs for that) - for graphics, we mostly need these props just like waydroid ro.hardware.gralloc=gbm ro.hardware.egl=mesa apkd: - providing some kind of host integration - probably for startup and management of the container - daemon running as root listening to com.jolla.apkd.control on dbus - user daemon apkd-bridge - install dbus configs not into /etc/ but into /usr/share/dbus-1/system.d/ - appears to want to talk to systemd about aliendalvik.service - that service needs to be installed apkd-bridge: - deps: - libnemonotifications compiled from jolla - libqt5contacts.so - sailfish-policy package (for library) from phone - (maybe not necessary) group privileged needs to exist, otherwise error - package packagekit-qt5 for libraries - forwards notifications and app launch requests to host - runs as user on host - only registers it's launcher thing on the binder if it sees that aliendalvik.service is running - can check with binder-list -d /dev/binder for alien.notification and alien.launcher - still doesn't seem to launch apps successfully though - ahaa, it seems like it only works when all HALs sucessfully load or something? alienaudioservice - needs libalienaudioservice - needs symlink from /usr/lib64 to /usr/lib :( - appears to need /etc/gbinder.conf and /etc/gbinder.d/alien.conf - alienaudioservice -d /dev/binder -n /dev/vndbinder -w /dev/hwbinder --verbose - ugh, the thing doesn't read configuration in /etc/appsupport.d/, so need to set binder devices via argument - now wants to connect to default_alien and AlienAudioService: fails there - ooof this one is tricky - it appears to be something on /dev/vndbinder - oh wow, it appears to work when starting android shortly before - probably it needs a service manager to be running to register the services - ERROR: service: Cannot connect to alien.audio.control/android.media.IAlienAudioControlService - seems to not be a problem/blocking at this stage, this service starts up fairly late in android - nothing to worry about as long as early startup isn't through - what is the problem is that this enumeration of audio devices doesn't happen - that's what it looks like on stdout with --verbose [AlienAudioService] service: Shared buffer fd 31 (0x7dd32d1000) size 7680 [AlienAudioService] service: Output standby (0/125) [AlienAudioService] service: Set parameters 125: "routing=2" [AlienAudioService] service: Open output (0) io_handle(133) devices(2) flags(0x00000008) sample_rate(48000) channel_mask(3) format(1) -> 0 - ugh.. the problem is the UID mapping in lxc container config.. the whole thing has to run as the UID mapped there - alright this thing works pretty well now - seems that with pipewire-pulse, sound output stops after a while - lets just use pulseaudio on the host for the time being apkd-bridge-user: - not needed to finish bootup - fairly independent from other things it seems. - what it does is bridge the HALs in #Proxies=android.hardware.graphics.allocator@4.0 et al into the container - when Proxies are set in config, Service 'package_native' will wait and block boot for these - install libQt5Sensors.so.5 from pacman (don't copy from dev, must match installed QT version) - for gps stuff it needs (somewhat optional, also starts without it) /usr/lib64/apkd-bridge-user/libgeo-qtpositioning.so (jolla pkg apkd-plugin-geo-qtpositioning) - that pulls in libQt5Positioning.so (arch pkg qt5-location) - aha, actually this thing somehow provides HALs on hwbinder for gnss, sensors, wifi.supplicant, wifi - it does a ton more stuff when looking at strings on the binary... - it also does the mpris indicator - yup, it also adds service on the normal binder: alien.NativeCall, alien.mediabrowsercontrol.bridge, alien.mce, wifinl80211 - arghhhh, I've spent 6 hours or something looking into why it doesn't install services on the hwbinder - and it ended up being another damn UID thing: ro.alien.privileged_host_uid needs to be set to the one that's mapped to 1 apparently system/vendor: - general strategy: use aliendalvik vendor blob and put waydroid vendor blob on top (alien doesn't ship mesa drivers that work with mainline) - symlinks of /etc/media_* must be removed and also replaced with waydroid ones - otherwise signal won't start? - graphics.allocator HAL? seems it's fine to comment that out - apparently it's also possible to make it work by installing the waydroid vendor/bin stuff - we can't *quite* reuse the normal aliendalvik vendor blob - in alien vendor lib(64)/hw points to /host_vendor/lib(64)/hw - we need lib(64) pointing to /host_vendor/lib(64) - why? because /host_vendor is waydroid vendor, and we need to access egl drivers in there (and also various libs these drivers need) - also in etc/vintf/manifest.xml, android.hardware.power and android.hardware.graphics.allocator need to be commented out - there's no power HAL nor graphics allocator HAL available - both are forwarded from hybris on sailfish - graphics allocator we could provide via waydroid vendor, but doesn't seem to get us any benefits video codecs: - with libhybris we could forward the HW decoder directly it seems - looks like we fail to decode h264/h265, but not in MKV container (test-videos.co.uk/bigbuckbunny is very helpful) - hmm with the mediaextractor minijail thing we did for Signal this seems to work, just super slow - so debug.stagefright.ccodec=0 makes stagefright try to use sw codecs - ccodec appears to the abstraction for hw codecs, going through libcodec2_client into libcodec2_vndk.so or libcodec2_hidl_client.so - it tries to use libcodec2_vndk.so by default, that tries to access /dev/ion and crashes - looks like ro.alien.hwservicemanager and ro.alien.host_has_hwservicemanager12 play a role here, they are used in all these libs [tester@suagaze system-img]$ grep -r ro.alien.hwservicemanager grep: system/lib64/libhidlbase.so: binary file matches grep: system/lib64/libcodec2_client.so: binary file matches grep: system/lib/libhidlbase.so: binary file matches grep: system/lib/libcodec2_client.so: binary file matches grep: system/apex/com.android.media.swcodec/lib64/libhidlbase.so: binary file matches grep: system/apex/com.android.media/lib64/extractors/libmpeg2extractor.so: binary file matches grep: system/apex/com.android.neuralnetworks/lib64/libneuralnetworks.so: binary file matches grep: system/apex/com.android.neuralnetworks/lib/libneuralnetworks.so: binary file matches - when unsetting ro.alien.hwservicemanager, android.hardware.media.omx fails to start and we hang when starting video - appears to crash in libminijail due to: blocked syscall: recvfrom - there should be policy for that in /vendor/etc/seccomp_policy/mediaswcodec.policy, but that file doesn't exist - now it's complaining about /host_vendor/etc/seccomp_policy/mediacodec.policy, give him that too - looks a lot like ro.alien.hwservicemanager=0 and debug.stagefright.ccodec=0 do the same thing - hmm couldn't figure that out, I feel like this debug message plays a role Unsupported profile 4 for video/mp4v-es - oh there's also a few properties that can be set by appsupport-generate-config tool: - ro.media.xml_variant.codecs, ro.media.xml_variant.codecs_performance, ro.media.xml_variant.profiles - also CodecXmlSuffix in config - playing videos in telegram doesn't work - in Signal, getting called gives us a mediaextractor crash - problem seems to be minijail blocking syscalls - works by adding /opt/alien/vendor/etc/seccomp_policy/mediaextractor.policy with this content - https://github.com/waydroid/android_external_stagefright-plugins/blob/da49cdba7b938ec9d973b9a74c9aac210b55bc8e/codec2/seccomp_policy/android.hardware.media.c2%401.1-ffmpeg-arm64.policy - but remove all the fancy comparisons and make it always 1, otherwise filter won't compile - outgoing call on whatsapp to iphone, voip connection takes super long 08-09 10:41:27.164 140 272 I WindowManager: Input event dispatching timed out sending to com.whatsapp/com.whatsapp.voipcalling.VoipActivityV2. Reason: ad09381 com.whatsapp/com.whatsapp.voipcalling.VoipActivityV2 (server) is not responding. Waited 5005ms for FocusEvent(hasFocus=true) input/OSK: - normal zwp_text_input through wayland appears to actually work - but it's buggy and crashes on preedit_string(null) - this is explicitly legal according to protocol - hack might be to not send preedit_string with NIL string?? - it's actually *very* messy - set_surrounding_text() only returns the text that's before the cursor, nothing behind it - it also doesn't handle selected text at all - preedit_string() doesn't appear to be handled at all - commit_string() is only handled when cursor is at 0 (maybe this is connected to an empty set_surrounded_text() coming in before) - or when doing commit_string() twice, but that might be the set_surrounded_text() reason - either way, any commit_string() causes it to disable() and re-enable() the input panel - this causes it to never disable() it anymore later. - oh wow even better the damn thing seems to append "\n" to any string - actually emulating normal wl_keyboard events might be our best bet - then the auto-hide should keep working, and we're left with the auto-hide bug only for the emoji panel - sailfish uses maliit and a custom keyboard on top of it - maliit itself just spawns a fullscreens wayland surface to show the OSK - yay, it's using qt_extended_surface protocol extension to implement always-on-top (https://github.com/qt/qtwayland/blob/dev/src/extensions/surface-extension.xml) - actually that protocol doesn't seem too bad - small dump of init of the OSK surface [3342860.994] -> wl_compositor@4.create_surface(new id wl_surface@20) [3342861.309] -> wl_registry@2.bind(11, "wl_shell", 1, new id [unknown]@21) [3342861.565] -> wl_shell@21.get_shell_surface(new id wl_shell_surface@22, wl_surface@20) [3342861.684] -> qt_surface_extension@9.get_extended_surface(new id qt_extended_surface@23, wl_surface@20) [3342861.806] -> wl_shell_surface@22.set_title("") [3342861.866] -> wl_shell_surface@22.set_class("maliit-server") [3342861.907] -> wl_shell_surface@22.set_toplevel() [3342861.947] -> wl_surface@20.set_buffer_scale(1) [3342861.997] -> qt_extended_surface@23.set_content_orientation_mask(0) [3342862.040] -> qt_extended_surface@23.set_window_flags(2) [3342862.128] -> wl_shell_surface@22.set_fullscreen(0, 0, nil) [3342862.208] -> wl_surface@20.set_buffer_transform(0) [3342862.248] -> wl_surface@20.commit() [3342863.572] -> wl_compositor@4.create_region(new id wl_region@24) [3342863.686] -> wl_region@24.add(0, 2520, 1080, 0) [3342863.796] -> wl_surface@20.set_opaque_region(wl_region@24) [3342863.839] -> wl_region@24.destroy() [3342863.989] -> qt_extended_surface@23.update_generic_property("CATEGORY", array) [3342864.076] -> qt_extended_surface@23.update_generic_property("MOUSE_REGION", array) [3342910.604] -> wl_compositor@4.create_surface(new id wl_surface@25) - maybe zwp_input_panel_surface_v1 is what we want for that actually - it seems that on sailfish, all IM/text input communication with OSK goes through peer-to-peer dbus socket, zero wayland involved - /run/user/uid/maliit-server/dbus-socket - could sniff that with advanced and very fancy eBPF stuff: https://bulimov.me/post/2021/12/02/unix-socket-snoop/, https://github.com/mechpen/sockdump - qt apps talk directly on that private dbus (in qt it proabably works via IM plugin, set using global QT_IM_MODULE=Maliit) - maliit also appears to support zwp_input_method_context_v1 - if we implement that in mutter, we could make communication Gtk<->maliit go through that - that'd be what we want for OSK's in the future either way - alienkeyboardservice talks directly to that socket just as qt - oh hey we can snoop that using QDBUS_DEBUG=1 alienkeyboardservice - uhh okay this is not too bad - maybe we could shim a few things and keep using wl_text_input_v3 - shifting up input fields on android works via maliit - - could try to shim that? - or we just run a full blown maliit as our keyboard - possibly supporting zwp_input_method_context_v1 is "all" we need for that in mutter - apparently there's also input_method_v2 from purism (https://lists.freedesktop.org/archives/wayland-devel/2018-August/039255.html) - seems not really worth it to implement v1 when it will get replaced anyway - clipboard sharing works on sailfish from container to host, not other way round - seems that sends proper wl_data_source.offer() via surfaceflinger, neat.... - alienkeyboardservice: - yayy, this thing has a -d argument for the binder dev, but it doesn't actually use it - can just use hex editor and change the binder dev in the binary, it's a NUL-terminated string, easy - talks to the inputmethod jolla inside android - talks to maliit-server over dbus p2p socket - still not sure how to enable debugging there, strings suggests it has a verbose mode, no idea how it works - we might want to shim maliit for the text-input shifting behavior inside android - oh well, shimming maliit was nicely possible with some fancy python things - buuut the damn thing crashes when wl_text_input is enabled at same time as alienkeyboard thingy - only solution for us is to kill wl_text_input (their implementation is super duper buggy anyway) - add a WAYLAND_DISABLE_PROTOCOL env var to wayland - and make our shim a small wayland client for zwp_text_input - pip3 install --user --break-system-packages pywayland - python3 -m pywayland.scanner --with-protocols -o protocols - oof, this is getting more and more tricky - had to go the whole route and disable wl_text_input_v3 for alien - now it does work, but the damn python dbus+wayland thing I wrote is pretty weird - so getting a working keyboard now needs - python fake-server.py - python test.py - alienkeyboardservice compositor things: - wayland socket is located at /run/display and is world-read+writeable on sailfish - this is to allow surfaceflinger in the android container (with different user) to access it - seems a bit dangerous that it's also accessible to random android processes? - looks like we can create a separate user+group for SurfaceFlinger (it runs with UID 501000) - then chown wayland socket for that group and make it 775 - okay fun, lipstick also implements a surface role for wayland: alien_manager / alien_surface - looks like that is actually just a way of working around that lipstick doesn't do xdg-toplevel/xdg-wm - seems like because of that we get to see the bugs now - tried implementing the protocol in mutter, but doing two surface roles at the same time is a bad idea (and surfaceflinger really wants to) - surfaceflinger crashes in wl_log() when enabling wayland debugging via debug.sf.wayland - so surfaceflinger crashes on closing the last open window, then opening a new one, then touching it - we send xdg_wm_base pings on input to windows to make sure they're alive - it seems that when it sees a ping in some cases, it crashes when handling the event - disabling pinging in mutter seems to do the trick - also surfaceflinger sometimes accesses xdg_surfaces that have implicitly been freed after it requested wl_surface.destroy() - causes client error from libwayland, tearing down the connection - these can be worked around by making those client errors non-fatal in wayland - another workaround seems to be waiting a bit longer with freeing the wl_resource on surface destroy in mutter - REPRODUCER: open netflix, error appears and click "learn more", app crashes and surfaceflinger fucks up - REPRODUCER: or open other apps and click the back button to leave them Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197137.171] -> xdg_surface#42.configure(93) Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197137.201] -> wl_keyboard#12.leave(301, wl_surface#41) Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197137.214] -> zwp_text_input_v3#3.leave(wl_surface#41) Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197141.457] wl_surface#41.destroy() Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197167.465] -> wl_display#1.delete_id(33) Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197167.501] -> wl_display#1.delete_id(42) Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197167.538] -> wl_display#1.delete_id(41) Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197167.549] wl_display#1.sync(new id wl_callback#46) Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197167.557] -> wl_callback#46.done(301) Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197167.563] -> wl_display#1.delete_id(46) Jul 12 15:36:19 oneplus6 gnome-shell[448812]: [4197167.780] -> wl_display#1.error(wl_display#1, 0, "invalid object 42") Jul 12 15:36:19 oneplus6 gnome-shell[448812]: WL: error in client communication (pid 456513) - another occurence Jul 12 14:52:47 oneplus6 gnome-shell[425720]: [1585117.972] -> wl_display@1.error(wl_display@1, 1, "invalid arguments for wl_surface@55.attach") Jul 12 14:52:47 oneplus6 gnome-shell[425720]: WL: unknown object (2117946272), message attach(?oii) Jul 12 14:52:47 oneplus6 gnome-shell[425720]: WL: error in client communication (pid 439093) - when starting apps, they often only start drawing on touch input - could have something to do with us only focusing the app on input? - maybe it's the configure() event we send them when focusing - scaling is borked, on hidpi alien windows are blurry - lipstick supports wl_output, but does wl_output.scale(1), apparently scaling is done via env variable or smth - can fix that by reading the wm_class and then special-casing alien windows in mutter - it seems they're leaking their wl_region's, lovely... - sailfish sets opaque regions too, good thing their phones have so much ram :D - we also get our fair share of bugs :) - looks like we sometimes send zwp_text_input.leave event after wl_surface.destroy() - REPRODUCER: sometimes this works: open netflix, error appears and click "learn more", now app crashes Jul 12 14:46:10 oneplus6 gnome-shell[425720]: [1187342.350] wl_surface@34.destroy() Jul 12 14:46:10 oneplus6 gnome-shell[425720]: [1187342.532] -> zwp_text_input_v3@3.leave(wl_surface@34) Jul 12 14:46:10 oneplus6 gnome-shell[425720]: WL: error marshalling arguments for leave (signature uo): null value passed for arg 1 - on the pinephone pro, we crash after a while in the gallium driver - fixed by setting different openglES version: ro.opengles.version=196609 network access/fake wifi: - there's two props that exclude each other: ro.alien.sailfish_networking ro.alien.default_networking - sailfish uses the former by default, controlled by /etc/appsupport.conf.d/property-pre-hooks/50-networking.sh - ah damn, it's also provided somehow by apkd-bridge-user - waydroid uses lxc networking spawning an eth0 inside the container - sets up manually a waydroid0 interface on host with firwall and masquerading (https://github.com/waydroid/waydroid/blob/822598850d0c16a968fb8ea4b5768d4ba323f0e5/data/scripts/waydroid-net.sh) - see for lxc config https://github.com/waydroid/waydroid/blob/822598850d0c16a968fb8ea4b5768d4ba323f0e5/data/configs/config_1 - probably due to being eth0, this requires fake wifi stuff - waydroid has a fake wifi thing controlled by persist.waydroid.fake_wifi (https://github.com/waydroid/android_vendor_waydroid/commit/629b76f254d07d373092f7c18efcbefbc0f9ad94) - seems to be per app (https://github.com/waydroid/docs/blob/9b5be41b9233aecf201471596fc6e84f7423ab85/usage/waydroid-prop-options.md?plain=1#L22) - not used by default? - alright, alien also uses lxc to install a bridge into the container - but at the same time it implements a wifi HAL to pretend to be connected to wifi - it asks connman for connected wifi and then returns that SSID, interesting - need to copy lxc-net from device, seems that arch lxc no longer ships that script - need to shim connman dbus - what we're looking for from the contianer is starting the scanner, then notifying the net com.jolla.apkd.wifi: apkd: android.net.wifi.nl80211.IWifiScannerImpl 10 com.jolla.apkd.wifi: apkd - supplicant - notifyWifiNetwork 0xaaaae832fac0 "iPhone von Jonas" - connman installed on system is still needed (probably only for the dbus interface definition) - alright took me like another hour to get the shim working for android to pick up the network - but then android said "no internet", I thought I'm missing something else in the shim - after two more hours of randomly shimming other apis and trying whatever finally figured it out - android can't resolve dns, and its not because of the shim - it'S because it uses the dns cache of the host and sets its dns 127.0.0.1 - connman provided a resolver on localhost:53, and the systemd-resolved NM uses apparently doesn't answer those queries - can test with "dig heise.de @127.0.0.1" - resolved listens on 127.0.0.53 by default - setting DNSStubListenerExtra=127.0.0.1 makes it work, arghhhhh. cellular network - android is always looking for iRadio HAL, need to check if that one's exposed by apkd-bridge on jolla - things work just fine with the wifi shim for now - looks like exposing cellular info via connman shim doesn't work :/ - actually iRadio HAL is not exposed by any apkd-* tools, instead it's exposed by ofono it seems - that's unfortunate, it's probably bound to ofono making use of hybris radio HALs somehow - yup, there's /usr/lib64/ofono/plugins/alienbinderplugin.so gps - good news, appears to go via geoclue - kinda works OOTB, but location is not as accurate as on host it seems - apkd-bridge-user has debug output for it - there's a nice gtk app for debugging: Satellite on flathub (it talks to ModemManager directly) - turns out modemManager doesn't do gps without a sim card https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/183 - okay, so there's the geoclue2 API backend for qtpositioning, that's good - sadly it doesn't have a satellites API anymore like Geoclue dbus api had - alright, let's build qtLocation 5.0 ourselves - looks like it really wants to use the old Geoclue1 api, the plugin has a higher prio - can run geoclue with debug using sudo G_MESSAGES_DEBUG=Geoclue /usr/lib/geoclue - aha, here's our problem: the thing only requests shit accuracy from geoclue - seems it relies on a thing that both the android and geoclue1 plugin do: set default accuracy to ALL in plugin constructor - if we do that too, things work!! sensors - qtsensors has a fairly minimal iio-sensor-proxy backend - no support for proximity - fairly easy, can wire that up quickly - no accellerometer (iio-sensor-proxy doesn't expose) - https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/-/merge_requests/193 - first need to allow querying iio-sensor-proxy as user by changing polkit /usr/share/polkit-1/actions/net.hadess.SensorProxy.policy - for compass access also need to change dbus policy /usr/share/dbus-1/system.d/net.hadess.SensorProxy.conf - compass doesn't have a backend that works on most phones yet, see https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/-/merge_requests/316 - rotation/gyro sensor is not really wanted in iio-sensor-proxy without a use-case https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/-/issues/221 - seems that messengers use proximity sensor for audio route during voice messages actually - looool telegram combines it with accelerometer readings it seems, how insane - seems like also android makes use of orientation sensor and rotates apps, we probably don't want that app rotation - android does it itself based on orientation sensor readings - looks weird and interferes with mutter, rotating, also doesn't adhere to "allow autorotation" gsetting - can disable with "settings put system accelerometer_rotation 0;" in container vibration - can debug feedbackd with G_MESSAGES_DEBUG=all /usr/lib/feedbackd - doesn't work by default - seems to be provided by alienaudioservice actually - more specifically by the sailfish plugin, interesting - let's try loading the plugin - fails without these libs: libprofile, libresource, libresource-glib, libngf0 - now it hangs up looking for org.maemo.resource.manager on dbus it seems - is exposed by ohmd (open hardware manager) - more specifically by this plugin it seems https://github.com/sailfishos/ohm-plugins-misc/blob/master/plugins/resource/ - trace of system dbus on initialization here: dbus-trace-alienaudio-sailfish-plugin.txt - let's shim it, ah neat preexisting stuff to shim the policy manager https://github.com/sailfishos/libresource/blob/master/tests/dbus/dummy-policy-manager.py audio routing: - goes through alienaudioservice sailfish plugin https://github.com/sailfishos/ohm-plugins-misc/blob/master/plugins/route/org.nemomobile.Route.Manager.xml https://github.com/sailfishos/ohm-plugins-misc/blob/master/plugins/route/ohm-ext/route.h - routing to earpiece during voice messages that goes a bit differently - sailfish doesn't re-route here - app reads sensors and sets media role: [AlienAudioService] sailfish: Stream 29 set 'media.role'='phone' [AlienAudioService] sailfish: Stream 29 set 'module-stream-restore.id'='sink-input-by-media-role:voip' - maybe this is how it works on android and we're supposed to route to earpiece now? lockscreen calls: - seems sailfish doesn't do fullscreen intents for incoming calls - we can possibly hack that and put app into lockscreen overlay by looking at notification - resident == true && category == call - activate default action and show surface as lockscreen overlay - tricky: telegram behaves differently depending on screen was off or on - when off, it shows swipy thing to not accidentlly click, when on, it shows clicky thing - what about ongoing calls on lockscreen - there's again a notification, maybe can use that still ringtone silencing - on sailfish, ngfd just enforces the silent profile by killing haptics https://github.com/sailfishos/ngfd/blob/master/src/ngf/haptic.c#L187 - seems like same goes for ringtone, the stream is created, but appears to be killed by pulse based on media.role=ringing - what do we do? - in the future, call ringtone and vibration will be played by notification server anyway - we know when an alien call is ringing, so can probably kill vibration and mute the alien stream in our audio shim to allow notification server taking over - kills custom ringtones on android, oh well - won't work for alarm clocks, there we don't know about ringing state - or we just let things through normally and enforce silent profile in the shim for both haptics and audio on incoming call - maybe that's the best way for now contacts sync: - another tricky one, they replace system contacts UI and database with host one - breaks things for us of course - we might have to shim com.jolla.contacts.ui dbus - we can see createContact() being called from android - handled by apkd-bridge - according to changelogs, bridge "Sync all contacts to alien on service connect" - to ensure it works, on startup of container, look for this com.jolla.apkd.binder: Connected to Alien Service alien.contacts com.jolla.apkd.contacts: Checking if Alien contacts service is ready for synchronisation com.jolla.apkd.contacts: Alien contacts service is available, performing initial sync Successfully notified Alien contacts service of current contacts. - also contact modification should be detected "Notifying Alien contacts service of contact addition:" - okayy, so this talks to libQtContacts and a custom sqlite backend on sailfish - wowwww, we're lucky, there's a libfolks backend from ~2010 for QtCOntacts available - https://wiki.gnome.org/Projects/Folks/QtFolks - https://blog.barisione.org/2010/11/17/folks-and-qtcontacts/ - https://launchpad.net/~m-gehre/+archive/ubuntu/ppa/+packages - damn was finding those sources hard - okay with a few adjustments it builds and the demo confirms it works, yaaaaay! - now still have to make sure it gets loaded and used by apkd-bridge - ah wow that was super tricky, because strings didn't find any references to the plugin name (org.nemomobile.contacts.sqlite) in any binaries - turns out apkd-bridge still demands that plugin, it probably puts the string together in an un-greppable way, damn.... - okay so we're gonna have to force our own plugin then via custom build of libQt5Contacts - ugh, it's still not working, but at least now apkd-bridge spews a log on contact changes in folks, let's try removing data dir - damn, another few hours later, managed to get some debug output from contacts sync on sailfish now - apkd-bridge can only read contacts db when run with invoker, but then we don't get debug output - so instead run it as root to read new contacts db, and create contacts with jolla-contacts run as root - okay now we know that successful initial sync looks like this [D] unknown:0 - Alien contacts service is available, performing initial sync [D] unknown:0 - Notifying Alien contacts service of all current contacts: 1 [D] unknown:0 - Successfully notified Alien contacts service of contact change. [W] unknown:0 - Successfully notified Alien contacts service of current contacts. - turns out there's also a race involved - apkd-bridge gets the contacts via ManagerEngine::contacts() before we got our invidiuals-changed from folks - this means it doesn't sync any contacts initially, but doesn't explain why it also won't pick up changes to contacts - oh woooow - adding and modifying contact changes seems to go via dbus (all with variant (au)) - org.nemomobile.contacts.sqlite.contactsAdded - org.nemomobile.contacts.sqlite.contactsChanged - deleting can go via both QtCOntacts API signal or dbus signal - org.nemomobile.contacts.sqlite.contactsRemoved - it seems that sailfish creates two contacts for everyone, possibly one system one and one android one - the IDs on their dbus output are QContactId.toString() - the IDs passed on their dbus signals are the QContactId without prefix 73716c2d3 (QByteArrayLiteral("sql-")) - so these dbus signals are emitted from the sqlite backend actually, no idea why that would be done in addition to the normal cpp-signals - after another two days, got it to pick up dbus emissions too by setting the QCollectionId (QByteArrayLiteral("col-")) and QContactType on individual contacts now, yaayyy desktop files for apps - mostly appears to work - jolla style of icons is a bit annoying - handled by apkd-bridge file sharing between host and container - looks like some xdg-folders are synced into container as sdcard - home directory is synced into android as sdcard via config MountHome - it's just mounted by lxc, neat other things - after startup bluetooth crashes all the time - seems to be an "upstream" bug, jolla solves this using alien-post-startup.sh by disabling bluetooth daemon (see comment in there) - video decoding for some videos doesn't work (see video codecs section) - the media control service can crash sometimes (playing around with switching between apps during playing spotify music) - see media-control-service-while-starting-spotify crash file - system webview is crashing - it appears to try using ashmem and then fails because 07-13 16:57:45.257 8198 8198 E chromium: [ERROR:platform_shared_memory_region_android.cc(189)] Ashmem region has a wrong protection mask: it is not read-only but it should be - it's a memfd instead of ashmem specific issue, there's a patch that fixes it in waydroid https://chromium.googlesource.com/chromium/src/+/HEAD/third_party/ashmem/patches/0004-Fixup-ashmem_get_prot_region-for-memfd.patch - can work around by replacing webview with the one from waydroid - camera will only work when running on top libhybris and forwarding the HAL what's needed to be done: - lots of dbus shimming (sorted by importance) - launching of system apps from within android (just a single dbus call invoking the thing) - browser - contacts - more... - send configure() wayland events so that clients start drawing immediately incomplete list of deps and files: apdk-bridge deps - libnemonotifications-qt5.so.1 (get from phone) - libpackagekitqt5.so.1 (arch pkg packagekit-qt5) - libQt5Contacts.so.5 (no arch pkg, build it ourselves) alienaudioservice - libalienaudioservice (get from phone) - libglibutil.so.1 (arch pkg libglibutil) - libgbinder.so.1 (arch pkg libgbinder) apkd-bridge-user - libmlite5.so.0 (arch pkg mlite) - libkeepalive.so.1 and libkeepalive-glib.so.1 (get from phone) - libambermpris (get from phone) - libapkd (get from phone) - libqt5sensors (arch pkg qt5-sensors) - libiphb.so.0 (get from phone) - libdbusaccess.so.1 (get from phone) - libconnman-qt5.so.1 (get from phone) - apkd-plugin-geo-qtpositioning - installs /usr/lib64/apkd-bridge-user/libgeo-qtpositioning.so - libQt5Positioning.so (arch pkg qt5-location) config files /etc/aas-seccomp-profile /etc/apkd/app-blacklist (here we removed settings app) /etc/apkd/notif-blacklist /etc/gbinder.conf /etc/gbinder.d/alien.conf /etc/appsupport.conf.d/* /usr/lib/systemd/system/aliendalvik.service aliendalvik system img + vendor img + build.prop: /opt/alien/vendor/* /opt/alien/system.img /opt/alien/build.prop useful stuff: all tools are using Qt debugging tools, debug using QT_LOGGING_RULES="*.debug=true" shell inside container: lxc-attach --name=aliendalvik --lxcpath=/tmp/appsupport -- /system/bin/sh trace files that get opened: strace -f -t -e trace=file binary debugging wayland because debug.sf.wayland causes crash: put WAYLAND_DEBUG into /etc/environment of host to use mutter debugging starting app inside android: am start com.android.settings installing app inside android: pm install -t -f /data/local/tmp/app.apk (needs right permissions) starting things automatically - it's kinda bound to be a mess :( - alien it depends on stuff running in the user session, and can only start when the user session is up - alien itself needs to be run by root though - and that's not enough, most things in the user session need to be started at a specific pointer after container is up - so what do we do? - really nice would be starting and stopping the whole thing from a user service - could talk to a root helper via dbus which then does configuration and starts/stops the container - would have to fiddle with user services as root again though - for data isolation between users - let's have the data dirs inside user dirs so they can be encrypted - maybe make it an img file that can be owned fully by the user and is mounted into lxc