Data Usage public API
Added new API consisting of android.app.usage.NetworkUsageManager and android.app.usage.NetworkUsageStats. Through them data usage on a network interface can be programmatically queried. Both summary and details are available. Bug: 19208876 Change-Id: I0e0c4b37ae23ad1e589d4b0c955b93f28ba4333e
This commit is contained in:
233
core/java/android/app/usage/NetworkStatsManager.java
Normal file
233
core/java/android/app/usage/NetworkStatsManager.java
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2015 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.app.usage;
|
||||||
|
|
||||||
|
import android.app.usage.NetworkUsageStats.Bucket;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkIdentity;
|
||||||
|
import android.net.NetworkTemplate;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides access to network usage history and statistics. Usage data is collected in
|
||||||
|
* discrete bins of time called 'Buckets'. See {@link NetworkUsageStats.Bucket} for details.
|
||||||
|
* <p />
|
||||||
|
* Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and
|
||||||
|
* Long.MAX_VALUE can be used to simulate open ended intervals). All queries (except
|
||||||
|
* {@link #querySummaryForDevice}) collect only network usage of apps belonging to the same user
|
||||||
|
* as the client. In addition tethering usage, usage by removed users and apps, and usage by system
|
||||||
|
* is also included in the results.
|
||||||
|
* <h3>
|
||||||
|
* Summary queries
|
||||||
|
* </h3>
|
||||||
|
* These queries aggregate network usage across the whole interval. Therefore there will be only one
|
||||||
|
* bucket for a particular key and state combination. In case of the user-wide and device-wide
|
||||||
|
* summaries a single bucket containing the totalised network usage is returned.
|
||||||
|
* <h3>
|
||||||
|
* History queries
|
||||||
|
* </h3>
|
||||||
|
* These queries do not aggregate over time but do aggregate over state. Therefore there can be
|
||||||
|
* multiple buckets for a particular key but all Bucket's state is going to be
|
||||||
|
* {@link NetworkUsageStats.Bucket#STATE_ALL}.
|
||||||
|
* <p />
|
||||||
|
* <b>NOTE:</b> This API requires the permission
|
||||||
|
* {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and
|
||||||
|
* will not be granted to third-party apps. However, declaring the permission implies intention to
|
||||||
|
* use the API and the user of the device can grant permission through the Settings application.
|
||||||
|
* Profile owner apps are automatically granted permission to query data on the profile they manage
|
||||||
|
* (that is, for any query except {@link #querySummaryForDevice}). Device owner apps likewise get
|
||||||
|
* access to usage data of the primary user.
|
||||||
|
*/
|
||||||
|
public class NetworkStatsManager {
|
||||||
|
private final static String TAG = "NetworkStatsManager";
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
public NetworkStatsManager(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Query network usage statistics summaries. Result is summarised data usage for the whole
|
||||||
|
* device. Result is a single Bucket aggregated over time, state and uid.
|
||||||
|
*
|
||||||
|
* @param networkType As defined in {@link ConnectivityManager}, e.g.
|
||||||
|
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
|
||||||
|
* etc.
|
||||||
|
* @param subscriberId If applicable, the subscriber id of the network interface.
|
||||||
|
* @param startTime Start of period. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @param endTime End of period. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @return Bucket object or null if permissions are insufficient or error happened during
|
||||||
|
* statistics collection.
|
||||||
|
*/
|
||||||
|
public Bucket querySummaryForDevice(int networkType, String subscriberId,
|
||||||
|
long startTime, long endTime) throws SecurityException, RemoteException {
|
||||||
|
NetworkTemplate template = createTemplate(networkType, subscriberId);
|
||||||
|
if (template == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bucket bucket = null;
|
||||||
|
NetworkUsageStats stats = new NetworkUsageStats(mContext, template, startTime, endTime);
|
||||||
|
bucket = stats.getDeviceSummaryForNetwork(startTime, endTime);
|
||||||
|
|
||||||
|
stats.close();
|
||||||
|
return bucket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query network usage statistics summaries. Result is summarised data usage for all uids
|
||||||
|
* belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
|
||||||
|
*
|
||||||
|
* @param networkType As defined in {@link ConnectivityManager}, e.g.
|
||||||
|
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
|
||||||
|
* etc.
|
||||||
|
* @param subscriberId If applicable, the subscriber id of the network interface.
|
||||||
|
* @param startTime Start of period. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @param endTime End of period. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @return Bucket object or null if permissions are insufficient or error happened during
|
||||||
|
* statistics collection.
|
||||||
|
*/
|
||||||
|
public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
|
||||||
|
long endTime) throws SecurityException, RemoteException {
|
||||||
|
NetworkTemplate template = createTemplate(networkType, subscriberId);
|
||||||
|
if (template == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkUsageStats stats;
|
||||||
|
stats = new NetworkUsageStats(mContext, template, startTime, endTime);
|
||||||
|
stats.startSummaryEnumeration(startTime, endTime);
|
||||||
|
|
||||||
|
stats.close();
|
||||||
|
return stats.getSummaryAggregate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query network usage statistics summaries. Result filtered to include only uids belonging to
|
||||||
|
* calling user. Result is aggregated over time, hence all buckets will have the same start and
|
||||||
|
* end timestamps. Not aggregated over state or uid.
|
||||||
|
*
|
||||||
|
* @param networkType As defined in {@link ConnectivityManager}, e.g.
|
||||||
|
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
|
||||||
|
* etc.
|
||||||
|
* @param subscriberId If applicable, the subscriber id of the network interface.
|
||||||
|
* @param startTime Start of period. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @param endTime End of period. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @return Statistics object or null if permissions are insufficient or error happened during
|
||||||
|
* statistics collection.
|
||||||
|
*/
|
||||||
|
public NetworkUsageStats querySummary(int networkType, String subscriberId, long startTime,
|
||||||
|
long endTime) throws SecurityException, RemoteException {
|
||||||
|
NetworkTemplate template = createTemplate(networkType, subscriberId);
|
||||||
|
if (template == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkUsageStats result;
|
||||||
|
result = new NetworkUsageStats(mContext, template, startTime, endTime);
|
||||||
|
result.startSummaryEnumeration(startTime, endTime);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query network usage statistics details. Only usable for uids belonging to calling user.
|
||||||
|
* Result is aggregated over state but not aggregated over time.
|
||||||
|
*
|
||||||
|
* @param networkType As defined in {@link ConnectivityManager}, e.g.
|
||||||
|
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
|
||||||
|
* etc.
|
||||||
|
* @param subscriberId If applicable, the subscriber id of the network interface.
|
||||||
|
* @param startTime Start of period. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @param endTime End of period. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @param uid UID of app
|
||||||
|
* @return Statistics object or null if permissions are insufficient or error happened during
|
||||||
|
* statistics collection.
|
||||||
|
*/
|
||||||
|
public NetworkUsageStats queryDetailsForUid(int networkType, String subscriberId,
|
||||||
|
long startTime, long endTime, int uid) throws SecurityException, RemoteException {
|
||||||
|
NetworkTemplate template = createTemplate(networkType, subscriberId);
|
||||||
|
if (template == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkUsageStats result;
|
||||||
|
result = new NetworkUsageStats(mContext, template, startTime, endTime);
|
||||||
|
result.startHistoryEnumeration(uid);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query network usage statistics details. Result filtered to include only uids belonging to
|
||||||
|
* calling user. Result is aggregated over state but not aggregated over time or uid.
|
||||||
|
*
|
||||||
|
* @param networkType As defined in {@link ConnectivityManager}, e.g.
|
||||||
|
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
|
||||||
|
* etc.
|
||||||
|
* @param subscriberId If applicable, the subscriber id of the network interface.
|
||||||
|
* @param startTime Start of period. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @param endTime End of period. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @return Statistics object or null if permissions are insufficient or error happened during
|
||||||
|
* statistics collection.
|
||||||
|
*/
|
||||||
|
public NetworkUsageStats queryDetails(int networkType, String subscriberId, long startTime,
|
||||||
|
long endTime) throws SecurityException, RemoteException {
|
||||||
|
NetworkTemplate template = createTemplate(networkType, subscriberId);
|
||||||
|
if (template == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
NetworkUsageStats result;
|
||||||
|
result = new NetworkUsageStats(mContext, template, startTime, endTime);
|
||||||
|
result.startUserUidEnumeration();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
|
||||||
|
NetworkTemplate template = null;
|
||||||
|
switch (networkType) {
|
||||||
|
case ConnectivityManager.TYPE_MOBILE: {
|
||||||
|
template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
|
||||||
|
} break;
|
||||||
|
case ConnectivityManager.TYPE_WIFI: {
|
||||||
|
template = NetworkTemplate.buildTemplateWifiWildcard();
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
Log.w(TAG, "Cannot create template for network type " + networkType
|
||||||
|
+ ", subscriberId '" + NetworkIdentity.scrubSubscriberId(subscriberId) +
|
||||||
|
"'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
}
|
||||||
479
core/java/android/app/usage/NetworkUsageStats.java
Normal file
479
core/java/android/app/usage/NetworkUsageStats.java
Normal file
@@ -0,0 +1,479 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2015 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.app.usage;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.INetworkStatsService;
|
||||||
|
import android.net.INetworkStatsSession;
|
||||||
|
import android.net.NetworkStats;
|
||||||
|
import android.net.NetworkStatsHistory;
|
||||||
|
import android.net.NetworkTemplate;
|
||||||
|
import android.net.TrafficStats;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import dalvik.system.CloseGuard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class providing enumeration over buckets of network usage statistics. NetworkUsageStats objects
|
||||||
|
* are returned as results to various queries in {@link NetworkStatsManager}.
|
||||||
|
*/
|
||||||
|
public final class NetworkUsageStats implements AutoCloseable {
|
||||||
|
private final static String TAG = "NetworkUsageStats";
|
||||||
|
|
||||||
|
private final CloseGuard mCloseGuard = CloseGuard.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start timestamp of stats collected
|
||||||
|
*/
|
||||||
|
private final long mStartTimeStamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End timestamp of stats collected
|
||||||
|
*/
|
||||||
|
private final long mEndTimeStamp;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-null array indicates the query enumerates over uids.
|
||||||
|
*/
|
||||||
|
private int[] mUids;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of the current uid in mUids when doing uid enumeration or a single uid value,
|
||||||
|
* depending on query type.
|
||||||
|
*/
|
||||||
|
private int mUidOrUidIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The session while the query requires it, null if all the stats have been collected or close()
|
||||||
|
* has been called.
|
||||||
|
*/
|
||||||
|
private INetworkStatsSession mSession;
|
||||||
|
private NetworkTemplate mTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Results of a summary query.
|
||||||
|
*/
|
||||||
|
private NetworkStats mSummary = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Results of detail queries.
|
||||||
|
*/
|
||||||
|
private NetworkStatsHistory mHistory = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where we are in enumerating over the current result.
|
||||||
|
*/
|
||||||
|
private int mEnumerationIndex = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recycling entry objects to prevent heap fragmentation.
|
||||||
|
*/
|
||||||
|
private NetworkStats.Entry mRecycledSummaryEntry = null;
|
||||||
|
private NetworkStatsHistory.Entry mRecycledHistoryEntry = null;
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
NetworkUsageStats(Context context, NetworkTemplate template, long startTimestamp,
|
||||||
|
long endTimestamp) throws RemoteException, SecurityException {
|
||||||
|
final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
|
||||||
|
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
|
||||||
|
// Open network stats session
|
||||||
|
mSession = statsService.openSessionForUsageStats(context.getOpPackageName());
|
||||||
|
mCloseGuard.open("close");
|
||||||
|
mTemplate = template;
|
||||||
|
mStartTimeStamp = startTimestamp;
|
||||||
|
mEndTimeStamp = endTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
try {
|
||||||
|
if (mCloseGuard != null) {
|
||||||
|
mCloseGuard.warnIfOpen();
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
} finally {
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------BEGINNING OF PUBLIC API-----------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buckets are the smallest elements of a query result. As some dimensions of a result may be
|
||||||
|
* aggregated (e.g. time or state) some values may be equal across all buckets.
|
||||||
|
*/
|
||||||
|
public static class Bucket {
|
||||||
|
/**
|
||||||
|
* Combined usage across all other states.
|
||||||
|
*/
|
||||||
|
public static final int STATE_ALL = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usage not accounted in any other states.
|
||||||
|
*/
|
||||||
|
public static final int STATE_DEFAULT = 0x1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Foreground usage.
|
||||||
|
*/
|
||||||
|
public static final int STATE_FOREGROUND = 0x2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special UID value for removed apps.
|
||||||
|
*/
|
||||||
|
public static final int UID_REMOVED = -4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special UID value for data usage by tethering.
|
||||||
|
*/
|
||||||
|
public static final int UID_TETHERING = -5;
|
||||||
|
|
||||||
|
private int mUid;
|
||||||
|
private int mState;
|
||||||
|
private long mBeginTimeStamp;
|
||||||
|
private long mEndTimeStamp;
|
||||||
|
private long mRxBytes;
|
||||||
|
private long mRxPackets;
|
||||||
|
private long mTxBytes;
|
||||||
|
private long mTxPackets;
|
||||||
|
|
||||||
|
private static int convertState(int networkStatsSet) {
|
||||||
|
switch (networkStatsSet) {
|
||||||
|
case NetworkStats.SET_ALL : return STATE_ALL;
|
||||||
|
case NetworkStats.SET_DEFAULT : return STATE_DEFAULT;
|
||||||
|
case NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int convertUid(int uid) {
|
||||||
|
switch (uid) {
|
||||||
|
case TrafficStats.UID_REMOVED: return UID_REMOVED;
|
||||||
|
case TrafficStats.UID_TETHERING: return UID_TETHERING;
|
||||||
|
}
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bucket() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key of the bucket. Usually an app uid or one of the following special values:<p />
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #UID_REMOVED}</li>
|
||||||
|
* <li>{@link #UID_TETHERING}</li>
|
||||||
|
* <li>{@link android.os.Process#SYSTEM_UID}</li>
|
||||||
|
* </ul>
|
||||||
|
* @return Bucket key.
|
||||||
|
*/
|
||||||
|
public int getUid() {
|
||||||
|
return mUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usage state. One of the following values:<p/>
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #STATE_ALL}</li>
|
||||||
|
* <li>{@link #STATE_DEFAULT}</li>
|
||||||
|
* <li>{@link #STATE_FOREGROUND}</li>
|
||||||
|
* </ul>
|
||||||
|
* @return Usage state.
|
||||||
|
*/
|
||||||
|
public int getState() {
|
||||||
|
return mState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @return Start of interval.
|
||||||
|
*/
|
||||||
|
public long getStartTimeStamp() {
|
||||||
|
return mBeginTimeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End timestamp of the bucket's time interval. Defined in terms of "Unix time", see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @return End of interval.
|
||||||
|
*/
|
||||||
|
public long getEndTimeStamp() {
|
||||||
|
return mEndTimeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of bytes received during the bucket's time interval. Statistics are measured at
|
||||||
|
* the network layer, so they include both TCP and UDP usage.
|
||||||
|
* @return Number of bytes.
|
||||||
|
*/
|
||||||
|
public long getRxBytes() {
|
||||||
|
return mRxBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of bytes transmitted during the bucket's time interval. Statistics are measured at
|
||||||
|
* the network layer, so they include both TCP and UDP usage.
|
||||||
|
* @return Number of bytes.
|
||||||
|
*/
|
||||||
|
public long getTxBytes() {
|
||||||
|
return mTxBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of packets received during the bucket's time interval. Statistics are measured at
|
||||||
|
* the network layer, so they include both TCP and UDP usage.
|
||||||
|
* @return Number of packets.
|
||||||
|
*/
|
||||||
|
public long getRxPackets() {
|
||||||
|
return mRxPackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of packets transmitted during the bucket's time interval. Statistics are measured
|
||||||
|
* at the network layer, so they include both TCP and UDP usage.
|
||||||
|
* @return Number of packets.
|
||||||
|
*/
|
||||||
|
public long getTxPackets() {
|
||||||
|
return mTxPackets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the recycled bucket with data of the next bin in the enumeration.
|
||||||
|
* @param bucketOut Bucket to be filled with data.
|
||||||
|
* @return true if successfully filled the bucket, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean getNextBucket(Bucket bucketOut) {
|
||||||
|
if (mSummary != null) {
|
||||||
|
return getNextSummaryBucket(bucketOut);
|
||||||
|
} else {
|
||||||
|
return getNextHistoryBucket(bucketOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if it is possible to ask for a next bucket in the enumeration.
|
||||||
|
* @return true if there is at least one more bucket.
|
||||||
|
*/
|
||||||
|
public boolean hasNextBucket() {
|
||||||
|
if (mSummary != null) {
|
||||||
|
return mEnumerationIndex < mSummary.size();
|
||||||
|
} else if (mHistory != null) {
|
||||||
|
return mEnumerationIndex < mHistory.size()
|
||||||
|
|| hasNextUid();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the enumeration. Call this method before this object gets out of scope.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (mSession != null) {
|
||||||
|
try {
|
||||||
|
mSession.close();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
// Otherwise, meh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mSession = null;
|
||||||
|
if (mCloseGuard != null) {
|
||||||
|
mCloseGuard.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------END OF PUBLIC API-----------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects device summary results into a Bucket.
|
||||||
|
* @param startTime
|
||||||
|
* @param endTime
|
||||||
|
* @throws RemoteException
|
||||||
|
*/
|
||||||
|
Bucket getDeviceSummaryForNetwork(long startTime, long endTime) throws RemoteException {
|
||||||
|
mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, startTime, endTime);
|
||||||
|
|
||||||
|
// Setting enumeration index beyond end to avoid accidental enumeration over data that does
|
||||||
|
// not belong to the calling user.
|
||||||
|
mEnumerationIndex = mSummary.size();
|
||||||
|
|
||||||
|
return getSummaryAggregate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects summary results and sets summary enumeration mode.
|
||||||
|
* @param startTime
|
||||||
|
* @param endTime
|
||||||
|
* @throws RemoteException
|
||||||
|
*/
|
||||||
|
void startSummaryEnumeration(long startTime, long endTime) throws RemoteException {
|
||||||
|
mSummary = mSession.getSummaryForAllUid(mTemplate, startTime, endTime, false);
|
||||||
|
|
||||||
|
mEnumerationIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects history results for uid and resets history enumeration index.
|
||||||
|
*/
|
||||||
|
void startHistoryEnumeration(int uid) {
|
||||||
|
mHistory = null;
|
||||||
|
try {
|
||||||
|
mHistory = mSession.getHistoryForUid(mTemplate, uid, NetworkStats.SET_ALL,
|
||||||
|
NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL);
|
||||||
|
setSingleUid(uid);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
// Leaving mHistory null
|
||||||
|
}
|
||||||
|
mEnumerationIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts uid enumeration for current user.
|
||||||
|
* @throws RemoteException
|
||||||
|
*/
|
||||||
|
void startUserUidEnumeration() throws RemoteException {
|
||||||
|
setUidEnumeration(mSession.getRelevantUids());
|
||||||
|
stepHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Steps to next uid in enumeration and collects history for that.
|
||||||
|
*/
|
||||||
|
private void stepHistory(){
|
||||||
|
if (hasNextUid()) {
|
||||||
|
stepUid();
|
||||||
|
mHistory = null;
|
||||||
|
try {
|
||||||
|
mHistory = mSession.getHistoryForUid(mTemplate, getUid(), NetworkStats.SET_ALL,
|
||||||
|
NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
// Leaving mHistory null
|
||||||
|
}
|
||||||
|
mEnumerationIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillBucketFromSummaryEntry(Bucket bucketOut) {
|
||||||
|
bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
|
||||||
|
bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
|
||||||
|
bucketOut.mBeginTimeStamp = mStartTimeStamp;
|
||||||
|
bucketOut.mEndTimeStamp = mEndTimeStamp;
|
||||||
|
bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes;
|
||||||
|
bucketOut.mRxPackets = mRecycledSummaryEntry.rxPackets;
|
||||||
|
bucketOut.mTxBytes = mRecycledSummaryEntry.txBytes;
|
||||||
|
bucketOut.mTxPackets = mRecycledSummaryEntry.txPackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getting the next item in summary enumeration.
|
||||||
|
* @param bucketOut Next item will be set here.
|
||||||
|
* @return true if a next item could be set.
|
||||||
|
*/
|
||||||
|
private boolean getNextSummaryBucket(Bucket bucketOut) {
|
||||||
|
if (bucketOut != null && mEnumerationIndex < mSummary.size()) {
|
||||||
|
mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry);
|
||||||
|
fillBucketFromSummaryEntry(bucketOut);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bucket getSummaryAggregate() {
|
||||||
|
if (mSummary == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Bucket bucket = new Bucket();
|
||||||
|
if (mRecycledSummaryEntry == null) {
|
||||||
|
mRecycledSummaryEntry = new NetworkStats.Entry();
|
||||||
|
}
|
||||||
|
mSummary.getTotal(mRecycledSummaryEntry);
|
||||||
|
fillBucketFromSummaryEntry(bucket);
|
||||||
|
return bucket;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Getting the next item in a history enumeration.
|
||||||
|
* @param bucketOut Next item will be set here.
|
||||||
|
* @return true if a next item could be set.
|
||||||
|
*/
|
||||||
|
private boolean getNextHistoryBucket(Bucket bucketOut) {
|
||||||
|
if (bucketOut != null && mHistory != null) {
|
||||||
|
if (mEnumerationIndex < mHistory.size()) {
|
||||||
|
mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++,
|
||||||
|
mRecycledHistoryEntry);
|
||||||
|
bucketOut.mUid = Bucket.convertUid(getUid());
|
||||||
|
bucketOut.mState = Bucket.STATE_ALL;
|
||||||
|
bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart;
|
||||||
|
bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart +
|
||||||
|
mRecycledHistoryEntry.bucketDuration;
|
||||||
|
bucketOut.mRxBytes = mRecycledHistoryEntry.rxBytes;
|
||||||
|
bucketOut.mRxPackets = mRecycledHistoryEntry.rxPackets;
|
||||||
|
bucketOut.mTxBytes = mRecycledHistoryEntry.txBytes;
|
||||||
|
bucketOut.mTxPackets = mRecycledHistoryEntry.txPackets;
|
||||||
|
return true;
|
||||||
|
} else if (hasNextUid()) {
|
||||||
|
stepHistory();
|
||||||
|
return getNextHistoryBucket(bucketOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------ UID LOGIC------------------------
|
||||||
|
|
||||||
|
private boolean isUidEnumeration() {
|
||||||
|
return mUids != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasNextUid() {
|
||||||
|
return isUidEnumeration() && (mUidOrUidIndex + 1) < mUids.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getUid() {
|
||||||
|
// Check if uid enumeration.
|
||||||
|
if (isUidEnumeration()) {
|
||||||
|
if (mUidOrUidIndex < 0 || mUidOrUidIndex >= mUids.length) {
|
||||||
|
throw new IndexOutOfBoundsException(
|
||||||
|
"Index=" + mUidOrUidIndex + " mUids.length=" + mUids.length);
|
||||||
|
}
|
||||||
|
return mUids[mUidOrUidIndex];
|
||||||
|
}
|
||||||
|
// Single uid mode.
|
||||||
|
return mUidOrUidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSingleUid(int uid) {
|
||||||
|
mUidOrUidIndex = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUidEnumeration(int[] uids) {
|
||||||
|
mUids = uids;
|
||||||
|
mUidOrUidIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stepUid() {
|
||||||
|
if (mUids != null) {
|
||||||
|
++mUidOrUidIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,14 @@ interface INetworkStatsService {
|
|||||||
/** Start a statistics query session. */
|
/** Start a statistics query session. */
|
||||||
INetworkStatsSession openSession();
|
INetworkStatsSession openSession();
|
||||||
|
|
||||||
|
/** Start a statistics query session. If calling package is profile or device owner then it is
|
||||||
|
* granted automatic access if apiLevel is NetworkStatsManager.API_LEVEL_DPC_ALLOWED. If
|
||||||
|
* apiLevel is at least NetworkStatsManager.API_LEVEL_REQUIRES_PACKAGE_USAGE_STATS then
|
||||||
|
* PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted
|
||||||
|
* READ_NETWORK_USAGE_STATS is checked for.
|
||||||
|
*/
|
||||||
|
INetworkStatsSession openSessionForUsageStats(String callingPackage);
|
||||||
|
|
||||||
/** Return network layer usage total for traffic that matches template. */
|
/** Return network layer usage total for traffic that matches template. */
|
||||||
long getNetworkTotalBytes(in NetworkTemplate template, long start, long end);
|
long getNetworkTotalBytes(in NetworkTemplate template, long start, long end);
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ import android.net.NetworkTemplate;
|
|||||||
/** {@hide} */
|
/** {@hide} */
|
||||||
interface INetworkStatsSession {
|
interface INetworkStatsSession {
|
||||||
|
|
||||||
|
/** Return device aggregated network layer usage summary for traffic that matches template. */
|
||||||
|
NetworkStats getDeviceSummaryForNetwork(in NetworkTemplate template, long start, long end);
|
||||||
|
|
||||||
/** Return network layer usage summary for traffic that matches template. */
|
/** Return network layer usage summary for traffic that matches template. */
|
||||||
NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
|
NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
|
||||||
/** Return historical network layer stats for traffic that matches template. */
|
/** Return historical network layer stats for traffic that matches template. */
|
||||||
@@ -33,6 +36,9 @@ interface INetworkStatsSession {
|
|||||||
/** Return historical network layer stats for specific UID traffic that matches template. */
|
/** Return historical network layer stats for specific UID traffic that matches template. */
|
||||||
NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
|
NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
|
||||||
|
|
||||||
|
/** Return array of uids that have stats and are accessible to the calling user */
|
||||||
|
int[] getRelevantUids();
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,21 +22,28 @@ import static android.net.NetworkStats.SET_DEFAULT;
|
|||||||
import static android.net.NetworkStats.TAG_NONE;
|
import static android.net.NetworkStats.TAG_NONE;
|
||||||
import static android.net.NetworkStats.UID_ALL;
|
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.text.format.DateUtils.SECOND_IN_MILLIS;
|
||||||
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
||||||
|
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkIdentity;
|
import android.net.NetworkIdentity;
|
||||||
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.net.TrafficStats;
|
import android.net.TrafficStats;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.AtomicFile;
|
import android.util.AtomicFile;
|
||||||
|
import android.util.IntArray;
|
||||||
|
|
||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
import com.android.internal.util.FileRotator;
|
import com.android.internal.util.FileRotator;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
|
||||||
import com.google.android.collect.Lists;
|
import com.google.android.collect.Lists;
|
||||||
import com.google.android.collect.Maps;
|
import com.google.android.collect.Maps;
|
||||||
|
|
||||||
@@ -129,6 +136,23 @@ public class NetworkStatsCollection implements FileRotator.Reader {
|
|||||||
return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
|
return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int[] getRelevantUids() {
|
||||||
|
final int callerUid = Binder.getCallingUid();
|
||||||
|
IntArray uids = new IntArray();
|
||||||
|
for (int i = 0; i < mStats.size(); i++) {
|
||||||
|
final Key key = mStats.keyAt(i);
|
||||||
|
if (isAccessibleToUser(key.uid, callerUid)) {
|
||||||
|
int j = uids.binarySearch(key.uid);
|
||||||
|
|
||||||
|
if (j < 0) {
|
||||||
|
j = ~j;
|
||||||
|
uids.add(j, key.uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uids.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combine all {@link NetworkStatsHistory} in this collection which match
|
* Combine all {@link NetworkStatsHistory} in this collection which match
|
||||||
* the requested parameters.
|
* the requested parameters.
|
||||||
@@ -144,8 +168,18 @@ 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) {
|
||||||
|
final int callerUid = Binder.getCallingUid();
|
||||||
|
if (!isAccessibleToUser(uid, callerUid)) {
|
||||||
|
throw new SecurityException("Network stats history of uid " + uid
|
||||||
|
+ " is forbidden for caller " + callerUid);
|
||||||
|
}
|
||||||
|
|
||||||
final NetworkStatsHistory combined = new NetworkStatsHistory(
|
final NetworkStatsHistory combined = new NetworkStatsHistory(
|
||||||
mBucketDuration, estimateBuckets(), fields);
|
mBucketDuration, start == end ? 1 : estimateBuckets(), fields);
|
||||||
|
|
||||||
|
// shortcut when we know stats will be empty
|
||||||
|
if (start == end) return combined;
|
||||||
|
|
||||||
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);
|
||||||
final boolean setMatches = set == SET_ALL || key.set == set;
|
final boolean setMatches = set == SET_ALL || key.set == set;
|
||||||
@@ -166,15 +200,16 @@ public class NetworkStatsCollection implements FileRotator.Reader {
|
|||||||
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);
|
||||||
final NetworkStats.Entry entry = new NetworkStats.Entry();
|
|
||||||
NetworkStatsHistory.Entry historyEntry = null;
|
|
||||||
|
|
||||||
// shortcut when we know stats will be empty
|
// shortcut when we know stats will be empty
|
||||||
if (start == end) return stats;
|
if (start == end) return stats;
|
||||||
|
|
||||||
|
final NetworkStats.Entry entry = new NetworkStats.Entry();
|
||||||
|
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) && isAccessibleToUser(key.uid, callerUid)) {
|
||||||
final NetworkStatsHistory value = mStats.valueAt(i);
|
final NetworkStatsHistory value = mStats.valueAt(i);
|
||||||
historyEntry = value.getValues(start, end, now, historyEntry);
|
historyEntry = value.getValues(start, end, now, historyEntry);
|
||||||
|
|
||||||
@@ -534,6 +569,12 @@ public class NetworkStatsCollection implements FileRotator.Reader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isAccessibleToUser(int uid, int callerUid) {
|
||||||
|
return callerUid == android.os.Process.SYSTEM_UID ||
|
||||||
|
uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING
|
||||||
|
|| UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
|
* Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
|
||||||
* in the given {@link NetworkIdentitySet}.
|
* in the given {@link NetworkIdentitySet}.
|
||||||
|
|||||||
@@ -62,9 +62,13 @@ import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
|
|||||||
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
|
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
|
||||||
import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
|
import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
|
import android.app.AppOpsManager;
|
||||||
import android.app.IAlarmManager;
|
import android.app.IAlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
import android.app.admin.DeviceAdminInfo;
|
||||||
|
import android.app.admin.DevicePolicyManagerInternal;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -93,7 +97,9 @@ import android.os.HandlerThread;
|
|||||||
import android.os.INetworkManagementService;
|
import android.os.INetworkManagementService;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceManager;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -116,6 +122,7 @@ import com.android.internal.util.ArrayUtils;
|
|||||||
import com.android.internal.util.FileRotator;
|
import com.android.internal.util.FileRotator;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
import com.android.server.EventLogTags;
|
import com.android.server.EventLogTags;
|
||||||
|
import com.android.server.LocalServices;
|
||||||
import com.android.server.connectivity.Tethering;
|
import com.android.server.connectivity.Tethering;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -429,7 +436,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public INetworkStatsSession openSession() {
|
public INetworkStatsSession openSession() {
|
||||||
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
|
return openSessionForUsageStats(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public INetworkStatsSession openSessionForUsageStats(final String callingPackage) {
|
||||||
assertBandwidthControlEnabled();
|
assertBandwidthControlEnabled();
|
||||||
|
|
||||||
// return an IBinder which holds strong references to any loaded stats
|
// return an IBinder which holds strong references to any loaded stats
|
||||||
@@ -438,6 +449,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
return new INetworkStatsSession.Stub() {
|
return new INetworkStatsSession.Stub() {
|
||||||
private NetworkStatsCollection mUidComplete;
|
private NetworkStatsCollection mUidComplete;
|
||||||
private NetworkStatsCollection mUidTagComplete;
|
private NetworkStatsCollection mUidTagComplete;
|
||||||
|
private String mCallingPackage = callingPackage;
|
||||||
|
|
||||||
private NetworkStatsCollection getUidComplete() {
|
private NetworkStatsCollection getUidComplete() {
|
||||||
synchronized (mStatsLock) {
|
synchronized (mStatsLock) {
|
||||||
@@ -457,9 +469,30 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getRelevantUids() {
|
||||||
|
enforcePermissionForManagedAdmin(mCallingPackage);
|
||||||
|
return getUidComplete().getRelevantUids();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start,
|
||||||
|
long end) {
|
||||||
|
enforcePermission(mCallingPackage);
|
||||||
|
NetworkStats result = new NetworkStats(end - start, 1);
|
||||||
|
final long ident = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
result.combineAllValues(internalGetSummaryForNetwork(template, start, end));
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(ident);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NetworkStats getSummaryForNetwork(
|
public NetworkStats getSummaryForNetwork(
|
||||||
NetworkTemplate template, long start, long end) {
|
NetworkTemplate template, long start, long end) {
|
||||||
|
enforcePermission(mCallingPackage);
|
||||||
return internalGetSummaryForNetwork(template, start, end);
|
return internalGetSummaryForNetwork(template, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,6 +504,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public NetworkStats getSummaryForAllUid(
|
public NetworkStats getSummaryForAllUid(
|
||||||
NetworkTemplate template, long start, long end, boolean includeTags) {
|
NetworkTemplate template, long start, long end, boolean includeTags) {
|
||||||
|
enforcePermissionForManagedAdmin(mCallingPackage);
|
||||||
final NetworkStats stats = getUidComplete().getSummary(template, start, end);
|
final NetworkStats stats = getUidComplete().getSummary(template, start, end);
|
||||||
if (includeTags) {
|
if (includeTags) {
|
||||||
final NetworkStats tagStats = getUidTagComplete()
|
final NetworkStats tagStats = getUidTagComplete()
|
||||||
@@ -483,6 +517,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public NetworkStatsHistory getHistoryForUid(
|
public NetworkStatsHistory getHistoryForUid(
|
||||||
NetworkTemplate template, int uid, int set, int tag, int fields) {
|
NetworkTemplate template, int uid, int set, int tag, int fields) {
|
||||||
|
enforcePermissionForManagedAdmin(mCallingPackage);
|
||||||
if (tag == TAG_NONE) {
|
if (tag == TAG_NONE) {
|
||||||
return getUidComplete().getHistory(template, uid, set, tag, fields);
|
return getUidComplete().getHistory(template, uid, set, tag, fields);
|
||||||
} else {
|
} else {
|
||||||
@@ -498,6 +533,53 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasAppOpsPermission(String callingPackage) {
|
||||||
|
final int callingUid = Binder.getCallingUid();
|
||||||
|
boolean appOpsAllow = false;
|
||||||
|
if (callingPackage != null) {
|
||||||
|
AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
|
||||||
|
Context.APP_OPS_SERVICE);
|
||||||
|
|
||||||
|
final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
|
||||||
|
callingUid, callingPackage);
|
||||||
|
if (mode == AppOpsManager.MODE_DEFAULT) {
|
||||||
|
// The default behavior here is to check if PackageManager has given the app
|
||||||
|
// permission.
|
||||||
|
final int permissionCheck = mContext.checkCallingPermission(
|
||||||
|
Manifest.permission.PACKAGE_USAGE_STATS);
|
||||||
|
appOpsAllow = permissionCheck == PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
appOpsAllow = (mode == AppOpsManager.MODE_ALLOWED);
|
||||||
|
}
|
||||||
|
return appOpsAllow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enforcePermissionForManagedAdmin(String callingPackage) {
|
||||||
|
boolean hasPermission = hasAppOpsPermission(callingPackage);
|
||||||
|
if (!hasPermission) {
|
||||||
|
// Profile and device owners are exempt from permission checking.
|
||||||
|
final int callingUid = Binder.getCallingUid();
|
||||||
|
final DevicePolicyManagerInternal dpmi = LocalServices.getService(
|
||||||
|
DevicePolicyManagerInternal.class);
|
||||||
|
if (dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)
|
||||||
|
|| dpmi.isActiveAdminWithPolicy(callingUid,
|
||||||
|
DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasPermission) {
|
||||||
|
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enforcePermission(String callingPackage) {
|
||||||
|
boolean appOpsAllow = hasAppOpsPermission(callingPackage);
|
||||||
|
if (!appOpsAllow) {
|
||||||
|
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return network summary, splicing between DEV and XT stats when
|
* Return network summary, splicing between DEV and XT stats when
|
||||||
* appropriate.
|
* appropriate.
|
||||||
|
|||||||
Reference in New Issue
Block a user