Name the three path namespaces, and where a crossing is legal

A path in this skill lives in one of three places -- the host filesystem, the device filesystem, or an
APK entry name -- and the same string means something different in each. Two properties decide most
of the failures that follow:

  * a host path does not exist on the device and vice versa; `adb push`/`adb pull` is the only place
    a translation happens, and it is the caller's to make;
  * an entry name is always `/`-separated and case-sensitive whatever the host OS is, so a path built
    with `os.path.join` matches nothing on Windows.

The symptom is a "no such file" naming a path you can see exists -- on the other side of the boundary.
`environment.md` now says to ask which namespace a string is in before asking whether the file is
there, and points at `validate_device_path`, which refuses a host-shaped path before it reaches the
device shell where it would fail far from the caller.

The leak scan caught the first draft: the example in the table was a real-looking POSIX home path and
`scan_leaks.py` flagged it as target identity. The scanner was right and the example was wrong; it now
uses a placeholder.
This commit is contained in:
inliver233
2026-10-16 19:23:59 +08:00
parent 5c3ba9cd2e
commit 905544ea89
@@ -47,6 +47,27 @@ See `scripts/devsh.py`.
Same class of bug: `javac` reads sources using the platform default encoding. Pass `-encoding UTF-8` or non-ASCII comments break the build.
### Three path namespaces, and none of them convert automatically
A path in this skill lives in exactly one of three places, and the same string means something
different in each:
| Namespace | Looks like | Who accepts it |
|---|---|---|
| **host** filesystem | `C:\work\app.apk`, `<home>/work/app.apk` | your python scripts, `aapt2`, `apksigner` |
| **device** filesystem | `/data/local/tmp/x`, `/sdcard/` | `adb shell`, `su -c`, `devsh.py` |
| **APK entry name** | `classes.dex`, `res/layout/main.xml` | `repack.py`, `so_constpatch.py`, `zipfile` |
Two properties matter. A host path **does not exist** on the device and vice versa — `adb push` and
`adb pull` take one of each, which is the only place a translation happens, and it is yours to make.
And an entry name is always `/`-separated and case-sensitive regardless of the host OS: a script that
builds one with `os.path.join` produces backslashes on Windows and matches nothing.
The symptom of a crossed boundary is a "no such file" naming a path you can see exists — on the other
side of it. When that appears, check which namespace the string is in before checking whether the file
is there. `device_shell.py`'s `validate_device_path` exists to refuse a host-shaped path before it
reaches the device shell, where it would otherwise fail far from the caller.
## Giving an offline device network over USB
Use when the device has no usable network (broken Wi-Fi, no SIM, restricted network) but your host does. **`adb reverse` runs on the device's loopback, so it needs no device-side network interface at all.**