Allow more than one source of tethering statistics.

Currently, netd is the only source of tethering statistics.
In order to support multiple sources, define a new
ITetheringStatsProvider interface that can be registered with
NetworkManagmentService. Convert the existing code into the
first ITetheringStatsProvider.

Bug: 29337859
Bug: 32163131
Test: builds, boots
Test: tethering stats continue to be collected
Change-Id: Ie1b5a5e47ae4bf5af922365b09fa241e834236e4
This commit is contained in:
Lorenzo Colitti
2017-07-10 19:06:57 +09:00
parent aa7b8b5322
commit ef7b2a13ce
4 changed files with 102 additions and 10 deletions

View File

@@ -238,6 +238,7 @@ LOCAL_SRC_FILES += \
core/java/android/net/INetworkScoreService.aidl \
core/java/android/net/INetworkStatsService.aidl \
core/java/android/net/INetworkStatsSession.aidl \
core/java/android/net/ITetheringStatsProvider.aidl \
core/java/android/net/nsd/INsdManager.aidl \
core/java/android/nfc/IAppCallback.aidl \
core/java/android/nfc/INfcAdapter.aidl \

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2017 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;
/**
* Interface that allows NetworkManagementService to query for tethering statistics.
*
* TODO: this does not really need to be an interface since Tethering runs in the same process
* as NetworkManagementService. Consider refactoring Tethering to use direct access to
* NetworkManagementService instead of using INetworkManagementService, and then deleting this
* interface.
*
* @hide
*/
interface ITetheringStatsProvider {
NetworkStats getTetherStats();
}

View File

@@ -20,6 +20,7 @@ package android.os;
import android.net.InterfaceConfiguration;
import android.net.INetd;
import android.net.INetworkManagementEventObserver;
import android.net.ITetheringStatsProvider;
import android.net.Network;
import android.net.NetworkStats;
import android.net.RouteInfo;
@@ -206,6 +207,18 @@ interface INetworkManagementService
*/
void disableNat(String internalInterface, String externalInterface);
/**
* Registers a {@code ITetheringStatsProvider} to provide tethering statistics.
* All registered providers will be called in order, and their results will be added together.
* Netd is always registered as a tethering stats provider.
*/
void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name);
/**
* Unregisters a previously-registered {@code ITetheringStatsProvider}.
*/
void unregisterTetheringStatsProvider(ITetheringStatsProvider provider);
/**
** PPPD
**/

View File

@@ -18,6 +18,7 @@ package com.android.server;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.SHUTDOWN;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
@@ -55,6 +56,7 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkManagementEventObserver;
import android.net.ITetheringStatsProvider;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -225,6 +227,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub
private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
@GuardedBy("mTetheringStatsProviders")
private final HashMap<ITetheringStatsProvider, String>
mTetheringStatsProviders = Maps.newHashMap();
/**
* If both locks need to be held, then they should be obtained in the order:
* first {@link #mQuotaLock} and then {@link #mRulesLock}.
@@ -331,6 +337,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub
Watchdog.getInstance().addMonitor(this);
LocalServices.addService(NetworkManagementInternal.class, new LocalService());
synchronized (mTetheringStatsProviders) {
mTetheringStatsProviders.put(new NetdTetheringStatsProvider(), "netd");
}
}
@VisibleForTesting
@@ -520,6 +530,23 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
}
@Override
public void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name) {
mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
Preconditions.checkNotNull(provider);
synchronized(mTetheringStatsProviders) {
mTetheringStatsProviders.put(provider, name);
}
}
@Override
public void unregisterTetheringStatsProvider(ITetheringStatsProvider provider) {
mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
synchronized(mTetheringStatsProviders) {
mTetheringStatsProviders.remove(provider);
}
}
// Sync the state of the given chain with the native daemon.
private void syncFirewallChainLocked(int chain, String name) {
SparseIntArray rules;
@@ -1789,14 +1816,16 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
}
@Override
public NetworkStats getNetworkStatsTethering() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
try {
final NativeDaemonEvent[] events = mConnector.executeForList(
"bandwidth", "gettetherstats");
private class NetdTetheringStatsProvider extends ITetheringStatsProvider.Stub {
@Override
public NetworkStats getTetherStats() {
final NativeDaemonEvent[] events;
try {
events = mConnector.executeForList("bandwidth", "gettetherstats");
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
for (NativeDaemonEvent event : events) {
if (event.getCode() != TetheringStatsListResult) continue;
@@ -1822,8 +1851,24 @@ public class NetworkManagementService extends INetworkManagementService.Stub
throw new IllegalStateException("problem parsing tethering stats: " + event);
}
}
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
return stats;
}
}
@Override
public NetworkStats getNetworkStatsTethering() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
synchronized (mTetheringStatsProviders) {
for (ITetheringStatsProvider provider: mTetheringStatsProviders.keySet()) {
try {
stats.combineAllValues(provider.getTetherStats());
} catch (RemoteException e) {
Log.e(TAG, "Problem reading tethering stats from " +
mTetheringStatsProviders.get(provider) + ": " + e);
}
}
}
return stats;
}