If an app registers a network agent and doesn't have NETWORK_FACTORY or
PERMISSION_MAINLINE_NETWORK_STACK, but does have
CREATE_APP_SPECIFIC_NETWORK, ConnectivityService will:
- Allow it to create a network
- Force the capabilities to contain only the app's UID
- Force the network to be restricted
- Ignore attempts to change the UID or make the network non-restricted
Test: TH
Flag: android.net.platform.flags.create_app_specific_network_permission
Bug: 435313135
Change-Id: I5a9517515e64f799c88aca4a51636b1a08e15817
Uses 16KiB ram, only caches ifindex < 1024, but in practice
that should usually be the case, as these are assigned
in sequential order by the kernel.
Note that in progs/netd.c:86 we have:
DEFINE_BPF_MAP_NO_NETD(iface_index_name_map, HASH, uint32_t, IfaceValue, 1000)
so stuff doesn't really work right once we go past 1000-ish
tracked interfaces...
(and worst case we're no worse off then we are now...)
Benefit should be significant as all our bpf map stats
dumping logic has to convert from ifindex to ifname
in order to strcmp against the interface we're trying to match,
ie. that's the first thing 3 of the 4 cases we support
do at the very top of their innermost loop.
This effectively eliminates 1 bpf() lookup systemcall, thus
getting us down to 2 (getNextKey + readValue/readValueAndDelete)
Note: the tests work because they're consistent in how they
map ifindex/ifname so they do not require cache clearing.
I believe we don't have to worry about threading, as
we're being called while traversing/consuming maps.
Thus I believe there must be locking external to us.
Also writes should be *super* uncommon, so even if this
were to run multithreaded, races should happen very rarely.
If they did, we'd just write in the same value twice (since
the mapping from ifindex->ifname should rarely if ever change)
Worst case once in a blue moon we'd fail to match an interface
that had *just* shown up (because of reading only half the name),
and we'd lose some stats...
(and since the entire value fits in 16 bytes, and thus in a single
cache line, in practice most cpus will probably write combine
and thus avoid a half write/read anyway, both x86-64 and aarch64
can potentially even do a 16-byte read/write in 1 instruction...
although unclear if that will happen, but worst case should be 2)
Test: TreeHugger, atest libnetworkstats_test
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I0d3ea6c5f1f2945adccd479af6c65008bf7d7c51
Maciej Żenczykowskicommited 2025-08-12 20:39:20 -07:00
To support L4S receiver functionality on TCP connections, AccECN
is implemented using eBPF programs. Eth and rawip packets are
handled by separate pairs of ingress and egress programs.
(cherry picked from https://partner-android-review.googlesource.com/q/commit:075c29658a91da2b0e9d36d871bd2403b74a4f69)
Flag: EXEMPT tcpAccECN is not used
Change-Id: Ib0a11880b3f2b1ea04e188fe33366cae9eabe898
k1.reddyauthored and Maciej Żenczykowskicommited 2025-08-12 18:44:01 -07:00
Convert BpfMap native methods to use @FastNative to reduce JNI overhead.
Refactor synchronizeKernelRCU() to be @CriticalNative for maximum
performance by changing its error handling to return an error code
instead of throwing directly from native code.
(In practice we don't expect it to *ever* fail)
FYI:
@FastNative and @CriticalNative are Android-specific annotations
that signal to the ART runtime to use a lower-overhead JNI transition,
resulting in better performance.
A standard JNI call tells the Garbage Collector (GC) that the thread
is transitioning to a 'Native' state. This is a signal to the GC that
the thread might be busy for a while and shouldn't be suspended arbitrarily.
@FastNative is for short, quick functions:
This provides a moderately faster JNI call (thread is still 'Runnable').
The native function signature remains the same as a standard JNI method,
and it can still access the JNIEnv* to interact with Java objects
or throw exceptions.
@CriticalNative is for short, quick & trivial functions:
This provides the fastest possible JNI transition and is intended
for simple, performance-critical leaf functions.
It comes with strict requirements:
- The native method cannot throw exceptions, create Java objects,
or make any other JNI calls.
- All arguments and the return type must be primitive, ie:
jboolean [bool]
jbyte [s8]
jchar [u16]
jshort [s16]
jint [s32]
jlong [s64]
jfloat [32-bit]
jdouble [64-bit]
void
Java objects like String or byte[] are not allowed.
Because of these restrictions, the native C++ function signature
must not include JNIEnv* or jobject/jclass parameters.
(This likely also means it must be 'static')
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I9b6107b26086df2e87218ff9274593e9f2eb6b0b
Maciej Żenczykowskicommited 2025-08-12 15:28:05 -07:00
The IPv6 Router Advertisement (RA) MTU is now derived from
the minimum of the interface MTU and the MTUs of all IPv6 routes
on the upstream interface, before being clamped to the 1280-1400 range.
This ensures the advertised MTU respects any smaller
MTUs specified by individual routes.
Bug: 432676104
Test: Treehugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: If371825bd8f773ae23d1122211caa42ebf5c1f2a
Maciej Żenczykowskicommited 2025-08-12 14:06:05 -07:00
This is the case (by code inspection): this map is read/written
by C++ jni code, but only read from java.
Getting rid of the java read (used in test/dump code only afaict)
would be annoying due to needing to return a java String from jni.
As such lets just flag it as R/O, this will allow write-through
caching in jni.
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: Iadf0a96f3100d32ea4ffd423b5293c6f2de706cb
Maciej Żenczykowskicommited 2025-08-11 23:44:42 -07:00
In practice this is already the case... If uname() execution
fails, or we fail to parse the result, we won't pass the
4.9+ required check in NetBpfLoad, which is required on S+,
and mainline no longer supports anything <S anyway.
We don't require subversion as technically "4.9" (ie. 4.9.0)
is enough for almost all usecases, although in practice I would
expect there will always be an LTS subversion present.
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I66a5eba5c7bcf9bd51997db93c0fefc8104945eb
Maciej Żenczykowskicommited 2025-08-11 21:27:04 -07:00
(this was basically an oversight, nothing should be setting this)
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I6e36d9cb7522272e4a725e77b630b43cb6a1494d
Maciej Żenczykowskicommited 2025-08-11 20:58:15 -07:00
(unfortunately need to keep kernelVersion() around for some uses outside of p/m/C)
The goal of this is to make isAtLeastKernelVersion() checks
cheaper. Currently they all have to check that we've already
parsed uname...
We use that all over the place, even at runtime in BpfMap.h.
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: Iaf53fc1e36eb9f88df20c39643cbd53f420ded4e
Maciej Żenczykowskicommited 2025-08-11 15:12:52 -07:00
(in the future consume() can be changed to use kernel bpf map bulk api)
Test: TreeHugger, atest libnetworkstats_test
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I43c3e7139cf38058da4c187d1cfeec4bf7fb0ca1
Maciej Żenczykowskicommited 2025-08-11 12:45:51 -07:00
Note that we no longer need the (void*) casts, this is because:
MAKE_JNI_NATIVE_METHOD() checks function args match
MAKE_JNI_NATIVE_METHOD_AUTOSIG() autogenerates the signature
Additionally:
nativeGetTotalStat()
nativeGetIfaceStat()
nativeGetUidStat()
should be faster now, by virtue of caching a bunch of calls.
This more-or-less mirrors what was already done in the other file.
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I5a715d15ca5c01b625b8b7a62bc0e10bc0cc213f
Maciej Żenczykowskicommited 2025-08-10 10:34:13 -07:00
Note: this is not quite a no-op, as we no longer do the ifname
lookup, which could (but shouldn't) fail and cause us to ignore the stats
(for that interface).
But since it shouldn't ever fail, the value lookup should basically always
happen. Switching to forAll() will allow bulk api optimization...
Test: TreeHugger, atest libbpf_android_test libnetworkstats_test netd_updatable_unit_test
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: Id30fa1d2b4f30c5b526b5eba80e401d1a201d95d
Maciej Żenczykowskicommited 2025-08-09 19:18:48 -07:00
switch some iterate to forAll()/consume()
Currently we only use:
BPF_MAP_LOOKUP_ELEM
BPF_MAP_UPDATE_ELEM
BPF_MAP_DELETE_ELEM
BPF_MAP_GET_NEXT_KEY
Our implementation does:
getFirstKey() -> BPF_MAP_GET_NEXT_KEY (with empty key, maybe newer kernels would accept null too)
getNextKey(K) -> BPF_MAP_GET_NEXT_KEY
readValue(K) -> BPF_MAP_LOOKUP_ELEM
iterate(f(K)) -> getFirstKey(), loop { getNextKey(K) }
forAll(f(K)) -> iterate(f(K))
iterate(f(K, V)) -> getFirstKey(), loop { getNextKey(K) readValue(K) }
forAll(f(K, V)) -> iterate(f(K, V))
isEmpty() -> getFirstKey()
writeValue(K, V) -> BPF_MAP_UPDATE_ELEM
deleteValue(K) -> BPF_MAP_DELETE_ELEM
clear() -> loop { getFirstKey() deleteValue(K) }
consume(f(K, V)) -> iterate(f(K, V) + deleteValue(K))
but bpf on newer kernels also supports:
BPF_MAP_LOOKUP_AND_DELETE_ELEM
and batch operations:
BPF_MAP_LOOKUP_BATCH
BPF_MAP_LOOKUP_AND_DELETE_BATCH
BPF_MAP_UPDATE_BATCH
BPF_MAP_DELETE_BATCH
that we don't currently use.
These can be utilized to lower the number of system calls:
- iterate(f(K, V)) might be able to use LOOPUP_BATCH(1)
- forAll() can probably use LOOKUP_BATCH(many)
- consume() can probably use one of LOOKUP_AND_DELETE_ELEM or LOOKUP_AND_DELETE_BATCH
UPDATE_BATCH seems like it could also be useful, though harder
to see how to make it useful from a clean API perspective...
(and obviously for bpf map ARRAYs [and thus bitmaps], mmap() is simply much better...)
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I2c142319c365aa1b9585256e2c604b221ba18c21
Maciej Żenczykowskicommited 2025-08-09 19:02:56 -07:00
(we've deleted the GTS test, so no need for this simple demo case)
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I7f5a060f53ac97d55f533aea7a8148d3c091856d
Maciej Żenczykowskicommited 2025-08-09 16:04:17 -07:00
which allows writes, but not deletes.
This is technically what bpf map arrays are capable of.
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I1f73bea5428c190af17442539c296282ce9e0786
Maciej Żenczykowskicommited 2025-08-09 16:03:46 -07:00
It's so much better to just pass in the map (if needed)
as part of the lambda capture...
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: If16fa9c8d0ade41628dc4f7ac1fa73127001b6b1
Maciej Żenczykowskicommited 2025-08-09 14:25:34 -07:00
Annotate APFv6 multi-device tests with `@CddTest`.
This marks these tests for compliance with specific CDD requirements.
Flag: EXEMPT test only
Bug: 437029299
Test: atest CtsConnectivityMultiDevicesTestCases:ApfV6Test
Change-Id: I686ca609c3f34daf106673e429c49b8776c97923
Annotate APFv4 multi-device tests with `@CddTest`.
This marks these tests for compliance with specific CDD requirements.
Flag: EXEMPT test only
Bug: 437034146
Test: atest CtsConnectivityMultiDevicesTestCases:ApfV4Test
Change-Id: Ibdd4c1652e21a708d5ddde79ecedbe258e318ac3
The mobile data preferred feature stores the list of UIDs in
Settings.Secure, which is per-user. But the code only sets, reads
and observes the setting for the current user instead of for all
users. This does not work on HSUM or automotive.
Fix this as follows:
- Register the ContentObserver on UserHandle.ALL
- Any time the observer fires, read the setting on all current
users, and operate on the merged result.
- Ensure that the code gets called on ACTION_USER_ADDED and
ACTION_USER_REMOVED.
Because the code now aggregates the setting for all UIDs, it
should just work on single-user devices. It should also work if
there are OEM devices that store all UIDs (for all users) in
Settings.Secure for user 0.
Because the bug is fixed, re-enable the test on automotive.
Also fix style nits.
Fix: 404186833
Flag: EXEMPT bug fix
Test: covered by existing CTS tests
Change-Id: I69ad789f1c7c7f3bab04ab8789dfb93ee0de553d
Lorenzo Colitticommited 2025-08-08 15:36:55 +09:00
ConnectivityService uses SettingsObservers to detect when
settings change. These are all set on user zero. This is fine
for most settings, which are in Settings.Global, but some
settings are per-user, such as MOBILE_DATA_PREFERRED_UIDS, which
is in Settings.Secure.
This CL adds the ability to register SettingsObservers on all
users. These observers will fire any time the setting changes
for any current user, and any time a user is added or removed.
This CL does not add or change any SettingsObservers and should
cause no behaviour changes.
Bug: 404186833
Flag: EXEMPT refactor
Test: covered by existing tests
Change-Id: I5954b196eea776414098f1ce4441eb02065438ef
Lorenzo Colitticommited 2025-08-08 15:36:54 +09:00
Perhaps not the best example, but virtually free considering
a bitmap of 64K bits is 8KiB no matter what.
Kernel will allocate:
1 page for internal metadata (rounded up to a full page)
N pages rounded up from array size, which is:
number of elements (65536 bits / 64 bits per u64) = 1024
* element size (u64 rounded up to a multiple of 8) = 8
= 8192
This rounding up is unique to *mmapable* arrays.
thus on 4KiB page size: 12 KiB - waste is at most a few (<4) KiB
and on 16KiB page size: 32 KiB - which isn't great, but well that's 16KiB...
(presumably 16KiB is being used on devices with a lot of ram,
where performance matters more than a little ram waste)
Note: AFAICT a kernel bpf program R/W map cannot be mapped R/O
into userspace, as the permissions on the page mapping would conflict.
(and obviously you cannot map R/W if you have only R/O access)
I'm not sure if this is architecture specific,
or simply an implementation limitation, but it is what I observed.
I think it's likely a missing kernel feature (even on 6.12)...
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I609ae61e17917ff441cac10a9b29af3fcacb53c5
Maciej Żenczykowskicommited 2025-08-07 15:54:01 -07:00
automatically fall back for older kernels
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: Ice377331442f71fa69f086a3be8a8c10cbc6575f
Maciej Żenczykowskicommited 2025-08-07 15:53:42 -07:00
This is more legible then a series of if's,
although thus require manually adding support for new map types.
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I8900eb8ced5e4a1cb161b49e5c68d2effe36af57
Maciej Żenczykowskicommited 2025-08-07 15:53:05 -07:00
(that this was missing appears to be an oversight)
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: Icd424324db11e56f820817f890985155d639175d
Maciej Żenczykowskicommited 2025-08-07 15:52:52 -07:00
(mostly autogenerated, with minor tweaks to make it build)
Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I2065c3fc6d4d37663a0a52281deb7624fd5c801d
Maciej Żenczykowskicommited 2025-08-07 15:52:35 -07:00