Merge "register callback to pull NetworkBpfMapInfo atom"
This commit is contained in:
commit
3dc2fb5378
4 changed files with 112 additions and 1 deletions
|
|
@ -143,6 +143,7 @@ java_library {
|
|||
"src/**/*.java",
|
||||
":framework-connectivity-shared-srcs",
|
||||
":services-connectivity-shared-srcs",
|
||||
":statslog-connectivity-java-gen",
|
||||
],
|
||||
libs: [
|
||||
"framework-annotations-lib",
|
||||
|
|
@ -152,6 +153,7 @@ java_library {
|
|||
"framework-wifi.stubs.module_lib",
|
||||
"unsupportedappusage",
|
||||
"ServiceConnectivityResources",
|
||||
"framework-statsd.stubs.module_lib",
|
||||
],
|
||||
static_libs: [
|
||||
// Do not add libs here if they are already included
|
||||
|
|
@ -332,3 +334,10 @@ java_genrule {
|
|||
"--output $(out)",
|
||||
visibility: ["//visibility:private"],
|
||||
}
|
||||
|
||||
genrule {
|
||||
name: "statslog-connectivity-java-gen",
|
||||
tools: ["stats-log-api-gen"],
|
||||
cmd: "$(location stats-log-api-gen) --java $(out) --module connectivity --javaPackage com.android.server --javaClass ConnectivityStatsLog",
|
||||
out: ["com/android/server/ConnectivityStatsLog.java"],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ import static android.system.OsConstants.ENODEV;
|
|||
import static android.system.OsConstants.ENOENT;
|
||||
import static android.system.OsConstants.EOPNOTSUPP;
|
||||
|
||||
import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO;
|
||||
|
||||
import android.app.StatsManager;
|
||||
import android.content.Context;
|
||||
import android.net.INetd;
|
||||
import android.os.RemoteException;
|
||||
|
|
@ -42,12 +45,15 @@ import android.system.ErrnoException;
|
|||
import android.system.Os;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.StatsEvent;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.modules.utils.BackgroundThread;
|
||||
import com.android.modules.utils.build.SdkLevel;
|
||||
import com.android.net.module.util.BpfMap;
|
||||
import com.android.net.module.util.DeviceConfigUtils;
|
||||
import com.android.net.module.util.IBpfMap;
|
||||
import com.android.net.module.util.Struct;
|
||||
import com.android.net.module.util.Struct.U32;
|
||||
import com.android.net.module.util.Struct.U8;
|
||||
import com.android.net.module.util.bpf.CookieTagMapKey;
|
||||
|
|
@ -55,6 +61,7 @@ import com.android.net.module.util.bpf.CookieTagMapValue;
|
|||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
|
@ -274,6 +281,15 @@ public class BpfNetMaps {
|
|||
public int synchronizeKernelRCU() {
|
||||
return native_synchronizeKernelRCU();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Stats Event for NETWORK_BPF_MAP_INFO atom
|
||||
*/
|
||||
public StatsEvent buildStatsEvent(final int cookieTagMapSize, final int uidOwnerMapSize,
|
||||
final int uidPermissionMapSize) {
|
||||
return ConnectivityStatsLog.buildStatsEvent(NETWORK_BPF_MAP_INFO, cookieTagMapSize,
|
||||
uidOwnerMapSize, uidPermissionMapSize);
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructor used after T that doesn't need to use netd anymore. */
|
||||
|
|
@ -849,6 +865,43 @@ public class BpfNetMaps {
|
|||
}
|
||||
}
|
||||
|
||||
/** Register callback for statsd to pull atom. */
|
||||
public void setPullAtomCallback(final Context context) {
|
||||
throwIfPreT("setPullAtomCallback is not available on pre-T devices");
|
||||
|
||||
final StatsManager statsManager = context.getSystemService(StatsManager.class);
|
||||
statsManager.setPullAtomCallback(NETWORK_BPF_MAP_INFO, null /* metadata */,
|
||||
BackgroundThread.getExecutor(), this::pullBpfMapInfoAtom);
|
||||
}
|
||||
|
||||
private <K extends Struct, V extends Struct> int getMapSize(IBpfMap<K, V> map)
|
||||
throws ErrnoException {
|
||||
// forEach could restart iteration from the beginning if there is a concurrent entry
|
||||
// deletion. netd and skDestroyListener could delete CookieTagMap entry concurrently.
|
||||
// So using Set to count the number of entry in the map.
|
||||
Set<K> keySet = new ArraySet<>();
|
||||
map.forEach((k, v) -> keySet.add(k));
|
||||
return keySet.size();
|
||||
}
|
||||
|
||||
/** Callback for StatsManager#setPullAtomCallback */
|
||||
@VisibleForTesting
|
||||
public int pullBpfMapInfoAtom(final int atomTag, final List<StatsEvent> data) {
|
||||
if (atomTag != NETWORK_BPF_MAP_INFO) {
|
||||
Log.e(TAG, "Unexpected atom tag: " + atomTag);
|
||||
return StatsManager.PULL_SKIP;
|
||||
}
|
||||
|
||||
try {
|
||||
data.add(mDeps.buildStatsEvent(getMapSize(sCookieTagMap), getMapSize(sUidOwnerMap),
|
||||
getMapSize(sUidPermissionMap)));
|
||||
} catch (ErrnoException e) {
|
||||
Log.e(TAG, "Failed to pull NETWORK_BPF_MAP_INFO atom: " + e);
|
||||
return StatsManager.PULL_SKIP;
|
||||
}
|
||||
return StatsManager.PULL_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump BPF maps
|
||||
*
|
||||
|
|
|
|||
|
|
@ -3040,6 +3040,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||
if (!ConnectivitySettingsManager.getMobileDataPreferredUids(mContext).isEmpty()) {
|
||||
updateMobileDataPreferredUids();
|
||||
}
|
||||
|
||||
// On T+ devices, register callback for statsd to pull NETWORK_BPF_MAP_INFO atom
|
||||
if (SdkLevel.isAtLeastT()) {
|
||||
mBpfNetMaps.setPullAtomCallback(mContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import static android.net.INetd.PERMISSION_INTERNET;
|
|||
import static android.net.INetd.PERMISSION_NONE;
|
||||
import static android.net.INetd.PERMISSION_UNINSTALLED;
|
||||
import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
|
||||
import static android.system.OsConstants.EINVAL;
|
||||
import static android.system.OsConstants.EPERM;
|
||||
|
||||
import static com.android.server.BpfNetMaps.DOZABLE_MATCH;
|
||||
|
|
@ -40,6 +41,7 @@ import static com.android.server.BpfNetMaps.NO_MATCH;
|
|||
import static com.android.server.BpfNetMaps.PENALTY_BOX_MATCH;
|
||||
import static com.android.server.BpfNetMaps.POWERSAVE_MATCH;
|
||||
import static com.android.server.BpfNetMaps.RESTRICTED_MATCH;
|
||||
import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
|
@ -47,13 +49,18 @@ import static org.junit.Assert.assertNull;
|
|||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.StatsManager;
|
||||
import android.content.Context;
|
||||
import android.net.INetd;
|
||||
import android.os.Build;
|
||||
import android.os.ServiceSpecificException;
|
||||
import android.system.ErrnoException;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
|
|
@ -76,6 +83,7 @@ import org.junit.runner.RunWith;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(DevSdkIgnoreRunner.class)
|
||||
|
|
@ -120,7 +128,7 @@ public final class BpfNetMapsTest {
|
|||
new TestBpfMap<>(U32.class, UidOwnerValue.class);
|
||||
private final IBpfMap<U32, U8> mUidPermissionMap = new TestBpfMap<>(U32.class, U8.class);
|
||||
private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap =
|
||||
new TestBpfMap<>(CookieTagMapKey.class, CookieTagMapValue.class);
|
||||
spy(new TestBpfMap<>(CookieTagMapKey.class, CookieTagMapValue.class));
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
|
@ -882,4 +890,40 @@ public final class BpfNetMapsTest {
|
|||
|
||||
assertThrows(ServiceSpecificException.class, () -> mBpfNetMaps.swapActiveStatsMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testPullBpfMapInfo() throws Exception {
|
||||
// mCookieTagMap has 1 entry
|
||||
mCookieTagMap.updateEntry(new CookieTagMapKey(0), new CookieTagMapValue(0, 0));
|
||||
|
||||
// mUidOwnerMap has 2 entries
|
||||
mUidOwnerMap.updateEntry(new U32(0), new UidOwnerValue(0, 0));
|
||||
mUidOwnerMap.updateEntry(new U32(1), new UidOwnerValue(0, 0));
|
||||
|
||||
// mUidPermissionMap has 3 entries
|
||||
mUidPermissionMap.updateEntry(new U32(0), new U8((short) 0));
|
||||
mUidPermissionMap.updateEntry(new U32(1), new U8((short) 0));
|
||||
mUidPermissionMap.updateEntry(new U32(2), new U8((short) 0));
|
||||
|
||||
final int ret = mBpfNetMaps.pullBpfMapInfoAtom(NETWORK_BPF_MAP_INFO, new ArrayList<>());
|
||||
assertEquals(StatsManager.PULL_SUCCESS, ret);
|
||||
verify(mDeps).buildStatsEvent(
|
||||
1 /* cookieTagMapSize */, 2 /* uidOwnerMapSize */, 3 /* uidPermissionMapSize */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testPullBpfMapInfoGetMapSizeFailure() throws Exception {
|
||||
doThrow(new ErrnoException("", EINVAL)).when(mCookieTagMap).forEach(any());
|
||||
final int ret = mBpfNetMaps.pullBpfMapInfoAtom(NETWORK_BPF_MAP_INFO, new ArrayList<>());
|
||||
assertEquals(StatsManager.PULL_SKIP, ret);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testPullBpfMapInfoUnexpectedAtomTag() {
|
||||
final int ret = mBpfNetMaps.pullBpfMapInfoAtom(-1 /* atomTag */, new ArrayList<>());
|
||||
assertEquals(StatsManager.PULL_SKIP, ret);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue