<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>kaiads &amp;mdash; affe-null</title>
    <link>https://blog.bananahackers.net/affe-null/tag:kaiads</link>
    <description></description>
    <pubDate>Mon, 04 May 2026 14:19:18 +0200</pubDate>
    <item>
      <title>More about the API daemon - remote services, wavoip and telemetry</title>
      <link>https://blog.bananahackers.net/affe-null/more-about-the-api-daemon-remote-services-wavoip-and-telemetry</link>
      <description>&lt;![CDATA[In the last post I wrote about the #ApiDaemon. In this post, I will show that it is possible to add &#34;add-on&#34; services to the daemon, and also explain what else the daemon does.&#xA;&#xA;Remote services&#xA;Remote services are like plugins for the API daemon. Unlike normal services, they don&#39;t have rust libraries that are compiled into the api-daemon binary, but instead run as a separate &#34;child&#34; daemon. When needed, the API daemon starts the child daemon with the environment variables LDLIBRARYPATH set to the remote service&#39;s path and IPCFD set to a file descriptor number that is used for IPC between the API daemon and the child daemon.&#xA;&#xA;General structure&#xA;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 validbuildprops.txt file. Remote services also need a JS library in the httproot. For example, the wavoip2 service contains the following files:&#xA;&#xA;/data/local/service/api-daemon/remote/wavoip2/daemon&#xA;/data/local/service/api-daemon/remote/wavoip2/libc++shared.so&#xA;/data/local/service/api-daemon/remote/wavoip2/libwavoip.so&#xA;/data/local/service/api-daemon/remote/wavoip2/validbuildprops.txt&#xA;/data/local/service/api-daemon/httproot/api/v1/wavoip2/service.js.gz&#xA;&#xA;The validbuildprops.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.&#xA;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&#39;t work on rooted or soft-rootable devices. However, you can spoof SELinux enforcing with the following commands:&#xA;&#xA;echo -n 1   /data/local/tmp/enforce&#xA;mount -o bind /data/local/tmp/enforce /sys/fs/selinux/enforce&#xA;&#xA;And if you then run setprop ro.build.cver QC890531049SEC1, wavoip will start successfully.&#xA;&#xA;I haven&#39;t figured out the IPC protocol yet, but looking at the API daemon&#39;s source code will probably help: https://github.com/kaiostech/api-daemon&#xA;&#xA;KaiAds&#xA;&#xA;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 &#34;SDK loader&#34; that decides whether to load the real SDK from kaiads.com or http://127.0.0.1:8081/sdk/ads.&#xA;&#xA;Telemetry&#xA;&#xA;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&#39;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.&#xA;&#xA;Also, I found the following lines in the daemon&#39;s configuration file:&#xA;&#xA;[telemetry]&#xA;enabled = true&#xA;sendappopenedevents = true&#xA;tokenuri = &#34;https://api.kaiostech.com/v3.0/applications&#34;&#xA;metricsuri = &#34;https://api.kaiostech.com/v3.0/apps/metrics&#34;&#xA;&#xA;so the daemon also sends &#34;app opened&#34; events to KaiOS.&#xA;&#xA;All of this can be disabled by setting enabled to false. But KaiOS also&#xA;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.&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>In the last post I wrote about the <a href="/affe-null/tag:ApiDaemon" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ApiDaemon</span></a>. 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.</p>

<h2 id="remote-services" id="remote-services">Remote services</h2>

<p>Remote services are like plugins for the API daemon. Unlike normal services, they don&#39;t have rust libraries that are compiled into the <code>api-daemon</code> binary, but instead run as a separate “child” daemon. When needed, the API daemon starts the child daemon with the environment variables <code>LD_LIBRARY_PATH</code> set to the remote service&#39;s path and <code>IPC_FD</code> set to a file descriptor number that is used for IPC between the API daemon and the child daemon.</p>

<h3 id="general-structure" id="general-structure">General structure</h3>

<p>Remote service daemons are located in subdirectories of <code>/data/local/service/api-daemon</code>. The subdirectories are named after the service. Each subdirectory should contain at least a <code>daemon</code> binary but can also have a <code>valid_build_props.txt</code> file. Remote services also need a JS library in the <code>http_root</code>. For example, the <code>wavoip2</code> service contains the following files:</p>

<pre><code>/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
</code></pre>

<p>The <code>valid_build_props.txt</code> file contains a whitelist of values of <code>ro.build.cver</code>. If the file exists, the service is only considered valid if <code>ro.build.cver</code> matches one of the lines <strong>and SELinux is in enforcing mode</strong>.
<code>wavoip2</code> is even more strict: Even if the daemon does start, it still checks for SELinux enforcing and <code>ro.build.cver</code> values. Because of this, WhatsApp calls don&#39;t work on rooted or soft-rootable devices. However, you can spoof SELinux enforcing with the following commands:</p>

<pre><code>echo -n 1 &gt; /data/local/tmp/enforce
mount -o bind /data/local/tmp/enforce /sys/fs/selinux/enforce
</code></pre>

<p>And if you then run <code>setprop ro.build.cver QC_8905_3_10_49_SEC_1</code>, wavoip will start successfully.</p>

<p>I haven&#39;t figured out the IPC protocol yet, but looking at the API daemon&#39;s source code will probably help: <a href="https://github.com/kaiostech/api-daemon" rel="nofollow">https://github.com/kaiostech/api-daemon</a></p>

<h2 id="kaiads" id="kaiads">KaiAds</h2>

<p>The API daemon also serves the <a href="/affe-null/tag:KaiAds" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">KaiAds</span></a> 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 <a href="http://127.0.0.1:8081/sdk/ads" rel="nofollow">http://127.0.0.1:8081/sdk/ads</a>.</p>

<h2 id="telemetry" id="telemetry">Telemetry</h2>

<p>Another thing which the daemon does is telemetry. I first noticed this when I tried enabling SELinux enforcing to get wavoip working. After running <code>setenforce 1</code>, my phone suddenly became very slow, and when I looked into logcat, there were a bunch of lines saying that the <strong>telemetry process couldn&#39;t read from /proc/kmsg!!!</strong> 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.</p>

<p>Also, I found the following lines in the daemon&#39;s configuration file:</p>

<pre><code>[telemetry]
enabled = true
send_app_opened_events = true
token_uri = &#34;https://api.kaiostech.com/v3.0/applications&#34;
metrics_uri = &#34;https://api.kaiostech.com/v3.0/apps/metrics&#34;
</code></pre>

<p>so the daemon also sends “app opened” events to KaiOS.</p>

<p>All of this can be disabled by setting <code>enabled</code> to <code>false</code>. But KaiOS also
provides development versions of the API daemon that have <code>enabled</code> set to <code>false</code> by default: <a href="https://packages.stage.kaiostech.com/base_23/api-daemon-1.4.26.zip" rel="nofollow">https://packages.stage.kaiostech.com/base_23/api-daemon-1.4.26.zip</a>. I will write about the <code>packages.*.kaiostech.com</code> domains in the next post.</p>
]]></content:encoded>
      <guid>https://blog.bananahackers.net/affe-null/more-about-the-api-daemon-remote-services-wavoip-and-telemetry</guid>
      <pubDate>Sat, 15 May 2021 15:07:34 +0200</pubDate>
    </item>
  </channel>
</rss>