Android userspace uses Java and can only talk to native code via JNI, which definitely isn't a C ABI.
Likewise there isn't any writing to metal on ChromeOS for the official userspace APIs, running Linux (Crostini) implies running a sandboxed version on top of the actual ChromeOS, while Android on ChromeOS not only has the same JNI restrictions, it also is sandboxed without access to host OS.
EDIT: I also forgot that ChromeOS and Android expose many of their key APIs to native code via OS IPC, on top of the constraints mentioned above. With endpoints written in a mix of C++, Java and now Rust.
JNI is very much a C ABI, yes. I should know, for I've written JNI FFIs more than once. Yes, you can also write JNIs in C++, but you don't have to because JNI's ABI is C not C++, and that is because C++ ABIs were not stable decades ago when JNI was written.
JNI is an API between the JVM and C- or C++-coded plugins that can implement native methods. "Native method" means "written in C (or C++)". There's a) a standard interface that C-coded methods must present (depending on their Java signature) and b) a set of utility C functions provided by the JVM.
Because these plugins are loaded via `dlopen()`/`LoadLibrary_Ex()`/etc. the JNI API has an ABI.
If you don't believe me go look it up. There's a ton of resources on JNI. Here's an example taken from the wikipedia page on JNI:
I would even go as far as to say that a good OS ABI only uses a safe subset of C. This excludes pass-by-value structs (and vector types), struct returns, and maybe even bitfields.
Even with these restrictions in place, modern register-based calling conventions can be still be rather complex, but these restrictions reduce it somewhat. They help to avoid areas in which implementations traditionally diverge, too.
What's wrong with pass-by-value structs? Yes, I'm aware that long ago there was a problem on SPARCs where Sun Studio and GCC handled struct value returns differently, but not pass-by-value. ABIs can and do define how to do pass by value of values of struct types.
The bits of C that need to be avoided in APIs are:
- bitfields unless no bitfield crosses a
byte boundary
- struct fields of enum types (because the
size of the enum type is implementation
specific)
C isn't used for defining ABIs. ABI's have content in them like which registers must be saved by a called function and which ones carry arguments. None of that is C. However, out of necessity, ABI definitions refer to some C concepts and must include details like how structures are to be laid out by C compilers.