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} and {@link #onSetAlert} indicates there is no limit.
33      */
34     public static final int QUOTA_UNLIMITED = -1;
35 
36     @NonNull private final INetworkStatsProvider mProviderBinder =
37             new INetworkStatsProvider.Stub() {
38 
39         @Override
40         public void onRequestStatsUpdate(int token) {
41             NetworkStatsProvider.this.onRequestStatsUpdate(token);
42         }
43 
44         @Override
45         public void onSetLimit(String iface, long quotaBytes) {
46             NetworkStatsProvider.this.onSetLimit(iface, quotaBytes);
47         }
48 
49         @Override
50         public void onSetAlert(long quotaBytes) {
51             NetworkStatsProvider.this.onSetAlert(quotaBytes);
52         }
53     };
54 
55     // The binder given by the service when successfully registering. Only null before registering,
56     // never null once non-null.
57     @Nullable
58     private INetworkStatsProviderCallback mProviderCbBinder;
59 
60     /**
61      * Return the binder invoked by the service and redirect function calls to the overridden
62      * methods.
63      * @hide
64      */
65     @NonNull
getProviderBinder()66     public INetworkStatsProvider getProviderBinder() {
67         return mProviderBinder;
68     }
69 
70     /**
71      * Store the binder that was returned by the service when successfully registering. Note that
72      * the provider cannot be re-registered. Hence this method can only be called once per provider.
73      *
74      * @hide
75      */
setProviderCallbackBinder(@onNull INetworkStatsProviderCallback binder)76     public void setProviderCallbackBinder(@NonNull INetworkStatsProviderCallback binder) {
77         if (mProviderCbBinder != null) {
78             throw new IllegalArgumentException("provider is already registered");
79         }
80         mProviderCbBinder = binder;
81     }
82 
83     /**
84      * Get the binder that was returned by the service when successfully registering. Or null if the
85      * provider was never registered.
86      *
87      * @hide
88      */
89     @Nullable
getProviderCallbackBinder()90     public INetworkStatsProviderCallback getProviderCallbackBinder() {
91         return mProviderCbBinder;
92     }
93 
94     /**
95      * Get the binder that was returned by the service when successfully registering. Throw an
96      * {@link IllegalStateException} if the provider is not registered.
97      *
98      * @hide
99      */
100     @NonNull
getProviderCallbackBinderOrThrow()101     public INetworkStatsProviderCallback getProviderCallbackBinderOrThrow() {
102         if (mProviderCbBinder == null) {
103             throw new IllegalStateException("the provider is not registered");
104         }
105         return mProviderCbBinder;
106     }
107 
108     /**
109      * Notify the system of new network statistics.
110      *
111      * Send the network statistics recorded since the last call to {@link #notifyStatsUpdated}. Must
112      * be called as soon as possible after {@link NetworkStatsProvider#onRequestStatsUpdate(int)}
113      * being called. Responding later increases the probability stats will be dropped. The
114      * provider can also call this whenever it wants to reports new stats for any reason.
115      * Note that the system will not necessarily immediately propagate the statistics to
116      * reflect the update.
117      *
118      * @param token the token under which these stats were gathered. Providers can call this method
119      *              with the current token as often as they want, until the token changes.
120      *              {@see NetworkStatsProvider#onRequestStatsUpdate()}
121      * @param ifaceStats the {@link NetworkStats} per interface to be reported.
122      *                   The provider should not include any traffic that is already counted by
123      *                   kernel interface counters.
124      * @param uidStats the same stats as above, but counts {@link NetworkStats}
125      *                 per uid.
126      */
notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats, @NonNull NetworkStats uidStats)127     public void notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats,
128             @NonNull NetworkStats uidStats) {
129         try {
130             getProviderCallbackBinderOrThrow().notifyStatsUpdated(token, ifaceStats, uidStats);
131         } catch (RemoteException e) {
132             e.rethrowAsRuntimeException();
133         }
134     }
135 
136     /**
137      * Notify system that the quota set by {@code onSetAlert} has been reached.
138      */
notifyAlertReached()139     public void notifyAlertReached() {
140         try {
141             getProviderCallbackBinderOrThrow().notifyAlertReached();
142         } catch (RemoteException e) {
143             e.rethrowAsRuntimeException();
144         }
145     }
146 
147     /**
148      * Notify system that the quota set by {@code onSetLimit} has been reached.
149      */
notifyLimitReached()150     public void notifyLimitReached() {
151         try {
152             getProviderCallbackBinderOrThrow().notifyLimitReached();
153         } catch (RemoteException e) {
154             e.rethrowAsRuntimeException();
155         }
156     }
157 
158     /**
159      * Called by {@code NetworkStatsService} when it requires to know updated stats.
160      * The provider MUST respond by calling {@link #notifyStatsUpdated} as soon as possible.
161      * Responding later increases the probability stats will be dropped. Memory allowing, the
162      * system will try to take stats into account up to one minute after calling
163      * {@link #onRequestStatsUpdate}.
164      *
165      * @param token a positive number identifying the new state of the system under which
166      *              {@link NetworkStats} have to be gathered from now on. When this is called,
167      *              custom implementations of providers MUST tally and report the latest stats with
168      *              the previous token, under which stats were being gathered so far.
169      */
onRequestStatsUpdate(int token)170     public abstract void onRequestStatsUpdate(int token);
171 
172     /**
173      * Called by {@code NetworkStatsService} when setting the interface quota for the specified
174      * upstream interface. When this is called, the custom implementation should block all egress
175      * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have
176      * been reached, and MUST respond to it by calling
177      * {@link NetworkStatsProvider#notifyLimitReached()}.
178      *
179      * @param iface the interface requiring the operation.
180      * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting
181      *                   from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
182      */
onSetLimit(@onNull String iface, long quotaBytes)183     public abstract void onSetLimit(@NonNull String iface, long quotaBytes);
184 
185     /**
186      * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations
187      * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes
188      * have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should
189      * not block all egress packets.
190      *
191      * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting
192      *                   from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert.
193      */
onSetAlert(long quotaBytes)194     public abstract void onSetAlert(long quotaBytes);
195 }
196