2323import static android .net .NetworkStats .TAG_NONE ;
2424import static android .net .NetworkStats .UID_ALL ;
2525import static android .net .TrafficStats .UID_TETHERING ;
26- import static android .provider .Settings .Secure .NETSTATS_ENABLED ;
2726import static com .android .server .NetworkManagementService .NetdResponseCode .InterfaceGetCfgResult ;
2827import static com .android .server .NetworkManagementService .NetdResponseCode .InterfaceListResult ;
2928import static com .android .server .NetworkManagementService .NetdResponseCode .InterfaceRxThrottleResult ;
4544import android .net .RouteInfo ;
4645import android .net .wifi .WifiConfiguration ;
4746import android .net .wifi .WifiConfiguration .KeyMgmt ;
47+ import android .os .Handler ;
4848import android .os .INetworkManagementService ;
4949import android .os .RemoteCallbackList ;
5050import android .os .RemoteException ;
5151import android .os .SystemClock ;
5252import android .os .SystemProperties ;
53- import android .provider .Settings ;
5453import android .util .Log ;
5554import android .util .Slog ;
5655import android .util .SparseBooleanArray ;
5756
5857import com .android .internal .net .NetworkStatsFactory ;
5958import com .android .server .NativeDaemonConnector .Command ;
60- import com .google .android .collect .Sets ;
59+ import com .google .android .collect .Maps ;
6160
6261import java .io .BufferedReader ;
6362import java .io .DataInputStream ;
7473import java .net .SocketException ;
7574import java .util .ArrayList ;
7675import java .util .Collection ;
77- import java .util .HashSet ;
76+ import java .util .HashMap ;
77+ import java .util .Map ;
7878import java .util .NoSuchElementException ;
7979import java .util .StringTokenizer ;
8080import 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