blob: 7639d2244cfe495f8022bf03add5751e35241e31 [file] [log] [blame]
/*
* 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} and {@link #onSetAlert} 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 onSetLimit(String iface, long quotaBytes) {
NetworkStatsProvider.this.onSetLimit(iface, quotaBytes);
}
@Override
public void onSetAlert(long quotaBytes) {
NetworkStatsProvider.this.onSetAlert(quotaBytes);
}
};
// 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 quota set by {@code onSetLimit} has been reached.
*/
public void notifyLimitReached() {
try {
getProviderCallbackBinderOrThrow().notifyLimitReached();
} 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 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);
}