Skip to content

Commit 6f28f9e

Browse files
jsharkeyAndroid (Google) Code Review
authored andcommitted
Merge "Push existing rules when netd reconnects." into jb-dev
2 parents 0cd4f67 + b24a785 commit 6f28f9e

File tree

1 file changed

+98
-51
lines changed

1 file changed

+98
-51
lines changed

services/java/com/android/server/NetworkManagementService.java

Lines changed: 98 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import static android.net.NetworkStats.TAG_NONE;
2424
import static android.net.NetworkStats.UID_ALL;
2525
import static android.net.TrafficStats.UID_TETHERING;
26-
import static android.provider.Settings.Secure.NETSTATS_ENABLED;
2726
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
2827
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
2928
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceRxThrottleResult;
@@ -45,19 +44,19 @@
4544
import android.net.RouteInfo;
4645
import android.net.wifi.WifiConfiguration;
4746
import android.net.wifi.WifiConfiguration.KeyMgmt;
47+
import android.os.Handler;
4848
import android.os.INetworkManagementService;
4949
import android.os.RemoteCallbackList;
5050
import android.os.RemoteException;
5151
import android.os.SystemClock;
5252
import android.os.SystemProperties;
53-
import android.provider.Settings;
5453
import android.util.Log;
5554
import android.util.Slog;
5655
import android.util.SparseBooleanArray;
5756

5857
import com.android.internal.net.NetworkStatsFactory;
5958
import com.android.server.NativeDaemonConnector.Command;
60-
import com.google.android.collect.Sets;
59+
import com.google.android.collect.Maps;
6160

6261
import java.io.BufferedReader;
6362
import java.io.DataInputStream;
@@ -74,7 +73,8 @@
7473
import java.net.SocketException;
7574
import java.util.ArrayList;
7675
import java.util.Collection;
77-
import java.util.HashSet;
76+
import java.util.HashMap;
77+
import java.util.Map;
7878
import java.util.NoSuchElementException;
7979
import java.util.StringTokenizer;
8080
import java.util.concurrent.CountDownLatch;
@@ -133,8 +133,10 @@ class NetdResponseCode {
133133
*/
134134
private NativeDaemonConnector mConnector;
135135

136+
private final Handler mMainHandler = new Handler();
137+
136138
private Thread mThread;
137-
private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
139+
private CountDownLatch mConnectedSignal = new CountDownLatch(1);
138140

139141
private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
140142
new RemoteCallbackList<INetworkManagementEventObserver>();
@@ -143,9 +145,9 @@ class NetdResponseCode {
143145

144146
private Object mQuotaLock = new Object();
145147
/** Set of interfaces with active quotas. */
146-
private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet();
148+
private HashMap<String, Long> mActiveQuotas = Maps.newHashMap();
147149
/** Set of interfaces with active alerts. */
148-
private HashSet<String> mActiveAlertIfaces = Sets.newHashSet();
150+
private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
149151
/** Set of UIDs with active reject rules. */
150152
private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
151153

@@ -172,35 +174,19 @@ private NetworkManagementService(Context context) {
172174
}
173175

174176
public static NetworkManagementService create(Context context) throws InterruptedException {
175-
NetworkManagementService service = new NetworkManagementService(context);
177+
final NetworkManagementService service = new NetworkManagementService(context);
178+
final CountDownLatch connectedSignal = service.mConnectedSignal;
176179
if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
177180
service.mThread.start();
178181
if (DBG) Slog.d(TAG, "Awaiting socket connection");
179-
service.mConnectedSignal.await();
182+
connectedSignal.await();
180183
if (DBG) Slog.d(TAG, "Connected");
181184
return service;
182185
}
183186

184187
public void systemReady() {
185-
// only enable bandwidth control when support exists, and requested by
186-
// system setting.
187-
final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
188-
final boolean shouldEnable =
189-
Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 1) != 0;
190-
191-
if (hasKernelSupport && shouldEnable) {
192-
Slog.d(TAG, "enabling bandwidth control");
193-
try {
194-
mConnector.execute("bandwidth", "enable");
195-
mBandwidthControlEnabled = true;
196-
} catch (NativeDaemonConnectorException e) {
197-
Log.wtf(TAG, "problem enabling bandwidth controls", e);
198-
}
199-
} else {
200-
Slog.d(TAG, "not enabling bandwidth control");
201-
}
202-
203-
SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
188+
prepareNativeDaemon();
189+
if (DBG) Slog.d(TAG, "Prepared");
204190
}
205191

206192
@Override
@@ -264,8 +250,8 @@ private void notifyInterfaceAdded(String iface) {
264250
private void notifyInterfaceRemoved(String iface) {
265251
// netd already clears out quota and alerts for removed ifaces; update
266252
// our sanity-checking state.
267-
mActiveAlertIfaces.remove(iface);
268-
mActiveQuotaIfaces.remove(iface);
253+
mActiveAlerts.remove(iface);
254+
mActiveQuotas.remove(iface);
269255

270256
final int length = mObservers.beginBroadcast();
271257
for (int i = 0; i < length; i++) {
@@ -292,24 +278,85 @@ private void notifyLimitReached(String limitName, String iface) {
292278
}
293279

294280
/**
295-
* Let us know the daemon is connected
281+
* Prepare native daemon once connected, enabling modules and pushing any
282+
* existing in-memory rules.
296283
*/
297-
protected void onDaemonConnected() {
298-
mConnectedSignal.countDown();
299-
}
284+
private void prepareNativeDaemon() {
285+
mBandwidthControlEnabled = false;
286+
287+
// only enable bandwidth control when support exists
288+
final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
289+
if (hasKernelSupport) {
290+
Slog.d(TAG, "enabling bandwidth control");
291+
try {
292+
mConnector.execute("bandwidth", "enable");
293+
mBandwidthControlEnabled = true;
294+
} catch (NativeDaemonConnectorException e) {
295+
Log.wtf(TAG, "problem enabling bandwidth controls", e);
296+
}
297+
} else {
298+
Slog.d(TAG, "not enabling bandwidth control");
299+
}
300+
301+
SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
300302

303+
// push any existing quota or UID rules
304+
synchronized (mQuotaLock) {
305+
int size = mActiveQuotas.size();
306+
if (size > 0) {
307+
Slog.d(TAG, "pushing " + size + " active quota rules");
308+
final HashMap<String, Long> activeQuotas = mActiveQuotas;
309+
mActiveQuotas = Maps.newHashMap();
310+
for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
311+
setInterfaceQuota(entry.getKey(), entry.getValue());
312+
}
313+
}
314+
315+
size = mActiveAlerts.size();
316+
if (size > 0) {
317+
Slog.d(TAG, "pushing " + size + " active alert rules");
318+
final HashMap<String, Long> activeAlerts = mActiveAlerts;
319+
mActiveAlerts = Maps.newHashMap();
320+
for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
321+
setInterfaceAlert(entry.getKey(), entry.getValue());
322+
}
323+
}
324+
325+
size = mUidRejectOnQuota.size();
326+
if (size > 0) {
327+
Slog.d(TAG, "pushing " + size + " active uid rules");
328+
final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota;
329+
mUidRejectOnQuota = new SparseBooleanArray();
330+
for (int i = 0; i < uidRejectOnQuota.size(); i++) {
331+
setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i));
332+
}
333+
}
334+
}
335+
}
301336

302337
//
303338
// Netd Callback handling
304339
//
305340

306-
class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
307-
/** {@inheritDoc} */
341+
private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
342+
@Override
308343
public void onDaemonConnected() {
309-
NetworkManagementService.this.onDaemonConnected();
344+
// event is dispatched from internal NDC thread, so we prepare the
345+
// daemon back on main thread.
346+
if (mConnectedSignal != null) {
347+
mConnectedSignal.countDown();
348+
mConnectedSignal = null;
349+
} else {
350+
mMainHandler.post(new Runnable() {
351+
@Override
352+
public void run() {
353+
prepareNativeDaemon();
354+
}
355+
});
356+
}
310357
}
311358

312-
/** {@inheritDoc} */
359+
@Override
313360
public boolean onEvent(int code, String raw, String[] cooked) {
314361
switch (code) {
315362
case NetdResponseCode.InterfaceChange:
@@ -962,14 +1009,14 @@ public void setInterfaceQuota(String iface, long quotaBytes) {
9621009
if (!mBandwidthControlEnabled) return;
9631010

9641011
synchronized (mQuotaLock) {
965-
if (mActiveQuotaIfaces.contains(iface)) {
1012+
if (mActiveQuotas.containsKey(iface)) {
9661013
throw new IllegalStateException("iface " + iface + " already has quota");
9671014
}
9681015

9691016
try {
9701017
// TODO: support quota shared across interfaces
9711018
mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
972-
mActiveQuotaIfaces.add(iface);
1019+
mActiveQuotas.put(iface, quotaBytes);
9731020
} catch (NativeDaemonConnectorException e) {
9741021
throw e.rethrowAsParcelableException();
9751022
}
@@ -985,13 +1032,13 @@ public void removeInterfaceQuota(String iface) {
9851032
if (!mBandwidthControlEnabled) return;
9861033

9871034
synchronized (mQuotaLock) {
988-
if (!mActiveQuotaIfaces.contains(iface)) {
1035+
if (!mActiveQuotas.containsKey(iface)) {
9891036
// TODO: eventually consider throwing
9901037
return;
9911038
}
9921039

993-
mActiveQuotaIfaces.remove(iface);
994-
mActiveAlertIfaces.remove(iface);
1040+
mActiveQuotas.remove(iface);
1041+
mActiveAlerts.remove(iface);
9951042

9961043
try {
9971044
// TODO: support quota shared across interfaces
@@ -1011,19 +1058,19 @@ public void setInterfaceAlert(String iface, long alertBytes) {
10111058
if (!mBandwidthControlEnabled) return;
10121059

10131060
// quick sanity check
1014-
if (!mActiveQuotaIfaces.contains(iface)) {
1061+
if (!mActiveQuotas.containsKey(iface)) {
10151062
throw new IllegalStateException("setting alert requires existing quota on iface");
10161063
}
10171064

10181065
synchronized (mQuotaLock) {
1019-
if (mActiveAlertIfaces.contains(iface)) {
1066+
if (mActiveAlerts.containsKey(iface)) {
10201067
throw new IllegalStateException("iface " + iface + " already has alert");
10211068
}
10221069

10231070
try {
10241071
// TODO: support alert shared across interfaces
10251072
mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
1026-
mActiveAlertIfaces.add(iface);
1073+
mActiveAlerts.put(iface, alertBytes);
10271074
} catch (NativeDaemonConnectorException e) {
10281075
throw e.rethrowAsParcelableException();
10291076
}
@@ -1039,15 +1086,15 @@ public void removeInterfaceAlert(String iface) {
10391086
if (!mBandwidthControlEnabled) return;
10401087

10411088
synchronized (mQuotaLock) {
1042-
if (!mActiveAlertIfaces.contains(iface)) {
1089+
if (!mActiveAlerts.containsKey(iface)) {
10431090
// TODO: eventually consider throwing
10441091
return;
10451092
}
10461093

10471094
try {
10481095
// TODO: support alert shared across interfaces
10491096
mConnector.execute("bandwidth", "removeinterfacealert", iface);
1050-
mActiveAlertIfaces.remove(iface);
1097+
mActiveAlerts.remove(iface);
10511098
} catch (NativeDaemonConnectorException e) {
10521099
throw e.rethrowAsParcelableException();
10531100
}
@@ -1077,7 +1124,7 @@ public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
10771124
// TODO: eventually migrate to be always enabled
10781125
if (!mBandwidthControlEnabled) return;
10791126

1080-
synchronized (mUidRejectOnQuota) {
1127+
synchronized (mQuotaLock) {
10811128
final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
10821129
if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
10831130
// TODO: eventually consider throwing
@@ -1272,8 +1319,8 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
12721319
pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
12731320

12741321
synchronized (mQuotaLock) {
1275-
pw.print("Active quota ifaces: "); pw.println(mActiveQuotaIfaces.toString());
1276-
pw.print("Active alert ifaces: "); pw.println(mActiveAlertIfaces.toString());
1322+
pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
1323+
pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
12771324
}
12781325

12791326
synchronized (mUidRejectOnQuota) {

0 commit comments

Comments
 (0)