ohmu
·
2026-10-15
1#pragma once
2
3#include "fastfetch.h"
4
5// The name an app presents to the user, which is not its package name: an app installed as
6// `com.termux` presents itself as `Termux:Launcher` on the launcher, in its notifications and on
7// the settings screen.
8//
9// Every route that answers with an *already resolved* label is closed to an app UID, and each one
10// was measured on the test device rather than assumed:
11//
12// * `dumpsys package` needs android.permission.DUMP.
13// * `cmd package dump` is filtered down to 929 bytes for an app UID, against 1.2 MB for the shell.
14// * The task descriptions the activity service hands out only ever describe the caller's own task.
15// * `getApplicationInfo` answers with `labelRes` -- a resource id -- and leaves `nonLocalizedLabel`
16// null, so there is no string in the reply to read.
17//
18// What is open is the APK itself. `getApplicationInfo` carries its path (`sourceDir`), APKs are
19// world readable, and the `resources.arsc` inside one is *stored* rather than deflated -- the
20// platform expects to mmap it -- so resolving an id out of it needs no decompressor. That is the
21// route this takes: one transaction, one mapping, no fork and no child process.
22//
23// The label is the resource id in the reply whose type is `string`. That is a rule about the reply
24// rather than about the parcel's field order, and it was audited against the manifest's own
25// `android:label` over every package installed on the test device: nine in ten have exactly one
26// `string` candidate and it is the right one every time, a handful more have two and the first is
27// still the right one, and the rest have none because their label is a literal string rather than a
28// reference (`android:label="Example"`), so the reply carries no id at all. No package resolved to
29// a wrong string; the counts behind that are in doc/app-label.md.
30//
31// Writes the label into `result` when it can be resolved, and leaves `result` alone otherwise --
32// which includes the cases above where there is nothing to resolve. The caller sets its fallback
33// first, so that an unresolved label costs nothing but the query.
34//
35// Returns nullptr on success, a static message when the query itself could not be made. An error is
36// not a fallback: it says the label was not looked for, not that the app has none.
37[[gnu::nonnull(1, 2), nodiscard]] const char* ffAndroidGetAppLabel(const char* packageName, FFstrbuf* result);