summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/net/ConnectivityManager.java36
-rw-r--r--core/java/android/net/IConnectivityManager.aidl4
-rw-r--r--core/java/android/net/INetworkPolicyListener.aidl24
-rw-r--r--core/java/android/net/INetworkPolicyManager.aidl5
-rw-r--r--core/java/android/net/NetworkInfo.java22
-rw-r--r--core/java/android/net/NetworkPolicyManager.java19
-rw-r--r--services/java/com/android/server/ConnectivityService.java165
-rw-r--r--services/java/com/android/server/SystemServer.java38
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java90
11 files changed, 310 insertions, 95 deletions
diff --git a/Android.mk b/Android.mk
index c838600..270ee2e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -110,6 +110,7 @@ LOCAL_SRC_FILES += \
core/java/android/net/IConnectivityManager.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
core/java/android/net/IThrottleManager.aidl \
+ core/java/android/net/INetworkPolicyListener.aidl \
core/java/android/net/INetworkPolicyManager.aidl \
core/java/android/nfc/ILlcpConnectionlessSocket.aidl \
core/java/android/nfc/ILlcpServiceSocket.aidl \
diff --git a/api/current.txt b/api/current.txt
index 9e87e9c..a1d4c4a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11041,6 +11041,7 @@ package android.net {
method public static android.net.NetworkInfo.DetailedState valueOf(java.lang.String);
method public static final android.net.NetworkInfo.DetailedState[] values();
enum_constant public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
+ enum_constant public static final android.net.NetworkInfo.DetailedState BLOCKED;
enum_constant public static final android.net.NetworkInfo.DetailedState CONNECTED;
enum_constant public static final android.net.NetworkInfo.DetailedState CONNECTING;
enum_constant public static final android.net.NetworkInfo.DetailedState DISCONNECTED;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 419288b..c72c4b0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -22,7 +22,6 @@ import android.os.Binder;
import android.os.RemoteException;
import java.net.InetAddress;
-import java.net.UnknownHostException;
/**
* Class that answers queries about the state of network connectivity. It also
@@ -40,8 +39,9 @@ import java.net.UnknownHostException;
* state of the available networks</li>
* </ol>
*/
-public class ConnectivityManager
-{
+public class ConnectivityManager {
+ private static final String TAG = "ConnectivityManager";
+
/**
* A change in network connectivity has occurred. A connection has either
* been established or lost. The NetworkInfo for the affected network is
@@ -109,7 +109,7 @@ public class ConnectivityManager
* The lookup key for an int that provides information about
* our connection to the internet at large. 0 indicates no connection,
* 100 indicates a great connection. Retrieve it with
- * {@link android.content.Intent@getIntExtra(String)}.
+ * {@link android.content.Intent#getIntExtra(String, int)}.
* {@hide}
*/
public static final String EXTRA_INET_CONDITION = "inetCondition";
@@ -120,13 +120,12 @@ public class ConnectivityManager
* <p>
* If an application uses the network in the background, it should listen
* for this broadcast and stop using the background data if the value is
- * false.
+ * {@code false}.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
"android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
-
/**
* Broadcast Action: The network connection may not be good
* uses {@code ConnectivityManager.EXTRA_INET_CONDITION} and
@@ -255,7 +254,7 @@ public class ConnectivityManager
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
- private IConnectivityManager mService;
+ private final IConnectivityManager mService;
static public boolean isNetworkTypeValid(int networkType) {
return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
@@ -284,6 +283,15 @@ public class ConnectivityManager
}
}
+ /** {@hide} */
+ public NetworkInfo getActiveNetworkInfoForUid(int uid) {
+ try {
+ return mService.getActiveNetworkInfoForUid(uid);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
public NetworkInfo getNetworkInfo(int networkType) {
try {
return mService.getNetworkInfo(networkType);
@@ -300,7 +308,7 @@ public class ConnectivityManager
}
}
- /** @hide */
+ /** {@hide} */
public LinkProperties getActiveLinkProperties() {
try {
return mService.getActiveLinkProperties();
@@ -309,7 +317,7 @@ public class ConnectivityManager
}
}
- /** @hide */
+ /** {@hide} */
public LinkProperties getLinkProperties(int networkType) {
try {
return mService.getLinkProperties(networkType);
@@ -479,19 +487,11 @@ public class ConnectivityManager
}
/**
- * Don't allow use of default constructor.
- */
- @SuppressWarnings({"UnusedDeclaration"})
- private ConnectivityManager() {
- }
-
- /**
* {@hide}
*/
public ConnectivityManager(IConnectivityManager service) {
if (service == null) {
- throw new IllegalArgumentException(
- "ConnectivityManager() cannot be constructed with null service");
+ throw new IllegalArgumentException("missing IConnectivityManager");
}
mService = service;
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 8be492c..647a60a 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -33,13 +33,11 @@ interface IConnectivityManager
int getNetworkPreference();
NetworkInfo getActiveNetworkInfo();
-
+ NetworkInfo getActiveNetworkInfoForUid(int uid);
NetworkInfo getNetworkInfo(int networkType);
-
NetworkInfo[] getAllNetworkInfo();
LinkProperties getActiveLinkProperties();
-
LinkProperties getLinkProperties(int networkType);
boolean setRadios(boolean onOff);
diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl
new file mode 100644
index 0000000..9230151
--- /dev/null
+++ b/core/java/android/net/INetworkPolicyListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/** {@hide} */
+oneway interface INetworkPolicyListener {
+
+ void onRulesChanged(int uid, int uidRules);
+
+}
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index d9351ee..24f2283 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -16,6 +16,8 @@
package android.net;
+import android.net.INetworkPolicyListener;
+
/**
* Interface that creates and modifies network policy rules.
*
@@ -26,6 +28,9 @@ interface INetworkPolicyManager {
void setUidPolicy(int uid, int policy);
int getUidPolicy(int uid);
+ void registerListener(INetworkPolicyListener listener);
+ void unregisterListener(INetworkPolicyListener listener);
+
// TODO: build API to surface stats details for settings UI
}
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 5f5e11c..537750a 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -74,7 +74,9 @@ public class NetworkInfo implements Parcelable {
/** IP traffic not available. */
DISCONNECTED,
/** Attempt to connect failed. */
- FAILED
+ FAILED,
+ /** Access to this network is blocked. */
+ BLOCKED
}
/**
@@ -96,6 +98,7 @@ public class NetworkInfo implements Parcelable {
stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING);
stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
+ stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);
}
private int mNetworkType;
@@ -138,6 +141,23 @@ public class NetworkInfo implements Parcelable {
mIsRoaming = false;
}
+ /** {@hide} */
+ public NetworkInfo(NetworkInfo source) {
+ if (source != null) {
+ mNetworkType = source.mNetworkType;
+ mSubtype = source.mSubtype;
+ mTypeName = source.mTypeName;
+ mSubtypeName = source.mSubtypeName;
+ mState = source.mState;
+ mDetailedState = source.mDetailedState;
+ mReason = source.mReason;
+ mExtraInfo = source.mExtraInfo;
+ mIsFailover = source.mIsFailover;
+ mIsRoaming = source.mIsRoaming;
+ mIsAvailable = source.mIsAvailable;
+ }
+ }
+
/**
* Reports the type of network (currently mobile or Wi-Fi) to which the
* info in this object pertains.
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 1913aa7..0851b12 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -28,12 +28,13 @@ public class NetworkPolicyManager {
/** No specific network policy, use system default. */
public static final int POLICY_NONE = 0x0;
- /** Reject network usage when application in background. */
- public static final int POLICY_REJECT_BACKGROUND = 0x1;
- /** Reject network usage on paid network connections. */
- public static final int POLICY_REJECT_PAID = 0x2;
- /** Application should conserve data. */
- public static final int POLICY_CONSERVE_DATA = 0x4;
+ /** Reject network usage on paid networks when application in background. */
+ public static final int POLICY_REJECT_PAID_BACKGROUND = 0x1;
+
+ /** All network traffic should be allowed. */
+ public static final int RULE_ALLOW_ALL = 0x0;
+ /** Reject traffic on paid networks. */
+ public static final int RULE_REJECT_PAID = 0x1;
private INetworkPolicyManager mService;
@@ -51,9 +52,8 @@ public class NetworkPolicyManager {
/**
* Set policy flags for specific UID.
*
- * @param policy {@link #POLICY_NONE} or combination of
- * {@link #POLICY_REJECT_BACKGROUND}, {@link #POLICY_REJECT_PAID},
- * or {@link #POLICY_CONSERVE_DATA}.
+ * @param policy {@link #POLICY_NONE} or combination of flags like
+ * {@link #POLICY_REJECT_PAID_BACKGROUND}.
*/
public void setUidPolicy(int uid, int policy) {
try {
@@ -69,5 +69,4 @@ public class NetworkPolicyManager {
return POLICY_NONE;
}
}
-
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index a564c2d..dd76eb8 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -16,6 +16,11 @@
package com.android.server;
+import static android.Manifest.permission.UPDATE_DEVICE_STATS;
+import static android.net.ConnectivityManager.isNetworkTypeValid;
+import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
+
import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.ContentResolver;
import android.content.Context;
@@ -26,11 +31,13 @@ import android.net.ConnectivityManager;
import android.net.DummyDataStateTracker;
import android.net.EthernetDataTracker;
import android.net.IConnectivityManager;
-import android.net.LinkAddress;
+import android.net.INetworkPolicyListener;
+import android.net.INetworkPolicyManager;
import android.net.LinkProperties;
import android.net.MobileDataStateTracker;
import android.net.NetworkConfig;
import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
import android.net.Proxy;
@@ -54,6 +61,7 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
+import android.util.SparseIntArray;
import com.android.internal.telephony.Phone;
import com.android.server.connectivity.Tethering;
@@ -62,13 +70,12 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
-import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.GregorianCalendar;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* @hide
@@ -78,6 +85,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private static final boolean DBG = true;
private static final String TAG = "ConnectivityService";
+ private static final boolean LOGD_RULES = false;
+
// how long to wait before switching back to a radio's default network
private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
// system property that can override the above value
@@ -91,6 +100,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private Tethering mTethering;
private boolean mTetheringConfigValid = false;
+ /** Currently active network rules by UID. */
+ private SparseIntArray mUidRules = new SparseIntArray();
+
/**
* Sometimes we want to refer to the individual network state
* trackers separately, and sometimes we just want to treat them
@@ -128,6 +140,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private AtomicBoolean mBackgroundDataEnabled = new AtomicBoolean(true);
private INetworkManagementService mNetd;
+ private INetworkPolicyManager mPolicyManager;
private static final int ENABLED = 1;
private static final int DISABLED = 0;
@@ -250,14 +263,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
RadioAttributes[] mRadioAttributes;
- public static synchronized ConnectivityService getInstance(Context context) {
- if (sServiceInstance == null) {
- sServiceInstance = new ConnectivityService(context);
- }
- return sServiceInstance;
- }
-
- private ConnectivityService(Context context) {
+ public ConnectivityService(
+ Context context, INetworkManagementService netd, INetworkPolicyManager policyManager) {
if (DBG) log("ConnectivityService starting up");
HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
@@ -290,9 +297,19 @@ public class ConnectivityService extends IConnectivityManager.Stub {
loge("Error setting defaultDns using " + dns);
}
- mContext = context;
+ mContext = checkNotNull(context, "missing Context");
+ mNetd = checkNotNull(netd, "missing INetworkManagementService");
+ mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
- PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ try {
+ mPolicyManager.registerListener(mPolicyListener);
+ } catch (RemoteException e) {
+ // ouch, no rules updates means some processes may never get network
+ Slog.e(TAG, "unable to register INetworkPolicyListener", e);
+ }
+
+ final PowerManager powerManager = (PowerManager) context.getSystemService(
+ Context.POWER_SERVICE);
mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
com.android.internal.R.integer.config_networkTransitionTimeout);
@@ -536,32 +553,92 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
/**
+ * Check if UID is blocked from using the given {@link NetworkInfo}.
+ */
+ private boolean isNetworkBlocked(NetworkInfo info, int uid) {
+ synchronized (mUidRules) {
+ return isNetworkBlockedLocked(info, uid);
+ }
+ }
+
+ /**
+ * Check if UID is blocked from using the given {@link NetworkInfo}.
+ */
+ private boolean isNetworkBlockedLocked(NetworkInfo info, int uid) {
+ // TODO: expand definition of "paid" network to cover tethered or paid
+ // hotspot use cases.
+ final boolean networkIsPaid = info.getType() != ConnectivityManager.TYPE_WIFI;
+ final int uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+
+ if (networkIsPaid && (uidRules & RULE_REJECT_PAID) != 0) {
+ return true;
+ }
+
+ // no restrictive rules; network is visible
+ return false;
+ }
+
+ /**
* Return NetworkInfo for the active (i.e., connected) network interface.
* It is assumed that at most one network is active at a time. If more
* than one is active, it is indeterminate which will be returned.
* @return the info for the active network, or {@code null} if none is
* active
*/
+ @Override
public NetworkInfo getActiveNetworkInfo() {
- return getNetworkInfo(mActiveDefaultNetwork);
+ enforceAccessPermission();
+ final int uid = Binder.getCallingUid();
+ return getNetworkInfo(mActiveDefaultNetwork, uid);
}
+ @Override
+ public NetworkInfo getActiveNetworkInfoForUid(int uid) {
+ enforceConnectivityInternalPermission();
+ return getNetworkInfo(mActiveDefaultNetwork, uid);
+ }
+
+ @Override
public NetworkInfo getNetworkInfo(int networkType) {
enforceAccessPermission();
- if (ConnectivityManager.isNetworkTypeValid(networkType)) {
- NetworkStateTracker t = mNetTrackers[networkType];
- if (t != null)
- return t.getNetworkInfo();
+ final int uid = Binder.getCallingUid();
+ return getNetworkInfo(networkType, uid);
+ }
+
+ private NetworkInfo getNetworkInfo(int networkType, int uid) {
+ NetworkInfo info = null;
+ if (isNetworkTypeValid(networkType)) {
+ final NetworkStateTracker tracker = mNetTrackers[networkType];
+ if (tracker != null) {
+ info = tracker.getNetworkInfo();
+ if (isNetworkBlocked(info, uid)) {
+ // network is blocked; clone and override state
+ info = new NetworkInfo(info);
+ info.setDetailedState(DetailedState.BLOCKED, null, null);
+ }
+ }
}
- return null;
+ return info;
}
+ @Override
public NetworkInfo[] getAllNetworkInfo() {
enforceAccessPermission();
- NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
+ final int uid = Binder.getCallingUid();
+ final NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
int i = 0;
- for (NetworkStateTracker t : mNetTrackers) {
- if(t != null) result[i++] = t.getNetworkInfo();
+ synchronized (mUidRules) {
+ for (NetworkStateTracker tracker : mNetTrackers) {
+ if (tracker != null) {
+ NetworkInfo info = tracker.getNetworkInfo();
+ if (isNetworkBlockedLocked(info, uid)) {
+ // network is blocked; clone and override state
+ info = new NetworkInfo(info);
+ info.setDetailedState(DetailedState.BLOCKED, null, null);
+ }
+ result[i++] = info;
+ }
+ }
}
return result;
}
@@ -574,15 +651,19 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* @return the ip properties for the active network, or {@code null} if
* none is active
*/
+ @Override
public LinkProperties getActiveLinkProperties() {
return getLinkProperties(mActiveDefaultNetwork);
}
+ @Override
public LinkProperties getLinkProperties(int networkType) {
enforceAccessPermission();
- if (ConnectivityManager.isNetworkTypeValid(networkType)) {
- NetworkStateTracker t = mNetTrackers[networkType];
- if (t != null) return t.getLinkProperties();
+ if (isNetworkTypeValid(networkType)) {
+ final NetworkStateTracker tracker = mNetTrackers[networkType];
+ if (tracker != null) {
+ return tracker.getLinkProperties();
+ }
}
return null;
}
@@ -1027,6 +1108,30 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
+ private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
+ @Override
+ public void onRulesChanged(int uid, int uidRules) {
+ // only someone like NPMS should only be calling us
+ // TODO: create permission for modifying data policy
+ mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
+
+ if (LOGD_RULES) {
+ Slog.d(TAG, "onRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
+ }
+
+ synchronized (mUidRules) {
+ // skip update when we've already applied rules
+ final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+ if (oldRules == uidRules) return;
+
+ mUidRules.put(uid, uidRules);
+ }
+
+ // TODO: dispatch into NMS to push rules towards kernel module
+ // TODO: notify UID when it has requested targeted updates
+ }
+ };
+
/**
* @see ConnectivityManager#setMobileDataEnabled(boolean)
*/
@@ -1284,9 +1389,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
void systemReady() {
- IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- mNetd = INetworkManagementService.Stub.asInterface(b);
-
synchronized(this) {
mSystemReady = true;
if (mInitialBroadcast != null) {
@@ -2255,4 +2357,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
return networkType;
}
+
+ private static <T> T checkNotNull(T value, String message) {
+ if (value == null) {
+ throw new NullPointerException(message);
+ }
+ return value;
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5355d44..4cd601f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,19 +16,6 @@
package com.android.server;
-import com.android.server.accessibility.AccessibilityManagerService;
-import com.android.server.am.ActivityManagerService;
-import com.android.server.net.NetworkPolicyManagerService;
-import com.android.server.pm.PackageManagerService;
-import com.android.server.usb.UsbService;
-import com.android.server.wm.WindowManagerService;
-import com.android.internal.app.ShutdownThread;
-import com.android.internal.os.BinderInternal;
-import com.android.internal.os.SamplingProfilerIntegration;
-
-import dalvik.system.VMRuntime;
-import dalvik.system.Zygote;
-
import android.accounts.AccountManagerService;
import android.app.ActivityManagerNative;
import android.bluetooth.BluetoothAdapter;
@@ -41,25 +28,34 @@ import android.content.pm.IPackageManager;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.media.AudioService;
-import android.os.Build;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.provider.Contacts.People;
import android.provider.Settings;
import android.server.BluetoothA2dpService;
import android.server.BluetoothService;
import android.server.search.SearchManagerService;
import android.util.DisplayMetrics;
import android.util.EventLog;
-import android.util.Log;
import android.util.Slog;
-import android.view.Display;
import android.view.WindowManager;
+import com.android.internal.app.ShutdownThread;
+import com.android.internal.os.BinderInternal;
+import com.android.internal.os.SamplingProfilerIntegration;
+import com.android.server.accessibility.AccessibilityManagerService;
+import com.android.server.am.ActivityManagerService;
+import com.android.server.net.NetworkPolicyManagerService;
+import com.android.server.pm.PackageManagerService;
+import com.android.server.usb.UsbService;
+import com.android.server.wm.WindowManagerService;
+
+import dalvik.system.VMRuntime;
+import dalvik.system.Zygote;
+
import java.io.File;
import java.util.Timer;
import java.util.TimerTask;
@@ -120,6 +116,7 @@ class ServerThread extends Thread {
LightsService lights = null;
PowerManagerService power = null;
BatteryService battery = null;
+ NetworkManagementService networkManagement = null;
NetworkPolicyManagerService networkPolicy = null;
ConnectivityService connectivity = null;
IPackageManager pm = null;
@@ -294,16 +291,15 @@ class ServerThread extends Thread {
try {
Slog.i(TAG, "NetworkManagement Service");
- ServiceManager.addService(
- Context.NETWORKMANAGEMENT_SERVICE,
- NetworkManagementService.create(context));
+ networkManagement = NetworkManagementService.create(context);
+ ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting NetworkManagement Service", e);
}
try {
Slog.i(TAG, "Connectivity Service");
- connectivity = ConnectivityService.getInstance(context);
+ connectivity = new ConnectivityService(context, networkManagement, networkPolicy);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Connectivity Service", e);
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index d083d01..0f31f81 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -19,8 +19,9 @@ package com.android.server.net;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.net.NetworkPolicyManager.POLICY_NONE;
-import static android.net.NetworkPolicyManager.POLICY_REJECT_BACKGROUND;
-import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND;
+import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
import android.app.IActivityManager;
import android.app.IProcessObserver;
@@ -28,8 +29,11 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
import android.os.IPowerManager;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
@@ -40,6 +44,10 @@ import android.util.SparseIntArray;
/**
* Service that maintains low-level network policy rules and collects usage
* statistics to drive those rules.
+ * <p>
+ * Derives active rules by combining a given policy with other system status,
+ * and delivers to listeners, such as {@link ConnectivityManager}, for
+ * enforcement.
*/
public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final String TAG = "NetworkPolicy";
@@ -51,19 +59,27 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private Object mRulesLock = new Object();
- private boolean mScreenOn = false;
+ private boolean mScreenOn;
/** Current network policy for each UID. */
private SparseIntArray mUidPolicy = new SparseIntArray();
+ /** Current derived network rules for each UID. */
+ private SparseIntArray mUidRules = new SparseIntArray();
/** Foreground at both UID and PID granularity. */
private SparseBooleanArray mUidForeground = new SparseBooleanArray();
private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
SparseBooleanArray>();
+ private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
+ INetworkPolicyListener>();
+
// TODO: periodically poll network stats and write to disk
// TODO: save/restore policy information from disk
+ // TODO: keep whitelist of system-critical services that should never have
+ // rules enforced, such as system, phone, and radio UIDs.
+
public NetworkPolicyManagerService(
Context context, IActivityManager activityManager, IPowerManager powerManager) {
mContext = checkNotNull(context, "missing context");
@@ -158,12 +174,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@Override
public void setUidPolicy(int uid, int policy) {
+ // TODO: create permission for modifying data policy
mContext.enforceCallingOrSelfPermission(
UPDATE_DEVICE_STATS, "requires UPDATE_DEVICE_STATS permission");
+ final int oldPolicy;
synchronized (mRulesLock) {
+ oldPolicy = getUidPolicy(uid);
mUidPolicy.put(uid, policy);
}
+
+ // TODO: consider dispatching BACKGROUND_DATA_SETTING broadcast
}
@Override
@@ -173,6 +194,36 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ @Override
+ public void registerListener(INetworkPolicyListener listener) {
+ mListeners.register(listener);
+
+ synchronized (mRulesLock) {
+ // dispatch any existing rules to new listeners
+ final int size = mUidRules.size();
+ for (int i = 0; i < size; i++) {
+ final int uid = mUidRules.keyAt(i);
+ final int uidRules = mUidRules.valueAt(i);
+ if (uidRules != RULE_ALLOW_ALL) {
+ try {
+ listener.onRulesChanged(uid, uidRules);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void unregisterListener(INetworkPolicyListener listener) {
+ mListeners.unregister(listener);
+ }
+
+ private boolean isUidForegroundL(int uid) {
+ // only really in foreground when screen is also on
+ return mUidForeground.get(uid, false) && mScreenOn;
+ }
+
/**
* Foreground for PID changed; recompute foreground at UID level. If
* changed, will trigger {@link #updateRulesForUidL(int)}.
@@ -223,22 +274,33 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
private void updateRulesForUidL(int uid) {
- // only really in foreground when screen on
- final boolean uidForeground = mUidForeground.get(uid, false) && mScreenOn;
final int uidPolicy = getUidPolicy(uid);
+ final boolean uidForeground = isUidForegroundL(uid);
- if (LOGD) {
- Log.d(TAG, "updateRulesForUid(uid=" + uid + ") found foreground=" + uidForeground
- + " and policy=" + uidPolicy);
+ // derive active rules based on policy and active state
+ int uidRules = RULE_ALLOW_ALL;
+ if (!uidForeground && (uidPolicy & POLICY_REJECT_PAID_BACKGROUND) != 0) {
+ // uid in background, and policy says to block paid data
+ uidRules = RULE_REJECT_PAID;
}
- if (!uidForeground && (uidPolicy & POLICY_REJECT_BACKGROUND) != 0) {
- // TODO: build updated rules and push to NMS
- } else if ((uidPolicy & POLICY_REJECT_PAID) != 0) {
- // TODO: build updated rules and push to NMS
- } else {
- // TODO: build updated rules and push to NMS
+ // TODO: only dispatch when rules actually change
+
+ // record rule locally to dispatch to new listeners
+ mUidRules.put(uid, uidRules);
+
+ // dispatch changed rule to existing listeners
+ final int length = mListeners.beginBroadcast();
+ for (int i = 0; i < length; i++) {
+ final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+ if (listener != null) {
+ try {
+ listener.onRulesChanged(uid, uidRules);
+ } catch (RemoteException e) {
+ }
+ }
}
+ mListeners.finishBroadcast();
}
private static <T> T checkNotNull(T value, String message) {