Loading core/java/android/app/usage/NetworkStatsManager.java +94 −5 Original line number Original line Diff line number Diff line Loading @@ -25,9 +25,15 @@ import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.DataUsageRequest; import android.net.NetworkIdentity; import android.net.NetworkIdentity; import android.net.NetworkTemplate; import android.net.NetworkTemplate; import android.net.INetworkStatsService; import android.os.Binder; import android.os.Build; import android.os.Build; import android.os.Message; import android.os.Messenger; import android.os.Handler; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Log; /** /** Loading Loading @@ -75,16 +81,26 @@ import android.util.Log; * not included. * not included. */ */ public class NetworkStatsManager { 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 Context mContext; private final INetworkStatsService mService; /** /** * {@hide} * {@hide} */ */ public NetworkStatsManager(Context context) { public NetworkStatsManager(Context context) { mContext = 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 * 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 * 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(policy, "DataUsagePolicy cannot be null"); checkNotNull(callback, "DataUsageCallback 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. * @param callback The {@link DataUsageCallback} used when registering. */ */ public void unregisterDataUsageCallback(DataUsageCallback callback) { public void unregisterDataUsageCallback(DataUsageCallback callback) { checkNotNull(callback, "DataUsageCallback cannot be null"); if (callback == null || callback.request == null || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { // TODO: Implement stub. 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; 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 Original line Diff line number Diff line Loading @@ -31,6 +31,11 @@ import java.util.Objects; */ */ public class DataUsageRequest implements Parcelable { public class DataUsageRequest implements Parcelable { /** * @hide */ public static final String PARCELABLE_KEY = "DataUsageRequest"; /** /** * @hide * @hide */ */ Loading core/java/android/net/INetworkStatsService.aidl +10 −0 Original line number Original line Diff line number Diff line Loading @@ -16,10 +16,13 @@ package android.net; package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.INetworkStatsSession; import android.net.NetworkStats; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.NetworkTemplate; import android.os.IBinder; import android.os.Messenger; /** {@hide} */ /** {@hide} */ interface INetworkStatsService { interface INetworkStatsService { Loading Loading @@ -57,4 +60,11 @@ interface INetworkStatsService { /** Advise persistance threshold; may be overridden internally. */ /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); 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 Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.net; package com.android.server.net; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; 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_REMOVED; import static android.net.TrafficStats.UID_TETHERING; import static android.net.TrafficStats.UID_TETHERING; Loading Loading @@ -48,6 +49,7 @@ public final class NetworkStatsAccess { @IntDef({ @IntDef({ Level.DEFAULT, Level.DEFAULT, Level.USER, Level.USER, Level.DEVICESUMMARY, Level.DEVICE, Level.DEVICE, }) }) @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -147,6 +149,12 @@ public final class NetworkStatsAccess { // Device-level access - can access usage for any uid. // Device-level access - can access usage for any uid. return true; return true; case NetworkStatsAccess.Level.DEVICESUMMARY: 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: case NetworkStatsAccess.Level.USER: // User-level access - can access usage for any app running in the same user, along // User-level access - can access usage for any app running in the same user, along // with some special uids (system, removed, or tethering). // with some special uids (system, removed, or tethering). Loading services/core/java/com/android/server/net/NetworkStatsCollection.java +25 −3 Original line number Original line Diff line number Diff line Loading @@ -135,7 +135,11 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { 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(); IntArray uids = new IntArray(); for (int i = 0; i < mStats.size(); i++) { for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); final Key key = mStats.keyAt(i); Loading Loading @@ -169,7 +173,17 @@ public class NetworkStatsCollection implements FileRotator.Reader { public NetworkStatsHistory getHistory( public NetworkStatsHistory getHistory( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, @NetworkStatsAccess.Level int accessLevel) { @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)) { if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) { throw new SecurityException("Network stats history of uid " + uid throw new SecurityException("Network stats history of uid " + uid + " is forbidden for caller " + callerUid); + " 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, public NetworkStats getSummary(NetworkTemplate template, long start, long end, @NetworkStatsAccess.Level int accessLevel) { @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 long now = System.currentTimeMillis(); final NetworkStats stats = new NetworkStats(end - start, 24); 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(); final NetworkStats.Entry entry = new NetworkStats.Entry(); NetworkStatsHistory.Entry historyEntry = null; NetworkStatsHistory.Entry historyEntry = null; final int callerUid = Binder.getCallingUid(); for (int i = 0; i < mStats.size(); i++) { for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); final Key key = mStats.keyAt(i); if (templateMatches(template, key.ident) if (templateMatches(template, key.ident) Loading Loading
core/java/android/app/usage/NetworkStatsManager.java +94 −5 Original line number Original line Diff line number Diff line Loading @@ -25,9 +25,15 @@ import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.DataUsageRequest; import android.net.NetworkIdentity; import android.net.NetworkIdentity; import android.net.NetworkTemplate; import android.net.NetworkTemplate; import android.net.INetworkStatsService; import android.os.Binder; import android.os.Build; import android.os.Build; import android.os.Message; import android.os.Messenger; import android.os.Handler; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Log; /** /** Loading Loading @@ -75,16 +81,26 @@ import android.util.Log; * not included. * not included. */ */ public class NetworkStatsManager { 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 Context mContext; private final INetworkStatsService mService; /** /** * {@hide} * {@hide} */ */ public NetworkStatsManager(Context context) { public NetworkStatsManager(Context context) { mContext = 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 * 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 * 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(policy, "DataUsagePolicy cannot be null"); checkNotNull(callback, "DataUsageCallback 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. * @param callback The {@link DataUsageCallback} used when registering. */ */ public void unregisterDataUsageCallback(DataUsageCallback callback) { public void unregisterDataUsageCallback(DataUsageCallback callback) { checkNotNull(callback, "DataUsageCallback cannot be null"); if (callback == null || callback.request == null || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { // TODO: Implement stub. 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; 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 Original line Diff line number Diff line Loading @@ -31,6 +31,11 @@ import java.util.Objects; */ */ public class DataUsageRequest implements Parcelable { public class DataUsageRequest implements Parcelable { /** * @hide */ public static final String PARCELABLE_KEY = "DataUsageRequest"; /** /** * @hide * @hide */ */ Loading
core/java/android/net/INetworkStatsService.aidl +10 −0 Original line number Original line Diff line number Diff line Loading @@ -16,10 +16,13 @@ package android.net; package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.INetworkStatsSession; import android.net.NetworkStats; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.NetworkTemplate; import android.os.IBinder; import android.os.Messenger; /** {@hide} */ /** {@hide} */ interface INetworkStatsService { interface INetworkStatsService { Loading Loading @@ -57,4 +60,11 @@ interface INetworkStatsService { /** Advise persistance threshold; may be overridden internally. */ /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); 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 Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.net; package com.android.server.net; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; 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_REMOVED; import static android.net.TrafficStats.UID_TETHERING; import static android.net.TrafficStats.UID_TETHERING; Loading Loading @@ -48,6 +49,7 @@ public final class NetworkStatsAccess { @IntDef({ @IntDef({ Level.DEFAULT, Level.DEFAULT, Level.USER, Level.USER, Level.DEVICESUMMARY, Level.DEVICE, Level.DEVICE, }) }) @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -147,6 +149,12 @@ public final class NetworkStatsAccess { // Device-level access - can access usage for any uid. // Device-level access - can access usage for any uid. return true; return true; case NetworkStatsAccess.Level.DEVICESUMMARY: 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: case NetworkStatsAccess.Level.USER: // User-level access - can access usage for any app running in the same user, along // User-level access - can access usage for any app running in the same user, along // with some special uids (system, removed, or tethering). // with some special uids (system, removed, or tethering). Loading
services/core/java/com/android/server/net/NetworkStatsCollection.java +25 −3 Original line number Original line Diff line number Diff line Loading @@ -135,7 +135,11 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { 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(); IntArray uids = new IntArray(); for (int i = 0; i < mStats.size(); i++) { for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); final Key key = mStats.keyAt(i); Loading Loading @@ -169,7 +173,17 @@ public class NetworkStatsCollection implements FileRotator.Reader { public NetworkStatsHistory getHistory( public NetworkStatsHistory getHistory( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, @NetworkStatsAccess.Level int accessLevel) { @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)) { if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) { throw new SecurityException("Network stats history of uid " + uid throw new SecurityException("Network stats history of uid " + uid + " is forbidden for caller " + callerUid); + " 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, public NetworkStats getSummary(NetworkTemplate template, long start, long end, @NetworkStatsAccess.Level int accessLevel) { @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 long now = System.currentTimeMillis(); final NetworkStats stats = new NetworkStats(end - start, 24); 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(); final NetworkStats.Entry entry = new NetworkStats.Entry(); NetworkStatsHistory.Entry historyEntry = null; NetworkStatsHistory.Entry historyEntry = null; final int callerUid = Binder.getCallingUid(); for (int i = 0; i < mStats.size(); i++) { for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); final Key key = mStats.keyAt(i); if (templateMatches(template, key.ident) if (templateMatches(template, key.ident) Loading