1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.netstats.provider; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SystemApi; 22 import android.net.NetworkStats; 23 import android.os.RemoteException; 24 25 /** 26 * A base class that allows external modules to implement a custom network statistics provider. 27 * @hide 28 */ 29 @SystemApi 30 public abstract class NetworkStatsProvider { 31 /** 32 * A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit} 33 * indicates there is no limit. 34 */ 35 public static final int QUOTA_UNLIMITED = -1; 36 37 @NonNull private final INetworkStatsProvider mProviderBinder = 38 new INetworkStatsProvider.Stub() { 39 40 @Override 41 public void onRequestStatsUpdate(int token) { 42 NetworkStatsProvider.this.onRequestStatsUpdate(token); 43 } 44 45 @Override 46 public void onSetAlert(long quotaBytes) { 47 NetworkStatsProvider.this.onSetAlert(quotaBytes); 48 } 49 50 @Override 51 public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) { 52 NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes); 53 } 54 }; 55 56 // The binder given by the service when successfully registering. Only null before registering, 57 // never null once non-null. 58 @Nullable 59 private INetworkStatsProviderCallback mProviderCbBinder; 60 61 /** 62 * Return the binder invoked by the service and redirect function calls to the overridden 63 * methods. 64 * @hide 65 */ 66 @NonNull getProviderBinder()67 public INetworkStatsProvider getProviderBinder() { 68 return mProviderBinder; 69 } 70 71 /** 72 * Store the binder that was returned by the service when successfully registering. Note that 73 * the provider cannot be re-registered. Hence this method can only be called once per provider. 74 * 75 * @hide 76 */ setProviderCallbackBinder(@onNull INetworkStatsProviderCallback binder)77 public void setProviderCallbackBinder(@NonNull INetworkStatsProviderCallback binder) { 78 if (mProviderCbBinder != null) { 79 throw new IllegalArgumentException("provider is already registered"); 80 } 81 mProviderCbBinder = binder; 82 } 83 84 /** 85 * Get the binder that was returned by the service when successfully registering. Or null if the 86 * provider was never registered. 87 * 88 * @hide 89 */ 90 @Nullable getProviderCallbackBinder()91 public INetworkStatsProviderCallback getProviderCallbackBinder() { 92 return mProviderCbBinder; 93 } 94 95 /** 96 * Get the binder that was returned by the service when successfully registering. Throw an 97 * {@link IllegalStateException} if the provider is not registered. 98 * 99 * @hide 100 */ 101 @NonNull getProviderCallbackBinderOrThrow()102 public INetworkStatsProviderCallback getProviderCallbackBinderOrThrow() { 103 if (mProviderCbBinder == null) { 104 throw new IllegalStateException("the provider is not registered"); 105 } 106 return mProviderCbBinder; 107 } 108 109 /** 110 * Notify the system of new network statistics. 111 * 112 * Send the network statistics recorded since the last call to {@link #notifyStatsUpdated}. Must 113 * be called as soon as possible after {@link NetworkStatsProvider#onRequestStatsUpdate(int)} 114 * being called. Responding later increases the probability stats will be dropped. The 115 * provider can also call this whenever it wants to reports new stats for any reason. 116 * Note that the system will not necessarily immediately propagate the statistics to 117 * reflect the update. 118 * 119 * @param token the token under which these stats were gathered. Providers can call this method 120 * with the current token as often as they want, until the token changes. 121 * {@see NetworkStatsProvider#onRequestStatsUpdate()} 122 * @param ifaceStats the {@link NetworkStats} per interface to be reported. 123 * The provider should not include any traffic that is already counted by 124 * kernel interface counters. 125 * @param uidStats the same stats as above, but counts {@link NetworkStats} 126 * per uid. 127 */ notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats, @NonNull NetworkStats uidStats)128 public void notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats, 129 @NonNull NetworkStats uidStats) { 130 try { 131 getProviderCallbackBinderOrThrow().notifyStatsUpdated(token, ifaceStats, uidStats); 132 } catch (RemoteException e) { 133 e.rethrowAsRuntimeException(); 134 } 135 } 136 137 /** 138 * Notify system that the quota set by {@code onSetAlert} has been reached. 139 */ notifyAlertReached()140 public void notifyAlertReached() { 141 try { 142 getProviderCallbackBinderOrThrow().notifyAlertReached(); 143 } catch (RemoteException e) { 144 e.rethrowAsRuntimeException(); 145 } 146 } 147 148 /** 149 * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached. 150 */ notifyWarningReached()151 public void notifyWarningReached() { 152 try { 153 // Reuse the code path to notify warning reached with limit reached 154 // since framework handles them in the same way. 155 getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); 156 } catch (RemoteException e) { 157 e.rethrowAsRuntimeException(); 158 } 159 } 160 161 /** 162 * Notify system that the quota set by {@link #onSetLimit} or limit set by 163 * {@link #onSetWarningAndLimit} has been reached. 164 */ notifyLimitReached()165 public void notifyLimitReached() { 166 try { 167 getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); 168 } catch (RemoteException e) { 169 e.rethrowAsRuntimeException(); 170 } 171 } 172 173 /** 174 * Called by {@code NetworkStatsService} when it requires to know updated stats. 175 * The provider MUST respond by calling {@link #notifyStatsUpdated} as soon as possible. 176 * Responding later increases the probability stats will be dropped. Memory allowing, the 177 * system will try to take stats into account up to one minute after calling 178 * {@link #onRequestStatsUpdate}. 179 * 180 * @param token a positive number identifying the new state of the system under which 181 * {@link NetworkStats} have to be gathered from now on. When this is called, 182 * custom implementations of providers MUST tally and report the latest stats with 183 * the previous token, under which stats were being gathered so far. 184 */ onRequestStatsUpdate(int token)185 public abstract void onRequestStatsUpdate(int token); 186 187 /** 188 * Called by {@code NetworkStatsService} when setting the interface quota for the specified 189 * upstream interface. When this is called, the custom implementation should block all egress 190 * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have 191 * been reached, and MUST respond to it by calling 192 * {@link NetworkStatsProvider#notifyLimitReached()}. 193 * 194 * @param iface the interface requiring the operation. 195 * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting 196 * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. 197 */ onSetLimit(@onNull String iface, long quotaBytes)198 public abstract void onSetLimit(@NonNull String iface, long quotaBytes); 199 200 /** 201 * Called by {@code NetworkStatsService} when setting the interface quotas for the specified 202 * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system 203 * will not call {@link #onSetLimit}. When this method is called, the implementation 204 * should behave as follows: 205 * 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on 206 * {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}. 207 * 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on 208 * {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}. 209 * 210 * @param iface the interface requiring the operation. 211 * @param warningBytes the warning defined as the number of bytes, starting from zero and 212 * counting from now. A value of {@link #QUOTA_UNLIMITED} indicates 213 * there is no warning. 214 * @param limitBytes the limit defined as the number of bytes, starting from zero and counting 215 * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. 216 */ onSetWarningAndLimit(@onNull String iface, long warningBytes, long limitBytes)217 public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) { 218 // Backward compatibility for those who didn't override this function. 219 onSetLimit(iface, limitBytes); 220 } 221 222 /** 223 * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations 224 * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes 225 * have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should 226 * not block all egress packets. 227 * 228 * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting 229 * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert. 230 */ onSetAlert(long quotaBytes)231 public abstract void onSetAlert(long quotaBytes); 232 } 233