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

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

Change-Id: Ic526e4f23bf78b9ab4ecc20884369b4386c2dc52
This commit is contained in:
Junyu Lai
2022-01-21 01:07:19 +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.
*/
void startHistoryEnumeration(int uid, int tag, int state) {
void startHistoryUidEnumeration(int uid, int tag, int state) {
mHistory = null;
try {
mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid,
@@ -570,6 +570,20 @@ public final class NetworkStats implements AutoCloseable {
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.
* @throws RemoteException

View File

@@ -433,6 +433,42 @@ public class NetworkStatsManager {
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.
* 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
* {@link java.lang.System#currentTimeMillis}.
* @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
* traffic from all states.
* @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);
}
/** @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 {
NetworkStats result;
try {
result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
result.startHistoryEnumeration(uid, tag, state);
final NetworkStats result = new NetworkStats(
mContext, template, mFlags, startTime, endTime, mService);
result.startHistoryUidEnumeration(uid, tag, state);
return result;
} catch (RemoteException e) {
Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag
+ " 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. */
@UnsupportedAppUsage
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.

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.BinderUtils;
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.PermissionUtils;
@@ -365,6 +366,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@NonNull
private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor;
@NonNull
private final LocationPermissionChecker mLocationPermissionChecker;
private static @NonNull File getDefaultSystemDir() {
return new File(Environment.getDataDirectory(), "system");
}
@@ -461,6 +465,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mContentResolver = mContext.getContentResolver();
mContentObserver = mDeps.makeContentObserver(mHandler, mSettings,
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
public NetworkStats getDeviceSummaryForNetwork(
NetworkTemplate template, long start, long end) {
enforceTemplatePermissions(template, callingPackage);
return internalGetSummaryForNetwork(template, restrictedFlags, start, end,
mAccessLevel, mCallingUid);
}
@@ -780,19 +793,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public NetworkStats getSummaryForNetwork(
NetworkTemplate template, long start, long end) {
enforceTemplatePermissions(template, callingPackage);
return internalGetSummaryForNetwork(template, restrictedFlags, start, end,
mAccessLevel, mCallingUid);
}
// TODO: Remove this after all callers are removed.
@Override
public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
enforceTemplatePermissions(template, callingPackage);
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
public NetworkStats getSummaryForAllUid(
NetworkTemplate template, long start, long end, boolean includeTags) {
enforceTemplatePermissions(template, callingPackage);
try {
final NetworkStats stats = getUidComplete()
.getSummary(template, start, end, mAccessLevel, mCallingUid);
@@ -810,6 +837,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public NetworkStats getTaggedSummaryForAllUid(
NetworkTemplate template, long start, long end) {
enforceTemplatePermissions(template, callingPackage);
try {
final NetworkStats tagStats = getUidTagComplete()
.getSummary(template, start, end, mAccessLevel, mCallingUid);
@@ -822,6 +850,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public NetworkStatsHistory getHistoryForUid(
NetworkTemplate template, int uid, int set, int tag, int fields) {
enforceTemplatePermissions(template, callingPackage);
// NOTE: We don't augment UID-level statistics
if (tag == TAG_NONE) {
return getUidComplete().getHistory(template, null, uid, set, tag, fields,
@@ -836,6 +865,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public NetworkStatsHistory getHistoryIntervalForUid(
NetworkTemplate template, int uid, int set, int tag, 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.
// NOTE: We don't augment UID-level statistics
if (tag == TAG_NONE) {
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) {
return NetworkStatsAccess.checkAccessLevel(
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
// splice DEV and XT together.
final NetworkStatsHistory history = internalGetHistoryForNetwork(template, flags, FIELD_ALL,
accessLevel, callingUid);
accessLevel, callingUid, start, end);
final long now = System.currentTimeMillis();
final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
@@ -910,14 +962,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
* appropriate.
*/
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
// splice DEV and XT together.
final SubscriptionPlan augmentPlan = resolveSubscriptionPlan(template, flags);
synchronized (mStatsLock) {
return mXtStatsCached.getHistory(template, augmentPlan,
UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, Long.MAX_VALUE,
accessLevel, callingUid);
UID_ALL, SET_ALL, TAG_NONE, fields, start, end, accessLevel, callingUid);
}
}