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 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.
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
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
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.
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
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.