[MS41.1] Prepare for APIs for querying usage with template
This CL includes: 1. Prepare for queryDetailsForDevice which allows callers to query history of networks that matches the given template. 2. Prepare for queryDetailsForUidTagState, which allows callers to query history uid stats with the given template, uid and other conditions. 3. Enforce fine location permission if the caller is querying data usage with a template which contains wifi network keys. Test: atest NetworkStatsServiceTest NetworkStatsManagerTest Bug: 204830222 Bug: 200768422 Change-Id: I6783d6bfd6e075e0b3ec8a3c91836377f1d71c7a
This commit is contained in:
@@ -556,7 +556,7 @@ public final class NetworkStats implements AutoCloseable {
|
|||||||
/**
|
/**
|
||||||
* Collects history results for uid and resets history enumeration index.
|
* Collects history results for uid and resets history enumeration index.
|
||||||
*/
|
*/
|
||||||
void startHistoryEnumeration(int uid, int tag, int state) {
|
void startHistoryUidEnumeration(int uid, int tag, int state) {
|
||||||
mHistory = null;
|
mHistory = null;
|
||||||
try {
|
try {
|
||||||
mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid,
|
mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid,
|
||||||
@@ -570,6 +570,20 @@ public final class NetworkStats implements AutoCloseable {
|
|||||||
mEnumerationIndex = 0;
|
mEnumerationIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects history results for network and resets history enumeration index.
|
||||||
|
*/
|
||||||
|
void startHistoryDeviceEnumeration() {
|
||||||
|
try {
|
||||||
|
mHistory = mSession.getHistoryIntervalForNetwork(
|
||||||
|
mTemplate, NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
mHistory = null;
|
||||||
|
}
|
||||||
|
mEnumerationIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts uid enumeration for current user.
|
* Starts uid enumeration for current user.
|
||||||
* @throws RemoteException
|
* @throws RemoteException
|
||||||
|
|||||||
@@ -433,6 +433,42 @@ public class NetworkStatsManager {
|
|||||||
return null; // To make the compiler happy.
|
return null; // To make the compiler happy.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query usage statistics details for networks matching a given {@link NetworkTemplate}.
|
||||||
|
*
|
||||||
|
* Result is not aggregated over time. This means buckets' start and
|
||||||
|
* end timestamps will be between 'startTime' and 'endTime' parameters.
|
||||||
|
* <p>Only includes buckets whose entire time period is included between
|
||||||
|
* startTime and endTime. Doesn't interpolate or return partial buckets.
|
||||||
|
* Since bucket length is in the order of hours, this
|
||||||
|
* method cannot be used to measure data usage on a fine grained time scale.
|
||||||
|
* This may take a long time, and apps should avoid calling this on their main thread.
|
||||||
|
*
|
||||||
|
* @param template Template used to match networks. See {@link NetworkTemplate}.
|
||||||
|
* @param startTime Start of period, in milliseconds since the Unix epoch, see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @param endTime End of period, in milliseconds since the Unix epoch, see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @return Statistics which is described above.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
// @SystemApi(client = MODULE_LIBRARIES)
|
||||||
|
@WorkerThread
|
||||||
|
public NetworkStats queryDetailsForDevice(@NonNull NetworkTemplate template,
|
||||||
|
long startTime, long endTime) {
|
||||||
|
try {
|
||||||
|
final NetworkStats result =
|
||||||
|
new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
|
||||||
|
result.startHistoryDeviceEnumeration();
|
||||||
|
return result;
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // To make the compiler happy.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query network usage statistics details for a given uid.
|
* Query network usage statistics details for a given uid.
|
||||||
* This may take a long time, and apps should avoid calling this on their main thread.
|
* This may take a long time, and apps should avoid calling this on their main thread.
|
||||||
@@ -499,7 +535,8 @@ public class NetworkStatsManager {
|
|||||||
* @param endTime End of period. Defined in terms of "Unix time", see
|
* @param endTime End of period. Defined in terms of "Unix time", see
|
||||||
* {@link java.lang.System#currentTimeMillis}.
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
* @param uid UID of app
|
* @param uid UID of app
|
||||||
* @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags.
|
* @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data
|
||||||
|
* across all the tags.
|
||||||
* @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate
|
* @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate
|
||||||
* traffic from all states.
|
* traffic from all states.
|
||||||
* @return Statistics object or null if an error happened during statistics collection.
|
* @return Statistics object or null if an error happened during statistics collection.
|
||||||
@@ -514,21 +551,51 @@ public class NetworkStatsManager {
|
|||||||
return queryDetailsForUidTagState(template, startTime, endTime, uid, tag, state);
|
return queryDetailsForUidTagState(template, startTime, endTime, uid, tag, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @hide */
|
/**
|
||||||
public NetworkStats queryDetailsForUidTagState(NetworkTemplate template,
|
* Query network usage statistics details for a given template, uid, tag, and state.
|
||||||
|
*
|
||||||
|
* Only usable for uids belonging to calling user. Result is not aggregated over time.
|
||||||
|
* This means buckets' start and end timestamps are going to be between 'startTime' and
|
||||||
|
* 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag
|
||||||
|
* the same as the 'tag' parameter, and the state the same as the 'state' parameter.
|
||||||
|
* defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
|
||||||
|
* metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
|
||||||
|
* roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
|
||||||
|
* <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
|
||||||
|
* interpolate across partial buckets. Since bucket length is in the order of hours, this
|
||||||
|
* method cannot be used to measure data usage on a fine grained time scale.
|
||||||
|
* This may take a long time, and apps should avoid calling this on their main thread.
|
||||||
|
*
|
||||||
|
* @param template Template used to match networks. See {@link NetworkTemplate}.
|
||||||
|
* @param startTime Start of period, in milliseconds since the Unix epoch, see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @param endTime End of period, in milliseconds since the Unix epoch, see
|
||||||
|
* {@link java.lang.System#currentTimeMillis}.
|
||||||
|
* @param uid UID of app
|
||||||
|
* @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data
|
||||||
|
* across all the tags.
|
||||||
|
* @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate
|
||||||
|
* traffic from all states.
|
||||||
|
* @return Statistics which is described above.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
// @SystemApi(client = MODULE_LIBRARIES)
|
||||||
|
@WorkerThread
|
||||||
|
public NetworkStats queryDetailsForUidTagState(@NonNull NetworkTemplate template,
|
||||||
long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
|
long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
|
||||||
|
|
||||||
NetworkStats result;
|
|
||||||
try {
|
try {
|
||||||
result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
|
final NetworkStats result = new NetworkStats(
|
||||||
result.startHistoryEnumeration(uid, tag, state);
|
mContext, template, mFlags, startTime, endTime, mService);
|
||||||
|
result.startHistoryUidEnumeration(uid, tag, state);
|
||||||
|
return result;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag
|
Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag
|
||||||
+ " state=" + state, e);
|
+ " state=" + state, e);
|
||||||
return null;
|
e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return null; // To make the compiler happy.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ interface INetworkStatsSession {
|
|||||||
/** Return historical network layer stats for traffic that matches template. */
|
/** Return historical network layer stats for traffic that matches template. */
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
|
NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
|
||||||
|
/**
|
||||||
|
* Return historical network layer stats for traffic that matches template, start and end
|
||||||
|
* timestamp.
|
||||||
|
*/
|
||||||
|
NetworkStatsHistory getHistoryIntervalForNetwork(in NetworkTemplate template, int fields, long start, long end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return network layer usage summary per UID for traffic that matches template.
|
* Return network layer usage summary per UID for traffic that matches template.
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
|
|||||||
import com.android.net.module.util.BestClock;
|
import com.android.net.module.util.BestClock;
|
||||||
import com.android.net.module.util.BinderUtils;
|
import com.android.net.module.util.BinderUtils;
|
||||||
import com.android.net.module.util.CollectionUtils;
|
import com.android.net.module.util.CollectionUtils;
|
||||||
|
import com.android.net.module.util.LocationPermissionChecker;
|
||||||
import com.android.net.module.util.NetworkStatsUtils;
|
import com.android.net.module.util.NetworkStatsUtils;
|
||||||
import com.android.net.module.util.PermissionUtils;
|
import com.android.net.module.util.PermissionUtils;
|
||||||
|
|
||||||
@@ -365,6 +366,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor;
|
private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final LocationPermissionChecker mLocationPermissionChecker;
|
||||||
|
|
||||||
private static @NonNull File getDefaultSystemDir() {
|
private static @NonNull File getDefaultSystemDir() {
|
||||||
return new File(Environment.getDataDirectory(), "system");
|
return new File(Environment.getDataDirectory(), "system");
|
||||||
}
|
}
|
||||||
@@ -461,6 +465,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
mContentResolver = mContext.getContentResolver();
|
mContentResolver = mContext.getContentResolver();
|
||||||
mContentObserver = mDeps.makeContentObserver(mHandler, mSettings,
|
mContentObserver = mDeps.makeContentObserver(mHandler, mSettings,
|
||||||
mNetworkStatsSubscriptionsMonitor);
|
mNetworkStatsSubscriptionsMonitor);
|
||||||
|
mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -508,6 +513,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see LocationPermissionChecker
|
||||||
|
*/
|
||||||
|
public LocationPermissionChecker makeLocationPermissionChecker(final Context context) {
|
||||||
|
return new LocationPermissionChecker(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -773,6 +785,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public NetworkStats getDeviceSummaryForNetwork(
|
public NetworkStats getDeviceSummaryForNetwork(
|
||||||
NetworkTemplate template, long start, long end) {
|
NetworkTemplate template, long start, long end) {
|
||||||
|
enforceTemplatePermissions(template, callingPackage);
|
||||||
return internalGetSummaryForNetwork(template, restrictedFlags, start, end,
|
return internalGetSummaryForNetwork(template, restrictedFlags, start, end,
|
||||||
mAccessLevel, mCallingUid);
|
mAccessLevel, mCallingUid);
|
||||||
}
|
}
|
||||||
@@ -780,19 +793,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public NetworkStats getSummaryForNetwork(
|
public NetworkStats getSummaryForNetwork(
|
||||||
NetworkTemplate template, long start, long end) {
|
NetworkTemplate template, long start, long end) {
|
||||||
|
enforceTemplatePermissions(template, callingPackage);
|
||||||
return internalGetSummaryForNetwork(template, restrictedFlags, start, end,
|
return internalGetSummaryForNetwork(template, restrictedFlags, start, end,
|
||||||
mAccessLevel, mCallingUid);
|
mAccessLevel, mCallingUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this after all callers are removed.
|
||||||
@Override
|
@Override
|
||||||
public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
|
public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
|
||||||
|
enforceTemplatePermissions(template, callingPackage);
|
||||||
return internalGetHistoryForNetwork(template, restrictedFlags, fields,
|
return internalGetHistoryForNetwork(template, restrictedFlags, fields,
|
||||||
mAccessLevel, mCallingUid);
|
mAccessLevel, mCallingUid, Long.MIN_VALUE, Long.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkStatsHistory getHistoryIntervalForNetwork(NetworkTemplate template,
|
||||||
|
int fields, long start, long end) {
|
||||||
|
enforceTemplatePermissions(template, callingPackage);
|
||||||
|
// TODO(b/200768422): Redact returned history if the template is location
|
||||||
|
// sensitive but the caller is not privileged.
|
||||||
|
return internalGetHistoryForNetwork(template, restrictedFlags, fields,
|
||||||
|
mAccessLevel, mCallingUid, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NetworkStats getSummaryForAllUid(
|
public NetworkStats getSummaryForAllUid(
|
||||||
NetworkTemplate template, long start, long end, boolean includeTags) {
|
NetworkTemplate template, long start, long end, boolean includeTags) {
|
||||||
|
enforceTemplatePermissions(template, callingPackage);
|
||||||
try {
|
try {
|
||||||
final NetworkStats stats = getUidComplete()
|
final NetworkStats stats = getUidComplete()
|
||||||
.getSummary(template, start, end, mAccessLevel, mCallingUid);
|
.getSummary(template, start, end, mAccessLevel, mCallingUid);
|
||||||
@@ -810,6 +837,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public NetworkStats getTaggedSummaryForAllUid(
|
public NetworkStats getTaggedSummaryForAllUid(
|
||||||
NetworkTemplate template, long start, long end) {
|
NetworkTemplate template, long start, long end) {
|
||||||
|
enforceTemplatePermissions(template, callingPackage);
|
||||||
try {
|
try {
|
||||||
final NetworkStats tagStats = getUidTagComplete()
|
final NetworkStats tagStats = getUidTagComplete()
|
||||||
.getSummary(template, start, end, mAccessLevel, mCallingUid);
|
.getSummary(template, start, end, mAccessLevel, mCallingUid);
|
||||||
@@ -822,6 +850,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) {
|
||||||
|
enforceTemplatePermissions(template, callingPackage);
|
||||||
// NOTE: We don't augment UID-level statistics
|
// NOTE: We don't augment UID-level statistics
|
||||||
if (tag == TAG_NONE) {
|
if (tag == TAG_NONE) {
|
||||||
return getUidComplete().getHistory(template, null, uid, set, tag, fields,
|
return getUidComplete().getHistory(template, null, uid, set, tag, fields,
|
||||||
@@ -836,6 +865,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
public NetworkStatsHistory getHistoryIntervalForUid(
|
public NetworkStatsHistory getHistoryIntervalForUid(
|
||||||
NetworkTemplate template, int uid, int set, int tag, int fields,
|
NetworkTemplate template, int uid, int set, int tag, int fields,
|
||||||
long start, long end) {
|
long start, long end) {
|
||||||
|
enforceTemplatePermissions(template, callingPackage);
|
||||||
|
// TODO(b/200768422): Redact returned history if the template is location
|
||||||
|
// sensitive but the caller is not privileged.
|
||||||
// NOTE: We don't augment UID-level statistics
|
// NOTE: We don't augment UID-level statistics
|
||||||
if (tag == TAG_NONE) {
|
if (tag == TAG_NONE) {
|
||||||
return getUidComplete().getHistory(template, null, uid, set, tag, fields,
|
return getUidComplete().getHistory(template, null, uid, set, tag, fields,
|
||||||
@@ -857,6 +889,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enforceTemplatePermissions(@NonNull NetworkTemplate template,
|
||||||
|
@NonNull String callingPackage) {
|
||||||
|
// For a template with wifi network keys, it is possible for a malicious
|
||||||
|
// client to track the user locations via querying data usage. Thus, enforce
|
||||||
|
// fine location permission check.
|
||||||
|
if (!template.getWifiNetworkKeys().isEmpty()) {
|
||||||
|
final boolean canAccessFineLocation = mLocationPermissionChecker
|
||||||
|
.checkCallersLocationPermission(callingPackage,
|
||||||
|
null /* featureId */,
|
||||||
|
Binder.getCallingUid(),
|
||||||
|
false /* coarseForTargetSdkLessThanQ */,
|
||||||
|
null /* message */);
|
||||||
|
if (!canAccessFineLocation) {
|
||||||
|
throw new SecurityException("Access fine location is required when querying"
|
||||||
|
+ " with wifi network keys, make sure the app has the necessary"
|
||||||
|
+ "permissions and the location toggle is on.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) {
|
private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) {
|
||||||
return NetworkStatsAccess.checkAccessLevel(
|
return NetworkStatsAccess.checkAccessLevel(
|
||||||
mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage);
|
mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage);
|
||||||
@@ -893,7 +945,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
// We've been using pure XT stats long enough that we no longer need to
|
// We've been using pure XT stats long enough that we no longer need to
|
||||||
// splice DEV and XT together.
|
// splice DEV and XT together.
|
||||||
final NetworkStatsHistory history = internalGetHistoryForNetwork(template, flags, FIELD_ALL,
|
final NetworkStatsHistory history = internalGetHistoryForNetwork(template, flags, FIELD_ALL,
|
||||||
accessLevel, callingUid);
|
accessLevel, callingUid, start, end);
|
||||||
|
|
||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
|
final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
|
||||||
@@ -910,14 +962,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
* appropriate.
|
* appropriate.
|
||||||
*/
|
*/
|
||||||
private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template,
|
private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template,
|
||||||
int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid) {
|
int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid,
|
||||||
|
long start, long end) {
|
||||||
// We've been using pure XT stats long enough that we no longer need to
|
// We've been using pure XT stats long enough that we no longer need to
|
||||||
// splice DEV and XT together.
|
// splice DEV and XT together.
|
||||||
final SubscriptionPlan augmentPlan = resolveSubscriptionPlan(template, flags);
|
final SubscriptionPlan augmentPlan = resolveSubscriptionPlan(template, flags);
|
||||||
synchronized (mStatsLock) {
|
synchronized (mStatsLock) {
|
||||||
return mXtStatsCached.getHistory(template, augmentPlan,
|
return mXtStatsCached.getHistory(template, augmentPlan,
|
||||||
UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, Long.MAX_VALUE,
|
UID_ALL, SET_ALL, TAG_NONE, fields, start, end, accessLevel, callingUid);
|
||||||
accessLevel, callingUid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user