More about the API daemon – remote services, wavoip and telemetry
In the last post I wrote about the #ApiDaemon. In this post, I will show that it is possible to add “add-on” services to the daemon, and also explain what else the daemon does.
Remote services
Remote services are like plugins for the API daemon. Unlike normal services, they don't have rust libraries that are compiled into the api-daemon
binary, but instead run as a separate “child” daemon. When needed, the API daemon starts the child daemon with the environment variables LD_LIBRARY_PATH
set to the remote service's path and IPC_FD
set to a file descriptor number that is used for IPC between the API daemon and the child daemon.
General structure
Remote service daemons are located in subdirectories of /data/local/service/api-daemon
. The subdirectories are named after the service. Each subdirectory should contain at least a daemon
binary but can also have a valid_build_props.txt
file. Remote services also need a JS library in the http_root
. For example, the wavoip2
service contains the following files:
/data/local/service/api-daemon/remote/wavoip2/daemon
/data/local/service/api-daemon/remote/wavoip2/libc++_shared.so
/data/local/service/api-daemon/remote/wavoip2/libwa_voip.so
/data/local/service/api-daemon/remote/wavoip2/valid_build_props.txt
/data/local/service/api-daemon/http_root/api/v1/wavoip2/service.js.gz
The valid_build_props.txt
file contains a whitelist of values of ro.build.cver
. If the file exists, the service is only considered valid if ro.build.cver
matches one of the lines and SELinux is in enforcing mode.
wavoip2
is even more strict: Even if the daemon does start, it still checks for SELinux enforcing and ro.build.cver
values. Because of this, WhatsApp calls don't work on rooted or soft-rootable devices. However, you can spoof SELinux enforcing with the following commands:
echo -n 1 > /data/local/tmp/enforce
mount -o bind /data/local/tmp/enforce /sys/fs/selinux/enforce
And if you then run setprop ro.build.cver QC_8905_3_10_49_SEC_1
, wavoip will start successfully.
I haven't figured out the IPC protocol yet, but looking at the API daemon's source code will probably help: https://github.com/kaiostech/api-daemon
KaiAds
The API daemon also serves the #KaiAds SDK for privileged apps. This is probably used because of CSP restrictions that apply only to privileged and certified apps. Newer versions of the SDK provide a “SDK loader” that decides whether to load the real SDK from kaiads.com or http://127.0.0.1:8081/sdk/ads.
Telemetry
Another thing which the daemon does is telemetry. I first noticed this when I tried enabling SELinux enforcing to get wavoip working. After running setenforce 1
, my phone suddenly became very slow, and when I looked into logcat, there were a bunch of lines saying that the telemetry process couldn't read from /proc/kmsg!!! Later I found out that this process belongs to the API daemon. This means that the API daemon reads the kernel log messages for telemetry purposes.
Also, I found the following lines in the daemon's configuration file:
[telemetry]
enabled = true
send_app_opened_events = true
token_uri = "https://api.kaiostech.com/v3.0/applications"
metrics_uri = "https://api.kaiostech.com/v3.0/apps/metrics"
so the daemon also sends “app opened” events to KaiOS.
All of this can be disabled by setting enabled
to false
. But KaiOS also
provides development versions of the API daemon that have enabled
set to false
by default: https://packages.stage.kaiostech.com/base_23/api-daemon-1.4.26.zip. I will write about the packages.*.kaiostech.com
domains in the next post.