blob: e444a12b6a18c109515e0e81f72a09ceaeaeba04 [file] [log] [blame]
Wayne Ma0ea3bdc2022-01-12 01:12:11 +08001/*
2 * Copyright (C) 2022 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
17package com.android.server;
18
Wayne Ma2fde98c2022-01-17 18:04:05 +080019import android.net.INetd;
20import android.os.RemoteException;
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080021import android.os.ServiceSpecificException;
22import android.system.Os;
23import android.util.Log;
24
25/**
26 * BpfNetMaps is responsible for providing traffic controller relevant functionality.
27 *
28 * {@hide}
29 */
30public class BpfNetMaps {
31 private static final String TAG = "BpfNetMaps";
Wayne Ma2fde98c2022-01-17 18:04:05 +080032 private final INetd mNetd;
33 // TODO: change USE_JNI to SdkLevel.isAtLeastT()
34 private static final boolean USE_JNI = false;
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080035
Wayne Ma790c83e2022-01-13 10:35:05 +080036 static {
Wayne Ma2fde98c2022-01-17 18:04:05 +080037 if (USE_JNI) {
38 System.loadLibrary("traffic_controller_jni");
39 native_init();
40 }
41 }
42
43 public BpfNetMaps(INetd netd) {
44 mNetd = netd;
Wayne Ma790c83e2022-01-13 10:35:05 +080045 }
46
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080047 /**
48 * Add naughty app bandwidth rule for specific app
49 *
50 * @param uid uid of target app
51 * @throws ServiceSpecificException in case of failure, with an error code indicating the
52 * cause of the failure.
53 */
54 public void addNaughtyApp(final int uid) {
Wayne Ma2fde98c2022-01-17 18:04:05 +080055 if (!USE_JNI) {
56 try {
57 mNetd.bandwidthAddNaughtyApp(uid);
58 } catch (RemoteException e) {
59 throw new IllegalStateException(e);
60 }
61 return;
62 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080063 final int err = native_addNaughtyApp(uid);
64 if (err != 0) {
Wayne Ma41c24482022-01-27 11:44:50 +080065 throw new ServiceSpecificException(err, "Unable to add naughty app: "
66 + Os.strerror(err));
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080067 }
68 }
69
70 /**
71 * Remove naughty app bandwidth rule for specific app
72 *
73 * @param uid uid of target app
74 * @throws ServiceSpecificException in case of failure, with an error code indicating the
75 * cause of the failure.
76 */
77 public void removeNaughtyApp(final int uid) {
Wayne Ma2fde98c2022-01-17 18:04:05 +080078 if (!USE_JNI) {
79 try {
80 mNetd.bandwidthRemoveNaughtyApp(uid);
81 } catch (RemoteException e) {
82 throw new IllegalStateException(e);
83 }
84 return;
85 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080086 final int err = native_removeNaughtyApp(uid);
87 if (err != 0) {
Wayne Ma41c24482022-01-27 11:44:50 +080088 throw new ServiceSpecificException(err, "Unable to remove naughty app: "
89 + Os.strerror(err));
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080090 }
91 }
92
93 /**
94 * Add nice app bandwidth rule for specific app
95 *
96 * @param uid uid of target app
97 * @throws ServiceSpecificException in case of failure, with an error code indicating the
98 * cause of the failure.
99 */
100 public void addNiceApp(final int uid) {
Wayne Ma2fde98c2022-01-17 18:04:05 +0800101 if (!USE_JNI) {
102 try {
103 mNetd.bandwidthAddNiceApp(uid);
104 } catch (RemoteException e) {
105 throw new IllegalStateException(e);
106 }
107 return;
108 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800109 final int err = native_addNiceApp(uid);
110 if (err != 0) {
Wayne Ma41c24482022-01-27 11:44:50 +0800111 throw new ServiceSpecificException(err, "Unable to add nice app: "
112 + Os.strerror(err));
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800113 }
114 }
115
116 /**
117 * Remove nice app bandwidth rule for specific app
118 *
119 * @param uid uid of target app
120 * @throws ServiceSpecificException in case of failure, with an error code indicating the
121 * cause of the failure.
122 */
123 public void removeNiceApp(final int uid) {
Wayne Ma2fde98c2022-01-17 18:04:05 +0800124 if (!USE_JNI) {
125 try {
126 mNetd.bandwidthRemoveNiceApp(uid);
127 } catch (RemoteException e) {
128 throw new IllegalStateException(e);
129 }
130 return;
131 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800132 final int err = native_removeNiceApp(uid);
133 if (err != 0) {
Wayne Ma41c24482022-01-27 11:44:50 +0800134 throw new ServiceSpecificException(err, "Unable to remove nice app: "
135 + Os.strerror(err));
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800136 }
137 }
138
139 /**
140 * Set target firewall child chain
141 *
142 * @param childChain target chain to enable
143 * @param enable whether to enable or disable child chain.
144 * @throws ServiceSpecificException in case of failure, with an error code indicating the
145 * cause of the failure.
146 */
147 public void setChildChain(final int childChain, final boolean enable) {
Wayne Ma2fde98c2022-01-17 18:04:05 +0800148 if (!USE_JNI) {
149 try {
150 mNetd.firewallEnableChildChain(childChain, enable);
151 } catch (RemoteException e) {
152 throw new IllegalStateException(e);
153 }
154 return;
155 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800156 final int err = native_setChildChain(childChain, enable);
157 if (err != 0) {
158 throw new ServiceSpecificException(-err, "Unable to set child chain: "
159 + Os.strerror(-err));
160 }
161 }
162
163 /**
164 * Replaces the contents of the specified UID-based firewall chain.
165 *
166 * The chain may be an allowlist chain or a denylist chain. A denylist chain contains DROP
167 * rules for the specified UIDs and a RETURN rule at the end. An allowlist chain contains RETURN
168 * rules for the system UID range (0 to {@code UID_APP} - 1), RETURN rules for for the specified
169 * UIDs, and a DROP rule at the end. The chain will be created if it does not exist.
170 *
171 * @param chainName The name of the chain to replace.
172 * @param isAllowlist Whether this is an allowlist or denylist chain.
173 * @param uids The list of UIDs to allow/deny.
174 * @return true if the chain was successfully replaced, false otherwise.
175 */
176 public int replaceUidChain(final String chainName, final boolean isAllowlist,
177 final int[] uids) {
Wayne Ma2fde98c2022-01-17 18:04:05 +0800178 if (!USE_JNI) {
179 try {
180 mNetd.firewallReplaceUidChain(chainName, isAllowlist, uids);
181 } catch (RemoteException e) {
182 throw new IllegalStateException(e);
183 }
184 return 0;
185 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800186 final int err = native_replaceUidChain(chainName, isAllowlist, uids);
187 if (err != 0) {
188 Log.e(TAG, "replaceUidChain failed: " + Os.strerror(-err));
189 }
190 return -err;
191 }
192
193 /**
194 * Set firewall rule for uid
195 *
196 * @param childChain target chain
197 * @param uid uid to allow/deny
198 * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
199 * @throws ServiceSpecificException in case of failure, with an error code indicating the
200 * cause of the failure.
201 */
Wayne Ma2fde98c2022-01-17 18:04:05 +0800202 public void setUidRule(final int childChain, final int uid, final int firewallRule) {
203 if (!USE_JNI) {
204 try {
205 mNetd.firewallSetUidRule(childChain, uid, firewallRule);
206 } catch (RemoteException e) {
207 throw new IllegalStateException(e);
208 }
209 return;
210 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800211 final int err = native_setUidRule(childChain, uid, firewallRule);
212 if (err != 0) {
213 throw new ServiceSpecificException(-err, "Unable to set uid rule: "
214 + Os.strerror(-err));
215 }
216 }
217
218 /**
219 * Add ingress interface filtering rules to a list of UIDs
220 *
221 * For a given uid, once a filtering rule is added, the kernel will only allow packets from the
222 * allowed interface and loopback to be sent to the list of UIDs.
223 *
224 * Calling this method on one or more UIDs with an existing filtering rule but a different
225 * interface name will result in the filtering rule being updated to allow the new interface
226 * instead. Otherwise calling this method will not affect existing rules set on other UIDs.
227 *
228 * @param ifName the name of the interface on which the filtering rules will allow packets to
229 be received.
230 * @param uids an array of UIDs which the filtering rules will be set
231 * @throws ServiceSpecificException in case of failure, with an error code indicating the
232 * cause of the failure.
233 */
234 public void addUidInterfaceRules(final String ifName, final int[] uids) {
Wayne Ma2fde98c2022-01-17 18:04:05 +0800235 if (!USE_JNI) {
236 try {
237 mNetd.firewallAddUidInterfaceRules(ifName, uids);
238 } catch (RemoteException e) {
239 Log.e(TAG, "Exception when updating permissions: " + e);
240 }
241 return;
242 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800243 final int err = native_addUidInterfaceRules(ifName, uids);
244 if (err != 0) {
Wayne Ma41c24482022-01-27 11:44:50 +0800245 throw new ServiceSpecificException(err, "Unable to add uid interface rules: "
246 + Os.strerror(err));
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800247 }
248 }
249
250 /**
251 * Remove ingress interface filtering rules from a list of UIDs
252 *
253 * Clear the ingress interface filtering rules from the list of UIDs which were previously set
254 * by addUidInterfaceRules(). Ignore any uid which does not have filtering rule.
255 *
256 * @param uids an array of UIDs from which the filtering rules will be removed
257 * @throws ServiceSpecificException in case of failure, with an error code indicating the
258 * cause of the failure.
259 */
260 public void removeUidInterfaceRules(final int[] uids) {
Wayne Ma2fde98c2022-01-17 18:04:05 +0800261 if (!USE_JNI) {
262 try {
263 mNetd.firewallRemoveUidInterfaceRules(uids);
264 } catch (RemoteException e) {
265 Log.e(TAG, "Exception when updating permissions: " + e);
266 }
267 return;
268 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800269 final int err = native_removeUidInterfaceRules(uids);
270 if (err != 0) {
Wayne Ma41c24482022-01-27 11:44:50 +0800271 throw new ServiceSpecificException(err, "Unable to remove uid interface rules: "
272 + Os.strerror(err));
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800273 }
274 }
275
276 /**
277 * Request netd to change the current active network stats map.
278 * @throws ServiceSpecificException in case of failure, with an error code indicating the
279 * cause of the failure.
280 */
281 public void swapActiveStatsMap() {
Wayne Ma2fde98c2022-01-17 18:04:05 +0800282 if (!USE_JNI) {
283 try {
284 mNetd.trafficSwapActiveStatsMap();
285 } catch (RemoteException e) {
286 throw new IllegalStateException(e);
287 }
288 return;
289 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800290 final int err = native_swapActiveStatsMap();
291 if (err != 0) {
Wayne Ma41c24482022-01-27 11:44:50 +0800292 throw new ServiceSpecificException(err, "Unable to swap active stats map: "
293 + Os.strerror(err));
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800294 }
295 }
296
297 /**
298 * Assigns android.permission.INTERNET and/or android.permission.UPDATE_DEVICE_STATS to the uids
299 * specified. Or remove all permissions from the uids.
300 *
301 * @param permission The permission to grant, it could be either PERMISSION_INTERNET and/or
302 * PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then
303 * revoke all permissions for the uids.
304 * @param uids uid of users to grant permission
305 */
Wayne Ma2fde98c2022-01-17 18:04:05 +0800306 public void setNetPermForUids(final int permissions, final int[] uids) {
307 if (!USE_JNI) {
308 try {
309 mNetd.trafficSetNetPermForUids(permissions, uids);
310 } catch (RemoteException e) {
311 Log.e(TAG, "Pass appId list of special permission failed." + e);
312 }
313 return;
314 }
315 native_setPermissionForUids(permissions, uids);
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800316 }
317
318 /**
319 * Set counter set for uid
320 *
321 * @param counterSet either SET_DEFAULT or SET_FOREGROUND
322 * @param uid uid to foreground/background
323 */
324 public int setCounterSet(final int counterSet, final int uid) {
325 final int err = native_setCounterSet(counterSet, uid);
326 if (err != 0) {
327 Log.e(TAG, "setCounterSet failed: " + Os.strerror(-err));
328 }
329 return -err;
330 }
331
332 /**
333 * Reset Uid stats
334 * @param tag default 0
335 * @param uid given uid to be clear
336 */
337 public int deleteTagData(final int tag, final int uid) {
338 final int err = native_deleteTagData(tag, uid);
339 if (err != 0) {
340 Log.e(TAG, "deleteTagData failed: " + Os.strerror(-err));
341 }
342 return -err;
343 }
344
Wayne Ma790c83e2022-01-13 10:35:05 +0800345 private static native void native_init();
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800346 private native int native_addNaughtyApp(int uid);
347 private native int native_removeNaughtyApp(int uid);
348 private native int native_addNiceApp(int uid);
349 private native int native_removeNiceApp(int uid);
350 private native int native_setChildChain(int childChain, boolean enable);
351 private native int native_replaceUidChain(String name, boolean isAllowlist, int[] uids);
352 private native int native_setUidRule(int childChain, int uid, int firewallRule);
353 private native int native_addUidInterfaceRules(String ifName, int[] uids);
354 private native int native_removeUidInterfaceRules(int[] uids);
355 private native int native_swapActiveStatsMap();
Wayne Ma2fde98c2022-01-17 18:04:05 +0800356 private native void native_setPermissionForUids(int permissions, int[] uids);
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800357 private native int native_setCounterSet(int counterSet, int uid);
358 private native int native_deleteTagData(int tag, int uid);
359}