Loading core/java/android/app/usage/NetworkStatsManager.java +94 −5 Original line number Diff line number Diff line Loading @@ -25,9 +25,15 @@ import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.NetworkIdentity; import android.net.NetworkTemplate; import android.net.INetworkStatsService; import android.os.Binder; import android.os.Build; import android.os.Message; import android.os.Messenger; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; /** Loading Loading @@ -75,16 +81,26 @@ import android.util.Log; * not included. */ public class NetworkStatsManager { private final static String TAG = "NetworkStatsManager"; private static final String TAG = "NetworkStatsManager"; private static final boolean DBG = false; /** @hide */ public static final int CALLBACK_LIMIT_REACHED = 0; /** @hide */ public static final int CALLBACK_RELEASED = 1; private final Context mContext; private final INetworkStatsService mService; /** * {@hide} */ public NetworkStatsManager(Context context) { mContext = context; mService = INetworkStatsService.Stub.asInterface( ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); } /** * Query network usage statistics summaries. Result is summarised data usage for the whole * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This Loading Loading @@ -322,7 +338,40 @@ public class NetworkStatsManager { checkNotNull(policy, "DataUsagePolicy cannot be null"); checkNotNull(callback, "DataUsageCallback cannot be null"); // TODO: Implement stub. final Looper looper; if (handler == null) { looper = Looper.myLooper(); } else { looper = handler.getLooper(); } if (DBG) Log.d(TAG, "registerDataUsageCallback called with " + policy); NetworkTemplate[] templates; if (policy.subscriberIds == null || policy.subscriberIds.length == 0) { templates = new NetworkTemplate[1]; templates[0] = createTemplate(policy.networkType, null /* subscriberId */); } else { templates = new NetworkTemplate[policy.subscriberIds.length]; for (int i = 0; i < policy.subscriberIds.length; i++) { templates[i] = createTemplate(policy.networkType, policy.subscriberIds[i]); } } DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, templates, policy.uids, policy.thresholdInBytes); try { CallbackHandler callbackHandler = new CallbackHandler(looper, callback); callback.request = mService.registerDataUsageCallback( mContext.getOpPackageName(), request, new Messenger(callbackHandler), new Binder()); if (DBG) Log.d(TAG, "registerDataUsageCallback returned " + callback.request); if (callback.request == null) { Log.e(TAG, "Request from callback is null; should not happen"); } } catch (RemoteException e) { if (DBG) Log.d(TAG, "Remote exception when registering callback"); } } /** Loading @@ -331,9 +380,15 @@ public class NetworkStatsManager { * @param callback The {@link DataUsageCallback} used when registering. */ public void unregisterDataUsageCallback(DataUsageCallback callback) { checkNotNull(callback, "DataUsageCallback cannot be null"); // TODO: Implement stub. if (callback == null || callback.request == null || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { throw new IllegalArgumentException("Invalid DataUsageCallback"); } try { mService.unregisterDataUsageRequest(callback.request); } catch (RemoteException e) { if (DBG) Log.d(TAG, "Remote exception when unregistering callback"); } } /** Loading Loading @@ -366,4 +421,38 @@ public class NetworkStatsManager { } return template; } private static class CallbackHandler extends Handler { private DataUsageCallback mCallback; CallbackHandler(Looper looper, DataUsageCallback callback) { super(looper); mCallback = callback; } @Override public void handleMessage(Message message) { DataUsageRequest request = (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY); switch (message.what) { case CALLBACK_LIMIT_REACHED: { if (mCallback != null) { mCallback.onLimitReached(); } else { Log.e(TAG, "limit reached with released callback for " + request); } break; } case CALLBACK_RELEASED: { if (DBG) Log.d(TAG, "callback released for " + request); mCallback = null; break; } } } private static Object getObject(Message msg, String key) { return msg.getData().getParcelable(key); } } } core/java/android/net/DataUsageRequest.java +5 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,11 @@ import java.util.Objects; */ public class DataUsageRequest implements Parcelable { /** * @hide */ public static final String PARCELABLE_KEY = "DataUsageRequest"; /** * @hide */ Loading core/java/android/net/INetworkStatsService.aidl +10 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,13 @@ package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.IBinder; import android.os.Messenger; /** {@hide} */ interface INetworkStatsService { Loading Loading @@ -57,4 +60,11 @@ interface INetworkStatsService { /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); /** Registers a callback on data usage. */ DataUsageRequest registerDataUsageCallback(String callingPackage, in DataUsageRequest request, in Messenger messenger, in IBinder binder); /** Unregisters a callback on data usage. */ void unregisterDataUsageRequest(in DataUsageRequest request); } services/core/java/com/android/server/net/NetworkStatsAccess.java +8 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.net; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_TETHERING; Loading Loading @@ -48,6 +49,7 @@ public final class NetworkStatsAccess { @IntDef({ Level.DEFAULT, Level.USER, Level.DEVICESUMMARY, Level.DEVICE, }) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -147,6 +149,12 @@ public final class NetworkStatsAccess { // Device-level access - can access usage for any uid. return true; case NetworkStatsAccess.Level.DEVICESUMMARY: // Can access usage for any app running in the same user, along // with some special uids (system, removed, or tethering) and // anonymized uids return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING || uid == UID_ALL || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); case NetworkStatsAccess.Level.USER: // User-level access - can access usage for any app running in the same user, along // with some special uids (system, removed, or tethering). Loading services/core/java/com/android/server/net/NetworkStatsCollection.java +25 −3 Original line number Diff line number Diff line Loading @@ -135,7 +135,11 @@ public class NetworkStatsCollection implements FileRotator.Reader { } public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { final int callerUid = Binder.getCallingUid(); return getRelevantUids(accessLevel, Binder.getCallingUid()); } public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel, final int callerUid) { IntArray uids = new IntArray(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); Loading Loading @@ -169,7 +173,17 @@ public class NetworkStatsCollection implements FileRotator.Reader { public NetworkStatsHistory getHistory( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, @NetworkStatsAccess.Level int accessLevel) { final int callerUid = Binder.getCallingUid(); return getHistory(template, uid, set, tag, fields, start, end, accessLevel, Binder.getCallingUid()); } /** * Combine all {@link NetworkStatsHistory} in this collection which match * the requested parameters. */ public NetworkStatsHistory getHistory( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, @NetworkStatsAccess.Level int accessLevel, int callerUid) { if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) { throw new SecurityException("Network stats history of uid " + uid + " is forbidden for caller " + callerUid); Loading Loading @@ -198,6 +212,15 @@ public class NetworkStatsCollection implements FileRotator.Reader { */ public NetworkStats getSummary(NetworkTemplate template, long start, long end, @NetworkStatsAccess.Level int accessLevel) { return getSummary(template, start, end, accessLevel, Binder.getCallingUid()); } /** * Summarize all {@link NetworkStatsHistory} in this collection which match * the requested parameters. */ public NetworkStats getSummary(NetworkTemplate template, long start, long end, @NetworkStatsAccess.Level int accessLevel, int callerUid) { final long now = System.currentTimeMillis(); final NetworkStats stats = new NetworkStats(end - start, 24); Loading @@ -207,7 +230,6 @@ public class NetworkStatsCollection implements FileRotator.Reader { final NetworkStats.Entry entry = new NetworkStats.Entry(); NetworkStatsHistory.Entry historyEntry = null; final int callerUid = Binder.getCallingUid(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); if (templateMatches(template, key.ident) Loading Loading
core/java/android/app/usage/NetworkStatsManager.java +94 −5 Original line number Diff line number Diff line Loading @@ -25,9 +25,15 @@ import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.NetworkIdentity; import android.net.NetworkTemplate; import android.net.INetworkStatsService; import android.os.Binder; import android.os.Build; import android.os.Message; import android.os.Messenger; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; /** Loading Loading @@ -75,16 +81,26 @@ import android.util.Log; * not included. */ public class NetworkStatsManager { private final static String TAG = "NetworkStatsManager"; private static final String TAG = "NetworkStatsManager"; private static final boolean DBG = false; /** @hide */ public static final int CALLBACK_LIMIT_REACHED = 0; /** @hide */ public static final int CALLBACK_RELEASED = 1; private final Context mContext; private final INetworkStatsService mService; /** * {@hide} */ public NetworkStatsManager(Context context) { mContext = context; mService = INetworkStatsService.Stub.asInterface( ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); } /** * Query network usage statistics summaries. Result is summarised data usage for the whole * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This Loading Loading @@ -322,7 +338,40 @@ public class NetworkStatsManager { checkNotNull(policy, "DataUsagePolicy cannot be null"); checkNotNull(callback, "DataUsageCallback cannot be null"); // TODO: Implement stub. final Looper looper; if (handler == null) { looper = Looper.myLooper(); } else { looper = handler.getLooper(); } if (DBG) Log.d(TAG, "registerDataUsageCallback called with " + policy); NetworkTemplate[] templates; if (policy.subscriberIds == null || policy.subscriberIds.length == 0) { templates = new NetworkTemplate[1]; templates[0] = createTemplate(policy.networkType, null /* subscriberId */); } else { templates = new NetworkTemplate[policy.subscriberIds.length]; for (int i = 0; i < policy.subscriberIds.length; i++) { templates[i] = createTemplate(policy.networkType, policy.subscriberIds[i]); } } DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, templates, policy.uids, policy.thresholdInBytes); try { CallbackHandler callbackHandler = new CallbackHandler(looper, callback); callback.request = mService.registerDataUsageCallback( mContext.getOpPackageName(), request, new Messenger(callbackHandler), new Binder()); if (DBG) Log.d(TAG, "registerDataUsageCallback returned " + callback.request); if (callback.request == null) { Log.e(TAG, "Request from callback is null; should not happen"); } } catch (RemoteException e) { if (DBG) Log.d(TAG, "Remote exception when registering callback"); } } /** Loading @@ -331,9 +380,15 @@ public class NetworkStatsManager { * @param callback The {@link DataUsageCallback} used when registering. */ public void unregisterDataUsageCallback(DataUsageCallback callback) { checkNotNull(callback, "DataUsageCallback cannot be null"); // TODO: Implement stub. if (callback == null || callback.request == null || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { throw new IllegalArgumentException("Invalid DataUsageCallback"); } try { mService.unregisterDataUsageRequest(callback.request); } catch (RemoteException e) { if (DBG) Log.d(TAG, "Remote exception when unregistering callback"); } } /** Loading Loading @@ -366,4 +421,38 @@ public class NetworkStatsManager { } return template; } private static class CallbackHandler extends Handler { private DataUsageCallback mCallback; CallbackHandler(Looper looper, DataUsageCallback callback) { super(looper); mCallback = callback; } @Override public void handleMessage(Message message) { DataUsageRequest request = (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY); switch (message.what) { case CALLBACK_LIMIT_REACHED: { if (mCallback != null) { mCallback.onLimitReached(); } else { Log.e(TAG, "limit reached with released callback for " + request); } break; } case CALLBACK_RELEASED: { if (DBG) Log.d(TAG, "callback released for " + request); mCallback = null; break; } } } private static Object getObject(Message msg, String key) { return msg.getData().getParcelable(key); } } }
core/java/android/net/DataUsageRequest.java +5 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,11 @@ import java.util.Objects; */ public class DataUsageRequest implements Parcelable { /** * @hide */ public static final String PARCELABLE_KEY = "DataUsageRequest"; /** * @hide */ Loading
core/java/android/net/INetworkStatsService.aidl +10 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,13 @@ package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.IBinder; import android.os.Messenger; /** {@hide} */ interface INetworkStatsService { Loading Loading @@ -57,4 +60,11 @@ interface INetworkStatsService { /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); /** Registers a callback on data usage. */ DataUsageRequest registerDataUsageCallback(String callingPackage, in DataUsageRequest request, in Messenger messenger, in IBinder binder); /** Unregisters a callback on data usage. */ void unregisterDataUsageRequest(in DataUsageRequest request); }
services/core/java/com/android/server/net/NetworkStatsAccess.java +8 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.net; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_TETHERING; Loading Loading @@ -48,6 +49,7 @@ public final class NetworkStatsAccess { @IntDef({ Level.DEFAULT, Level.USER, Level.DEVICESUMMARY, Level.DEVICE, }) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -147,6 +149,12 @@ public final class NetworkStatsAccess { // Device-level access - can access usage for any uid. return true; case NetworkStatsAccess.Level.DEVICESUMMARY: // Can access usage for any app running in the same user, along // with some special uids (system, removed, or tethering) and // anonymized uids return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING || uid == UID_ALL || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); case NetworkStatsAccess.Level.USER: // User-level access - can access usage for any app running in the same user, along // with some special uids (system, removed, or tethering). Loading
services/core/java/com/android/server/net/NetworkStatsCollection.java +25 −3 Original line number Diff line number Diff line Loading @@ -135,7 +135,11 @@ public class NetworkStatsCollection implements FileRotator.Reader { } public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { final int callerUid = Binder.getCallingUid(); return getRelevantUids(accessLevel, Binder.getCallingUid()); } public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel, final int callerUid) { IntArray uids = new IntArray(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); Loading Loading @@ -169,7 +173,17 @@ public class NetworkStatsCollection implements FileRotator.Reader { public NetworkStatsHistory getHistory( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, @NetworkStatsAccess.Level int accessLevel) { final int callerUid = Binder.getCallingUid(); return getHistory(template, uid, set, tag, fields, start, end, accessLevel, Binder.getCallingUid()); } /** * Combine all {@link NetworkStatsHistory} in this collection which match * the requested parameters. */ public NetworkStatsHistory getHistory( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, @NetworkStatsAccess.Level int accessLevel, int callerUid) { if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) { throw new SecurityException("Network stats history of uid " + uid + " is forbidden for caller " + callerUid); Loading Loading @@ -198,6 +212,15 @@ public class NetworkStatsCollection implements FileRotator.Reader { */ public NetworkStats getSummary(NetworkTemplate template, long start, long end, @NetworkStatsAccess.Level int accessLevel) { return getSummary(template, start, end, accessLevel, Binder.getCallingUid()); } /** * Summarize all {@link NetworkStatsHistory} in this collection which match * the requested parameters. */ public NetworkStats getSummary(NetworkTemplate template, long start, long end, @NetworkStatsAccess.Level int accessLevel, int callerUid) { final long now = System.currentTimeMillis(); final NetworkStats stats = new NetworkStats(end - start, 24); Loading @@ -207,7 +230,6 @@ public class NetworkStatsCollection implements FileRotator.Reader { final NetworkStats.Entry entry = new NetworkStats.Entry(); NetworkStatsHistory.Entry historyEntry = null; final int callerUid = Binder.getCallingUid(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); if (templateMatches(template, key.ident) Loading