[MS08] Move NetworkStats files to f/b/package/ConnectivityT
NetworkStatsService is going to be moved into ConnectivityService module. Move all related files to packages/ConnectivityT so that it can be easily migrate these files to connectivity module after clearing the hidden API usages. Bug: 197717846 Test: TH Change-Id: Iead00832b5eb7b1dc40a92027c5a14ae8316b16c
This commit is contained in:
717
framework-t/src/android/app/usage/NetworkStats.java
Normal file
717
framework-t/src/android/app/usage/NetworkStats.java
Normal file
@@ -0,0 +1,717 @@
|
||||
/**
|
||||
* 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.annotation.IntDef;
|
||||
import android.content.Context;
|
||||
import android.net.INetworkStatsService;
|
||||
import android.net.INetworkStatsSession;
|
||||
import android.net.NetworkStatsHistory;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.net.TrafficStats;
|
||||
import android.os.RemoteException;
|
||||
import android.util.IntArray;
|
||||
import android.util.Log;
|
||||
|
||||
import dalvik.system.CloseGuard;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects
|
||||
* are returned as results to various queries in {@link NetworkStatsManager}.
|
||||
*/
|
||||
public final class NetworkStats implements AutoCloseable {
|
||||
private final static String TAG = "NetworkStats";
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Tag id in case if was specified in the query.
|
||||
*/
|
||||
private int mTag = android.net.NetworkStats.TAG_NONE;
|
||||
|
||||
/**
|
||||
* State in case it was not specified in the query.
|
||||
*/
|
||||
private int mState = Bucket.STATE_ALL;
|
||||
|
||||
/**
|
||||
* 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 android.net.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 android.net.NetworkStats.Entry mRecycledSummaryEntry = null;
|
||||
private NetworkStatsHistory.Entry mRecycledHistoryEntry = null;
|
||||
|
||||
/** @hide */
|
||||
NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp,
|
||||
long endTimestamp, INetworkStatsService statsService)
|
||||
throws RemoteException, SecurityException {
|
||||
// Open network stats session
|
||||
mSession = statsService.openSessionForUsageStats(flags, 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 {
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "STATE_" }, value = {
|
||||
STATE_ALL,
|
||||
STATE_DEFAULT,
|
||||
STATE_FOREGROUND
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface State {}
|
||||
|
||||
/**
|
||||
* Combined usage across all states.
|
||||
*/
|
||||
public static final int STATE_ALL = -1;
|
||||
|
||||
/**
|
||||
* Usage not accounted for in any other state.
|
||||
*/
|
||||
public static final int STATE_DEFAULT = 0x1;
|
||||
|
||||
/**
|
||||
* Foreground usage.
|
||||
*/
|
||||
public static final int STATE_FOREGROUND = 0x2;
|
||||
|
||||
/**
|
||||
* Special UID value for aggregate/unspecified.
|
||||
*/
|
||||
public static final int UID_ALL = android.net.NetworkStats.UID_ALL;
|
||||
|
||||
/**
|
||||
* Special UID value for removed apps.
|
||||
*/
|
||||
public static final int UID_REMOVED = TrafficStats.UID_REMOVED;
|
||||
|
||||
/**
|
||||
* Special UID value for data usage by tethering.
|
||||
*/
|
||||
public static final int UID_TETHERING = TrafficStats.UID_TETHERING;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "METERED_" }, value = {
|
||||
METERED_ALL,
|
||||
METERED_NO,
|
||||
METERED_YES
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Metered {}
|
||||
|
||||
/**
|
||||
* Combined usage across all metered states. Covers metered and unmetered usage.
|
||||
*/
|
||||
public static final int METERED_ALL = -1;
|
||||
|
||||
/**
|
||||
* Usage that occurs on an unmetered network.
|
||||
*/
|
||||
public static final int METERED_NO = 0x1;
|
||||
|
||||
/**
|
||||
* Usage that occurs on a metered network.
|
||||
*
|
||||
* <p>A network is classified as metered when the user is sensitive to heavy data usage on
|
||||
* that connection.
|
||||
*/
|
||||
public static final int METERED_YES = 0x2;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "ROAMING_" }, value = {
|
||||
ROAMING_ALL,
|
||||
ROAMING_NO,
|
||||
ROAMING_YES
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Roaming {}
|
||||
|
||||
/**
|
||||
* Combined usage across all roaming states. Covers both roaming and non-roaming usage.
|
||||
*/
|
||||
public static final int ROAMING_ALL = -1;
|
||||
|
||||
/**
|
||||
* Usage that occurs on a home, non-roaming network.
|
||||
*
|
||||
* <p>Any cellular usage in this bucket was incurred while the device was connected to a
|
||||
* tower owned or operated by the user's wireless carrier, or a tower that the user's
|
||||
* wireless carrier has indicated should be treated as a home network regardless.
|
||||
*
|
||||
* <p>This is also the default value for network types that do not support roaming.
|
||||
*/
|
||||
public static final int ROAMING_NO = 0x1;
|
||||
|
||||
/**
|
||||
* Usage that occurs on a roaming network.
|
||||
*
|
||||
* <p>Any cellular usage in this bucket as incurred while the device was roaming on another
|
||||
* carrier's network, for which additional charges may apply.
|
||||
*/
|
||||
public static final int ROAMING_YES = 0x2;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "DEFAULT_NETWORK_" }, value = {
|
||||
DEFAULT_NETWORK_ALL,
|
||||
DEFAULT_NETWORK_NO,
|
||||
DEFAULT_NETWORK_YES
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface DefaultNetworkStatus {}
|
||||
|
||||
/**
|
||||
* Combined usage for this network regardless of default network status.
|
||||
*/
|
||||
public static final int DEFAULT_NETWORK_ALL = -1;
|
||||
|
||||
/**
|
||||
* Usage that occurs while this network is not a default network.
|
||||
*
|
||||
* <p>This implies that the app responsible for this usage requested that it occur on a
|
||||
* specific network different from the one(s) the system would have selected for it.
|
||||
*/
|
||||
public static final int DEFAULT_NETWORK_NO = 0x1;
|
||||
|
||||
/**
|
||||
* Usage that occurs while this network is a default network.
|
||||
*
|
||||
* <p>This implies that the app either did not select a specific network for this usage,
|
||||
* or it selected a network that the system could have selected for app traffic.
|
||||
*/
|
||||
public static final int DEFAULT_NETWORK_YES = 0x2;
|
||||
|
||||
/**
|
||||
* Special TAG value for total data across all tags
|
||||
*/
|
||||
public static final int TAG_NONE = android.net.NetworkStats.TAG_NONE;
|
||||
|
||||
private int mUid;
|
||||
private int mTag;
|
||||
private int mState;
|
||||
private int mDefaultNetworkStatus;
|
||||
private int mMetered;
|
||||
private int mRoaming;
|
||||
private long mBeginTimeStamp;
|
||||
private long mEndTimeStamp;
|
||||
private long mRxBytes;
|
||||
private long mRxPackets;
|
||||
private long mTxBytes;
|
||||
private long mTxPackets;
|
||||
|
||||
private static int convertSet(@State int state) {
|
||||
switch (state) {
|
||||
case STATE_ALL: return android.net.NetworkStats.SET_ALL;
|
||||
case STATE_DEFAULT: return android.net.NetworkStats.SET_DEFAULT;
|
||||
case STATE_FOREGROUND: return android.net.NetworkStats.SET_FOREGROUND;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static @State int convertState(int networkStatsSet) {
|
||||
switch (networkStatsSet) {
|
||||
case android.net.NetworkStats.SET_ALL : return STATE_ALL;
|
||||
case android.net.NetworkStats.SET_DEFAULT : return STATE_DEFAULT;
|
||||
case android.net.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;
|
||||
}
|
||||
|
||||
private static int convertTag(int tag) {
|
||||
switch (tag) {
|
||||
case android.net.NetworkStats.TAG_NONE: return TAG_NONE;
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
private static @Metered int convertMetered(int metered) {
|
||||
switch (metered) {
|
||||
case android.net.NetworkStats.METERED_ALL : return METERED_ALL;
|
||||
case android.net.NetworkStats.METERED_NO: return METERED_NO;
|
||||
case android.net.NetworkStats.METERED_YES: return METERED_YES;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static @Roaming int convertRoaming(int roaming) {
|
||||
switch (roaming) {
|
||||
case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL;
|
||||
case android.net.NetworkStats.ROAMING_NO: return ROAMING_NO;
|
||||
case android.net.NetworkStats.ROAMING_YES: return ROAMING_YES;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static @DefaultNetworkStatus int convertDefaultNetworkStatus(
|
||||
int defaultNetworkStatus) {
|
||||
switch (defaultNetworkStatus) {
|
||||
case android.net.NetworkStats.DEFAULT_NETWORK_ALL : return DEFAULT_NETWORK_ALL;
|
||||
case android.net.NetworkStats.DEFAULT_NETWORK_NO: return DEFAULT_NETWORK_NO;
|
||||
case android.net.NetworkStats.DEFAULT_NETWORK_YES: return DEFAULT_NETWORK_YES;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag of the bucket.<p />
|
||||
* @return Bucket tag.
|
||||
*/
|
||||
public int getTag() {
|
||||
return mTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @State int getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Metered state. One of the following values:<p/>
|
||||
* <ul>
|
||||
* <li>{@link #METERED_ALL}</li>
|
||||
* <li>{@link #METERED_NO}</li>
|
||||
* <li>{@link #METERED_YES}</li>
|
||||
* </ul>
|
||||
* <p>A network is classified as metered when the user is sensitive to heavy data usage on
|
||||
* that connection. Apps may warn before using these networks for large downloads. The
|
||||
* metered state can be set by the user within data usage network restrictions.
|
||||
*/
|
||||
public @Metered int getMetered() {
|
||||
return mMetered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Roaming state. One of the following values:<p/>
|
||||
* <ul>
|
||||
* <li>{@link #ROAMING_ALL}</li>
|
||||
* <li>{@link #ROAMING_NO}</li>
|
||||
* <li>{@link #ROAMING_YES}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public @Roaming int getRoaming() {
|
||||
return mRoaming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default network status. One of the following values:<p/>
|
||||
* <ul>
|
||||
* <li>{@link #DEFAULT_NETWORK_ALL}</li>
|
||||
* <li>{@link #DEFAULT_NETWORK_NO}</li>
|
||||
* <li>{@link #DEFAULT_NETWORK_YES}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public @DefaultNetworkStatus int getDefaultNetworkStatus() {
|
||||
return mDefaultNetworkStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @throws RemoteException
|
||||
*/
|
||||
Bucket getDeviceSummaryForNetwork() throws RemoteException {
|
||||
mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, mStartTimeStamp, mEndTimeStamp);
|
||||
|
||||
// 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.
|
||||
* @throws RemoteException
|
||||
*/
|
||||
void startSummaryEnumeration() throws RemoteException {
|
||||
mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp,
|
||||
false /* includeTags */);
|
||||
mEnumerationIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects history results for uid and resets history enumeration index.
|
||||
*/
|
||||
void startHistoryEnumeration(int uid, int tag, int state) {
|
||||
mHistory = null;
|
||||
try {
|
||||
mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid,
|
||||
Bucket.convertSet(state), tag, NetworkStatsHistory.FIELD_ALL,
|
||||
mStartTimeStamp, mEndTimeStamp);
|
||||
setSingleUidTagState(uid, tag, state);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
// Leaving mHistory null
|
||||
}
|
||||
mEnumerationIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts uid enumeration for current user.
|
||||
* @throws RemoteException
|
||||
*/
|
||||
void startUserUidEnumeration() throws RemoteException {
|
||||
// TODO: getRelevantUids should be sensitive to time interval. When that's done,
|
||||
// the filtering logic below can be removed.
|
||||
int[] uids = mSession.getRelevantUids();
|
||||
// Filtering of uids with empty history.
|
||||
IntArray filteredUids = new IntArray(uids.length);
|
||||
for (int uid : uids) {
|
||||
try {
|
||||
NetworkStatsHistory history = mSession.getHistoryIntervalForUid(mTemplate, uid,
|
||||
android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE,
|
||||
NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp);
|
||||
if (history != null && history.size() > 0) {
|
||||
filteredUids.add(uid);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Error while getting history of uid " + uid, e);
|
||||
}
|
||||
}
|
||||
mUids = filteredUids.toArray();
|
||||
mUidOrUidIndex = -1;
|
||||
stepHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Steps to next uid in enumeration and collects history for that.
|
||||
*/
|
||||
private void stepHistory(){
|
||||
if (hasNextUid()) {
|
||||
stepUid();
|
||||
mHistory = null;
|
||||
try {
|
||||
mHistory = mSession.getHistoryIntervalForUid(mTemplate, getUid(),
|
||||
android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE,
|
||||
NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
// Leaving mHistory null
|
||||
}
|
||||
mEnumerationIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void fillBucketFromSummaryEntry(Bucket bucketOut) {
|
||||
bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
|
||||
bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag);
|
||||
bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
|
||||
bucketOut.mDefaultNetworkStatus = Bucket.convertDefaultNetworkStatus(
|
||||
mRecycledSummaryEntry.defaultNetwork);
|
||||
bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered);
|
||||
bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming);
|
||||
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 android.net.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.mTag = Bucket.convertTag(mTag);
|
||||
bucketOut.mState = mState;
|
||||
bucketOut.mDefaultNetworkStatus = Bucket.DEFAULT_NETWORK_ALL;
|
||||
bucketOut.mMetered = Bucket.METERED_ALL;
|
||||
bucketOut.mRoaming = Bucket.ROAMING_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 setSingleUidTagState(int uid, int tag, int state) {
|
||||
mUidOrUidIndex = uid;
|
||||
mTag = tag;
|
||||
mState = state;
|
||||
}
|
||||
|
||||
private void stepUid() {
|
||||
if (mUids != null) {
|
||||
++mUidOrUidIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
767
framework-t/src/android/app/usage/NetworkStatsManager.java
Normal file
767
framework-t/src/android/app/usage/NetworkStatsManager.java
Normal file
@@ -0,0 +1,767 @@
|
||||
/**
|
||||
* 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 static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.annotation.TestApi;
|
||||
import android.annotation.WorkerThread;
|
||||
import android.app.usage.NetworkStats.Bucket;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.DataUsageRequest;
|
||||
import android.net.INetworkStatsService;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkStack;
|
||||
import android.net.NetworkStateSnapshot;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.net.UnderlyingNetworkInfo;
|
||||
import android.net.netstats.provider.INetworkStatsProviderCallback;
|
||||
import android.net.netstats.provider.NetworkStatsProvider;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DataUnit;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.net.module.util.NetworkIdentityUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Provides access to network usage history and statistics. Usage data is collected in
|
||||
* discrete bins of time called 'Buckets'. See {@link NetworkStats.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). By default, apps can only obtain
|
||||
* data about themselves. See the below note for special cases in which apps can obtain data about
|
||||
* other applications.
|
||||
* <h3>
|
||||
* Summary queries
|
||||
* </h3>
|
||||
* {@link #querySummaryForDevice} <p />
|
||||
* {@link #querySummaryForUser} <p />
|
||||
* {@link #querySummary} <p />
|
||||
* These queries aggregate network usage across the whole interval. Therefore there will be only one
|
||||
* bucket for a particular key, state, metered and roaming 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>
|
||||
* {@link #queryDetailsForUid} <p />
|
||||
* {@link #queryDetails} <p />
|
||||
* These queries do not aggregate over time but do aggregate over state, metered and roaming.
|
||||
* Therefore there can be multiple buckets for a particular key. However, all Buckets will have
|
||||
* {@code state} {@link NetworkStats.Bucket#STATE_ALL},
|
||||
* {@code defaultNetwork} {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
|
||||
* {@code metered } {@link NetworkStats.Bucket#METERED_ALL},
|
||||
* {@code roaming} {@link NetworkStats.Bucket#ROAMING_ALL}.
|
||||
* <p />
|
||||
* <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the
|
||||
* calling app 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.
|
||||
* <p />
|
||||
* 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 and carrier-
|
||||
* privileged apps likewise get access to usage data for all users on the device.
|
||||
* <p />
|
||||
* In addition to tethering usage, usage by removed users and apps, and usage by the system
|
||||
* is also included in the results for callers with one of these higher levels of access.
|
||||
* <p />
|
||||
* <b>NOTE:</b> Prior to API level {@value android.os.Build.VERSION_CODES#N}, all calls to these APIs required
|
||||
* the above permission, even to access an app's own data usage, and carrier-privileged apps were
|
||||
* not included.
|
||||
*/
|
||||
@SystemService(Context.NETWORK_STATS_SERVICE)
|
||||
public class NetworkStatsManager {
|
||||
private static final String TAG = "NetworkStatsManager";
|
||||
private static final boolean DBG = false;
|
||||
|
||||
/** @hide */
|
||||
public static final int CALLBACK_LIMIT_REACHED = 0;
|
||||
/** @hide */
|
||||
public static final int CALLBACK_RELEASED = 1;
|
||||
|
||||
/**
|
||||
* Minimum data usage threshold for registering usage callbacks.
|
||||
*
|
||||
* Requests registered with a threshold lower than this will only be triggered once this minimum
|
||||
* is reached.
|
||||
* @hide
|
||||
*/
|
||||
public static final long MIN_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(2);
|
||||
|
||||
private final Context mContext;
|
||||
private final INetworkStatsService mService;
|
||||
|
||||
/** @hide */
|
||||
public static final int FLAG_POLL_ON_OPEN = 1 << 0;
|
||||
/** @hide */
|
||||
public static final int FLAG_POLL_FORCE = 1 << 1;
|
||||
/** @hide */
|
||||
public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 2;
|
||||
|
||||
private int mFlags;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public NetworkStatsManager(Context context) throws ServiceNotFoundException {
|
||||
this(context, INetworkStatsService.Stub.asInterface(
|
||||
ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)));
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public NetworkStatsManager(Context context, INetworkStatsService service) {
|
||||
mContext = context;
|
||||
mService = service;
|
||||
setPollOnOpen(true);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setPollOnOpen(boolean pollOnOpen) {
|
||||
if (pollOnOpen) {
|
||||
mFlags |= FLAG_POLL_ON_OPEN;
|
||||
} else {
|
||||
mFlags &= ~FLAG_POLL_ON_OPEN;
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
@TestApi
|
||||
public void setPollForce(boolean pollForce) {
|
||||
if (pollForce) {
|
||||
mFlags |= FLAG_POLL_FORCE;
|
||||
} else {
|
||||
mFlags &= ~FLAG_POLL_FORCE;
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) {
|
||||
if (augmentWithSubscriptionPlan) {
|
||||
mFlags |= FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
|
||||
} else {
|
||||
mFlags &= ~FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public Bucket querySummaryForDevice(NetworkTemplate template,
|
||||
long startTime, long endTime) throws SecurityException, RemoteException {
|
||||
Bucket bucket = null;
|
||||
NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime,
|
||||
mService);
|
||||
bucket = stats.getDeviceSummaryForNetwork();
|
||||
|
||||
stats.close();
|
||||
return bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query network usage statistics summaries. Result is summarised data usage for the whole
|
||||
* device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
|
||||
* roaming. This means the bucket's start and end timestamp are going to be the same as the
|
||||
* 'startTime' and 'endTime' parameters. State is going to be
|
||||
* {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
|
||||
* tag {@link NetworkStats.Bucket#TAG_NONE},
|
||||
* default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
|
||||
* metered {@link NetworkStats.Bucket#METERED_ALL},
|
||||
* and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
|
||||
* This may take a long time, and apps should avoid calling this on their main thread.
|
||||
*
|
||||
* @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.
|
||||
* <p>Starting with API level 29, the {@code subscriberId} is guarded by
|
||||
* additional restrictions. Calling apps that do not meet the new
|
||||
* requirements to access the {@code subscriberId} can provide a {@code
|
||||
* null} value when querying for the mobile network type to receive usage
|
||||
* for all mobile networks. For additional details see {@link
|
||||
* TelephonyManager#getSubscriberId()}.
|
||||
* <p>Starting with API level 31, calling apps can provide a
|
||||
* {@code subscriberId} with wifi network type to receive usage for
|
||||
* wifi networks which is under the given subscription if applicable.
|
||||
* Otherwise, pass {@code null} when querying all wifi networks.
|
||||
* @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.
|
||||
*/
|
||||
@WorkerThread
|
||||
public Bucket querySummaryForDevice(int networkType, String subscriberId,
|
||||
long startTime, long endTime) throws SecurityException, RemoteException {
|
||||
NetworkTemplate template;
|
||||
try {
|
||||
template = createTemplate(networkType, subscriberId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (DBG) Log.e(TAG, "Cannot create template", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return querySummaryForDevice(template, startTime, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* This means the bucket's start and end timestamp are going to be the same as the 'startTime'
|
||||
* and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL},
|
||||
* uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE},
|
||||
* metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming
|
||||
* {@link NetworkStats.Bucket#ROAMING_ALL}.
|
||||
* This may take a long time, and apps should avoid calling this on their main thread.
|
||||
*
|
||||
* @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.
|
||||
* <p>Starting with API level 29, the {@code subscriberId} is guarded by
|
||||
* additional restrictions. Calling apps that do not meet the new
|
||||
* requirements to access the {@code subscriberId} can provide a {@code
|
||||
* null} value when querying for the mobile network type to receive usage
|
||||
* for all mobile networks. For additional details see {@link
|
||||
* TelephonyManager#getSubscriberId()}.
|
||||
* <p>Starting with API level 31, calling apps can provide a
|
||||
* {@code subscriberId} with wifi network type to receive usage for
|
||||
* wifi networks which is under the given subscription if applicable.
|
||||
* Otherwise, pass {@code null} when querying all wifi networks.
|
||||
* @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.
|
||||
*/
|
||||
@WorkerThread
|
||||
public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
|
||||
long endTime) throws SecurityException, RemoteException {
|
||||
NetworkTemplate template;
|
||||
try {
|
||||
template = createTemplate(networkType, subscriberId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (DBG) Log.e(TAG, "Cannot create template", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
NetworkStats stats;
|
||||
stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
|
||||
stats.startSummaryEnumeration();
|
||||
|
||||
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, uid, default network, metered, or roaming. This
|
||||
* means buckets' start and end timestamps are going to be the same as the 'startTime' and
|
||||
* 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to
|
||||
* be the same.
|
||||
* This may take a long time, and apps should avoid calling this on their main thread.
|
||||
*
|
||||
* @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.
|
||||
* <p>Starting with API level 29, the {@code subscriberId} is guarded by
|
||||
* additional restrictions. Calling apps that do not meet the new
|
||||
* requirements to access the {@code subscriberId} can provide a {@code
|
||||
* null} value when querying for the mobile network type to receive usage
|
||||
* for all mobile networks. For additional details see {@link
|
||||
* TelephonyManager#getSubscriberId()}.
|
||||
* <p>Starting with API level 31, calling apps can provide a
|
||||
* {@code subscriberId} with wifi network type to receive usage for
|
||||
* wifi networks which is under the given subscription if applicable.
|
||||
* Otherwise, pass {@code null} when querying all wifi networks.
|
||||
* @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.
|
||||
*/
|
||||
@WorkerThread
|
||||
public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
|
||||
long endTime) throws SecurityException, RemoteException {
|
||||
NetworkTemplate template;
|
||||
try {
|
||||
template = createTemplate(networkType, subscriberId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (DBG) Log.e(TAG, "Cannot create template", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return querySummary(template, startTime, endTime);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public NetworkStats querySummary(NetworkTemplate template, long startTime,
|
||||
long endTime) throws SecurityException, RemoteException {
|
||||
NetworkStats result;
|
||||
result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
|
||||
result.startSummaryEnumeration();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
|
||||
*/
|
||||
@WorkerThread
|
||||
public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
|
||||
long startTime, long endTime, int uid) throws SecurityException {
|
||||
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
|
||||
NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public NetworkStats queryDetailsForUid(NetworkTemplate template,
|
||||
long startTime, long endTime, int uid) throws SecurityException {
|
||||
return queryDetailsForUidTagState(template, startTime, endTime, uid,
|
||||
NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query network usage statistics details for a given uid and tag.
|
||||
* This may take a long time, and apps should avoid calling this on their main thread.
|
||||
*
|
||||
* @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
|
||||
*/
|
||||
@WorkerThread
|
||||
public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
|
||||
long startTime, long endTime, int uid, int tag) throws SecurityException {
|
||||
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
|
||||
tag, NetworkStats.Bucket.STATE_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query network usage statistics details for a given 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 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.
|
||||
* <p>Starting with API level 29, the {@code subscriberId} is guarded by
|
||||
* additional restrictions. Calling apps that do not meet the new
|
||||
* requirements to access the {@code subscriberId} can provide a {@code
|
||||
* null} value when querying for the mobile network type to receive usage
|
||||
* for all mobile networks. For additional details see {@link
|
||||
* TelephonyManager#getSubscriberId()}.
|
||||
* <p>Starting with API level 31, calling apps can provide a
|
||||
* {@code subscriberId} with wifi network type to receive usage for
|
||||
* wifi networks which is under the given subscription if applicable.
|
||||
* Otherwise, pass {@code null} when querying all wifi networks.
|
||||
* @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
|
||||
* @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no 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.
|
||||
* @throws SecurityException if permissions are insufficient to read network statistics.
|
||||
*/
|
||||
@WorkerThread
|
||||
public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId,
|
||||
long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
|
||||
NetworkTemplate template;
|
||||
template = createTemplate(networkType, subscriberId);
|
||||
|
||||
return queryDetailsForUidTagState(template, startTime, endTime, uid, tag, state);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public NetworkStats queryDetailsForUidTagState(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);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag
|
||||
+ " state=" + state, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
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, uid, tag,
|
||||
* metered, nor roaming. This means buckets' start and end timestamps are going to be between
|
||||
* 'startTime' and 'endTime' parameters. State is going to be
|
||||
* {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
|
||||
* tag {@link NetworkStats.Bucket#TAG_NONE},
|
||||
* default network 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 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.
|
||||
* <p>Starting with API level 29, the {@code subscriberId} is guarded by
|
||||
* additional restrictions. Calling apps that do not meet the new
|
||||
* requirements to access the {@code subscriberId} can provide a {@code
|
||||
* null} value when querying for the mobile network type to receive usage
|
||||
* for all mobile networks. For additional details see {@link
|
||||
* TelephonyManager#getSubscriberId()}.
|
||||
* <p>Starting with API level 31, calling apps can provide a
|
||||
* {@code subscriberId} with wifi network type to receive usage for
|
||||
* wifi networks which is under the given subscription if applicable.
|
||||
* Otherwise, pass {@code null} when querying all wifi networks.
|
||||
* @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.
|
||||
*/
|
||||
@WorkerThread
|
||||
public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
|
||||
long endTime) throws SecurityException, RemoteException {
|
||||
NetworkTemplate template;
|
||||
try {
|
||||
template = createTemplate(networkType, subscriberId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (DBG) Log.e(TAG, "Cannot create template", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
NetworkStats result;
|
||||
result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
|
||||
result.startUserUidEnumeration();
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void registerUsageCallback(NetworkTemplate template, int networkType,
|
||||
long thresholdBytes, UsageCallback callback, @Nullable Handler handler) {
|
||||
Objects.requireNonNull(callback, "UsageCallback cannot be null");
|
||||
|
||||
final Looper looper;
|
||||
if (handler == null) {
|
||||
looper = Looper.myLooper();
|
||||
} else {
|
||||
looper = handler.getLooper();
|
||||
}
|
||||
|
||||
DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET,
|
||||
template, thresholdBytes);
|
||||
try {
|
||||
CallbackHandler callbackHandler = new CallbackHandler(looper, networkType,
|
||||
template.getSubscriberId(), callback);
|
||||
callback.request = mService.registerUsageCallback(
|
||||
mContext.getOpPackageName(), request, new Messenger(callbackHandler),
|
||||
new Binder());
|
||||
if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request);
|
||||
|
||||
if (callback.request == null) {
|
||||
Log.e(TAG, "Request from callback is null; should not happen");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
if (DBG) Log.d(TAG, "Remote exception when registering callback");
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers to receive notifications about data usage on specified networks.
|
||||
*
|
||||
* @see #registerUsageCallback(int, String, long, UsageCallback, Handler)
|
||||
*/
|
||||
public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
|
||||
UsageCallback callback) {
|
||||
registerUsageCallback(networkType, subscriberId, thresholdBytes, callback,
|
||||
null /* handler */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers to receive notifications about data usage on specified networks.
|
||||
*
|
||||
* <p>The callbacks will continue to be called as long as the process is live or
|
||||
* {@link #unregisterUsageCallback} is called.
|
||||
*
|
||||
* @param networkType Type of network to monitor. Either
|
||||
{@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}.
|
||||
* @param subscriberId If applicable, the subscriber id of the network interface.
|
||||
* <p>Starting with API level 29, the {@code subscriberId} is guarded by
|
||||
* additional restrictions. Calling apps that do not meet the new
|
||||
* requirements to access the {@code subscriberId} can provide a {@code
|
||||
* null} value when registering for the mobile network type to receive
|
||||
* notifications for all mobile networks. For additional details see {@link
|
||||
* TelephonyManager#getSubscriberId()}.
|
||||
* <p>Starting with API level 31, calling apps can provide a
|
||||
* {@code subscriberId} with wifi network type to receive usage for
|
||||
* wifi networks which is under the given subscription if applicable.
|
||||
* Otherwise, pass {@code null} when querying all wifi networks.
|
||||
* @param thresholdBytes Threshold in bytes to be notified on.
|
||||
* @param callback The {@link UsageCallback} that the system will call when data usage
|
||||
* has exceeded the specified threshold.
|
||||
* @param handler to dispatch callback events through, otherwise if {@code null} it uses
|
||||
* the calling thread.
|
||||
*/
|
||||
public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
|
||||
UsageCallback callback, @Nullable Handler handler) {
|
||||
NetworkTemplate template = createTemplate(networkType, subscriberId);
|
||||
if (DBG) {
|
||||
Log.d(TAG, "registerUsageCallback called with: {"
|
||||
+ " networkType=" + networkType
|
||||
+ " subscriberId=" + subscriberId
|
||||
+ " thresholdBytes=" + thresholdBytes
|
||||
+ " }");
|
||||
}
|
||||
registerUsageCallback(template, networkType, thresholdBytes, callback, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters callbacks on data usage.
|
||||
*
|
||||
* @param callback The {@link UsageCallback} used when registering.
|
||||
*/
|
||||
public void unregisterUsageCallback(UsageCallback callback) {
|
||||
if (callback == null || callback.request == null
|
||||
|| callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
|
||||
throw new IllegalArgumentException("Invalid UsageCallback");
|
||||
}
|
||||
try {
|
||||
mService.unregisterUsageRequest(callback.request);
|
||||
} catch (RemoteException e) {
|
||||
if (DBG) Log.d(TAG, "Remote exception when unregistering callback");
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for usage callbacks. Should be extended by applications wanting notifications.
|
||||
*/
|
||||
public static abstract class UsageCallback {
|
||||
|
||||
/**
|
||||
* Called when data usage has reached the given threshold.
|
||||
*/
|
||||
public abstract void onThresholdReached(int networkType, String subscriberId);
|
||||
|
||||
/**
|
||||
* @hide used for internal bookkeeping
|
||||
*/
|
||||
private DataUsageRequest request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics
|
||||
* to the system. To unregister, invoke {@link #unregisterNetworkStatsProvider}.
|
||||
* Note that no de-duplication of statistics between providers is performed, so each provider
|
||||
* must only report network traffic that is not being reported by any other provider. Also note
|
||||
* that the provider cannot be re-registered after unregistering.
|
||||
*
|
||||
* @param tag a human readable identifier of the custom network stats provider. This is only
|
||||
* used for debugging.
|
||||
* @param provider the subclass of {@link NetworkStatsProvider} that needs to be
|
||||
* registered to the system.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(anyOf = {
|
||||
android.Manifest.permission.NETWORK_STATS_PROVIDER,
|
||||
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
|
||||
@NonNull public void registerNetworkStatsProvider(
|
||||
@NonNull String tag,
|
||||
@NonNull NetworkStatsProvider provider) {
|
||||
try {
|
||||
if (provider.getProviderCallbackBinder() != null) {
|
||||
throw new IllegalArgumentException("provider is already registered");
|
||||
}
|
||||
final INetworkStatsProviderCallback cbBinder =
|
||||
mService.registerNetworkStatsProvider(tag, provider.getProviderBinder());
|
||||
provider.setProviderCallbackBinder(cbBinder);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters an instance of {@link NetworkStatsProvider}.
|
||||
*
|
||||
* @param provider the subclass of {@link NetworkStatsProvider} that needs to be
|
||||
* unregistered to the system.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(anyOf = {
|
||||
android.Manifest.permission.NETWORK_STATS_PROVIDER,
|
||||
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
|
||||
@NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
|
||||
try {
|
||||
provider.getProviderCallbackBinderOrThrow().unregister();
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
|
||||
final NetworkTemplate template;
|
||||
switch (networkType) {
|
||||
case ConnectivityManager.TYPE_MOBILE:
|
||||
template = subscriberId == null
|
||||
? NetworkTemplate.buildTemplateMobileWildcard()
|
||||
: NetworkTemplate.buildTemplateMobileAll(subscriberId);
|
||||
break;
|
||||
case ConnectivityManager.TYPE_WIFI:
|
||||
template = TextUtils.isEmpty(subscriberId)
|
||||
? NetworkTemplate.buildTemplateWifiWildcard()
|
||||
: NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL,
|
||||
subscriberId);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Cannot create template for network type "
|
||||
+ networkType + ", subscriberId '"
|
||||
+ NetworkIdentityUtils.scrubSubscriberId(subscriberId) + "'.");
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify {@code NetworkStatsService} about network status changed.
|
||||
*
|
||||
* Notifies NetworkStatsService of network state changes for data usage accounting purposes.
|
||||
*
|
||||
* To avoid races that attribute data usage to wrong network, such as new network with
|
||||
* the same interface after SIM hot-swap, this function will not return until
|
||||
* {@code NetworkStatsService} finishes its work of retrieving traffic statistics from
|
||||
* all data sources.
|
||||
*
|
||||
* @param defaultNetworks the list of all networks that could be used by network traffic that
|
||||
* does not explicitly select a network.
|
||||
* @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for
|
||||
* each network that is currently connected.
|
||||
* @param activeIface the active (i.e., connected) default network interface for the calling
|
||||
* uid. Used to determine on which network future calls to
|
||||
* {@link android.net.TrafficStats#incrementOperationCount} applies to.
|
||||
* @param underlyingNetworkInfos the list of underlying network information for all
|
||||
* currently-connected VPNs.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
@RequiresPermission(anyOf = {
|
||||
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
|
||||
android.Manifest.permission.NETWORK_STACK})
|
||||
public void notifyNetworkStatus(
|
||||
@NonNull List<Network> defaultNetworks,
|
||||
@NonNull List<NetworkStateSnapshot> networkStateSnapshots,
|
||||
@Nullable String activeIface,
|
||||
@NonNull List<UnderlyingNetworkInfo> underlyingNetworkInfos) {
|
||||
try {
|
||||
Objects.requireNonNull(defaultNetworks);
|
||||
Objects.requireNonNull(networkStateSnapshots);
|
||||
Objects.requireNonNull(underlyingNetworkInfos);
|
||||
mService.notifyNetworkStatus(defaultNetworks.toArray(new Network[0]),
|
||||
networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface,
|
||||
underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0]));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private static class CallbackHandler extends Handler {
|
||||
private final int mNetworkType;
|
||||
private final String mSubscriberId;
|
||||
private UsageCallback mCallback;
|
||||
|
||||
CallbackHandler(Looper looper, int networkType, String subscriberId,
|
||||
UsageCallback callback) {
|
||||
super(looper);
|
||||
mNetworkType = networkType;
|
||||
mSubscriberId = subscriberId;
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
DataUsageRequest request =
|
||||
(DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY);
|
||||
|
||||
switch (message.what) {
|
||||
case CALLBACK_LIMIT_REACHED: {
|
||||
if (mCallback != null) {
|
||||
mCallback.onThresholdReached(mNetworkType, mSubscriberId);
|
||||
} else {
|
||||
Log.e(TAG, "limit reached with released callback for " + request);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CALLBACK_RELEASED: {
|
||||
if (DBG) Log.d(TAG, "callback released for " + request);
|
||||
mCallback = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Object getObject(Message msg, String key) {
|
||||
return msg.getData().getParcelable(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
framework-t/src/android/net/DataUsageRequest.aidl
Normal file
19
framework-t/src/android/net/DataUsageRequest.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2016, 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.net;
|
||||
|
||||
parcelable DataUsageRequest;
|
||||
112
framework-t/src/android/net/DataUsageRequest.java
Normal file
112
framework-t/src/android/net/DataUsageRequest.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (C) 2016 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.net;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Defines a request to register a callbacks. Used to be notified on data usage via
|
||||
* {@link android.app.usage.NetworkStatsManager#registerDataUsageCallback}.
|
||||
* If no {@code uid}s are set, callbacks are restricted to device-owners,
|
||||
* carrier-privileged apps, or system apps.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class DataUsageRequest implements Parcelable {
|
||||
|
||||
public static final String PARCELABLE_KEY = "DataUsageRequest";
|
||||
public static final int REQUEST_ID_UNSET = 0;
|
||||
|
||||
/**
|
||||
* Identifies the request. {@link DataUsageRequest}s should only be constructed by
|
||||
* the Framework and it is used internally to identify the request.
|
||||
*/
|
||||
public final int requestId;
|
||||
|
||||
/**
|
||||
* {@link NetworkTemplate} describing the network to monitor.
|
||||
*/
|
||||
public final NetworkTemplate template;
|
||||
|
||||
/**
|
||||
* Threshold in bytes to be notified on.
|
||||
*/
|
||||
public final long thresholdInBytes;
|
||||
|
||||
public DataUsageRequest(int requestId, NetworkTemplate template, long thresholdInBytes) {
|
||||
this.requestId = requestId;
|
||||
this.template = template;
|
||||
this.thresholdInBytes = thresholdInBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(requestId);
|
||||
dest.writeParcelable(template, flags);
|
||||
dest.writeLong(thresholdInBytes);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<DataUsageRequest> CREATOR =
|
||||
new Creator<DataUsageRequest>() {
|
||||
@Override
|
||||
public DataUsageRequest createFromParcel(Parcel in) {
|
||||
int requestId = in.readInt();
|
||||
NetworkTemplate template = in.readParcelable(null);
|
||||
long thresholdInBytes = in.readLong();
|
||||
DataUsageRequest result = new DataUsageRequest(requestId, template,
|
||||
thresholdInBytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataUsageRequest[] newArray(int size) {
|
||||
return new DataUsageRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DataUsageRequest [ requestId=" + requestId
|
||||
+ ", networkTemplate=" + template
|
||||
+ ", thresholdInBytes=" + thresholdInBytes + " ]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof DataUsageRequest == false) return false;
|
||||
DataUsageRequest that = (DataUsageRequest) obj;
|
||||
return that.requestId == this.requestId
|
||||
&& Objects.equals(that.template, this.template)
|
||||
&& that.thresholdInBytes == this.thresholdInBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(requestId, template, thresholdInBytes);
|
||||
}
|
||||
|
||||
}
|
||||
97
framework-t/src/android/net/INetworkStatsService.aidl
Normal file
97
framework-t/src/android/net/INetworkStatsService.aidl
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.net;
|
||||
|
||||
import android.net.DataUsageRequest;
|
||||
import android.net.INetworkStatsSession;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkStateSnapshot;
|
||||
import android.net.NetworkStats;
|
||||
import android.net.NetworkStatsHistory;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.net.UnderlyingNetworkInfo;
|
||||
import android.net.netstats.provider.INetworkStatsProvider;
|
||||
import android.net.netstats.provider.INetworkStatsProviderCallback;
|
||||
import android.os.IBinder;
|
||||
import android.os.Messenger;
|
||||
|
||||
/** {@hide} */
|
||||
interface INetworkStatsService {
|
||||
|
||||
/** Start a statistics query session. */
|
||||
@UnsupportedAppUsage
|
||||
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.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
|
||||
INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage);
|
||||
|
||||
/** Return data layer snapshot of UID network usage. */
|
||||
@UnsupportedAppUsage
|
||||
NetworkStats getDataLayerSnapshotForUid(int uid);
|
||||
|
||||
/** Get a detailed snapshot of stats since boot for all UIDs.
|
||||
*
|
||||
* <p>Results will not always be limited to stats on requiredIfaces when specified: stats for
|
||||
* interfaces stacked on the specified interfaces, or for interfaces on which the specified
|
||||
* interfaces are stacked on, will also be included.
|
||||
* @param requiredIfaces Interface names to get data for, or {@link NetworkStats#INTERFACES_ALL}.
|
||||
*/
|
||||
NetworkStats getDetailedUidStats(in String[] requiredIfaces);
|
||||
|
||||
/** Return set of any ifaces associated with mobile networks since boot. */
|
||||
@UnsupportedAppUsage
|
||||
String[] getMobileIfaces();
|
||||
|
||||
/** Increment data layer count of operations performed for UID and tag. */
|
||||
void incrementOperationCount(int uid, int tag, int operationCount);
|
||||
|
||||
/** Notify {@code NetworkStatsService} about network status changed. */
|
||||
void notifyNetworkStatus(
|
||||
in Network[] defaultNetworks,
|
||||
in NetworkStateSnapshot[] snapshots,
|
||||
in String activeIface,
|
||||
in UnderlyingNetworkInfo[] underlyingNetworkInfos);
|
||||
/** Force update of statistics. */
|
||||
@UnsupportedAppUsage
|
||||
void forceUpdate();
|
||||
|
||||
/** Registers a callback on data usage. */
|
||||
DataUsageRequest registerUsageCallback(String callingPackage,
|
||||
in DataUsageRequest request, in Messenger messenger, in IBinder binder);
|
||||
|
||||
/** Unregisters a callback on data usage. */
|
||||
void unregisterUsageRequest(in DataUsageRequest request);
|
||||
|
||||
/** Get the uid stats information since boot */
|
||||
long getUidStats(int uid, int type);
|
||||
|
||||
/** Get the iface stats information since boot */
|
||||
long getIfaceStats(String iface, int type);
|
||||
|
||||
/** Get the total network stats information since boot */
|
||||
long getTotalStats(int type);
|
||||
|
||||
/** Registers a network stats provider */
|
||||
INetworkStatsProviderCallback registerNetworkStatsProvider(String tag,
|
||||
in INetworkStatsProvider provider);
|
||||
}
|
||||
61
framework-t/src/android/net/INetworkStatsSession.aidl
Normal file
61
framework-t/src/android/net/INetworkStatsSession.aidl
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.net;
|
||||
|
||||
import android.net.NetworkStats;
|
||||
import android.net.NetworkStatsHistory;
|
||||
import android.net.NetworkTemplate;
|
||||
|
||||
/** {@hide} */
|
||||
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. */
|
||||
@UnsupportedAppUsage
|
||||
NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
|
||||
/** Return historical network layer stats for traffic that matches template. */
|
||||
@UnsupportedAppUsage
|
||||
NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
|
||||
|
||||
/**
|
||||
* Return network layer usage summary per UID for traffic that matches template.
|
||||
*
|
||||
* <p>The resulting {@code NetworkStats#getElapsedRealtime()} contains time delta between
|
||||
* {@code start} and {@code end}.
|
||||
*
|
||||
* @param template - a predicate to filter netstats.
|
||||
* @param start - start of the range, timestamp in milliseconds since the epoch.
|
||||
* @param end - end of the range, timestamp in milliseconds since the epoch.
|
||||
* @param includeTags - includes data usage tags if true.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
|
||||
/** Return historical network layer stats for specific UID traffic that matches template. */
|
||||
@UnsupportedAppUsage
|
||||
NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
|
||||
/** Return historical network layer stats for specific UID traffic that matches template. */
|
||||
NetworkStatsHistory getHistoryIntervalForUid(in NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end);
|
||||
|
||||
/** Return array of uids that have stats and are accessible to the calling user */
|
||||
int[] getRelevantUids();
|
||||
|
||||
@UnsupportedAppUsage
|
||||
void close();
|
||||
|
||||
}
|
||||
286
framework-t/src/android/net/NetworkIdentity.java
Normal file
286
framework-t/src/android/net/NetworkIdentity.java
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.net;
|
||||
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.service.NetworkIdentityProto;
|
||||
import android.telephony.Annotation.NetworkType;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.net.module.util.NetworkCapabilitiesUtils;
|
||||
import com.android.net.module.util.NetworkIdentityUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Network definition that includes strong identity. Analogous to combining
|
||||
* {@link NetworkCapabilities} and an IMSI.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class NetworkIdentity implements Comparable<NetworkIdentity> {
|
||||
private static final String TAG = "NetworkIdentity";
|
||||
|
||||
public static final int SUBTYPE_COMBINED = -1;
|
||||
|
||||
/**
|
||||
* Network has no {@code NetworkCapabilities#NET_CAPABILITY_OEM_*}.
|
||||
* @hide
|
||||
*/
|
||||
public static final int OEM_NONE = 0x0;
|
||||
/**
|
||||
* Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}.
|
||||
* @hide
|
||||
*/
|
||||
public static final int OEM_PAID = 0x1;
|
||||
/**
|
||||
* Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}.
|
||||
* @hide
|
||||
*/
|
||||
public static final int OEM_PRIVATE = 0x2;
|
||||
|
||||
final int mType;
|
||||
final int mSubType;
|
||||
final String mSubscriberId;
|
||||
final String mNetworkId;
|
||||
final boolean mRoaming;
|
||||
final boolean mMetered;
|
||||
final boolean mDefaultNetwork;
|
||||
final int mOemManaged;
|
||||
|
||||
public NetworkIdentity(
|
||||
int type, int subType, String subscriberId, String networkId, boolean roaming,
|
||||
boolean metered, boolean defaultNetwork, int oemManaged) {
|
||||
mType = type;
|
||||
mSubType = subType;
|
||||
mSubscriberId = subscriberId;
|
||||
mNetworkId = networkId;
|
||||
mRoaming = roaming;
|
||||
mMetered = metered;
|
||||
mDefaultNetwork = defaultNetwork;
|
||||
mOemManaged = oemManaged;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered,
|
||||
mDefaultNetwork, mOemManaged);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof NetworkIdentity) {
|
||||
final NetworkIdentity ident = (NetworkIdentity) obj;
|
||||
return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming
|
||||
&& Objects.equals(mSubscriberId, ident.mSubscriberId)
|
||||
&& Objects.equals(mNetworkId, ident.mNetworkId)
|
||||
&& mMetered == ident.mMetered
|
||||
&& mDefaultNetwork == ident.mDefaultNetwork
|
||||
&& mOemManaged == ident.mOemManaged;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder("{");
|
||||
builder.append("type=").append(mType);
|
||||
builder.append(", subType=");
|
||||
if (mSubType == SUBTYPE_COMBINED) {
|
||||
builder.append("COMBINED");
|
||||
} else {
|
||||
builder.append(mSubType);
|
||||
}
|
||||
if (mSubscriberId != null) {
|
||||
builder.append(", subscriberId=")
|
||||
.append(NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
|
||||
}
|
||||
if (mNetworkId != null) {
|
||||
builder.append(", networkId=").append(mNetworkId);
|
||||
}
|
||||
if (mRoaming) {
|
||||
builder.append(", ROAMING");
|
||||
}
|
||||
builder.append(", metered=").append(mMetered);
|
||||
builder.append(", defaultNetwork=").append(mDefaultNetwork);
|
||||
builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged));
|
||||
return builder.append("}").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the human readable representation of a bitfield representing the OEM managed state of a
|
||||
* network.
|
||||
*/
|
||||
static String getOemManagedNames(int oemManaged) {
|
||||
if (oemManaged == OEM_NONE) {
|
||||
return "OEM_NONE";
|
||||
}
|
||||
final int[] bitPositions = NetworkCapabilitiesUtils.unpackBits(oemManaged);
|
||||
final ArrayList<String> oemManagedNames = new ArrayList<String>();
|
||||
for (int position : bitPositions) {
|
||||
oemManagedNames.add(nameOfOemManaged(1 << position));
|
||||
}
|
||||
return String.join(",", oemManagedNames);
|
||||
}
|
||||
|
||||
private static String nameOfOemManaged(int oemManagedBit) {
|
||||
switch (oemManagedBit) {
|
||||
case OEM_PAID:
|
||||
return "OEM_PAID";
|
||||
case OEM_PRIVATE:
|
||||
return "OEM_PRIVATE";
|
||||
default:
|
||||
return "Invalid(" + oemManagedBit + ")";
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpDebug(ProtoOutputStream proto, long tag) {
|
||||
final long start = proto.start(tag);
|
||||
|
||||
proto.write(NetworkIdentityProto.TYPE, mType);
|
||||
|
||||
// Not dumping mSubType, subtypes are no longer supported.
|
||||
|
||||
if (mSubscriberId != null) {
|
||||
proto.write(NetworkIdentityProto.SUBSCRIBER_ID,
|
||||
NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
|
||||
}
|
||||
proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId);
|
||||
proto.write(NetworkIdentityProto.ROAMING, mRoaming);
|
||||
proto.write(NetworkIdentityProto.METERED, mMetered);
|
||||
proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork);
|
||||
proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged);
|
||||
|
||||
proto.end(start);
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
public int getSubType() {
|
||||
return mSubType;
|
||||
}
|
||||
|
||||
public String getSubscriberId() {
|
||||
return mSubscriberId;
|
||||
}
|
||||
|
||||
public String getNetworkId() {
|
||||
return mNetworkId;
|
||||
}
|
||||
|
||||
public boolean getRoaming() {
|
||||
return mRoaming;
|
||||
}
|
||||
|
||||
public boolean getMetered() {
|
||||
return mMetered;
|
||||
}
|
||||
|
||||
public boolean getDefaultNetwork() {
|
||||
return mDefaultNetwork;
|
||||
}
|
||||
|
||||
public int getOemManaged() {
|
||||
return mOemManaged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link NetworkIdentity} from the given {@link NetworkStateSnapshot} and
|
||||
* {@code subType}, assuming that any mobile networks are using the current IMSI.
|
||||
* The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_*
|
||||
* constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
|
||||
*/
|
||||
public static NetworkIdentity buildNetworkIdentity(Context context,
|
||||
NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) {
|
||||
final int legacyType = snapshot.getLegacyType();
|
||||
|
||||
final String subscriberId = snapshot.getSubscriberId();
|
||||
String networkId = null;
|
||||
boolean roaming = !snapshot.getNetworkCapabilities().hasCapability(
|
||||
NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
|
||||
boolean metered = !(snapshot.getNetworkCapabilities().hasCapability(
|
||||
NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
|
||||
|| snapshot.getNetworkCapabilities().hasCapability(
|
||||
NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED));
|
||||
|
||||
final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities());
|
||||
|
||||
if (legacyType == TYPE_WIFI) {
|
||||
networkId = snapshot.getNetworkCapabilities().getSsid();
|
||||
if (networkId == null) {
|
||||
final WifiManager wifi = context.getSystemService(WifiManager.class);
|
||||
final WifiInfo info = wifi.getConnectionInfo();
|
||||
networkId = info != null ? info.getSSID() : null;
|
||||
}
|
||||
}
|
||||
|
||||
return new NetworkIdentity(legacyType, subType, subscriberId, networkId, roaming, metered,
|
||||
defaultNetwork, oemManaged);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a bitfield of {@code NetworkIdentity.OEM_*} based on {@link NetworkCapabilities}.
|
||||
* @hide
|
||||
*/
|
||||
public static int getOemBitfield(NetworkCapabilities nc) {
|
||||
int oemManaged = OEM_NONE;
|
||||
|
||||
if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID)) {
|
||||
oemManaged |= OEM_PAID;
|
||||
}
|
||||
if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE)) {
|
||||
oemManaged |= OEM_PRIVATE;
|
||||
}
|
||||
|
||||
return oemManaged;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(NetworkIdentity another) {
|
||||
int res = Integer.compare(mType, another.mType);
|
||||
if (res == 0) {
|
||||
res = Integer.compare(mSubType, another.mSubType);
|
||||
}
|
||||
if (res == 0 && mSubscriberId != null && another.mSubscriberId != null) {
|
||||
res = mSubscriberId.compareTo(another.mSubscriberId);
|
||||
}
|
||||
if (res == 0 && mNetworkId != null && another.mNetworkId != null) {
|
||||
res = mNetworkId.compareTo(another.mNetworkId);
|
||||
}
|
||||
if (res == 0) {
|
||||
res = Boolean.compare(mRoaming, another.mRoaming);
|
||||
}
|
||||
if (res == 0) {
|
||||
res = Boolean.compare(mMetered, another.mMetered);
|
||||
}
|
||||
if (res == 0) {
|
||||
res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork);
|
||||
}
|
||||
if (res == 0) {
|
||||
res = Integer.compare(mOemManaged, another.mOemManaged);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
173
framework-t/src/android/net/NetworkStateSnapshot.java
Normal file
173
framework-t/src/android/net/NetworkStateSnapshot.java
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.net;
|
||||
|
||||
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.net.module.util.NetworkIdentityUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Snapshot of network state.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
public final class NetworkStateSnapshot implements Parcelable {
|
||||
/** The network associated with this snapshot. */
|
||||
@NonNull
|
||||
private final Network mNetwork;
|
||||
|
||||
/** The {@link NetworkCapabilities} of the network associated with this snapshot. */
|
||||
@NonNull
|
||||
private final NetworkCapabilities mNetworkCapabilities;
|
||||
|
||||
/** The {@link LinkProperties} of the network associated with this snapshot. */
|
||||
@NonNull
|
||||
private final LinkProperties mLinkProperties;
|
||||
|
||||
/**
|
||||
* The Subscriber Id of the network associated with this snapshot. See
|
||||
* {@link android.telephony.TelephonyManager#getSubscriberId()}.
|
||||
*/
|
||||
@Nullable
|
||||
private final String mSubscriberId;
|
||||
|
||||
/**
|
||||
* The legacy type of the network associated with this snapshot. See
|
||||
* {@code ConnectivityManager#TYPE_*}.
|
||||
*/
|
||||
private final int mLegacyType;
|
||||
|
||||
public NetworkStateSnapshot(@NonNull Network network,
|
||||
@NonNull NetworkCapabilities networkCapabilities,
|
||||
@NonNull LinkProperties linkProperties,
|
||||
@Nullable String subscriberId, int legacyType) {
|
||||
mNetwork = Objects.requireNonNull(network);
|
||||
mNetworkCapabilities = Objects.requireNonNull(networkCapabilities);
|
||||
mLinkProperties = Objects.requireNonNull(linkProperties);
|
||||
mSubscriberId = subscriberId;
|
||||
mLegacyType = legacyType;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public NetworkStateSnapshot(@NonNull Parcel in) {
|
||||
mNetwork = in.readParcelable(null);
|
||||
mNetworkCapabilities = in.readParcelable(null);
|
||||
mLinkProperties = in.readParcelable(null);
|
||||
mSubscriberId = in.readString();
|
||||
mLegacyType = in.readInt();
|
||||
}
|
||||
|
||||
/** Get the network associated with this snapshot */
|
||||
@NonNull
|
||||
public Network getNetwork() {
|
||||
return mNetwork;
|
||||
}
|
||||
|
||||
/** Get {@link NetworkCapabilities} of the network associated with this snapshot. */
|
||||
@NonNull
|
||||
public NetworkCapabilities getNetworkCapabilities() {
|
||||
return mNetworkCapabilities;
|
||||
}
|
||||
|
||||
/** Get the {@link LinkProperties} of the network associated with this snapshot. */
|
||||
@NonNull
|
||||
public LinkProperties getLinkProperties() {
|
||||
return mLinkProperties;
|
||||
}
|
||||
|
||||
/** Get the Subscriber Id of the network associated with this snapshot. */
|
||||
@Nullable
|
||||
public String getSubscriberId() {
|
||||
return mSubscriberId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy type of the network associated with this snapshot.
|
||||
* @return the legacy network type. See {@code ConnectivityManager#TYPE_*}.
|
||||
*/
|
||||
public int getLegacyType() {
|
||||
return mLegacyType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel out, int flags) {
|
||||
out.writeParcelable(mNetwork, flags);
|
||||
out.writeParcelable(mNetworkCapabilities, flags);
|
||||
out.writeParcelable(mLinkProperties, flags);
|
||||
out.writeString(mSubscriberId);
|
||||
out.writeInt(mLegacyType);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<NetworkStateSnapshot> CREATOR =
|
||||
new Creator<NetworkStateSnapshot>() {
|
||||
@NonNull
|
||||
@Override
|
||||
public NetworkStateSnapshot createFromParcel(@NonNull Parcel in) {
|
||||
return new NetworkStateSnapshot(in);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public NetworkStateSnapshot[] newArray(int size) {
|
||||
return new NetworkStateSnapshot[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof NetworkStateSnapshot)) return false;
|
||||
NetworkStateSnapshot that = (NetworkStateSnapshot) o;
|
||||
return mLegacyType == that.mLegacyType
|
||||
&& Objects.equals(mNetwork, that.mNetwork)
|
||||
&& Objects.equals(mNetworkCapabilities, that.mNetworkCapabilities)
|
||||
&& Objects.equals(mLinkProperties, that.mLinkProperties)
|
||||
&& Objects.equals(mSubscriberId, that.mSubscriberId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mNetwork,
|
||||
mNetworkCapabilities, mLinkProperties, mSubscriberId, mLegacyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NetworkStateSnapshot{"
|
||||
+ "network=" + mNetwork
|
||||
+ ", networkCapabilities=" + mNetworkCapabilities
|
||||
+ ", linkProperties=" + mLinkProperties
|
||||
+ ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(mSubscriberId) + '\''
|
||||
+ ", legacyType=" + mLegacyType
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
1738
framework-t/src/android/net/NetworkStats.java
Normal file
1738
framework-t/src/android/net/NetworkStats.java
Normal file
File diff suppressed because it is too large
Load Diff
19
framework-t/src/android/net/NetworkStatsHistory.aidl
Normal file
19
framework-t/src/android/net/NetworkStatsHistory.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2011, 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.net;
|
||||
|
||||
parcelable NetworkStatsHistory;
|
||||
881
framework-t/src/android/net/NetworkStatsHistory.java
Normal file
881
framework-t/src/android/net/NetworkStatsHistory.java
Normal file
@@ -0,0 +1,881 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.net;
|
||||
|
||||
import static android.net.NetworkStats.IFACE_ALL;
|
||||
import static android.net.NetworkStats.SET_DEFAULT;
|
||||
import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray;
|
||||
import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray;
|
||||
import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray;
|
||||
import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
|
||||
import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
|
||||
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
|
||||
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
|
||||
|
||||
import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
|
||||
import static com.android.internal.util.ArrayUtils.total;
|
||||
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.service.NetworkStatsHistoryBucketProto;
|
||||
import android.service.NetworkStatsHistoryProto;
|
||||
import android.util.MathUtils;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.io.CharArrayWriter;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.ProtocolException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Collection of historical network statistics, recorded into equally-sized
|
||||
* "buckets" in time. Internally it stores data in {@code long} series for more
|
||||
* efficient persistence.
|
||||
* <p>
|
||||
* Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for
|
||||
* {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is
|
||||
* sorted at all times.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class NetworkStatsHistory implements Parcelable {
|
||||
private static final int VERSION_INIT = 1;
|
||||
private static final int VERSION_ADD_PACKETS = 2;
|
||||
private static final int VERSION_ADD_ACTIVE = 3;
|
||||
|
||||
public static final int FIELD_ACTIVE_TIME = 0x01;
|
||||
public static final int FIELD_RX_BYTES = 0x02;
|
||||
public static final int FIELD_RX_PACKETS = 0x04;
|
||||
public static final int FIELD_TX_BYTES = 0x08;
|
||||
public static final int FIELD_TX_PACKETS = 0x10;
|
||||
public static final int FIELD_OPERATIONS = 0x20;
|
||||
|
||||
public static final int FIELD_ALL = 0xFFFFFFFF;
|
||||
|
||||
private long bucketDuration;
|
||||
private int bucketCount;
|
||||
private long[] bucketStart;
|
||||
private long[] activeTime;
|
||||
private long[] rxBytes;
|
||||
private long[] rxPackets;
|
||||
private long[] txBytes;
|
||||
private long[] txPackets;
|
||||
private long[] operations;
|
||||
private long totalBytes;
|
||||
|
||||
public static class Entry {
|
||||
public static final long UNKNOWN = -1;
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public long bucketDuration;
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public long bucketStart;
|
||||
public long activeTime;
|
||||
@UnsupportedAppUsage
|
||||
public long rxBytes;
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public long rxPackets;
|
||||
@UnsupportedAppUsage
|
||||
public long txBytes;
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public long txPackets;
|
||||
public long operations;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public NetworkStatsHistory(long bucketDuration) {
|
||||
this(bucketDuration, 10, FIELD_ALL);
|
||||
}
|
||||
|
||||
public NetworkStatsHistory(long bucketDuration, int initialSize) {
|
||||
this(bucketDuration, initialSize, FIELD_ALL);
|
||||
}
|
||||
|
||||
public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) {
|
||||
this.bucketDuration = bucketDuration;
|
||||
bucketStart = new long[initialSize];
|
||||
if ((fields & FIELD_ACTIVE_TIME) != 0) activeTime = new long[initialSize];
|
||||
if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize];
|
||||
if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize];
|
||||
if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize];
|
||||
if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
|
||||
if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
|
||||
bucketCount = 0;
|
||||
totalBytes = 0;
|
||||
}
|
||||
|
||||
public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) {
|
||||
this(bucketDuration, existing.estimateResizeBuckets(bucketDuration));
|
||||
recordEntireHistory(existing);
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public NetworkStatsHistory(Parcel in) {
|
||||
bucketDuration = in.readLong();
|
||||
bucketStart = readLongArray(in);
|
||||
activeTime = readLongArray(in);
|
||||
rxBytes = readLongArray(in);
|
||||
rxPackets = readLongArray(in);
|
||||
txBytes = readLongArray(in);
|
||||
txPackets = readLongArray(in);
|
||||
operations = readLongArray(in);
|
||||
bucketCount = bucketStart.length;
|
||||
totalBytes = in.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeLong(bucketDuration);
|
||||
writeLongArray(out, bucketStart, bucketCount);
|
||||
writeLongArray(out, activeTime, bucketCount);
|
||||
writeLongArray(out, rxBytes, bucketCount);
|
||||
writeLongArray(out, rxPackets, bucketCount);
|
||||
writeLongArray(out, txBytes, bucketCount);
|
||||
writeLongArray(out, txPackets, bucketCount);
|
||||
writeLongArray(out, operations, bucketCount);
|
||||
out.writeLong(totalBytes);
|
||||
}
|
||||
|
||||
public NetworkStatsHistory(DataInput in) throws IOException {
|
||||
final int version = in.readInt();
|
||||
switch (version) {
|
||||
case VERSION_INIT: {
|
||||
bucketDuration = in.readLong();
|
||||
bucketStart = readFullLongArray(in);
|
||||
rxBytes = readFullLongArray(in);
|
||||
rxPackets = new long[bucketStart.length];
|
||||
txBytes = readFullLongArray(in);
|
||||
txPackets = new long[bucketStart.length];
|
||||
operations = new long[bucketStart.length];
|
||||
bucketCount = bucketStart.length;
|
||||
totalBytes = total(rxBytes) + total(txBytes);
|
||||
break;
|
||||
}
|
||||
case VERSION_ADD_PACKETS:
|
||||
case VERSION_ADD_ACTIVE: {
|
||||
bucketDuration = in.readLong();
|
||||
bucketStart = readVarLongArray(in);
|
||||
activeTime = (version >= VERSION_ADD_ACTIVE) ? readVarLongArray(in)
|
||||
: new long[bucketStart.length];
|
||||
rxBytes = readVarLongArray(in);
|
||||
rxPackets = readVarLongArray(in);
|
||||
txBytes = readVarLongArray(in);
|
||||
txPackets = readVarLongArray(in);
|
||||
operations = readVarLongArray(in);
|
||||
bucketCount = bucketStart.length;
|
||||
totalBytes = total(rxBytes) + total(txBytes);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new ProtocolException("unexpected version: " + version);
|
||||
}
|
||||
}
|
||||
|
||||
if (bucketStart.length != bucketCount || rxBytes.length != bucketCount
|
||||
|| rxPackets.length != bucketCount || txBytes.length != bucketCount
|
||||
|| txPackets.length != bucketCount || operations.length != bucketCount) {
|
||||
throw new ProtocolException("Mismatched history lengths");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToStream(DataOutput out) throws IOException {
|
||||
out.writeInt(VERSION_ADD_ACTIVE);
|
||||
out.writeLong(bucketDuration);
|
||||
writeVarLongArray(out, bucketStart, bucketCount);
|
||||
writeVarLongArray(out, activeTime, bucketCount);
|
||||
writeVarLongArray(out, rxBytes, bucketCount);
|
||||
writeVarLongArray(out, rxPackets, bucketCount);
|
||||
writeVarLongArray(out, txBytes, bucketCount);
|
||||
writeVarLongArray(out, txPackets, bucketCount);
|
||||
writeVarLongArray(out, operations, bucketCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public int size() {
|
||||
return bucketCount;
|
||||
}
|
||||
|
||||
public long getBucketDuration() {
|
||||
return bucketDuration;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public long getStart() {
|
||||
if (bucketCount > 0) {
|
||||
return bucketStart[0];
|
||||
} else {
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public long getEnd() {
|
||||
if (bucketCount > 0) {
|
||||
return bucketStart[bucketCount - 1] + bucketDuration;
|
||||
} else {
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return total bytes represented by this history.
|
||||
*/
|
||||
public long getTotalBytes() {
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return index of bucket that contains or is immediately before the
|
||||
* requested time.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public int getIndexBefore(long time) {
|
||||
int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
|
||||
if (index < 0) {
|
||||
index = (~index) - 1;
|
||||
} else {
|
||||
index -= 1;
|
||||
}
|
||||
return MathUtils.constrain(index, 0, bucketCount - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return index of bucket that contains or is immediately after the
|
||||
* requested time.
|
||||
*/
|
||||
public int getIndexAfter(long time) {
|
||||
int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
|
||||
if (index < 0) {
|
||||
index = ~index;
|
||||
} else {
|
||||
index += 1;
|
||||
}
|
||||
return MathUtils.constrain(index, 0, bucketCount - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return specific stats entry.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public Entry getValues(int i, Entry recycle) {
|
||||
final Entry entry = recycle != null ? recycle : new Entry();
|
||||
entry.bucketStart = bucketStart[i];
|
||||
entry.bucketDuration = bucketDuration;
|
||||
entry.activeTime = getLong(activeTime, i, UNKNOWN);
|
||||
entry.rxBytes = getLong(rxBytes, i, UNKNOWN);
|
||||
entry.rxPackets = getLong(rxPackets, i, UNKNOWN);
|
||||
entry.txBytes = getLong(txBytes, i, UNKNOWN);
|
||||
entry.txPackets = getLong(txPackets, i, UNKNOWN);
|
||||
entry.operations = getLong(operations, i, UNKNOWN);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void setValues(int i, Entry entry) {
|
||||
// Unwind old values
|
||||
if (rxBytes != null) totalBytes -= rxBytes[i];
|
||||
if (txBytes != null) totalBytes -= txBytes[i];
|
||||
|
||||
bucketStart[i] = entry.bucketStart;
|
||||
setLong(activeTime, i, entry.activeTime);
|
||||
setLong(rxBytes, i, entry.rxBytes);
|
||||
setLong(rxPackets, i, entry.rxPackets);
|
||||
setLong(txBytes, i, entry.txBytes);
|
||||
setLong(txPackets, i, entry.txPackets);
|
||||
setLong(operations, i, entry.operations);
|
||||
|
||||
// Apply new values
|
||||
if (rxBytes != null) totalBytes += rxBytes[i];
|
||||
if (txBytes != null) totalBytes += txBytes[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that data traffic occurred in the given time range. Will
|
||||
* distribute across internal buckets, creating new buckets as needed.
|
||||
*/
|
||||
@Deprecated
|
||||
public void recordData(long start, long end, long rxBytes, long txBytes) {
|
||||
recordData(start, end, new NetworkStats.Entry(
|
||||
IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that data traffic occurred in the given time range. Will
|
||||
* distribute across internal buckets, creating new buckets as needed.
|
||||
*/
|
||||
public void recordData(long start, long end, NetworkStats.Entry entry) {
|
||||
long rxBytes = entry.rxBytes;
|
||||
long rxPackets = entry.rxPackets;
|
||||
long txBytes = entry.txBytes;
|
||||
long txPackets = entry.txPackets;
|
||||
long operations = entry.operations;
|
||||
|
||||
if (entry.isNegative()) {
|
||||
throw new IllegalArgumentException("tried recording negative data");
|
||||
}
|
||||
if (entry.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create any buckets needed by this range
|
||||
ensureBuckets(start, end);
|
||||
|
||||
// distribute data usage into buckets
|
||||
long duration = end - start;
|
||||
final int startIndex = getIndexAfter(end);
|
||||
for (int i = startIndex; i >= 0; i--) {
|
||||
final long curStart = bucketStart[i];
|
||||
final long curEnd = curStart + bucketDuration;
|
||||
|
||||
// bucket is older than record; we're finished
|
||||
if (curEnd < start) break;
|
||||
// bucket is newer than record; keep looking
|
||||
if (curStart > end) continue;
|
||||
|
||||
final long overlap = Math.min(curEnd, end) - Math.max(curStart, start);
|
||||
if (overlap <= 0) continue;
|
||||
|
||||
// integer math each time is faster than floating point
|
||||
final long fracRxBytes = multiplySafeByRational(rxBytes, overlap, duration);
|
||||
final long fracRxPackets = multiplySafeByRational(rxPackets, overlap, duration);
|
||||
final long fracTxBytes = multiplySafeByRational(txBytes, overlap, duration);
|
||||
final long fracTxPackets = multiplySafeByRational(txPackets, overlap, duration);
|
||||
final long fracOperations = multiplySafeByRational(operations, overlap, duration);
|
||||
|
||||
|
||||
addLong(activeTime, i, overlap);
|
||||
addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes;
|
||||
addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets;
|
||||
addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes;
|
||||
addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets;
|
||||
addLong(this.operations, i, fracOperations); operations -= fracOperations;
|
||||
|
||||
duration -= overlap;
|
||||
}
|
||||
|
||||
totalBytes += entry.rxBytes + entry.txBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record an entire {@link NetworkStatsHistory} into this history. Usually
|
||||
* for combining together stats for external reporting.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public void recordEntireHistory(NetworkStatsHistory input) {
|
||||
recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record given {@link NetworkStatsHistory} into this history, copying only
|
||||
* buckets that atomically occur in the inclusive time range. Doesn't
|
||||
* interpolate across partial buckets.
|
||||
*/
|
||||
public void recordHistory(NetworkStatsHistory input, long start, long end) {
|
||||
final NetworkStats.Entry entry = new NetworkStats.Entry(
|
||||
IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
|
||||
for (int i = 0; i < input.bucketCount; i++) {
|
||||
final long bucketStart = input.bucketStart[i];
|
||||
final long bucketEnd = bucketStart + input.bucketDuration;
|
||||
|
||||
// skip when bucket is outside requested range
|
||||
if (bucketStart < start || bucketEnd > end) continue;
|
||||
|
||||
entry.rxBytes = getLong(input.rxBytes, i, 0L);
|
||||
entry.rxPackets = getLong(input.rxPackets, i, 0L);
|
||||
entry.txBytes = getLong(input.txBytes, i, 0L);
|
||||
entry.txPackets = getLong(input.txPackets, i, 0L);
|
||||
entry.operations = getLong(input.operations, i, 0L);
|
||||
|
||||
recordData(bucketStart, bucketEnd, entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that buckets exist for given time range, creating as needed.
|
||||
*/
|
||||
private void ensureBuckets(long start, long end) {
|
||||
// normalize incoming range to bucket boundaries
|
||||
start -= start % bucketDuration;
|
||||
end += (bucketDuration - (end % bucketDuration)) % bucketDuration;
|
||||
|
||||
for (long now = start; now < end; now += bucketDuration) {
|
||||
// try finding existing bucket
|
||||
final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now);
|
||||
if (index < 0) {
|
||||
// bucket missing, create and insert
|
||||
insertBucket(~index, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert new bucket at requested index and starting time.
|
||||
*/
|
||||
private void insertBucket(int index, long start) {
|
||||
// create more buckets when needed
|
||||
if (bucketCount >= bucketStart.length) {
|
||||
final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
|
||||
bucketStart = Arrays.copyOf(bucketStart, newLength);
|
||||
if (activeTime != null) activeTime = Arrays.copyOf(activeTime, newLength);
|
||||
if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength);
|
||||
if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength);
|
||||
if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength);
|
||||
if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength);
|
||||
if (operations != null) operations = Arrays.copyOf(operations, newLength);
|
||||
}
|
||||
|
||||
// create gap when inserting bucket in middle
|
||||
if (index < bucketCount) {
|
||||
final int dstPos = index + 1;
|
||||
final int length = bucketCount - index;
|
||||
|
||||
System.arraycopy(bucketStart, index, bucketStart, dstPos, length);
|
||||
if (activeTime != null) System.arraycopy(activeTime, index, activeTime, dstPos, length);
|
||||
if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
|
||||
if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
|
||||
if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length);
|
||||
if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length);
|
||||
if (operations != null) System.arraycopy(operations, index, operations, dstPos, length);
|
||||
}
|
||||
|
||||
bucketStart[index] = start;
|
||||
setLong(activeTime, index, 0L);
|
||||
setLong(rxBytes, index, 0L);
|
||||
setLong(rxPackets, index, 0L);
|
||||
setLong(txBytes, index, 0L);
|
||||
setLong(txPackets, index, 0L);
|
||||
setLong(operations, index, 0L);
|
||||
bucketCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all data stored in this object.
|
||||
*/
|
||||
public void clear() {
|
||||
bucketStart = EmptyArray.LONG;
|
||||
if (activeTime != null) activeTime = EmptyArray.LONG;
|
||||
if (rxBytes != null) rxBytes = EmptyArray.LONG;
|
||||
if (rxPackets != null) rxPackets = EmptyArray.LONG;
|
||||
if (txBytes != null) txBytes = EmptyArray.LONG;
|
||||
if (txPackets != null) txPackets = EmptyArray.LONG;
|
||||
if (operations != null) operations = EmptyArray.LONG;
|
||||
bucketCount = 0;
|
||||
totalBytes = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove buckets older than requested cutoff.
|
||||
*/
|
||||
@Deprecated
|
||||
public void removeBucketsBefore(long cutoff) {
|
||||
int i;
|
||||
for (i = 0; i < bucketCount; i++) {
|
||||
final long curStart = bucketStart[i];
|
||||
final long curEnd = curStart + bucketDuration;
|
||||
|
||||
// cutoff happens before or during this bucket; everything before
|
||||
// this bucket should be removed.
|
||||
if (curEnd > cutoff) break;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
final int length = bucketStart.length;
|
||||
bucketStart = Arrays.copyOfRange(bucketStart, i, length);
|
||||
if (activeTime != null) activeTime = Arrays.copyOfRange(activeTime, i, length);
|
||||
if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length);
|
||||
if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length);
|
||||
if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length);
|
||||
if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
|
||||
if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
|
||||
bucketCount -= i;
|
||||
|
||||
// TODO: subtract removed values from totalBytes
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return interpolated data usage across the requested range. Interpolates
|
||||
* across buckets, so values may be rounded slightly.
|
||||
*
|
||||
* <p>If the active bucket is not completed yet, it returns the proportional value of it
|
||||
* based on its duration and the {@code end} param.
|
||||
*
|
||||
* @param start - start of the range, timestamp in milliseconds since the epoch.
|
||||
* @param end - end of the range, timestamp in milliseconds since the epoch.
|
||||
* @param recycle - entry instance for performance, could be null.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public Entry getValues(long start, long end, Entry recycle) {
|
||||
return getValues(start, end, Long.MAX_VALUE, recycle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return interpolated data usage across the requested range. Interpolates
|
||||
* across buckets, so values may be rounded slightly.
|
||||
*
|
||||
* @param start - start of the range, timestamp in milliseconds since the epoch.
|
||||
* @param end - end of the range, timestamp in milliseconds since the epoch.
|
||||
* @param now - current timestamp in milliseconds since the epoch (wall clock).
|
||||
* @param recycle - entry instance for performance, could be null.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public Entry getValues(long start, long end, long now, Entry recycle) {
|
||||
final Entry entry = recycle != null ? recycle : new Entry();
|
||||
entry.bucketDuration = end - start;
|
||||
entry.bucketStart = start;
|
||||
entry.activeTime = activeTime != null ? 0 : UNKNOWN;
|
||||
entry.rxBytes = rxBytes != null ? 0 : UNKNOWN;
|
||||
entry.rxPackets = rxPackets != null ? 0 : UNKNOWN;
|
||||
entry.txBytes = txBytes != null ? 0 : UNKNOWN;
|
||||
entry.txPackets = txPackets != null ? 0 : UNKNOWN;
|
||||
entry.operations = operations != null ? 0 : UNKNOWN;
|
||||
|
||||
final int startIndex = getIndexAfter(end);
|
||||
for (int i = startIndex; i >= 0; i--) {
|
||||
final long curStart = bucketStart[i];
|
||||
long curEnd = curStart + bucketDuration;
|
||||
|
||||
// bucket is older than request; we're finished
|
||||
if (curEnd <= start) break;
|
||||
// bucket is newer than request; keep looking
|
||||
if (curStart >= end) continue;
|
||||
|
||||
// the active bucket is shorter then a normal completed bucket
|
||||
if (curEnd > now) curEnd = now;
|
||||
// usually this is simply bucketDuration
|
||||
final long bucketSpan = curEnd - curStart;
|
||||
// prevent division by zero
|
||||
if (bucketSpan <= 0) continue;
|
||||
|
||||
final long overlapEnd = curEnd < end ? curEnd : end;
|
||||
final long overlapStart = curStart > start ? curStart : start;
|
||||
final long overlap = overlapEnd - overlapStart;
|
||||
if (overlap <= 0) continue;
|
||||
|
||||
// integer math each time is faster than floating point
|
||||
if (activeTime != null) {
|
||||
entry.activeTime += multiplySafeByRational(activeTime[i], overlap, bucketSpan);
|
||||
}
|
||||
if (rxBytes != null) {
|
||||
entry.rxBytes += multiplySafeByRational(rxBytes[i], overlap, bucketSpan);
|
||||
}
|
||||
if (rxPackets != null) {
|
||||
entry.rxPackets += multiplySafeByRational(rxPackets[i], overlap, bucketSpan);
|
||||
}
|
||||
if (txBytes != null) {
|
||||
entry.txBytes += multiplySafeByRational(txBytes[i], overlap, bucketSpan);
|
||||
}
|
||||
if (txPackets != null) {
|
||||
entry.txPackets += multiplySafeByRational(txPackets[i], overlap, bucketSpan);
|
||||
}
|
||||
if (operations != null) {
|
||||
entry.operations += multiplySafeByRational(operations[i], overlap, bucketSpan);
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated only for temporary testing
|
||||
*/
|
||||
@Deprecated
|
||||
public void generateRandom(long start, long end, long bytes) {
|
||||
final Random r = new Random();
|
||||
|
||||
final float fractionRx = r.nextFloat();
|
||||
final long rxBytes = (long) (bytes * fractionRx);
|
||||
final long txBytes = (long) (bytes * (1 - fractionRx));
|
||||
|
||||
final long rxPackets = rxBytes / 1024;
|
||||
final long txPackets = txBytes / 1024;
|
||||
final long operations = rxBytes / 2048;
|
||||
|
||||
generateRandom(start, end, rxBytes, rxPackets, txBytes, txPackets, operations, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated only for temporary testing
|
||||
*/
|
||||
@Deprecated
|
||||
public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes,
|
||||
long txPackets, long operations, Random r) {
|
||||
ensureBuckets(start, end);
|
||||
|
||||
final NetworkStats.Entry entry = new NetworkStats.Entry(
|
||||
IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
|
||||
while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128
|
||||
|| operations > 32) {
|
||||
final long curStart = randomLong(r, start, end);
|
||||
final long curEnd = curStart + randomLong(r, 0, (end - curStart) / 2);
|
||||
|
||||
entry.rxBytes = randomLong(r, 0, rxBytes);
|
||||
entry.rxPackets = randomLong(r, 0, rxPackets);
|
||||
entry.txBytes = randomLong(r, 0, txBytes);
|
||||
entry.txPackets = randomLong(r, 0, txPackets);
|
||||
entry.operations = randomLong(r, 0, operations);
|
||||
|
||||
rxBytes -= entry.rxBytes;
|
||||
rxPackets -= entry.rxPackets;
|
||||
txBytes -= entry.txBytes;
|
||||
txPackets -= entry.txPackets;
|
||||
operations -= entry.operations;
|
||||
|
||||
recordData(curStart, curEnd, entry);
|
||||
}
|
||||
}
|
||||
|
||||
public static long randomLong(Random r, long start, long end) {
|
||||
return (long) (start + (r.nextFloat() * (end - start)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Quickly determine if this history intersects with given window.
|
||||
*/
|
||||
public boolean intersects(long start, long end) {
|
||||
final long dataStart = getStart();
|
||||
final long dataEnd = getEnd();
|
||||
if (start >= dataStart && start <= dataEnd) return true;
|
||||
if (end >= dataStart && end <= dataEnd) return true;
|
||||
if (dataStart >= start && dataStart <= end) return true;
|
||||
if (dataEnd >= start && dataEnd <= end) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void dump(IndentingPrintWriter pw, boolean fullHistory) {
|
||||
pw.print("NetworkStatsHistory: bucketDuration=");
|
||||
pw.println(bucketDuration / SECOND_IN_MILLIS);
|
||||
pw.increaseIndent();
|
||||
|
||||
final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
|
||||
if (start > 0) {
|
||||
pw.print("(omitting "); pw.print(start); pw.println(" buckets)");
|
||||
}
|
||||
|
||||
for (int i = start; i < bucketCount; i++) {
|
||||
pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS);
|
||||
if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); }
|
||||
if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); }
|
||||
if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); }
|
||||
if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); }
|
||||
if (operations != null) { pw.print(" op="); pw.print(operations[i]); }
|
||||
pw.println();
|
||||
}
|
||||
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
public void dumpCheckin(PrintWriter pw) {
|
||||
pw.print("d,");
|
||||
pw.print(bucketDuration / SECOND_IN_MILLIS);
|
||||
pw.println();
|
||||
|
||||
for (int i = 0; i < bucketCount; i++) {
|
||||
pw.print("b,");
|
||||
pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(',');
|
||||
if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(',');
|
||||
if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(',');
|
||||
if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(',');
|
||||
if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(',');
|
||||
if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); }
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpDebug(ProtoOutputStream proto, long tag) {
|
||||
final long start = proto.start(tag);
|
||||
|
||||
proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
|
||||
|
||||
for (int i = 0; i < bucketCount; i++) {
|
||||
final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
|
||||
|
||||
proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]);
|
||||
dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
|
||||
dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
|
||||
dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
|
||||
dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
|
||||
dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
|
||||
|
||||
proto.end(startBucket);
|
||||
}
|
||||
|
||||
proto.end(start);
|
||||
}
|
||||
|
||||
private static void dumpDebug(ProtoOutputStream proto, long tag, long[] array, int index) {
|
||||
if (array != null) {
|
||||
proto.write(tag, array[index]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final CharArrayWriter writer = new CharArrayWriter();
|
||||
dump(new IndentingPrintWriter(writer, " "), false);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public static final @android.annotation.NonNull Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() {
|
||||
@Override
|
||||
public NetworkStatsHistory createFromParcel(Parcel in) {
|
||||
return new NetworkStatsHistory(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkStatsHistory[] newArray(int size) {
|
||||
return new NetworkStatsHistory[size];
|
||||
}
|
||||
};
|
||||
|
||||
private static long getLong(long[] array, int i, long value) {
|
||||
return array != null ? array[i] : value;
|
||||
}
|
||||
|
||||
private static void setLong(long[] array, int i, long value) {
|
||||
if (array != null) array[i] = value;
|
||||
}
|
||||
|
||||
private static void addLong(long[] array, int i, long value) {
|
||||
if (array != null) array[i] += value;
|
||||
}
|
||||
|
||||
public int estimateResizeBuckets(long newBucketDuration) {
|
||||
return (int) (size() * getBucketDuration() / newBucketDuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility methods for interacting with {@link DataInputStream} and
|
||||
* {@link DataOutputStream}, mostly dealing with writing partial arrays.
|
||||
*/
|
||||
public static class DataStreamUtils {
|
||||
@Deprecated
|
||||
public static long[] readFullLongArray(DataInput in) throws IOException {
|
||||
final int size = in.readInt();
|
||||
if (size < 0) throw new ProtocolException("negative array size");
|
||||
final long[] values = new long[size];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = in.readLong();
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read variable-length {@link Long} using protobuf-style approach.
|
||||
*/
|
||||
public static long readVarLong(DataInput in) throws IOException {
|
||||
int shift = 0;
|
||||
long result = 0;
|
||||
while (shift < 64) {
|
||||
byte b = in.readByte();
|
||||
result |= (long) (b & 0x7F) << shift;
|
||||
if ((b & 0x80) == 0)
|
||||
return result;
|
||||
shift += 7;
|
||||
}
|
||||
throw new ProtocolException("malformed long");
|
||||
}
|
||||
|
||||
/**
|
||||
* Write variable-length {@link Long} using protobuf-style approach.
|
||||
*/
|
||||
public static void writeVarLong(DataOutput out, long value) throws IOException {
|
||||
while (true) {
|
||||
if ((value & ~0x7FL) == 0) {
|
||||
out.writeByte((int) value);
|
||||
return;
|
||||
} else {
|
||||
out.writeByte(((int) value & 0x7F) | 0x80);
|
||||
value >>>= 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static long[] readVarLongArray(DataInput in) throws IOException {
|
||||
final int size = in.readInt();
|
||||
if (size == -1) return null;
|
||||
if (size < 0) throw new ProtocolException("negative array size");
|
||||
final long[] values = new long[size];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = readVarLong(in);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
public static void writeVarLongArray(DataOutput out, long[] values, int size)
|
||||
throws IOException {
|
||||
if (values == null) {
|
||||
out.writeInt(-1);
|
||||
return;
|
||||
}
|
||||
if (size > values.length) {
|
||||
throw new IllegalArgumentException("size larger than length");
|
||||
}
|
||||
out.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
writeVarLong(out, values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility methods for interacting with {@link Parcel} structures, mostly
|
||||
* dealing with writing partial arrays.
|
||||
*/
|
||||
public static class ParcelUtils {
|
||||
public static long[] readLongArray(Parcel in) {
|
||||
final int size = in.readInt();
|
||||
if (size == -1) return null;
|
||||
final long[] values = new long[size];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = in.readLong();
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
public static void writeLongArray(Parcel out, long[] values, int size) {
|
||||
if (values == null) {
|
||||
out.writeInt(-1);
|
||||
return;
|
||||
}
|
||||
if (size > values.length) {
|
||||
throw new IllegalArgumentException("size larger than length");
|
||||
}
|
||||
out.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
out.writeLong(values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
906
framework-t/src/android/net/NetworkTemplate.java
Normal file
906
framework-t/src/android/net/NetworkTemplate.java
Normal file
@@ -0,0 +1,906 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.net;
|
||||
|
||||
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
|
||||
import static android.net.ConnectivityManager.TYPE_ETHERNET;
|
||||
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
||||
import static android.net.ConnectivityManager.TYPE_PROXY;
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
|
||||
import static android.net.ConnectivityManager.TYPE_WIMAX;
|
||||
import static android.net.NetworkIdentity.OEM_NONE;
|
||||
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
|
||||
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
|
||||
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
|
||||
import static android.net.NetworkStats.METERED_ALL;
|
||||
import static android.net.NetworkStats.METERED_NO;
|
||||
import static android.net.NetworkStats.METERED_YES;
|
||||
import static android.net.NetworkStats.ROAMING_ALL;
|
||||
import static android.net.NetworkStats.ROAMING_NO;
|
||||
import static android.net.NetworkStats.ROAMING_YES;
|
||||
import static android.net.wifi.WifiInfo.sanitizeSsid;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.telephony.Annotation.NetworkType;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.BackupUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.net.module.util.NetworkIdentityUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Predicate used to match {@link NetworkIdentity}, usually when collecting
|
||||
* statistics. (It should probably have been named {@code NetworkPredicate}.)
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class NetworkTemplate implements Parcelable {
|
||||
private static final String TAG = "NetworkTemplate";
|
||||
|
||||
/**
|
||||
* Initial Version of the backup serializer.
|
||||
*/
|
||||
public static final int BACKUP_VERSION_1_INIT = 1;
|
||||
/**
|
||||
* Version of the backup serializer that added carrier template support.
|
||||
*/
|
||||
public static final int BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE = 2;
|
||||
/**
|
||||
* Current Version of the Backup Serializer.
|
||||
*/
|
||||
private static final int BACKUP_VERSION = BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE;
|
||||
|
||||
public static final int MATCH_MOBILE = 1;
|
||||
public static final int MATCH_WIFI = 4;
|
||||
public static final int MATCH_ETHERNET = 5;
|
||||
public static final int MATCH_MOBILE_WILDCARD = 6;
|
||||
public static final int MATCH_WIFI_WILDCARD = 7;
|
||||
public static final int MATCH_BLUETOOTH = 8;
|
||||
public static final int MATCH_PROXY = 9;
|
||||
public static final int MATCH_CARRIER = 10;
|
||||
|
||||
/**
|
||||
* Value of the match rule of the subscriberId to match networks with specific subscriberId.
|
||||
*/
|
||||
public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0;
|
||||
/**
|
||||
* Value of the match rule of the subscriberId to match networks with any subscriberId which
|
||||
* includes null and non-null.
|
||||
*/
|
||||
public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1;
|
||||
|
||||
/**
|
||||
* Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that
|
||||
* should be fixed), so it's not possible to want to match null vs
|
||||
* non-null. Therefore it's fine to use null as a sentinel for Network ID.
|
||||
*/
|
||||
public static final String WIFI_NETWORKID_ALL = null;
|
||||
|
||||
/**
|
||||
* Include all network types when filtering. This is meant to merge in with the
|
||||
* {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int NETWORK_TYPE_ALL = -1;
|
||||
/**
|
||||
* Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is
|
||||
* still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along
|
||||
* with NR state as connected. This should not be overlapped with any of the
|
||||
* {@code TelephonyManager.NETWORK_TYPE_*} constants.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int NETWORK_TYPE_5G_NSA = -2;
|
||||
|
||||
/**
|
||||
* Value to match both OEM managed and unmanaged networks (all networks).
|
||||
* @hide
|
||||
*/
|
||||
public static final int OEM_MANAGED_ALL = -1;
|
||||
/**
|
||||
* Value to match networks which are not OEM managed.
|
||||
* @hide
|
||||
*/
|
||||
public static final int OEM_MANAGED_NO = OEM_NONE;
|
||||
/**
|
||||
* Value to match any OEM managed network.
|
||||
* @hide
|
||||
*/
|
||||
public static final int OEM_MANAGED_YES = -2;
|
||||
|
||||
private static boolean isKnownMatchRule(final int rule) {
|
||||
switch (rule) {
|
||||
case MATCH_MOBILE:
|
||||
case MATCH_WIFI:
|
||||
case MATCH_ETHERNET:
|
||||
case MATCH_MOBILE_WILDCARD:
|
||||
case MATCH_WIFI_WILDCARD:
|
||||
case MATCH_BLUETOOTH:
|
||||
case MATCH_PROXY:
|
||||
case MATCH_CARRIER:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
|
||||
* the given IMSI.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
|
||||
return new NetworkTemplate(MATCH_MOBILE, subscriberId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to match cellular networks with the given IMSI, {@code ratType} and
|
||||
* {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when
|
||||
* filtering. See {@code TelephonyManager.NETWORK_TYPE_*}.
|
||||
*/
|
||||
public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
|
||||
@NetworkType int ratType, int metered) {
|
||||
if (TextUtils.isEmpty(subscriberId)) {
|
||||
return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
|
||||
metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
|
||||
SUBSCRIBER_ID_MATCH_RULE_EXACT);
|
||||
}
|
||||
return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
|
||||
metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
|
||||
SUBSCRIBER_ID_MATCH_RULE_EXACT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks,
|
||||
* regardless of IMSI.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public static NetworkTemplate buildTemplateMobileWildcard() {
|
||||
return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks,
|
||||
* regardless of SSID.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public static NetworkTemplate buildTemplateWifiWildcard() {
|
||||
// TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL
|
||||
// and SUBSCRIBER_ID_MATCH_RULE_ALL.
|
||||
return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@UnsupportedAppUsage
|
||||
public static NetworkTemplate buildTemplateWifi() {
|
||||
return buildTemplateWifiWildcard();
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
|
||||
* given SSID.
|
||||
*/
|
||||
public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) {
|
||||
Objects.requireNonNull(networkId);
|
||||
return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */,
|
||||
new String[] { null } /* matchSubscriberIds */,
|
||||
networkId, METERED_ALL, ROAMING_ALL,
|
||||
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
|
||||
SUBSCRIBER_ID_MATCH_RULE_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID,
|
||||
* and IMSI.
|
||||
*
|
||||
* Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID.
|
||||
*/
|
||||
public static NetworkTemplate buildTemplateWifi(@Nullable String networkId,
|
||||
@Nullable String subscriberId) {
|
||||
return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId },
|
||||
networkId, METERED_ALL, ROAMING_ALL,
|
||||
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
|
||||
SUBSCRIBER_ID_MATCH_RULE_EXACT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style
|
||||
* networks together.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public static NetworkTemplate buildTemplateEthernet() {
|
||||
return new NetworkTemplate(MATCH_ETHERNET, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style
|
||||
* networks together.
|
||||
*/
|
||||
public static NetworkTemplate buildTemplateBluetooth() {
|
||||
return new NetworkTemplate(MATCH_BLUETOOTH, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to combine all {@link ConnectivityManager#TYPE_PROXY} style
|
||||
* networks together.
|
||||
*/
|
||||
public static NetworkTemplate buildTemplateProxy() {
|
||||
return new NetworkTemplate(MATCH_PROXY, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to match all metered carrier networks with the given IMSI.
|
||||
*/
|
||||
public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) {
|
||||
Objects.requireNonNull(subscriberId);
|
||||
return new NetworkTemplate(MATCH_CARRIER, subscriberId,
|
||||
new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL,
|
||||
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
|
||||
SUBSCRIBER_ID_MATCH_RULE_EXACT);
|
||||
}
|
||||
|
||||
private final int mMatchRule;
|
||||
private final String mSubscriberId;
|
||||
|
||||
/**
|
||||
* Ugh, templates are designed to target a single subscriber, but we might
|
||||
* need to match several "merged" subscribers. These are the subscribers
|
||||
* that should be considered to match this template.
|
||||
* <p>
|
||||
* Since the merge set is dynamic, it should <em>not</em> be persisted or
|
||||
* used for determining equality.
|
||||
*/
|
||||
private final String[] mMatchSubscriberIds;
|
||||
|
||||
private final String mNetworkId;
|
||||
|
||||
// Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
|
||||
private final int mMetered;
|
||||
private final int mRoaming;
|
||||
private final int mDefaultNetwork;
|
||||
private final int mSubType;
|
||||
/**
|
||||
* The subscriber Id match rule defines how the template should match networks with
|
||||
* specific subscriberId(s). See NetworkTemplate#SUBSCRIBER_ID_MATCH_RULE_* for more detail.
|
||||
*/
|
||||
private final int mSubscriberIdMatchRule;
|
||||
|
||||
// Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
|
||||
private final int mOemManaged;
|
||||
|
||||
private void checkValidSubscriberIdMatchRule() {
|
||||
switch (mMatchRule) {
|
||||
case MATCH_MOBILE:
|
||||
case MATCH_CARRIER:
|
||||
// MOBILE and CARRIER templates must always specify a subscriber ID.
|
||||
if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
|
||||
throw new IllegalArgumentException("Invalid SubscriberIdMatchRule"
|
||||
+ "on match rule: " + getMatchRuleName(mMatchRule));
|
||||
}
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S)
|
||||
@UnsupportedAppUsage
|
||||
public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
|
||||
this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
|
||||
}
|
||||
|
||||
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
|
||||
String networkId) {
|
||||
// Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates
|
||||
// to metered networks. It is now possible to match mobile with any meteredness, but
|
||||
// in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
|
||||
//constructor passes METERED_YES for these types.
|
||||
this(matchRule, subscriberId, matchSubscriberIds, networkId,
|
||||
(matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES
|
||||
: METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
|
||||
OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT);
|
||||
}
|
||||
|
||||
// TODO: Remove it after updating all of the caller.
|
||||
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
|
||||
String networkId, int metered, int roaming, int defaultNetwork, int subType,
|
||||
int oemManaged) {
|
||||
this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming,
|
||||
defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT);
|
||||
}
|
||||
|
||||
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
|
||||
String networkId, int metered, int roaming, int defaultNetwork, int subType,
|
||||
int oemManaged, int subscriberIdMatchRule) {
|
||||
mMatchRule = matchRule;
|
||||
mSubscriberId = subscriberId;
|
||||
// TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when
|
||||
// mSubscriberId is null
|
||||
mMatchSubscriberIds = matchSubscriberIds;
|
||||
mNetworkId = networkId;
|
||||
mMetered = metered;
|
||||
mRoaming = roaming;
|
||||
mDefaultNetwork = defaultNetwork;
|
||||
mSubType = subType;
|
||||
mOemManaged = oemManaged;
|
||||
mSubscriberIdMatchRule = subscriberIdMatchRule;
|
||||
checkValidSubscriberIdMatchRule();
|
||||
if (!isKnownMatchRule(matchRule)) {
|
||||
throw new IllegalArgumentException("Unknown network template rule " + matchRule
|
||||
+ " will not match any identity.");
|
||||
}
|
||||
}
|
||||
|
||||
private NetworkTemplate(Parcel in) {
|
||||
mMatchRule = in.readInt();
|
||||
mSubscriberId = in.readString();
|
||||
mMatchSubscriberIds = in.createStringArray();
|
||||
mNetworkId = in.readString();
|
||||
mMetered = in.readInt();
|
||||
mRoaming = in.readInt();
|
||||
mDefaultNetwork = in.readInt();
|
||||
mSubType = in.readInt();
|
||||
mOemManaged = in.readInt();
|
||||
mSubscriberIdMatchRule = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mMatchRule);
|
||||
dest.writeString(mSubscriberId);
|
||||
dest.writeStringArray(mMatchSubscriberIds);
|
||||
dest.writeString(mNetworkId);
|
||||
dest.writeInt(mMetered);
|
||||
dest.writeInt(mRoaming);
|
||||
dest.writeInt(mDefaultNetwork);
|
||||
dest.writeInt(mSubType);
|
||||
dest.writeInt(mOemManaged);
|
||||
dest.writeInt(mSubscriberIdMatchRule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder("NetworkTemplate: ");
|
||||
builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
|
||||
if (mSubscriberId != null) {
|
||||
builder.append(", subscriberId=").append(
|
||||
NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
|
||||
}
|
||||
if (mMatchSubscriberIds != null) {
|
||||
builder.append(", matchSubscriberIds=").append(
|
||||
Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds)));
|
||||
}
|
||||
if (mNetworkId != null) {
|
||||
builder.append(", networkId=").append(mNetworkId);
|
||||
}
|
||||
if (mMetered != METERED_ALL) {
|
||||
builder.append(", metered=").append(NetworkStats.meteredToString(mMetered));
|
||||
}
|
||||
if (mRoaming != ROAMING_ALL) {
|
||||
builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming));
|
||||
}
|
||||
if (mDefaultNetwork != DEFAULT_NETWORK_ALL) {
|
||||
builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString(
|
||||
mDefaultNetwork));
|
||||
}
|
||||
if (mSubType != NETWORK_TYPE_ALL) {
|
||||
builder.append(", subType=").append(mSubType);
|
||||
}
|
||||
if (mOemManaged != OEM_MANAGED_ALL) {
|
||||
builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged));
|
||||
}
|
||||
builder.append(", subscriberIdMatchRule=")
|
||||
.append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
|
||||
mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof NetworkTemplate) {
|
||||
final NetworkTemplate other = (NetworkTemplate) obj;
|
||||
return mMatchRule == other.mMatchRule
|
||||
&& Objects.equals(mSubscriberId, other.mSubscriberId)
|
||||
&& Objects.equals(mNetworkId, other.mNetworkId)
|
||||
&& mMetered == other.mMetered
|
||||
&& mRoaming == other.mRoaming
|
||||
&& mDefaultNetwork == other.mDefaultNetwork
|
||||
&& mSubType == other.mSubType
|
||||
&& mOemManaged == other.mOemManaged
|
||||
&& mSubscriberIdMatchRule == other.mSubscriberIdMatchRule;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String subscriberIdMatchRuleToString(int rule) {
|
||||
switch (rule) {
|
||||
case SUBSCRIBER_ID_MATCH_RULE_EXACT:
|
||||
return "EXACT_MATCH";
|
||||
case SUBSCRIBER_ID_MATCH_RULE_ALL:
|
||||
return "ALL";
|
||||
default:
|
||||
return "Unknown rule " + rule;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMatchRuleMobile() {
|
||||
switch (mMatchRule) {
|
||||
case MATCH_MOBILE:
|
||||
case MATCH_MOBILE_WILDCARD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPersistable() {
|
||||
switch (mMatchRule) {
|
||||
case MATCH_MOBILE_WILDCARD:
|
||||
case MATCH_WIFI_WILDCARD:
|
||||
return false;
|
||||
case MATCH_CARRIER:
|
||||
return mSubscriberId != null;
|
||||
case MATCH_WIFI:
|
||||
if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL)
|
||||
&& mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public int getMatchRule() {
|
||||
return mMatchRule;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public String getSubscriberId() {
|
||||
return mSubscriberId;
|
||||
}
|
||||
|
||||
public String getNetworkId() {
|
||||
return mNetworkId;
|
||||
}
|
||||
|
||||
public int getSubscriberIdMatchRule() {
|
||||
return mSubscriberIdMatchRule;
|
||||
}
|
||||
|
||||
public int getMeteredness() {
|
||||
return mMetered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if given {@link NetworkIdentity} matches this template.
|
||||
*/
|
||||
public boolean matches(NetworkIdentity ident) {
|
||||
if (!matchesMetered(ident)) return false;
|
||||
if (!matchesRoaming(ident)) return false;
|
||||
if (!matchesDefaultNetwork(ident)) return false;
|
||||
if (!matchesOemNetwork(ident)) return false;
|
||||
|
||||
switch (mMatchRule) {
|
||||
case MATCH_MOBILE:
|
||||
return matchesMobile(ident);
|
||||
case MATCH_WIFI:
|
||||
return matchesWifi(ident);
|
||||
case MATCH_ETHERNET:
|
||||
return matchesEthernet(ident);
|
||||
case MATCH_MOBILE_WILDCARD:
|
||||
return matchesMobileWildcard(ident);
|
||||
case MATCH_WIFI_WILDCARD:
|
||||
return matchesWifiWildcard(ident);
|
||||
case MATCH_BLUETOOTH:
|
||||
return matchesBluetooth(ident);
|
||||
case MATCH_PROXY:
|
||||
return matchesProxy(ident);
|
||||
case MATCH_CARRIER:
|
||||
return matchesCarrier(ident);
|
||||
default:
|
||||
// We have no idea what kind of network template we are, so we
|
||||
// just claim not to match anything.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean matchesMetered(NetworkIdentity ident) {
|
||||
return (mMetered == METERED_ALL)
|
||||
|| (mMetered == METERED_YES && ident.mMetered)
|
||||
|| (mMetered == METERED_NO && !ident.mMetered);
|
||||
}
|
||||
|
||||
private boolean matchesRoaming(NetworkIdentity ident) {
|
||||
return (mRoaming == ROAMING_ALL)
|
||||
|| (mRoaming == ROAMING_YES && ident.mRoaming)
|
||||
|| (mRoaming == ROAMING_NO && !ident.mRoaming);
|
||||
}
|
||||
|
||||
private boolean matchesDefaultNetwork(NetworkIdentity ident) {
|
||||
return (mDefaultNetwork == DEFAULT_NETWORK_ALL)
|
||||
|| (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork)
|
||||
|| (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork);
|
||||
}
|
||||
|
||||
private boolean matchesOemNetwork(NetworkIdentity ident) {
|
||||
return (mOemManaged == OEM_MANAGED_ALL)
|
||||
|| (mOemManaged == OEM_MANAGED_YES
|
||||
&& ident.mOemManaged != OEM_NONE)
|
||||
|| (mOemManaged == ident.mOemManaged);
|
||||
}
|
||||
|
||||
private boolean matchesCollapsedRatType(NetworkIdentity ident) {
|
||||
return mSubType == NETWORK_TYPE_ALL
|
||||
|| getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this template matches {@code subscriberId}. Returns true if this
|
||||
* template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a
|
||||
* {@code mMatchSubscriberIds} array that contains {@code subscriberId}.
|
||||
*/
|
||||
public boolean matchesSubscriberId(@Nullable String subscriberId) {
|
||||
return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL
|
||||
|| ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if network with matching SSID. Returns true when the SSID matches, or when
|
||||
* {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}.
|
||||
*/
|
||||
private boolean matchesWifiNetworkId(@Nullable String networkId) {
|
||||
return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL)
|
||||
|| Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if mobile network with matching IMSI.
|
||||
*/
|
||||
private boolean matchesMobile(NetworkIdentity ident) {
|
||||
if (ident.mType == TYPE_WIMAX) {
|
||||
// TODO: consider matching against WiMAX subscriber identity
|
||||
return true;
|
||||
} else {
|
||||
return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds)
|
||||
&& ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
|
||||
&& matchesCollapsedRatType(ident);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Radio Access Technology(RAT) type that is representative of a group of RAT types.
|
||||
* The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}.
|
||||
*
|
||||
* @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}.
|
||||
*/
|
||||
// TODO: 1. Consider move this to TelephonyManager if used by other modules.
|
||||
// 2. Consider make this configurable.
|
||||
// 3. Use TelephonyManager APIs when available.
|
||||
public static int getCollapsedRatType(int ratType) {
|
||||
switch (ratType) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||
case TelephonyManager.NETWORK_TYPE_GSM:
|
||||
case TelephonyManager.NETWORK_TYPE_EDGE:
|
||||
case TelephonyManager.NETWORK_TYPE_IDEN:
|
||||
case TelephonyManager.NETWORK_TYPE_CDMA:
|
||||
case TelephonyManager.NETWORK_TYPE_1xRTT:
|
||||
return TelephonyManager.NETWORK_TYPE_GSM;
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_0:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_A:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_B:
|
||||
case TelephonyManager.NETWORK_TYPE_EHRPD:
|
||||
case TelephonyManager.NETWORK_TYPE_UMTS:
|
||||
case TelephonyManager.NETWORK_TYPE_HSDPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSUPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPAP:
|
||||
case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
|
||||
return TelephonyManager.NETWORK_TYPE_UMTS;
|
||||
case TelephonyManager.NETWORK_TYPE_LTE:
|
||||
case TelephonyManager.NETWORK_TYPE_IWLAN:
|
||||
return TelephonyManager.NETWORK_TYPE_LTE;
|
||||
case TelephonyManager.NETWORK_TYPE_NR:
|
||||
return TelephonyManager.NETWORK_TYPE_NR;
|
||||
// Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}.
|
||||
case NetworkTemplate.NETWORK_TYPE_5G_NSA:
|
||||
return NetworkTemplate.NETWORK_TYPE_5G_NSA;
|
||||
default:
|
||||
return TelephonyManager.NETWORK_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all supported collapsed RAT types that could be returned by
|
||||
* {@link #getCollapsedRatType(int)}.
|
||||
*/
|
||||
@NonNull
|
||||
public static final int[] getAllCollapsedRatTypes() {
|
||||
final int[] ratTypes = TelephonyManager.getAllNetworkTypes();
|
||||
final HashSet<Integer> collapsedRatTypes = new HashSet<>();
|
||||
for (final int ratType : ratTypes) {
|
||||
collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType));
|
||||
}
|
||||
// Add NETWORK_TYPE_5G_NSA to the returned list since 5G NSA is a virtual RAT type and
|
||||
// it is not in TelephonyManager#NETWORK_TYPE_* constants.
|
||||
// See {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}.
|
||||
collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(NETWORK_TYPE_5G_NSA));
|
||||
// Ensure that unknown type is returned.
|
||||
collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN);
|
||||
return toIntArray(collapsedRatTypes);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static int[] toIntArray(@NonNull Collection<Integer> list) {
|
||||
final int[] array = new int[list.size()];
|
||||
int i = 0;
|
||||
for (final Integer item : list) {
|
||||
array[i++] = item;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if matches Wi-Fi network template.
|
||||
*/
|
||||
private boolean matchesWifi(NetworkIdentity ident) {
|
||||
switch (ident.mType) {
|
||||
case TYPE_WIFI:
|
||||
return matchesSubscriberId(ident.mSubscriberId)
|
||||
&& matchesWifiNetworkId(ident.mNetworkId);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if matches Ethernet network template.
|
||||
*/
|
||||
private boolean matchesEthernet(NetworkIdentity ident) {
|
||||
if (ident.mType == TYPE_ETHERNET) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if matches carrier network. The carrier networks means it includes the subscriberId.
|
||||
*/
|
||||
private boolean matchesCarrier(NetworkIdentity ident) {
|
||||
return ident.mSubscriberId != null
|
||||
&& !ArrayUtils.isEmpty(mMatchSubscriberIds)
|
||||
&& ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
|
||||
}
|
||||
|
||||
private boolean matchesMobileWildcard(NetworkIdentity ident) {
|
||||
if (ident.mType == TYPE_WIMAX) {
|
||||
return true;
|
||||
} else {
|
||||
return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean matchesWifiWildcard(NetworkIdentity ident) {
|
||||
switch (ident.mType) {
|
||||
case TYPE_WIFI:
|
||||
case TYPE_WIFI_P2P:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if matches Bluetooth network template.
|
||||
*/
|
||||
private boolean matchesBluetooth(NetworkIdentity ident) {
|
||||
if (ident.mType == TYPE_BLUETOOTH) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if matches Proxy network template.
|
||||
*/
|
||||
private boolean matchesProxy(NetworkIdentity ident) {
|
||||
return ident.mType == TYPE_PROXY;
|
||||
}
|
||||
|
||||
private static String getMatchRuleName(int matchRule) {
|
||||
switch (matchRule) {
|
||||
case MATCH_MOBILE:
|
||||
return "MOBILE";
|
||||
case MATCH_WIFI:
|
||||
return "WIFI";
|
||||
case MATCH_ETHERNET:
|
||||
return "ETHERNET";
|
||||
case MATCH_MOBILE_WILDCARD:
|
||||
return "MOBILE_WILDCARD";
|
||||
case MATCH_WIFI_WILDCARD:
|
||||
return "WIFI_WILDCARD";
|
||||
case MATCH_BLUETOOTH:
|
||||
return "BLUETOOTH";
|
||||
case MATCH_PROXY:
|
||||
return "PROXY";
|
||||
case MATCH_CARRIER:
|
||||
return "CARRIER";
|
||||
default:
|
||||
return "UNKNOWN(" + matchRule + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private static String getOemManagedNames(int oemManaged) {
|
||||
switch (oemManaged) {
|
||||
case OEM_MANAGED_ALL:
|
||||
return "OEM_MANAGED_ALL";
|
||||
case OEM_MANAGED_NO:
|
||||
return "OEM_MANAGED_NO";
|
||||
case OEM_MANAGED_YES:
|
||||
return "OEM_MANAGED_YES";
|
||||
default:
|
||||
return NetworkIdentity.getOemManagedNames(oemManaged);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine the given template and normalize it.
|
||||
* We pick the "lowest" merged subscriber as the primary
|
||||
* for key purposes, and expand the template to match all other merged
|
||||
* subscribers.
|
||||
* <p>
|
||||
* For example, given an incoming template matching B, and the currently
|
||||
* active merge set [A,B], we'd return a new template that primarily matches
|
||||
* A, but also matches B.
|
||||
* TODO: remove and use {@link #normalize(NetworkTemplate, List)}.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) {
|
||||
return normalize(template, Arrays.<String[]>asList(merged));
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine the given template and normalize it.
|
||||
* We pick the "lowest" merged subscriber as the primary
|
||||
* for key purposes, and expand the template to match all other merged
|
||||
* subscribers.
|
||||
*
|
||||
* There can be multiple merged subscriberIds for multi-SIM devices.
|
||||
*
|
||||
* <p>
|
||||
* For example, given an incoming template matching B, and the currently
|
||||
* active merge set [A,B], we'd return a new template that primarily matches
|
||||
* A, but also matches B.
|
||||
*/
|
||||
public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) {
|
||||
// Now there are several types of network which uses SubscriberId to store network
|
||||
// information. For instances:
|
||||
// The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network.
|
||||
// The TYPE_CARRIER means that the network associate to specific carrier network.
|
||||
|
||||
if (template.mSubscriberId == null) return template;
|
||||
|
||||
for (String[] merged : mergedList) {
|
||||
if (ArrayUtils.contains(merged, template.mSubscriberId)) {
|
||||
// Requested template subscriber is part of the merge group; return
|
||||
// a template that matches all merged subscribers.
|
||||
return new NetworkTemplate(template.mMatchRule, merged[0], merged,
|
||||
template.mNetworkId);
|
||||
}
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public static final @android.annotation.NonNull Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
|
||||
@Override
|
||||
public NetworkTemplate createFromParcel(Parcel in) {
|
||||
return new NetworkTemplate(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkTemplate[] newArray(int size) {
|
||||
return new NetworkTemplate[size];
|
||||
}
|
||||
};
|
||||
|
||||
public byte[] getBytesForBackup() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(baos);
|
||||
|
||||
if (!isPersistable()) {
|
||||
Log.wtf(TAG, "Trying to backup non-persistable template: " + this);
|
||||
}
|
||||
|
||||
out.writeInt(BACKUP_VERSION);
|
||||
|
||||
out.writeInt(mMatchRule);
|
||||
BackupUtils.writeString(out, mSubscriberId);
|
||||
BackupUtils.writeString(out, mNetworkId);
|
||||
out.writeInt(mMetered);
|
||||
out.writeInt(mSubscriberIdMatchRule);
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
|
||||
throws IOException, BackupUtils.BadVersionException {
|
||||
int version = in.readInt();
|
||||
if (version < BACKUP_VERSION_1_INIT || version > BACKUP_VERSION) {
|
||||
throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
|
||||
}
|
||||
|
||||
int matchRule = in.readInt();
|
||||
String subscriberId = BackupUtils.readString(in);
|
||||
String networkId = BackupUtils.readString(in);
|
||||
|
||||
final int metered;
|
||||
final int subscriberIdMatchRule;
|
||||
if (version >= BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE) {
|
||||
metered = in.readInt();
|
||||
subscriberIdMatchRule = in.readInt();
|
||||
} else {
|
||||
// For backward compatibility, fill the missing filters from match rules.
|
||||
metered = (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD
|
||||
|| matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL;
|
||||
subscriberIdMatchRule = SUBSCRIBER_ID_MATCH_RULE_EXACT;
|
||||
}
|
||||
|
||||
try {
|
||||
return new NetworkTemplate(matchRule,
|
||||
subscriberId, new String[] { subscriberId },
|
||||
networkId, metered, NetworkStats.ROAMING_ALL,
|
||||
NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL,
|
||||
NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new BackupUtils.BadVersionException(
|
||||
"Restored network template contains unknown match rule " + matchRule, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
1032
framework-t/src/android/net/TrafficStats.java
Normal file
1032
framework-t/src/android/net/TrafficStats.java
Normal file
File diff suppressed because it is too large
Load Diff
19
framework-t/src/android/net/UnderlyingNetworkInfo.aidl
Normal file
19
framework-t/src/android/net/UnderlyingNetworkInfo.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.net;
|
||||
|
||||
parcelable UnderlyingNetworkInfo;
|
||||
135
framework-t/src/android/net/UnderlyingNetworkInfo.java
Normal file
135
framework-t/src/android/net/UnderlyingNetworkInfo.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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.net;
|
||||
|
||||
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A lightweight container used to carry information on the networks that underly a given
|
||||
* virtual network.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
public final class UnderlyingNetworkInfo implements Parcelable {
|
||||
/** The owner of this network. */
|
||||
private final int mOwnerUid;
|
||||
|
||||
/** The interface name of this network. */
|
||||
@NonNull
|
||||
private final String mIface;
|
||||
|
||||
/** The names of the interfaces underlying this network. */
|
||||
@NonNull
|
||||
private final List<String> mUnderlyingIfaces;
|
||||
|
||||
public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface,
|
||||
@NonNull List<String> underlyingIfaces) {
|
||||
Objects.requireNonNull(iface);
|
||||
Objects.requireNonNull(underlyingIfaces);
|
||||
mOwnerUid = ownerUid;
|
||||
mIface = iface;
|
||||
mUnderlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces));
|
||||
}
|
||||
|
||||
private UnderlyingNetworkInfo(@NonNull Parcel in) {
|
||||
mOwnerUid = in.readInt();
|
||||
mIface = in.readString();
|
||||
List<String> underlyingIfaces = new ArrayList<>();
|
||||
in.readList(underlyingIfaces, null /*classLoader*/);
|
||||
mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces);
|
||||
}
|
||||
|
||||
/** Get the owner of this network. */
|
||||
public int getOwnerUid() {
|
||||
return mOwnerUid;
|
||||
}
|
||||
|
||||
/** Get the interface name of this network. */
|
||||
@NonNull
|
||||
public String getInterface() {
|
||||
return mIface;
|
||||
}
|
||||
|
||||
/** Get the names of the interfaces underlying this network. */
|
||||
@NonNull
|
||||
public List<String> getUnderlyingInterfaces() {
|
||||
return mUnderlyingIfaces;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UnderlyingNetworkInfo{"
|
||||
+ "ownerUid=" + mOwnerUid
|
||||
+ ", iface='" + mIface + '\''
|
||||
+ ", underlyingIfaces='" + mUnderlyingIfaces.toString() + '\''
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mOwnerUid);
|
||||
dest.writeString(mIface);
|
||||
dest.writeList(mUnderlyingIfaces);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<UnderlyingNetworkInfo> CREATOR =
|
||||
new Parcelable.Creator<UnderlyingNetworkInfo>() {
|
||||
@NonNull
|
||||
@Override
|
||||
public UnderlyingNetworkInfo createFromParcel(@NonNull Parcel in) {
|
||||
return new UnderlyingNetworkInfo(in);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public UnderlyingNetworkInfo[] newArray(int size) {
|
||||
return new UnderlyingNetworkInfo[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof UnderlyingNetworkInfo)) return false;
|
||||
final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o;
|
||||
return mOwnerUid == that.getOwnerUid()
|
||||
&& Objects.equals(mIface, that.getInterface())
|
||||
&& Objects.equals(mUnderlyingIfaces, that.getUnderlyingInterfaces());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mOwnerUid, mIface, mUnderlyingIfaces);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.net.netstats.provider;
|
||||
|
||||
/**
|
||||
* Interface for NetworkStatsService to query network statistics and set data limits.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface INetworkStatsProvider {
|
||||
void onRequestStatsUpdate(int token);
|
||||
void onSetAlert(long quotaBytes);
|
||||
void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.net.netstats.provider;
|
||||
|
||||
import android.net.NetworkStats;
|
||||
|
||||
/**
|
||||
* Interface for implementor of {@link INetworkStatsProviderCallback} to push events
|
||||
* such as network statistics update or notify limit reached.
|
||||
* @hide
|
||||
*/
|
||||
oneway interface INetworkStatsProviderCallback {
|
||||
void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
|
||||
void notifyAlertReached();
|
||||
void notifyWarningOrLimitReached();
|
||||
void unregister();
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.net.netstats.provider;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.net.NetworkStats;
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* A base class that allows external modules to implement a custom network statistics provider.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public abstract class NetworkStatsProvider {
|
||||
/**
|
||||
* A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit}
|
||||
* indicates there is no limit.
|
||||
*/
|
||||
public static final int QUOTA_UNLIMITED = -1;
|
||||
|
||||
@NonNull private final INetworkStatsProvider mProviderBinder =
|
||||
new INetworkStatsProvider.Stub() {
|
||||
|
||||
@Override
|
||||
public void onRequestStatsUpdate(int token) {
|
||||
NetworkStatsProvider.this.onRequestStatsUpdate(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetAlert(long quotaBytes) {
|
||||
NetworkStatsProvider.this.onSetAlert(quotaBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) {
|
||||
NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes);
|
||||
}
|
||||
};
|
||||
|
||||
// The binder given by the service when successfully registering. Only null before registering,
|
||||
// never null once non-null.
|
||||
@Nullable
|
||||
private INetworkStatsProviderCallback mProviderCbBinder;
|
||||
|
||||
/**
|
||||
* Return the binder invoked by the service and redirect function calls to the overridden
|
||||
* methods.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public INetworkStatsProvider getProviderBinder() {
|
||||
return mProviderBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the binder that was returned by the service when successfully registering. Note that
|
||||
* the provider cannot be re-registered. Hence this method can only be called once per provider.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setProviderCallbackBinder(@NonNull INetworkStatsProviderCallback binder) {
|
||||
if (mProviderCbBinder != null) {
|
||||
throw new IllegalArgumentException("provider is already registered");
|
||||
}
|
||||
mProviderCbBinder = binder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the binder that was returned by the service when successfully registering. Or null if the
|
||||
* provider was never registered.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public INetworkStatsProviderCallback getProviderCallbackBinder() {
|
||||
return mProviderCbBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the binder that was returned by the service when successfully registering. Throw an
|
||||
* {@link IllegalStateException} if the provider is not registered.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public INetworkStatsProviderCallback getProviderCallbackBinderOrThrow() {
|
||||
if (mProviderCbBinder == null) {
|
||||
throw new IllegalStateException("the provider is not registered");
|
||||
}
|
||||
return mProviderCbBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the system of new network statistics.
|
||||
*
|
||||
* Send the network statistics recorded since the last call to {@link #notifyStatsUpdated}. Must
|
||||
* be called as soon as possible after {@link NetworkStatsProvider#onRequestStatsUpdate(int)}
|
||||
* being called. Responding later increases the probability stats will be dropped. The
|
||||
* provider can also call this whenever it wants to reports new stats for any reason.
|
||||
* Note that the system will not necessarily immediately propagate the statistics to
|
||||
* reflect the update.
|
||||
*
|
||||
* @param token the token under which these stats were gathered. Providers can call this method
|
||||
* with the current token as often as they want, until the token changes.
|
||||
* {@see NetworkStatsProvider#onRequestStatsUpdate()}
|
||||
* @param ifaceStats the {@link NetworkStats} per interface to be reported.
|
||||
* The provider should not include any traffic that is already counted by
|
||||
* kernel interface counters.
|
||||
* @param uidStats the same stats as above, but counts {@link NetworkStats}
|
||||
* per uid.
|
||||
*/
|
||||
public void notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats,
|
||||
@NonNull NetworkStats uidStats) {
|
||||
try {
|
||||
getProviderCallbackBinderOrThrow().notifyStatsUpdated(token, ifaceStats, uidStats);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify system that the quota set by {@code onSetAlert} has been reached.
|
||||
*/
|
||||
public void notifyAlertReached() {
|
||||
try {
|
||||
getProviderCallbackBinderOrThrow().notifyAlertReached();
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached.
|
||||
*/
|
||||
public void notifyWarningReached() {
|
||||
try {
|
||||
// Reuse the code path to notify warning reached with limit reached
|
||||
// since framework handles them in the same way.
|
||||
getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify system that the quota set by {@link #onSetLimit} or limit set by
|
||||
* {@link #onSetWarningAndLimit} has been reached.
|
||||
*/
|
||||
public void notifyLimitReached() {
|
||||
try {
|
||||
getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@code NetworkStatsService} when it requires to know updated stats.
|
||||
* The provider MUST respond by calling {@link #notifyStatsUpdated} as soon as possible.
|
||||
* Responding later increases the probability stats will be dropped. Memory allowing, the
|
||||
* system will try to take stats into account up to one minute after calling
|
||||
* {@link #onRequestStatsUpdate}.
|
||||
*
|
||||
* @param token a positive number identifying the new state of the system under which
|
||||
* {@link NetworkStats} have to be gathered from now on. When this is called,
|
||||
* custom implementations of providers MUST tally and report the latest stats with
|
||||
* the previous token, under which stats were being gathered so far.
|
||||
*/
|
||||
public abstract void onRequestStatsUpdate(int token);
|
||||
|
||||
/**
|
||||
* Called by {@code NetworkStatsService} when setting the interface quota for the specified
|
||||
* upstream interface. When this is called, the custom implementation should block all egress
|
||||
* packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have
|
||||
* been reached, and MUST respond to it by calling
|
||||
* {@link NetworkStatsProvider#notifyLimitReached()}.
|
||||
*
|
||||
* @param iface the interface requiring the operation.
|
||||
* @param quotaBytes the quota defined as the number of bytes, starting from zero and counting
|
||||
* from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
|
||||
*/
|
||||
public abstract void onSetLimit(@NonNull String iface, long quotaBytes);
|
||||
|
||||
/**
|
||||
* Called by {@code NetworkStatsService} when setting the interface quotas for the specified
|
||||
* upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system
|
||||
* will not call {@link #onSetLimit}. When this method is called, the implementation
|
||||
* should behave as follows:
|
||||
* 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on
|
||||
* {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}.
|
||||
* 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on
|
||||
* {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}.
|
||||
*
|
||||
* @param iface the interface requiring the operation.
|
||||
* @param warningBytes the warning defined as the number of bytes, starting from zero and
|
||||
* counting from now. A value of {@link #QUOTA_UNLIMITED} indicates
|
||||
* there is no warning.
|
||||
* @param limitBytes the limit defined as the number of bytes, starting from zero and counting
|
||||
* from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
|
||||
*/
|
||||
public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) {
|
||||
// Backward compatibility for those who didn't override this function.
|
||||
onSetLimit(iface, limitBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations
|
||||
* MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes
|
||||
* have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should
|
||||
* not block all egress packets.
|
||||
*
|
||||
* @param quotaBytes the quota defined as the number of bytes, starting from zero and counting
|
||||
* from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert.
|
||||
*/
|
||||
public abstract void onSetAlert(long quotaBytes);
|
||||
}
|
||||
Reference in New Issue
Block a user