Merge "[MS41.1] Prepare for APIs for querying usage with template" am: 22c1481659 am: 39f1142822 am: b8e7864780

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1937268

Change-Id: Ie10cd1aedf4b7449356cdba0f64ba6c5d088640b
This commit is contained in:
Junyu Lai
2022-01-21 01:30:48 +00:00
committed by Automerger Merge Worker
4 changed files with 153 additions and 15 deletions

View File

@@ -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

View File

@@ -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.
} }
/** /**

View File

@@ -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.

View File

@@ -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);
} }
} }