blob: 2b4ecb6f9c54d4caca398bd8d57a9d77d5efb6e5 [file] [log] [blame]
Wayne Ma4d692332022-01-19 16:04:04 +08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "TrafficController"
18#include <inttypes.h>
19#include <linux/bpf.h>
20#include <linux/if_ether.h>
21#include <linux/in.h>
22#include <linux/inet_diag.h>
23#include <linux/netlink.h>
24#include <linux/sock_diag.h>
25#include <linux/unistd.h>
26#include <net/if.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/socket.h>
30#include <sys/stat.h>
31#include <sys/types.h>
32#include <sys/utsname.h>
33#include <sys/wait.h>
34#include <mutex>
35#include <unordered_set>
36#include <vector>
37
38#include <android-base/stringprintf.h>
39#include <android-base/strings.h>
40#include <android-base/unique_fd.h>
41#include <netdutils/StatusOr.h>
42
43#include <netdutils/Misc.h>
44#include <netdutils/NetlinkListener.h>
45#include <netdutils/Syscalls.h>
46#include <netdutils/Utils.h>
47#include <processgroup/processgroup.h>
48#include "TrafficController.h"
49#include "bpf/BpfMap.h"
50
51#include "netdutils/DumpWriter.h"
52
53namespace android {
54namespace net {
55
56using base::StringPrintf;
57using base::unique_fd;
58using bpf::BpfMap;
59using bpf::getSocketCookie;
60using bpf::NONEXISTENT_COOKIE;
61using bpf::OVERFLOW_COUNTERSET;
62using bpf::retrieveProgram;
63using bpf::synchronizeKernelRCU;
64using netdutils::DumpWriter;
65using netdutils::extract;
66using netdutils::getIfaceList;
67using netdutils::NetlinkListener;
68using netdutils::NetlinkListenerInterface;
69using netdutils::ScopedIndent;
70using netdutils::Slice;
71using netdutils::sSyscalls;
72using netdutils::Status;
73using netdutils::statusFromErrno;
74using netdutils::StatusOr;
75using netdutils::status::ok;
76
77constexpr int kSockDiagMsgType = SOCK_DIAG_BY_FAMILY;
78constexpr int kSockDiagDoneMsgType = NLMSG_DONE;
79constexpr int PER_UID_STATS_ENTRIES_LIMIT = 500;
80// At most 90% of the stats map may be used by tagged traffic entries. This ensures
81// that 10% of the map is always available to count untagged traffic, one entry per UID.
82// Otherwise, apps would be able to avoid data usage accounting entirely by filling up the
83// map with tagged traffic entries.
84constexpr int TOTAL_UID_STATS_ENTRIES_LIMIT = STATS_MAP_SIZE * 0.9;
85
86const char* TrafficController::LOCAL_DOZABLE = "fw_dozable";
87const char* TrafficController::LOCAL_STANDBY = "fw_standby";
88const char* TrafficController::LOCAL_POWERSAVE = "fw_powersave";
89const char* TrafficController::LOCAL_RESTRICTED = "fw_restricted";
90
91static_assert(BPF_PERMISSION_INTERNET == INetd::PERMISSION_INTERNET,
92 "Mismatch between BPF and AIDL permissions: PERMISSION_INTERNET");
93static_assert(BPF_PERMISSION_UPDATE_DEVICE_STATS == INetd::PERMISSION_UPDATE_DEVICE_STATS,
94 "Mismatch between BPF and AIDL permissions: PERMISSION_UPDATE_DEVICE_STATS");
95static_assert(STATS_MAP_SIZE - TOTAL_UID_STATS_ENTRIES_LIMIT > 100,
96 "The limit for stats map is to high, stats data may be lost due to overflow");
97
98#define FLAG_MSG_TRANS(result, flag, value) \
99 do { \
100 if ((value) & (flag)) { \
101 (result).append(" " #flag); \
102 (value) &= ~(flag); \
103 } \
104 } while (0)
105
106const std::string uidMatchTypeToString(uint8_t match) {
107 std::string matchType;
108 FLAG_MSG_TRANS(matchType, HAPPY_BOX_MATCH, match);
109 FLAG_MSG_TRANS(matchType, PENALTY_BOX_MATCH, match);
110 FLAG_MSG_TRANS(matchType, DOZABLE_MATCH, match);
111 FLAG_MSG_TRANS(matchType, STANDBY_MATCH, match);
112 FLAG_MSG_TRANS(matchType, POWERSAVE_MATCH, match);
113 FLAG_MSG_TRANS(matchType, RESTRICTED_MATCH, match);
114 FLAG_MSG_TRANS(matchType, IIF_MATCH, match);
115 if (match) {
116 return StringPrintf("Unknown match: %u", match);
117 }
118 return matchType;
119}
120
121bool TrafficController::hasUpdateDeviceStatsPermission(uid_t uid) {
122 // This implementation is the same logic as method ActivityManager#checkComponentPermission.
123 // It implies that the calling uid can never be the same as PER_USER_RANGE.
124 uint32_t appId = uid % PER_USER_RANGE;
125 return ((appId == AID_ROOT) || (appId == AID_SYSTEM) ||
126 mPrivilegedUser.find(appId) != mPrivilegedUser.end());
127}
128
129const std::string UidPermissionTypeToString(int permission) {
130 if (permission == INetd::PERMISSION_NONE) {
131 return "PERMISSION_NONE";
132 }
133 if (permission == INetd::PERMISSION_UNINSTALLED) {
134 // This should never appear in the map, complain loudly if it does.
135 return "PERMISSION_UNINSTALLED error!";
136 }
137 std::string permissionType;
138 FLAG_MSG_TRANS(permissionType, BPF_PERMISSION_INTERNET, permission);
139 FLAG_MSG_TRANS(permissionType, BPF_PERMISSION_UPDATE_DEVICE_STATS, permission);
140 if (permission) {
141 return StringPrintf("Unknown permission: %u", permission);
142 }
143 return permissionType;
144}
145
146StatusOr<std::unique_ptr<NetlinkListenerInterface>> TrafficController::makeSkDestroyListener() {
147 const auto& sys = sSyscalls.get();
148 ASSIGN_OR_RETURN(auto event, sys.eventfd(0, EFD_CLOEXEC));
149 const int domain = AF_NETLINK;
150 const int type = SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
151 const int protocol = NETLINK_INET_DIAG;
152 ASSIGN_OR_RETURN(auto sock, sys.socket(domain, type, protocol));
153
154 // TODO: if too many sockets are closed too quickly, we can overflow the socket buffer, and
155 // some entries in mCookieTagMap will not be freed. In order to fix this we would need to
156 // periodically dump all sockets and remove the tag entries for sockets that have been closed.
157 // For now, set a large-enough buffer that we can close hundreds of sockets without getting
158 // ENOBUFS and leaking mCookieTagMap entries.
159 int rcvbuf = 512 * 1024;
160 auto ret = sys.setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
161 if (!ret.ok()) {
162 ALOGW("Failed to set SkDestroyListener buffer size to %d: %s", rcvbuf, ret.msg().c_str());
163 }
164
165 sockaddr_nl addr = {
166 .nl_family = AF_NETLINK,
167 .nl_groups = 1 << (SKNLGRP_INET_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET_UDP_DESTROY - 1) |
168 1 << (SKNLGRP_INET6_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET6_UDP_DESTROY - 1)};
169 RETURN_IF_NOT_OK(sys.bind(sock, addr));
170
171 const sockaddr_nl kernel = {.nl_family = AF_NETLINK};
172 RETURN_IF_NOT_OK(sys.connect(sock, kernel));
173
174 std::unique_ptr<NetlinkListenerInterface> listener =
175 std::make_unique<NetlinkListener>(std::move(event), std::move(sock), "SkDestroyListen");
176
177 return listener;
178}
179
180TrafficController::TrafficController()
181 : mPerUidStatsEntriesLimit(PER_UID_STATS_ENTRIES_LIMIT),
182 mTotalUidStatsEntriesLimit(TOTAL_UID_STATS_ENTRIES_LIMIT) {}
183
184TrafficController::TrafficController(uint32_t perUidLimit, uint32_t totalLimit)
185 : mPerUidStatsEntriesLimit(perUidLimit), mTotalUidStatsEntriesLimit(totalLimit) {}
186
187Status TrafficController::initMaps() {
188 std::lock_guard guard(mMutex);
189
190 RETURN_IF_NOT_OK(mCookieTagMap.init(COOKIE_TAG_MAP_PATH));
191 RETURN_IF_NOT_OK(mUidCounterSetMap.init(UID_COUNTERSET_MAP_PATH));
192 RETURN_IF_NOT_OK(mAppUidStatsMap.init(APP_UID_STATS_MAP_PATH));
193 RETURN_IF_NOT_OK(mStatsMapA.init(STATS_MAP_A_PATH));
194 RETURN_IF_NOT_OK(mStatsMapB.init(STATS_MAP_B_PATH));
195 RETURN_IF_NOT_OK(mIfaceIndexNameMap.init(IFACE_INDEX_NAME_MAP_PATH));
196 RETURN_IF_NOT_OK(mIfaceStatsMap.init(IFACE_STATS_MAP_PATH));
197
198 RETURN_IF_NOT_OK(mConfigurationMap.init(CONFIGURATION_MAP_PATH));
199 RETURN_IF_NOT_OK(
200 mConfigurationMap.writeValue(UID_RULES_CONFIGURATION_KEY, DEFAULT_CONFIG, BPF_ANY));
201 RETURN_IF_NOT_OK(mConfigurationMap.writeValue(CURRENT_STATS_MAP_CONFIGURATION_KEY, SELECT_MAP_A,
202 BPF_ANY));
203
204 RETURN_IF_NOT_OK(mUidOwnerMap.init(UID_OWNER_MAP_PATH));
205 RETURN_IF_NOT_OK(mUidOwnerMap.clear());
206 RETURN_IF_NOT_OK(mUidPermissionMap.init(UID_PERMISSION_MAP_PATH));
207
208 return netdutils::status::ok;
209}
210
211static Status attachProgramToCgroup(const char* programPath, const unique_fd& cgroupFd,
212 bpf_attach_type type) {
213 unique_fd cgroupProg(retrieveProgram(programPath));
214 if (cgroupProg == -1) {
215 int ret = errno;
216 ALOGE("Failed to get program from %s: %s", programPath, strerror(ret));
217 return statusFromErrno(ret, "cgroup program get failed");
218 }
219 if (android::bpf::attachProgram(type, cgroupProg, cgroupFd)) {
220 int ret = errno;
221 ALOGE("Program from %s attach failed: %s", programPath, strerror(ret));
222 return statusFromErrno(ret, "program attach failed");
223 }
224 return netdutils::status::ok;
225}
226
227static Status initPrograms() {
228 std::string cg2_path;
229
230 if (!CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &cg2_path)) {
231 int ret = errno;
232 ALOGE("Failed to find cgroup v2 root");
233 return statusFromErrno(ret, "Failed to find cgroup v2 root");
234 }
235
236 unique_fd cg_fd(open(cg2_path.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
237 if (cg_fd == -1) {
238 int ret = errno;
239 ALOGE("Failed to open the cgroup directory: %s", strerror(ret));
240 return statusFromErrno(ret, "Open the cgroup directory failed");
241 }
242 RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_EGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_EGRESS));
243 RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_INGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_INGRESS));
244
245 // For the devices that support cgroup socket filter, the socket filter
246 // should be loaded successfully by bpfloader. So we attach the filter to
247 // cgroup if the program is pinned properly.
248 // TODO: delete the if statement once all devices should support cgroup
249 // socket filter (ie. the minimum kernel version required is 4.14).
250 if (!access(CGROUP_SOCKET_PROG_PATH, F_OK)) {
251 RETURN_IF_NOT_OK(
252 attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
253 }
254 return netdutils::status::ok;
255}
256
257Status TrafficController::start() {
258 /* When netd restarts from a crash without total system reboot, the program
259 * is still attached to the cgroup, detach it so the program can be freed
260 * and we can load and attach new program into the target cgroup.
261 *
262 * TODO: Scrape existing socket when run-time restart and clean up the map
263 * if the socket no longer exist
264 */
265
266 RETURN_IF_NOT_OK(initMaps());
267
268 RETURN_IF_NOT_OK(initPrograms());
269
270 // Fetch the list of currently-existing interfaces. At this point NetlinkHandler is
271 // already running, so it will call addInterface() when any new interface appears.
272 std::map<std::string, uint32_t> ifacePairs;
273 ASSIGN_OR_RETURN(ifacePairs, getIfaceList());
274 for (const auto& ifacePair:ifacePairs) {
275 addInterface(ifacePair.first.c_str(), ifacePair.second);
276 }
277
278 auto result = makeSkDestroyListener();
279 if (!isOk(result)) {
280 ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
281 } else {
282 mSkDestroyListener = std::move(result.value());
283 }
284 // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
285 const auto rxHandler = [this](const nlmsghdr&, const Slice msg) {
286 std::lock_guard guard(mMutex);
287 inet_diag_msg diagmsg = {};
288 if (extract(msg, diagmsg) < sizeof(inet_diag_msg)) {
289 ALOGE("Unrecognized netlink message: %s", toString(msg).c_str());
290 return;
291 }
292 uint64_t sock_cookie = static_cast<uint64_t>(diagmsg.id.idiag_cookie[0]) |
293 (static_cast<uint64_t>(diagmsg.id.idiag_cookie[1]) << 32);
294
295 Status s = mCookieTagMap.deleteValue(sock_cookie);
296 if (!isOk(s) && s.code() != ENOENT) {
297 ALOGE("Failed to delete cookie %" PRIx64 ": %s", sock_cookie, toString(s).c_str());
298 return;
299 }
300 };
301 expectOk(mSkDestroyListener->subscribe(kSockDiagMsgType, rxHandler));
302
303 // In case multiple netlink message comes in as a stream, we need to handle the rxDone message
304 // properly.
305 const auto rxDoneHandler = [](const nlmsghdr&, const Slice msg) {
306 // Ignore NLMSG_DONE messages
307 inet_diag_msg diagmsg = {};
308 extract(msg, diagmsg);
309 };
310 expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
311
312 return netdutils::status::ok;
313}
314
315int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid, uid_t callingUid) {
316 std::lock_guard guard(mMutex);
317 if (uid != callingUid && !hasUpdateDeviceStatsPermission(callingUid)) {
318 return -EPERM;
319 }
320 return privilegedTagSocketLocked(sockFd, tag, uid);
321}
322
323int TrafficController::privilegedTagSocket(int sockFd, uint32_t tag, uid_t uid) {
324 std::lock_guard guard(mMutex);
325 return privilegedTagSocketLocked(sockFd, tag, uid);
326}
327
328int TrafficController::privilegedTagSocketLocked(int sockFd, uint32_t tag, uid_t uid) {
329 uint64_t sock_cookie = getSocketCookie(sockFd);
330 if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
331 UidTagValue newKey = {.uid = (uint32_t)uid, .tag = tag};
332
333 uint32_t totalEntryCount = 0;
334 uint32_t perUidEntryCount = 0;
335 // Now we go through the stats map and count how many entries are associated
336 // with target uid. If the uid entry hit the limit for each uid, we block
337 // the request to prevent the map from overflow. It is safe here to iterate
338 // over the map since when mMutex is hold, system server cannot toggle
339 // the live stats map and clean it. So nobody can delete entries from the map.
340 const auto countUidStatsEntries = [uid, &totalEntryCount, &perUidEntryCount](
341 const StatsKey& key,
342 const BpfMap<StatsKey, StatsValue>&) {
343 if (key.uid == uid) {
344 perUidEntryCount++;
345 }
346 totalEntryCount++;
347 return base::Result<void>();
348 };
349 auto configuration = mConfigurationMap.readValue(CURRENT_STATS_MAP_CONFIGURATION_KEY);
350 if (!configuration.ok()) {
351 ALOGE("Failed to get current configuration: %s, fd: %d",
352 strerror(configuration.error().code()), mConfigurationMap.getMap().get());
353 return -configuration.error().code();
354 }
355 if (configuration.value() != SELECT_MAP_A && configuration.value() != SELECT_MAP_B) {
356 ALOGE("unknown configuration value: %d", configuration.value());
357 return -EINVAL;
358 }
359
360 BpfMap<StatsKey, StatsValue>& currentMap =
361 (configuration.value() == SELECT_MAP_A) ? mStatsMapA : mStatsMapB;
362 base::Result<void> res = currentMap.iterate(countUidStatsEntries);
363 if (!res.ok()) {
364 ALOGE("Failed to count the stats entry in map %d: %s", currentMap.getMap().get(),
365 strerror(res.error().code()));
366 return -res.error().code();
367 }
368
369 if (totalEntryCount > mTotalUidStatsEntriesLimit ||
370 perUidEntryCount > mPerUidStatsEntriesLimit) {
371 ALOGE("Too many stats entries in the map, total count: %u, uid(%u) count: %u, blocking tag"
372 " request to prevent map overflow",
373 totalEntryCount, uid, perUidEntryCount);
374 return -EMFILE;
375 }
376 // Update the tag information of a socket to the cookieUidMap. Use BPF_ANY
377 // flag so it will insert a new entry to the map if that value doesn't exist
378 // yet. And update the tag if there is already a tag stored. Since the eBPF
379 // program in kernel only read this map, and is protected by rcu read lock. It
380 // should be fine to cocurrently update the map while eBPF program is running.
381 res = mCookieTagMap.writeValue(sock_cookie, newKey, BPF_ANY);
382 if (!res.ok()) {
383 ALOGE("Failed to tag the socket: %s, fd: %d", strerror(res.error().code()),
384 mCookieTagMap.getMap().get());
385 return -res.error().code();
386 }
387 return 0;
388}
389
390int TrafficController::untagSocket(int sockFd) {
391 std::lock_guard guard(mMutex);
392 uint64_t sock_cookie = getSocketCookie(sockFd);
393
394 if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
395 base::Result<void> res = mCookieTagMap.deleteValue(sock_cookie);
396 if (!res.ok()) {
397 ALOGE("Failed to untag socket: %s\n", strerror(res.error().code()));
398 return -res.error().code();
399 }
400 return 0;
401}
402
403int TrafficController::setCounterSet(int counterSetNum, uid_t uid, uid_t callingUid) {
404 if (counterSetNum < 0 || counterSetNum >= OVERFLOW_COUNTERSET) return -EINVAL;
405
406 std::lock_guard guard(mMutex);
407 if (!hasUpdateDeviceStatsPermission(callingUid)) return -EPERM;
408
409 // The default counter set for all uid is 0, so deleting the current counterset for that uid
410 // will automatically set it to 0.
411 if (counterSetNum == 0) {
412 Status res = mUidCounterSetMap.deleteValue(uid);
413 if (isOk(res) || (!isOk(res) && res.code() == ENOENT)) {
414 return 0;
415 } else {
416 ALOGE("Failed to delete the counterSet: %s\n", strerror(res.code()));
417 return -res.code();
418 }
419 }
420 uint8_t tmpCounterSetNum = (uint8_t)counterSetNum;
421 Status res = mUidCounterSetMap.writeValue(uid, tmpCounterSetNum, BPF_ANY);
422 if (!isOk(res)) {
423 ALOGE("Failed to set the counterSet: %s, fd: %d", strerror(res.code()),
424 mUidCounterSetMap.getMap().get());
425 return -res.code();
426 }
427 return 0;
428}
429
430// This method only get called by system_server when an app get uinstalled, it
431// is called inside removeUidsLocked() while holding mStatsLock. So it is safe
432// to iterate and modify the stats maps.
433int TrafficController::deleteTagData(uint32_t tag, uid_t uid, uid_t callingUid) {
434 std::lock_guard guard(mMutex);
435 if (!hasUpdateDeviceStatsPermission(callingUid)) return -EPERM;
436
437 // First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
438 // the tags related to the uid if the tag is 0.
439 const auto deleteMatchedCookieEntries = [uid, tag](const uint64_t& key,
440 const UidTagValue& value,
441 BpfMap<uint64_t, UidTagValue>& map) {
442 if (value.uid == uid && (value.tag == tag || tag == 0)) {
443 auto res = map.deleteValue(key);
444 if (res.ok() || (res.error().code() == ENOENT)) {
445 return base::Result<void>();
446 }
447 ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", key,
448 strerror(res.error().code()));
449 }
450 // Move forward to next cookie in the map.
451 return base::Result<void>();
452 };
453 mCookieTagMap.iterateWithValue(deleteMatchedCookieEntries);
454 // Now we go through the Tag stats map and delete the data entry with correct uid and tag
455 // combination. Or all tag stats under that uid if the target tag is 0.
456 const auto deleteMatchedUidTagEntries = [uid, tag](const StatsKey& key,
457 BpfMap<StatsKey, StatsValue>& map) {
458 if (key.uid == uid && (key.tag == tag || tag == 0)) {
459 auto res = map.deleteValue(key);
460 if (res.ok() || (res.error().code() == ENOENT)) {
461 //Entry is deleted, use the current key to get a new nextKey;
462 return base::Result<void>();
463 }
464 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", key.uid, key.tag,
465 strerror(res.error().code()));
466 }
467 return base::Result<void>();
468 };
469 mStatsMapB.iterate(deleteMatchedUidTagEntries);
470 mStatsMapA.iterate(deleteMatchedUidTagEntries);
471 // If the tag is not zero, we already deleted all the data entry required. If tag is 0, we also
472 // need to delete the stats stored in uidStatsMap and counterSet map.
473 if (tag != 0) return 0;
474
475 auto res = mUidCounterSetMap.deleteValue(uid);
476 if (!res.ok() && res.error().code() != ENOENT) {
477 ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag,
478 strerror(res.error().code()));
479 }
480
481 auto deleteAppUidStatsEntry = [uid](const uint32_t& key,
482 BpfMap<uint32_t, StatsValue>& map) -> base::Result<void> {
483 if (key == uid) {
484 auto res = map.deleteValue(key);
485 if (res.ok() || (res.error().code() == ENOENT)) {
486 return {};
487 }
488 ALOGE("Failed to delete data(uid=%u): %s", key, strerror(res.error().code()));
489 }
490 return {};
491 };
492 mAppUidStatsMap.iterate(deleteAppUidStatsEntry);
493 return 0;
494}
495
496int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
497 IfaceValue iface;
498 if (ifaceIndex == 0) {
499 ALOGE("Unknown interface %s(%d)", name, ifaceIndex);
500 return -1;
501 }
502
503 strlcpy(iface.name, name, sizeof(IfaceValue));
504 Status res = mIfaceIndexNameMap.writeValue(ifaceIndex, iface, BPF_ANY);
505 if (!isOk(res)) {
506 ALOGE("Failed to add iface %s(%d): %s", name, ifaceIndex, strerror(res.code()));
507 return -res.code();
508 }
509 return 0;
510}
511
512Status TrafficController::updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
513 FirewallType type) {
514 std::lock_guard guard(mMutex);
515 if ((rule == ALLOW && type == ALLOWLIST) || (rule == DENY && type == DENYLIST)) {
516 RETURN_IF_NOT_OK(addRule(uid, match));
517 } else if ((rule == ALLOW && type == DENYLIST) || (rule == DENY && type == ALLOWLIST)) {
518 RETURN_IF_NOT_OK(removeRule(uid, match));
519 } else {
520 //Cannot happen.
521 return statusFromErrno(EINVAL, "");
522 }
523 return netdutils::status::ok;
524}
525
526Status TrafficController::removeRule(uint32_t uid, UidOwnerMatchType match) {
527 auto oldMatch = mUidOwnerMap.readValue(uid);
528 if (oldMatch.ok()) {
529 UidOwnerValue newMatch = {
530 .iif = (match == IIF_MATCH) ? 0 : oldMatch.value().iif,
531 .rule = static_cast<uint8_t>(oldMatch.value().rule & ~match),
532 };
533 if (newMatch.rule == 0) {
534 RETURN_IF_NOT_OK(mUidOwnerMap.deleteValue(uid));
535 } else {
536 RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
537 }
538 } else {
539 return statusFromErrno(ENOENT, StringPrintf("uid: %u does not exist in map", uid));
540 }
541 return netdutils::status::ok;
542}
543
544Status TrafficController::addRule(uint32_t uid, UidOwnerMatchType match, uint32_t iif) {
545 // iif should be non-zero if and only if match == MATCH_IIF
546 if (match == IIF_MATCH && iif == 0) {
547 return statusFromErrno(EINVAL, "Interface match must have nonzero interface index");
548 } else if (match != IIF_MATCH && iif != 0) {
549 return statusFromErrno(EINVAL, "Non-interface match must have zero interface index");
550 }
551 auto oldMatch = mUidOwnerMap.readValue(uid);
552 if (oldMatch.ok()) {
553 UidOwnerValue newMatch = {
554 .iif = iif ? iif : oldMatch.value().iif,
555 .rule = static_cast<uint8_t>(oldMatch.value().rule | match),
556 };
557 RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
558 } else {
559 UidOwnerValue newMatch = {
560 .iif = iif,
561 .rule = static_cast<uint8_t>(match),
562 };
563 RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
564 }
565 return netdutils::status::ok;
566}
567
568Status TrafficController::updateUidOwnerMap(const std::vector<uint32_t>& appUids,
569 UidOwnerMatchType matchType, IptOp op) {
570 std::lock_guard guard(mMutex);
571 for (uint32_t uid : appUids) {
572 if (op == IptOpDelete) {
573 RETURN_IF_NOT_OK(removeRule(uid, matchType));
574 } else if (op == IptOpInsert) {
575 RETURN_IF_NOT_OK(addRule(uid, matchType));
576 } else {
577 // Cannot happen.
578 return statusFromErrno(EINVAL, StringPrintf("invalid IptOp: %d, %d", op, matchType));
579 }
580 }
581 return netdutils::status::ok;
582}
583
584FirewallType TrafficController::getFirewallType(ChildChain chain) {
585 switch (chain) {
586 case DOZABLE:
587 return ALLOWLIST;
588 case STANDBY:
589 return DENYLIST;
590 case POWERSAVE:
591 return ALLOWLIST;
592 case RESTRICTED:
593 return ALLOWLIST;
594 case NONE:
595 default:
596 return DENYLIST;
597 }
598}
599
600int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallRule rule,
601 FirewallType type) {
602 Status res;
603 switch (chain) {
604 case DOZABLE:
605 res = updateOwnerMapEntry(DOZABLE_MATCH, uid, rule, type);
606 break;
607 case STANDBY:
608 res = updateOwnerMapEntry(STANDBY_MATCH, uid, rule, type);
609 break;
610 case POWERSAVE:
611 res = updateOwnerMapEntry(POWERSAVE_MATCH, uid, rule, type);
612 break;
613 case RESTRICTED:
614 res = updateOwnerMapEntry(RESTRICTED_MATCH, uid, rule, type);
615 break;
616 case NONE:
617 default:
618 ALOGW("Unknown child chain: %d", chain);
619 return -EINVAL;
620 }
621 if (!isOk(res)) {
622 ALOGE("change uid(%u) rule of %d failed: %s, rule: %d, type: %d", uid, chain,
623 res.msg().c_str(), rule, type);
624 return -res.code();
625 }
626 return 0;
627}
628
629Status TrafficController::replaceRulesInMap(const UidOwnerMatchType match,
630 const std::vector<int32_t>& uids) {
631 std::lock_guard guard(mMutex);
632 std::set<int32_t> uidSet(uids.begin(), uids.end());
633 std::vector<uint32_t> uidsToDelete;
634 auto getUidsToDelete = [&uidsToDelete, &uidSet](const uint32_t& key,
635 const BpfMap<uint32_t, UidOwnerValue>&) {
636 if (uidSet.find((int32_t) key) == uidSet.end()) {
637 uidsToDelete.push_back(key);
638 }
639 return base::Result<void>();
640 };
641 RETURN_IF_NOT_OK(mUidOwnerMap.iterate(getUidsToDelete));
642
643 for(auto uid : uidsToDelete) {
644 RETURN_IF_NOT_OK(removeRule(uid, match));
645 }
646
647 for (auto uid : uids) {
648 RETURN_IF_NOT_OK(addRule(uid, match));
649 }
650 return netdutils::status::ok;
651}
652
653Status TrafficController::addUidInterfaceRules(const int iif,
654 const std::vector<int32_t>& uidsToAdd) {
655 if (!iif) {
656 return statusFromErrno(EINVAL, "Interface rule must specify interface");
657 }
658 std::lock_guard guard(mMutex);
659
660 for (auto uid : uidsToAdd) {
661 netdutils::Status result = addRule(uid, IIF_MATCH, iif);
662 if (!isOk(result)) {
663 ALOGW("addRule failed(%d): uid=%d iif=%d", result.code(), uid, iif);
664 }
665 }
666 return netdutils::status::ok;
667}
668
669Status TrafficController::removeUidInterfaceRules(const std::vector<int32_t>& uidsToDelete) {
670 std::lock_guard guard(mMutex);
671
672 for (auto uid : uidsToDelete) {
673 netdutils::Status result = removeRule(uid, IIF_MATCH);
674 if (!isOk(result)) {
675 ALOGW("removeRule failed(%d): uid=%d", result.code(), uid);
676 }
677 }
678 return netdutils::status::ok;
679}
680
681int TrafficController::replaceUidOwnerMap(const std::string& name, bool isAllowlist __unused,
682 const std::vector<int32_t>& uids) {
683 // FirewallRule rule = isAllowlist ? ALLOW : DENY;
684 // FirewallType type = isAllowlist ? ALLOWLIST : DENYLIST;
685 Status res;
686 if (!name.compare(LOCAL_DOZABLE)) {
687 res = replaceRulesInMap(DOZABLE_MATCH, uids);
688 } else if (!name.compare(LOCAL_STANDBY)) {
689 res = replaceRulesInMap(STANDBY_MATCH, uids);
690 } else if (!name.compare(LOCAL_POWERSAVE)) {
691 res = replaceRulesInMap(POWERSAVE_MATCH, uids);
692 } else if (!name.compare(LOCAL_RESTRICTED)) {
693 res = replaceRulesInMap(RESTRICTED_MATCH, uids);
694 } else {
695 ALOGE("unknown chain name: %s", name.c_str());
696 return -EINVAL;
697 }
698 if (!isOk(res)) {
699 ALOGE("Failed to clean up chain: %s: %s", name.c_str(), res.msg().c_str());
700 return -res.code();
701 }
702 return 0;
703}
704
705int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
706 std::lock_guard guard(mMutex);
707 uint32_t key = UID_RULES_CONFIGURATION_KEY;
708 auto oldConfiguration = mConfigurationMap.readValue(key);
709 if (!oldConfiguration.ok()) {
710 ALOGE("Cannot read the old configuration from map: %s",
711 oldConfiguration.error().message().c_str());
712 return -oldConfiguration.error().code();
713 }
714 Status res;
715 BpfConfig newConfiguration;
716 uint8_t match;
717 switch (chain) {
718 case DOZABLE:
719 match = DOZABLE_MATCH;
720 break;
721 case STANDBY:
722 match = STANDBY_MATCH;
723 break;
724 case POWERSAVE:
725 match = POWERSAVE_MATCH;
726 break;
727 case RESTRICTED:
728 match = RESTRICTED_MATCH;
729 break;
730 default:
731 return -EINVAL;
732 }
733 newConfiguration =
734 enable ? (oldConfiguration.value() | match) : (oldConfiguration.value() & (~match));
735 res = mConfigurationMap.writeValue(key, newConfiguration, BPF_EXIST);
736 if (!isOk(res)) {
737 ALOGE("Failed to toggleUidOwnerMap(%d): %s", chain, res.msg().c_str());
738 }
739 return -res.code();
740}
741
742Status TrafficController::swapActiveStatsMap() {
743 std::lock_guard guard(mMutex);
744
745 uint32_t key = CURRENT_STATS_MAP_CONFIGURATION_KEY;
746 auto oldConfiguration = mConfigurationMap.readValue(key);
747 if (!oldConfiguration.ok()) {
748 ALOGE("Cannot read the old configuration from map: %s",
749 oldConfiguration.error().message().c_str());
750 return Status(oldConfiguration.error().code(), oldConfiguration.error().message());
751 }
752
753 // Write to the configuration map to inform the kernel eBPF program to switch
754 // from using one map to the other. Use flag BPF_EXIST here since the map should
755 // be already populated in initMaps.
756 uint8_t newConfigure = (oldConfiguration.value() == SELECT_MAP_A) ? SELECT_MAP_B : SELECT_MAP_A;
757 auto res = mConfigurationMap.writeValue(CURRENT_STATS_MAP_CONFIGURATION_KEY, newConfigure,
758 BPF_EXIST);
759 if (!res.ok()) {
760 ALOGE("Failed to toggle the stats map: %s", strerror(res.error().code()));
761 return res;
762 }
763 // After changing the config, we need to make sure all the current running
764 // eBPF programs are finished and all the CPUs are aware of this config change
765 // before we modify the old map. So we do a special hack here to wait for
766 // the kernel to do a synchronize_rcu(). Once the kernel called
767 // synchronize_rcu(), the config we just updated will be available to all cores
768 // and the next eBPF programs triggered inside the kernel will use the new
769 // map configuration. So once this function returns we can safely modify the
770 // old stats map without concerning about race between the kernel and
771 // userspace.
772 int ret = synchronizeKernelRCU();
773 if (ret) {
774 ALOGE("map swap synchronize_rcu() ended with failure: %s", strerror(-ret));
775 return statusFromErrno(-ret, "map swap synchronize_rcu() failed");
776 }
777 return netdutils::status::ok;
778}
779
780void TrafficController::setPermissionForUids(int permission, const std::vector<uid_t>& uids) {
781 std::lock_guard guard(mMutex);
782 if (permission == INetd::PERMISSION_UNINSTALLED) {
783 for (uid_t uid : uids) {
784 // Clean up all permission information for the related uid if all the
785 // packages related to it are uninstalled.
786 mPrivilegedUser.erase(uid);
787 Status ret = mUidPermissionMap.deleteValue(uid);
788 if (!isOk(ret) && ret.code() != ENOENT) {
789 ALOGE("Failed to clean up the permission for %u: %s", uid, strerror(ret.code()));
790 }
791 }
792 return;
793 }
794
795 bool privileged = (permission & INetd::PERMISSION_UPDATE_DEVICE_STATS);
796
797 for (uid_t uid : uids) {
798 if (privileged) {
799 mPrivilegedUser.insert(uid);
800 } else {
801 mPrivilegedUser.erase(uid);
802 }
803
804 // The map stores all the permissions that the UID has, except if the only permission
805 // the UID has is the INTERNET permission, then the UID should not appear in the map.
806 if (permission != INetd::PERMISSION_INTERNET) {
807 Status ret = mUidPermissionMap.writeValue(uid, permission, BPF_ANY);
808 if (!isOk(ret)) {
809 ALOGE("Failed to set permission: %s of uid(%u) to permission map: %s",
810 UidPermissionTypeToString(permission).c_str(), uid, strerror(ret.code()));
811 }
812 } else {
813 Status ret = mUidPermissionMap.deleteValue(uid);
814 if (!isOk(ret) && ret.code() != ENOENT) {
815 ALOGE("Failed to remove uid %u from permission map: %s", uid, strerror(ret.code()));
816 }
817 }
818 }
819}
820
821std::string getProgramStatus(const char *path) {
822 int ret = access(path, R_OK);
823 if (ret == 0) {
824 return StringPrintf("OK");
825 }
826 if (ret != 0 && errno == ENOENT) {
827 return StringPrintf("program is missing at: %s", path);
828 }
829 return StringPrintf("check Program %s error: %s", path, strerror(errno));
830}
831
832std::string getMapStatus(const base::unique_fd& map_fd, const char* path) {
833 if (map_fd.get() < 0) {
834 return StringPrintf("map fd lost");
835 }
836 if (access(path, F_OK) != 0) {
837 return StringPrintf("map not pinned to location: %s", path);
838 }
839 return StringPrintf("OK");
840}
841
842// NOLINTNEXTLINE(google-runtime-references): grandfathered pass by non-const reference
843void dumpBpfMap(const std::string& mapName, DumpWriter& dw, const std::string& header) {
844 dw.blankline();
845 dw.println("%s:", mapName.c_str());
846 if (!header.empty()) {
847 dw.println(header);
848 }
849}
850
851const String16 TrafficController::DUMP_KEYWORD = String16("trafficcontroller");
852
853void TrafficController::dump(DumpWriter& dw, bool verbose) {
854 std::lock_guard guard(mMutex);
855 ScopedIndent indentTop(dw);
856 dw.println("TrafficController");
857
858 ScopedIndent indentPreBpfModule(dw);
859
860 dw.blankline();
861 dw.println("mCookieTagMap status: %s",
862 getMapStatus(mCookieTagMap.getMap(), COOKIE_TAG_MAP_PATH).c_str());
863 dw.println("mUidCounterSetMap status: %s",
864 getMapStatus(mUidCounterSetMap.getMap(), UID_COUNTERSET_MAP_PATH).c_str());
865 dw.println("mAppUidStatsMap status: %s",
866 getMapStatus(mAppUidStatsMap.getMap(), APP_UID_STATS_MAP_PATH).c_str());
867 dw.println("mStatsMapA status: %s",
868 getMapStatus(mStatsMapA.getMap(), STATS_MAP_A_PATH).c_str());
869 dw.println("mStatsMapB status: %s",
870 getMapStatus(mStatsMapB.getMap(), STATS_MAP_B_PATH).c_str());
871 dw.println("mIfaceIndexNameMap status: %s",
872 getMapStatus(mIfaceIndexNameMap.getMap(), IFACE_INDEX_NAME_MAP_PATH).c_str());
873 dw.println("mIfaceStatsMap status: %s",
874 getMapStatus(mIfaceStatsMap.getMap(), IFACE_STATS_MAP_PATH).c_str());
875 dw.println("mConfigurationMap status: %s",
876 getMapStatus(mConfigurationMap.getMap(), CONFIGURATION_MAP_PATH).c_str());
877 dw.println("mUidOwnerMap status: %s",
878 getMapStatus(mUidOwnerMap.getMap(), UID_OWNER_MAP_PATH).c_str());
879
880 dw.blankline();
881 dw.println("Cgroup ingress program status: %s",
882 getProgramStatus(BPF_INGRESS_PROG_PATH).c_str());
883 dw.println("Cgroup egress program status: %s", getProgramStatus(BPF_EGRESS_PROG_PATH).c_str());
884 dw.println("xt_bpf ingress program status: %s",
885 getProgramStatus(XT_BPF_INGRESS_PROG_PATH).c_str());
886 dw.println("xt_bpf egress program status: %s",
887 getProgramStatus(XT_BPF_EGRESS_PROG_PATH).c_str());
888 dw.println("xt_bpf bandwidth allowlist program status: %s",
889 getProgramStatus(XT_BPF_ALLOWLIST_PROG_PATH).c_str());
890 dw.println("xt_bpf bandwidth denylist program status: %s",
891 getProgramStatus(XT_BPF_DENYLIST_PROG_PATH).c_str());
892
893 if (!verbose) {
894 return;
895 }
896
897 dw.blankline();
898 dw.println("BPF map content:");
899
900 ScopedIndent indentForMapContent(dw);
901
902 // Print CookieTagMap content.
903 dumpBpfMap("mCookieTagMap", dw, "");
904 const auto printCookieTagInfo = [&dw](const uint64_t& key, const UidTagValue& value,
905 const BpfMap<uint64_t, UidTagValue>&) {
906 dw.println("cookie=%" PRIu64 " tag=0x%x uid=%u", key, value.tag, value.uid);
907 return base::Result<void>();
908 };
909 base::Result<void> res = mCookieTagMap.iterateWithValue(printCookieTagInfo);
910 if (!res.ok()) {
911 dw.println("mCookieTagMap print end with error: %s", res.error().message().c_str());
912 }
913
914 // Print UidCounterSetMap Content
915 dumpBpfMap("mUidCounterSetMap", dw, "");
916 const auto printUidInfo = [&dw](const uint32_t& key, const uint8_t& value,
917 const BpfMap<uint32_t, uint8_t>&) {
918 dw.println("%u %u", key, value);
919 return base::Result<void>();
920 };
921 res = mUidCounterSetMap.iterateWithValue(printUidInfo);
922 if (!res.ok()) {
923 dw.println("mUidCounterSetMap print end with error: %s", res.error().message().c_str());
924 }
925
926 // Print AppUidStatsMap content
927 std::string appUidStatsHeader = StringPrintf("uid rxBytes rxPackets txBytes txPackets");
928 dumpBpfMap("mAppUidStatsMap:", dw, appUidStatsHeader);
929 auto printAppUidStatsInfo = [&dw](const uint32_t& key, const StatsValue& value,
930 const BpfMap<uint32_t, StatsValue>&) {
931 dw.println("%u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, key, value.rxBytes,
932 value.rxPackets, value.txBytes, value.txPackets);
933 return base::Result<void>();
934 };
935 res = mAppUidStatsMap.iterateWithValue(printAppUidStatsInfo);
936 if (!res.ok()) {
937 dw.println("mAppUidStatsMap print end with error: %s", res.error().message().c_str());
938 }
939
940 // Print uidStatsMap content
941 std::string statsHeader = StringPrintf("ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes"
942 " rxPackets txBytes txPackets");
943 dumpBpfMap("mStatsMapA", dw, statsHeader);
944 const auto printStatsInfo = [&dw, this](const StatsKey& key, const StatsValue& value,
945 const BpfMap<StatsKey, StatsValue>&) {
946 uint32_t ifIndex = key.ifaceIndex;
947 auto ifname = mIfaceIndexNameMap.readValue(ifIndex);
948 if (!ifname.ok()) {
949 ifname = IfaceValue{"unknown"};
950 }
951 dw.println("%u %s 0x%x %u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, ifIndex,
952 ifname.value().name, key.tag, key.uid, key.counterSet, value.rxBytes,
953 value.rxPackets, value.txBytes, value.txPackets);
954 return base::Result<void>();
955 };
956 res = mStatsMapA.iterateWithValue(printStatsInfo);
957 if (!res.ok()) {
958 dw.println("mStatsMapA print end with error: %s", res.error().message().c_str());
959 }
960
961 // Print TagStatsMap content.
962 dumpBpfMap("mStatsMapB", dw, statsHeader);
963 res = mStatsMapB.iterateWithValue(printStatsInfo);
964 if (!res.ok()) {
965 dw.println("mStatsMapB print end with error: %s", res.error().message().c_str());
966 }
967
968 // Print ifaceIndexToNameMap content.
969 dumpBpfMap("mIfaceIndexNameMap", dw, "");
970 const auto printIfaceNameInfo = [&dw](const uint32_t& key, const IfaceValue& value,
971 const BpfMap<uint32_t, IfaceValue>&) {
972 const char* ifname = value.name;
973 dw.println("ifaceIndex=%u ifaceName=%s", key, ifname);
974 return base::Result<void>();
975 };
976 res = mIfaceIndexNameMap.iterateWithValue(printIfaceNameInfo);
977 if (!res.ok()) {
978 dw.println("mIfaceIndexNameMap print end with error: %s", res.error().message().c_str());
979 }
980
981 // Print ifaceStatsMap content
982 std::string ifaceStatsHeader = StringPrintf("ifaceIndex ifaceName rxBytes rxPackets txBytes"
983 " txPackets");
984 dumpBpfMap("mIfaceStatsMap:", dw, ifaceStatsHeader);
985 const auto printIfaceStatsInfo = [&dw, this](const uint32_t& key, const StatsValue& value,
986 const BpfMap<uint32_t, StatsValue>&) {
987 auto ifname = mIfaceIndexNameMap.readValue(key);
988 if (!ifname.ok()) {
989 ifname = IfaceValue{"unknown"};
990 }
991 dw.println("%u %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, key, ifname.value().name,
992 value.rxBytes, value.rxPackets, value.txBytes, value.txPackets);
993 return base::Result<void>();
994 };
995 res = mIfaceStatsMap.iterateWithValue(printIfaceStatsInfo);
996 if (!res.ok()) {
997 dw.println("mIfaceStatsMap print end with error: %s", res.error().message().c_str());
998 }
999
1000 dw.blankline();
1001
1002 uint32_t key = UID_RULES_CONFIGURATION_KEY;
1003 auto configuration = mConfigurationMap.readValue(key);
1004 if (configuration.ok()) {
1005 dw.println("current ownerMatch configuration: %d%s", configuration.value(),
1006 uidMatchTypeToString(configuration.value()).c_str());
1007 } else {
1008 dw.println("mConfigurationMap read ownerMatch configure failed with error: %s",
1009 configuration.error().message().c_str());
1010 }
1011
1012 key = CURRENT_STATS_MAP_CONFIGURATION_KEY;
1013 configuration = mConfigurationMap.readValue(key);
1014 if (configuration.ok()) {
1015 const char* statsMapDescription = "???";
1016 switch (configuration.value()) {
1017 case SELECT_MAP_A:
1018 statsMapDescription = "SELECT_MAP_A";
1019 break;
1020 case SELECT_MAP_B:
1021 statsMapDescription = "SELECT_MAP_B";
1022 break;
1023 // No default clause, so if we ever add a third map, this code will fail to build.
1024 }
1025 dw.println("current statsMap configuration: %d %s", configuration.value(),
1026 statsMapDescription);
1027 } else {
1028 dw.println("mConfigurationMap read stats map configure failed with error: %s",
1029 configuration.error().message().c_str());
1030 }
1031 dumpBpfMap("mUidOwnerMap", dw, "");
1032 const auto printUidMatchInfo = [&dw, this](const uint32_t& key, const UidOwnerValue& value,
1033 const BpfMap<uint32_t, UidOwnerValue>&) {
1034 if (value.rule & IIF_MATCH) {
1035 auto ifname = mIfaceIndexNameMap.readValue(value.iif);
1036 if (ifname.ok()) {
1037 dw.println("%u %s %s", key, uidMatchTypeToString(value.rule).c_str(),
1038 ifname.value().name);
1039 } else {
1040 dw.println("%u %s %u", key, uidMatchTypeToString(value.rule).c_str(), value.iif);
1041 }
1042 } else {
1043 dw.println("%u %s", key, uidMatchTypeToString(value.rule).c_str());
1044 }
1045 return base::Result<void>();
1046 };
1047 res = mUidOwnerMap.iterateWithValue(printUidMatchInfo);
1048 if (!res.ok()) {
1049 dw.println("mUidOwnerMap print end with error: %s", res.error().message().c_str());
1050 }
1051 dumpBpfMap("mUidPermissionMap", dw, "");
1052 const auto printUidPermissionInfo = [&dw](const uint32_t& key, const int& value,
1053 const BpfMap<uint32_t, uint8_t>&) {
1054 dw.println("%u %s", key, UidPermissionTypeToString(value).c_str());
1055 return base::Result<void>();
1056 };
1057 res = mUidPermissionMap.iterateWithValue(printUidPermissionInfo);
1058 if (!res.ok()) {
1059 dw.println("mUidPermissionMap print end with error: %s", res.error().message().c_str());
1060 }
1061
1062 dumpBpfMap("mPrivilegedUser", dw, "");
1063 for (uid_t uid : mPrivilegedUser) {
1064 dw.println("%u ALLOW_UPDATE_DEVICE_STATS", (uint32_t)uid);
1065 }
1066}
1067
1068} // namespace net
1069} // namespace android