affe-null

KaiAds

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.