diff options
Diffstat (limited to 'services')
5 files changed, 448 insertions, 142 deletions
diff --git a/services/java/com/android/server/NetStatService.java b/services/java/com/android/server/NetStatService.java deleted file mode 100644 index 7fe6743..0000000 --- a/services/java/com/android/server/NetStatService.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2008 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 com.android.server; - -import android.content.Context; -import android.net.TrafficStats; -import android.os.INetStatService; -import android.os.SystemClock; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -public class NetStatService extends INetStatService.Stub { - private final Context mContext; - - public NetStatService(Context context) { - mContext = context; - } - - public long getMobileTxPackets() { - return TrafficStats.getMobileTxPackets(); - } - - public long getMobileRxPackets() { - return TrafficStats.getMobileRxPackets(); - } - - public long getMobileTxBytes() { - return TrafficStats.getMobileTxBytes(); - } - - public long getMobileRxBytes() { - return TrafficStats.getMobileRxBytes(); - } - - public long getTotalTxPackets() { - return TrafficStats.getTotalTxPackets(); - } - - public long getTotalRxPackets() { - return TrafficStats.getTotalRxPackets(); - } - - public long getTotalTxBytes() { - return TrafficStats.getTotalTxBytes(); - } - - public long getTotalRxBytes() { - return TrafficStats.getTotalRxBytes(); - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - // This data is accessible to any app -- no permission check needed. - - pw.print("Elapsed: total="); - pw.print(SystemClock.elapsedRealtime()); - pw.print("ms awake="); - pw.print(SystemClock.uptimeMillis()); - pw.println("ms"); - - pw.print("Mobile: Tx="); - pw.print(getMobileTxBytes()); - pw.print("B/"); - pw.print(getMobileTxPackets()); - pw.print("Pkts Rx="); - pw.print(getMobileRxBytes()); - pw.print("B/"); - pw.print(getMobileRxPackets()); - pw.println("Pkts"); - - pw.print("Total: Tx="); - pw.print(getTotalTxBytes()); - pw.print("B/"); - pw.print(getTotalTxPackets()); - pw.print("Pkts Rx="); - pw.print(getTotalRxBytes()); - pw.print("B/"); - pw.print(getTotalRxPackets()); - pw.println("Pkts"); - } -} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 4cd601f..596cbac 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -49,6 +49,7 @@ 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.net.NetworkStatsService; import com.android.server.pm.PackageManagerService; import com.android.server.usb.UsbService; import com.android.server.wm.WindowManagerService; @@ -116,7 +117,9 @@ class ServerThread extends Thread { LightsService lights = null; PowerManagerService power = null; BatteryService battery = null; + AlarmManagerService alarm = null; NetworkManagementService networkManagement = null; + NetworkStatsService networkStats = null; NetworkPolicyManagerService networkPolicy = null; ConnectivityService connectivity = null; IPackageManager pm = null; @@ -188,7 +191,7 @@ class ServerThread extends Thread { power.init(context, lights, ActivityManagerService.getDefault(), battery); Slog.i(TAG, "Alarm Manager"); - AlarmManagerService alarm = new AlarmManagerService(context); + alarm = new AlarmManagerService(context); ServiceManager.addService(Context.ALARM_SERVICE, alarm); Slog.i(TAG, "Init Watchdog"); @@ -274,27 +277,28 @@ class ServerThread extends Thread { } try { - Slog.i(TAG, "NetStat Service"); - ServiceManager.addService("netstat", new NetStatService(context)); + Slog.i(TAG, "NetworkManagement Service"); + networkManagement = NetworkManagementService.create(context); + ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement); } catch (Throwable e) { - Slog.e(TAG, "Failure starting NetStat Service", e); + Slog.e(TAG, "Failure starting NetworkManagement Service", e); } try { - Slog.i(TAG, "NetworkPolicy Service"); - networkPolicy = new NetworkPolicyManagerService( - context, ActivityManagerService.self(), power); - ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy); + Slog.i(TAG, "NetworkStats Service"); + networkStats = new NetworkStatsService(context, networkManagement, alarm); + ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Connectivity Service", e); + Slog.e(TAG, "Failure starting NetworkStats Service", e); } try { - Slog.i(TAG, "NetworkManagement Service"); - networkManagement = NetworkManagementService.create(context); - ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement); + Slog.i(TAG, "NetworkPolicy Service"); + networkPolicy = new NetworkPolicyManagerService( + context, ActivityManagerService.self(), power, networkStats); + ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy); } catch (Throwable e) { - Slog.e(TAG, "Failure starting NetworkManagement Service", e); + Slog.e(TAG, "Failure starting NetworkPolicy Service", e); } try { @@ -535,6 +539,7 @@ class ServerThread extends Thread { // These are needed to propagate to the runnable below. final Context contextF = context; final BatteryService batteryF = battery; + final NetworkStatsService networkStatsF = networkStats; final NetworkPolicyManagerService networkPolicyF = networkPolicy; final ConnectivityService connectivityF = connectivity; final DockObserver dockF = dock; @@ -561,6 +566,7 @@ class ServerThread extends Thread { startSystemUi(contextF); if (batteryF != null) batteryF.systemReady(); + if (networkStatsF != null) networkStatsF.systemReady(); if (networkPolicyF != null) networkPolicyF.systemReady(); if (connectivityF != null) connectivityF.systemReady(); if (dockF != null) dockF.systemReady(); diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 1ae8284..17c7161 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -35,10 +35,10 @@ import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; +import android.net.INetworkStatsService; import android.os.IPowerManager; import android.os.RemoteCallbackList; import android.os.RemoteException; -import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -59,11 +59,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final String TAG = "NetworkPolicy"; private static final boolean LOGD = true; - private Context mContext; - private IActivityManager mActivityManager; - private IPowerManager mPowerManager; + private final Context mContext; + private final IActivityManager mActivityManager; + private final IPowerManager mPowerManager; + private final INetworkStatsService mNetworkStats; - private Object mRulesLock = new Object(); + private final Object mRulesLock = new Object(); private boolean mScreenOn; @@ -80,21 +81,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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) { + // TODO: keep record of billing cycle details, and limit rules + // TODO: keep map of interfaces-to-billing-relationship + + public NetworkPolicyManagerService(Context context, IActivityManager activityManager, + IPowerManager powerManager, INetworkStatsService networkStats) { mContext = checkNotNull(context, "missing context"); mActivityManager = checkNotNull(activityManager, "missing activityManager"); mPowerManager = checkNotNull(powerManager, "missing powerManager"); + mNetworkStats = checkNotNull(networkStats, "missing networkStats"); } public void systemReady() { - // TODO: read current policy+stats from disk and generate NMS rules + // TODO: read current policy from disk updateScreenOn(); @@ -114,18 +118,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { screenFilter.addAction(Intent.ACTION_SCREEN_OFF); mContext.registerReceiver(mScreenReceiver, screenFilter); - final IntentFilter shutdownFilter = new IntentFilter(); - shutdownFilter.addAction(Intent.ACTION_SHUTDOWN); - mContext.registerReceiver(mShutdownReceiver, shutdownFilter); - } private IProcessObserver mProcessObserver = new IProcessObserver.Stub() { @Override public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { // only someone like AMS should only be calling us - mContext.enforceCallingOrSelfPermission( - MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission"); + mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG); synchronized (mRulesLock) { // because a uid can have multiple pids running inside, we need to @@ -145,8 +144,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void onProcessDied(int pid, int uid) { // only someone like AMS should only be calling us - mContext.enforceCallingOrSelfPermission( - MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission"); + mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG); synchronized (mRulesLock) { // clear records and recompute, when they exist @@ -170,19 +168,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }; - private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // TODO: persist any pending stats during clean shutdown - Log.d(TAG, "persisting stats"); - } - }; - @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"); + mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); final int oldPolicy; synchronized (mRulesLock) { @@ -228,7 +217,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { - mContext.enforceCallingOrSelfPermission(DUMP, "requires DUMP permission"); + mContext.enforceCallingOrSelfPermission(DUMP, TAG); synchronized (mRulesLock) { fout.println("Policy status for known UIDs:"); @@ -366,7 +355,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } return value; } - + private static void collectKeys(SparseIntArray source, SparseBooleanArray target) { final int size = source.size(); for (int i = 0; i < size; i++) { diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java new file mode 100644 index 0000000..d9c1f25 --- /dev/null +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2008 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 com.android.server.net; + +import static android.Manifest.permission.DUMP; +import static android.Manifest.permission.SHUTDOWN; +import static android.Manifest.permission.UPDATE_DEVICE_STATS; +import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.NetworkStats.UID_ALL; + +import android.app.AlarmManager; +import android.app.IAlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.INetworkStatsService; +import android.net.LinkProperties; +import android.net.NetworkStats; +import android.net.NetworkStatsHistory; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.INetworkManagementService; +import android.os.RemoteException; +import android.os.SystemClock; +import android.telephony.TelephonyManager; +import android.text.format.DateUtils; +import android.util.NtpTrustedTime; +import android.util.Slog; +import android.util.TrustedTime; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyIntents; +import com.google.android.collect.Maps; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.HashMap; + +/** + * Collect and persist detailed network statistics, and provide this data to + * other system services. + */ +public class NetworkStatsService extends INetworkStatsService.Stub { + private static final String TAG = "NetworkStatsService"; + private static final boolean LOGD = true; + + private final Context mContext; + private final INetworkManagementService mNetworkManager; + private final IAlarmManager mAlarmManager; + private final TrustedTime mTime; + + private static final String ACTION_NETWORK_STATS_POLL = + "com.android.server.action.NETWORK_STATS_POLL"; + + private PendingIntent mPollIntent; + + // TODO: move tweakable params to Settings.Secure + // TODO: listen for kernel push events through netd instead of polling + + private static final long KB_IN_BYTES = 1024; + + private static final long POLL_INTERVAL = AlarmManager.INTERVAL_FIFTEEN_MINUTES; + private static final long SUMMARY_BUCKET_DURATION = 6 * DateUtils.HOUR_IN_MILLIS; + private static final long SUMMARY_MAX_HISTORY = 90 * DateUtils.DAY_IN_MILLIS; + + // TODO: remove these high-frequency testing values +// private static final long POLL_INTERVAL = 5 * DateUtils.SECOND_IN_MILLIS; +// private static final long SUMMARY_BUCKET_DURATION = 10 * DateUtils.SECOND_IN_MILLIS; +// private static final long SUMMARY_MAX_HISTORY = 2 * DateUtils.MINUTE_IN_MILLIS; + + /** Minimum delta required to persist to disk. */ + private static final long SUMMARY_PERSIST_THRESHOLD = 64 * KB_IN_BYTES; + + private static final long TIME_CACHE_MAX_AGE = DateUtils.DAY_IN_MILLIS; + + private final Object mStatsLock = new Object(); + + /** Set of active ifaces during this boot. */ + private HashMap<String, InterfaceInfo> mActiveIface = Maps.newHashMap(); + /** Set of historical stats for known ifaces. */ + private HashMap<InterfaceInfo, NetworkStatsHistory> mIfaceStats = Maps.newHashMap(); + + private NetworkStats mLastPollStats; + private NetworkStats mLastPersistStats; + + private final HandlerThread mHandlerThread; + private final Handler mHandler; + + // TODO: collect detailed uid stats, storing tag-granularity data until next + // dropbox, and uid summary for a specific bucket count. + + // TODO: periodically compile statistics and send to dropbox. + + public NetworkStatsService( + Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { + // TODO: move to using cached NtpTrustedTime + this(context, networkManager, alarmManager, new NtpTrustedTime()); + } + + public NetworkStatsService(Context context, INetworkManagementService networkManager, + IAlarmManager alarmManager, TrustedTime time) { + mContext = checkNotNull(context, "missing Context"); + mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); + mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager"); + mTime = checkNotNull(time, "missing TrustedTime"); + + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + } + + public void systemReady() { + // read historical stats from disk + readStatsLocked(); + + // watch other system services that claim interfaces + // TODO: protect incoming broadcast with permissions check. + // TODO: consider migrating this to ConnectivityService, but it might + // cause a circular dependency. + final IntentFilter interfaceFilter = new IntentFilter(); + interfaceFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); + interfaceFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mContext.registerReceiver(mInterfaceReceiver, interfaceFilter); + + // listen for periodic polling events + final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); + mContext.registerReceiver(mPollReceiver, pollFilter, UPDATE_DEVICE_STATS, mHandler); + + // persist stats during clean shutdown + final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN); + mContext.registerReceiver(mShutdownReceiver, shutdownFilter, SHUTDOWN, null); + + try { + registerPollAlarmLocked(); + } catch (RemoteException e) { + Slog.w(TAG, "unable to register poll alarm"); + } + } + + /** + * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and + * reschedule based on current {@link #POLL_INTERVAL} value. + */ + private void registerPollAlarmLocked() throws RemoteException { + if (mPollIntent != null) { + mAlarmManager.remove(mPollIntent); + } + + mPollIntent = PendingIntent.getBroadcast( + mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); + + final long currentRealtime = SystemClock.elapsedRealtime(); + mAlarmManager.setInexactRepeating( + AlarmManager.ELAPSED_REALTIME, currentRealtime, POLL_INTERVAL, mPollIntent); + } + + @Override + public NetworkStatsHistory[] getNetworkStatsSummary(int networkType) { + // TODO: return history for requested types + return null; + } + + @Override + public NetworkStatsHistory getNetworkStatsUid(int uid) { + // TODO: return history for requested uid + return null; + } + + /** + * Receiver that watches for other system components that claim network + * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} + * with mobile interfaces. + */ + private BroadcastReceiver mInterfaceReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED.equals(action)) { + final LinkProperties prop = intent.getParcelableExtra( + Phone.DATA_LINK_PROPERTIES_KEY); + final String iface = prop != null ? prop.getInterfaceName() : null; + if (iface != null) { + final TelephonyManager teleManager = (TelephonyManager) context + .getSystemService(Context.TELEPHONY_SERVICE); + final InterfaceInfo info = new InterfaceInfo( + iface, TYPE_MOBILE, teleManager.getSubscriberId()); + reportActiveInterface(info); + } + } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { + final LinkProperties prop = intent.getParcelableExtra( + WifiManager.EXTRA_LINK_PROPERTIES); + final String iface = prop != null ? prop.getInterfaceName() : null; + if (iface != null) { + final InterfaceInfo info = new InterfaceInfo(iface, TYPE_WIFI, null); + reportActiveInterface(info); + } + } + } + }; + + private BroadcastReceiver mPollReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // already running on background handler, network/io is safe, and + // caller verified to have UPDATE_DEVICE_STATS permission above. + synchronized (mStatsLock) { + // TODO: acquire wakelock while performing poll + performPollLocked(); + } + } + }; + + private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // persist stats during clean shutdown + synchronized (mStatsLock) { + writeStatsLocked(); + } + } + }; + + private void performPollLocked() { + if (LOGD) Slog.v(TAG, "performPollLocked()"); + + // try refreshing time source when stale + if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) { + mTime.forceRefresh(); + } + + // TODO: consider marking "untrusted" times in historical stats + final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() + : System.currentTimeMillis(); + + final NetworkStats current; + try { + current = mNetworkManager.getNetworkStatsSummary(); + } catch (RemoteException e) { + Slog.w(TAG, "problem reading network stats"); + return; + } + + // update historical usage with delta since last poll + final NetworkStats pollDelta = computeStatsDelta(mLastPollStats, current); + final long timeStart = currentTime - pollDelta.elapsedRealtime; + for (String iface : pollDelta.getKnownIfaces()) { + final InterfaceInfo info = mActiveIface.get(iface); + if (info == null) { + if (LOGD) Slog.w(TAG, "unknown interface " + iface + ", ignoring stats"); + continue; + } + + final int index = pollDelta.findIndex(iface, UID_ALL); + final long rx = pollDelta.rx[index]; + final long tx = pollDelta.tx[index]; + + final NetworkStatsHistory history = findOrCreateHistoryLocked(info); + history.recordData(timeStart, currentTime, rx, tx); + history.removeBucketsBefore(currentTime - SUMMARY_MAX_HISTORY); + } + + mLastPollStats = current; + + // decide if enough has changed to trigger persist + final NetworkStats persistDelta = computeStatsDelta(mLastPersistStats, current); + for (String iface : persistDelta.getKnownIfaces()) { + final int index = persistDelta.findIndex(iface, UID_ALL); + if (persistDelta.rx[index] > SUMMARY_PERSIST_THRESHOLD + || persistDelta.tx[index] > SUMMARY_PERSIST_THRESHOLD) { + writeStatsLocked(); + mLastPersistStats = current; + break; + } + } + } + + private NetworkStatsHistory findOrCreateHistoryLocked(InterfaceInfo info) { + NetworkStatsHistory stats = mIfaceStats.get(info); + if (stats == null) { + stats = new NetworkStatsHistory( + info.networkType, info.identity, UID_ALL, SUMMARY_BUCKET_DURATION); + mIfaceStats.put(info, stats); + } + return stats; + } + + private void readStatsLocked() { + if (LOGD) Slog.v(TAG, "readStatsLocked()"); + // TODO: read historical stats from disk using AtomicFile + } + + private void writeStatsLocked() { + if (LOGD) Slog.v(TAG, "writeStatsLocked()"); + // TODO: persist historical stats to disk using AtomicFile + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mContext.enforceCallingOrSelfPermission(DUMP, TAG); + + pw.println("Active interfaces:"); + for (InterfaceInfo info : mActiveIface.values()) { + info.dump(" ", pw); + } + + pw.println("Known historical stats:"); + for (NetworkStatsHistory stats : mIfaceStats.values()) { + stats.dump(" ", pw); + } + } + + /** + * Details for a well-known network interface, including its name, network + * type, and billing relationship identity (such as IMSI). + */ + private static class InterfaceInfo { + public final String iface; + public final int networkType; + public final String identity; + + public InterfaceInfo(String iface, int networkType, String identity) { + this.iface = iface; + this.networkType = networkType; + this.identity = identity; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((identity == null) ? 0 : identity.hashCode()); + result = prime * result + ((iface == null) ? 0 : iface.hashCode()); + result = prime * result + networkType; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof InterfaceInfo) { + final InterfaceInfo info = (InterfaceInfo) obj; + return equal(iface, info.iface) && networkType == info.networkType + && equal(identity, info.identity); + } + return false; + } + + public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); + pw.print("InterfaceInfo: iface="); pw.print(iface); + pw.print(" networkType="); pw.print(networkType); + pw.print(" identity="); pw.println(identity); + } + } + + private void reportActiveInterface(InterfaceInfo info) { + synchronized (mStatsLock) { + // TODO: when interface redefined, port over historical stats + mActiveIface.put(info.iface, info); + } + } + + /** + * Return the delta between two {@link NetworkStats} snapshots, where {@code + * before} can be {@code null}. + */ + private static NetworkStats computeStatsDelta(NetworkStats before, NetworkStats current) { + if (before != null) { + return current.subtract(before, false); + } else { + return current; + } + } + + private static boolean equal(Object a, Object b) { + return a == b || (a != null && a.equals(b)); + } + + private static <T> T checkNotNull(T value, String message) { + if (value == null) { + throw new NullPointerException(message); + } + return value; + } + +} diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index cf1171f..6552cdf 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -32,6 +32,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.INetworkPolicyListener; +import android.net.INetworkStatsService; import android.os.Binder; import android.os.IPowerManager; import android.test.AndroidTestCase; @@ -57,6 +58,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { private IActivityManager mActivityManager; private IPowerManager mPowerManager; + private INetworkStatsService mStatsService; private INetworkPolicyListener mPolicyListener; private NetworkPolicyManagerService mService; @@ -90,10 +92,11 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { mActivityManager = createMock(IActivityManager.class); mPowerManager = createMock(IPowerManager.class); + mStatsService = createMock(INetworkStatsService.class); mPolicyListener = createMock(INetworkPolicyListener.class); mService = new NetworkPolicyManagerService( - mServiceContext, mActivityManager, mPowerManager); + mServiceContext, mActivityManager, mPowerManager, mStatsService); // RemoteCallbackList needs a binder to use as key expect(mPolicyListener.asBinder()).andReturn(mStubBinder).atLeastOnce(); @@ -123,6 +126,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { mActivityManager = null; mPowerManager = null; + mStatsService = null; mPolicyListener = null; mService = null; @@ -262,11 +266,11 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } private void replay() { - EasyMock.replay(mActivityManager, mPowerManager, mPolicyListener); + EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener); } private void verifyAndReset() { - EasyMock.verify(mActivityManager, mPowerManager, mPolicyListener); - EasyMock.reset(mActivityManager, mPowerManager, mPolicyListener); + EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener); + EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener); } } |