Merge changes I3a38af76,I5e21de05 am: b261573ab0

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2618634

Change-Id: I40bccf34f6ad08817ea12e5ea89aff9aa5c97bb3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Hansen Kurli
2023-06-13 09:39:18 +00:00
committed by Automerger Merge Worker
4 changed files with 163 additions and 7 deletions

View File

@@ -94,6 +94,7 @@ public class AutomaticOnOffKeepaliveTracker {
private static final int ADJUST_TCP_POLLING_DELAY_MS = 2000;
private static final String AUTOMATIC_ON_OFF_KEEPALIVE_VERSION =
"automatic_on_off_keepalive_version";
public static final long METRICS_COLLECTION_DURATION_MS = 24 * 60 * 60 * 1_000L;
// ConnectivityService parses message constants from itself and AutomaticOnOffKeepaliveTracker
// with MessageUtils for debugging purposes, and crashes if some messages have the same values.
@@ -180,6 +181,9 @@ public class AutomaticOnOffKeepaliveTracker {
private final LocalLog mEventLog = new LocalLog(MAX_EVENTS_LOGS);
private final KeepaliveStatsTracker mKeepaliveStatsTracker;
private final long mMetricsWriteTimeBase;
/**
* Information about a managed keepalive.
*
@@ -311,7 +315,26 @@ public class AutomaticOnOffKeepaliveTracker {
mContext, mConnectivityServiceHandler);
mAlarmManager = mDependencies.getAlarmManager(context);
mKeepaliveStatsTracker = new KeepaliveStatsTracker(context, handler);
mKeepaliveStatsTracker =
mDependencies.newKeepaliveStatsTracker(context, handler);
final long time = mDependencies.getElapsedRealtime();
mMetricsWriteTimeBase = time % METRICS_COLLECTION_DURATION_MS;
final long triggerAtMillis = mMetricsWriteTimeBase + METRICS_COLLECTION_DURATION_MS;
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, TAG,
this::writeMetricsAndRescheduleAlarm, handler);
}
private void writeMetricsAndRescheduleAlarm() {
mKeepaliveStatsTracker.writeAndResetMetrics();
final long time = mDependencies.getElapsedRealtime();
final long triggerAtMillis =
mMetricsWriteTimeBase
+ (time - time % METRICS_COLLECTION_DURATION_MS)
+ METRICS_COLLECTION_DURATION_MS;
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, TAG,
this::writeMetricsAndRescheduleAlarm, mConnectivityServiceHandler);
}
private void startTcpPollingAlarm(@NonNull AutomaticOnOffKeepalive ki) {
@@ -897,6 +920,14 @@ public class AutomaticOnOffKeepaliveTracker {
return new KeepaliveTracker(mContext, connectivityserviceHander);
}
/**
* Construct a new KeepaliveStatsTracker.
*/
public KeepaliveStatsTracker newKeepaliveStatsTracker(@NonNull Context context,
@NonNull Handler connectivityserviceHander) {
return new KeepaliveStatsTracker(context, connectivityserviceHander);
}
/**
* Find out if a feature is enabled from DeviceConfig.
*

View File

@@ -19,7 +19,10 @@ package com.android.server.connectivity;
import static android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkSpecifier;
@@ -42,6 +45,8 @@ import com.android.metrics.DurationPerNumOfKeepalive;
import com.android.metrics.KeepaliveLifetimeForCarrier;
import com.android.metrics.KeepaliveLifetimePerCarrier;
import com.android.modules.utils.BackgroundThread;
import com.android.net.module.util.CollectionUtils;
import com.android.server.ConnectivityStatsLog;
import java.util.ArrayList;
import java.util.HashMap;
@@ -67,9 +72,7 @@ public class KeepaliveStatsTracker {
// Mapping of subId to carrierId. Updates are received from OnSubscriptionsChangedListener
private final SparseIntArray mCachedCarrierIdPerSubId = new SparseIntArray();
// The default subscription id obtained from SubscriptionManager.getDefaultSubscriptionId.
// Updates are done from the OnSubscriptionsChangedListener. Note that there is no callback done
// to OnSubscriptionsChangedListener when the default sub id changes.
// TODO: Register a listener for the default subId when it is possible.
// Updates are received from the ACTION_DEFAULT_SUBSCRIPTION_CHANGED broadcast.
private int mCachedDefaultSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
// Class to store network information, lifetime durations and active state of a keepalive.
@@ -267,6 +270,19 @@ public class KeepaliveStatsTracker {
Objects.requireNonNull(context.getSystemService(SubscriptionManager.class));
mLastUpdateDurationsTimestamp = mDependencies.getElapsedRealtime();
context.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mCachedDefaultSubscriptionId =
intent.getIntExtra(
SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
}
},
new IntentFilter(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED),
/* broadcastPermission= */ null,
mConnectivityServiceHandler);
// The default constructor for OnSubscriptionsChangedListener will always implicitly grab
// the looper of the current thread. In the case the current thread does not have a looper,
@@ -284,11 +300,8 @@ public class KeepaliveStatsTracker {
// but not necessarily empty, simply ignore it. Another call to the
// listener will be invoked in the future.
if (activeSubInfoList == null) return;
final int defaultSubId =
subscriptionManager.getDefaultSubscriptionId();
mConnectivityServiceHandler.post(() -> {
mCachedCarrierIdPerSubId.clear();
mCachedDefaultSubscriptionId = defaultSubId;
for (final SubscriptionInfo subInfo : activeSubInfoList) {
mCachedCarrierIdPerSubId.put(subInfo.getSubscriptionId(),
@@ -592,6 +605,7 @@ public class KeepaliveStatsTracker {
*
* @return the DailykeepaliveInfoReported proto that was built.
*/
@VisibleForTesting
public @NonNull DailykeepaliveInfoReported buildAndResetMetrics() {
ensureRunningOnHandlerThread();
final long timeNow = mDependencies.getElapsedRealtime();
@@ -620,6 +634,20 @@ public class KeepaliveStatsTracker {
return metrics;
}
/** Writes the stored metrics to ConnectivityStatsLog and resets. */
public void writeAndResetMetrics() {
ensureRunningOnHandlerThread();
final DailykeepaliveInfoReported dailyKeepaliveInfoReported = buildAndResetMetrics();
ConnectivityStatsLog.write(
ConnectivityStatsLog.DAILY_KEEPALIVE_INFO_REPORTED,
dailyKeepaliveInfoReported.getDurationPerNumOfKeepalive().toByteArray(),
dailyKeepaliveInfoReported.getKeepaliveLifetimePerCarrier().toByteArray(),
dailyKeepaliveInfoReported.getKeepaliveRequests(),
dailyKeepaliveInfoReported.getAutomaticKeepaliveRequests(),
dailyKeepaliveInfoReported.getDistinctUserCount(),
CollectionUtils.toIntArray(dailyKeepaliveInfoReported.getUidList()));
}
private void ensureRunningOnHandlerThread() {
if (mConnectivityServiceHandler.getLooper().getThread() != Thread.currentThread()) {
throw new IllegalStateException(

View File

@@ -21,6 +21,7 @@ import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static com.android.server.connectivity.AutomaticOnOffKeepaliveTracker.METRICS_COLLECTION_DURATION_MS;
import static com.android.testutils.HandlerUtils.visibleOnHandlerThread;
import static org.junit.Assert.assertEquals;
@@ -42,6 +43,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.ignoreStubs;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -125,6 +127,7 @@ public class AutomaticOnOffKeepaliveTrackerTest {
@Mock NetworkAgentInfo mNai;
@Mock SubscriptionManager mSubscriptionManager;
KeepaliveStatsTracker mKeepaliveStatsTracker;
TestKeepaliveTracker mKeepaliveTracker;
AOOTestHandler mTestHandler;
TestTcpKeepaliveController mTcpController;
@@ -344,8 +347,14 @@ public class AutomaticOnOffKeepaliveTrackerTest {
mTestHandler = new AOOTestHandler(mHandlerThread.getLooper());
mTcpController = new TestTcpKeepaliveController(mTestHandler);
mKeepaliveTracker = new TestKeepaliveTracker(mCtx, mTestHandler, mTcpController);
mKeepaliveStatsTracker = spy(new KeepaliveStatsTracker(mCtx, mTestHandler));
doReturn(mKeepaliveTracker).when(mDependencies).newKeepaliveTracker(mCtx, mTestHandler);
doReturn(mKeepaliveStatsTracker)
.when(mDependencies)
.newKeepaliveStatsTracker(mCtx, mTestHandler);
doReturn(true).when(mDependencies).isFeatureEnabled(any(), anyBoolean());
doReturn(0L).when(mDependencies).getElapsedRealtime();
mAOOKeepaliveTracker =
new AutomaticOnOffKeepaliveTracker(mCtx, mTestHandler, mDependencies);
}
@@ -499,6 +508,30 @@ public class AutomaticOnOffKeepaliveTrackerTest {
assertEquals(testInfo.underpinnedNetwork, mTestHandler.mLastAutoKi.getUnderpinnedNetwork());
}
@Test
public void testAlarm_writeMetrics() throws Exception {
final ArgumentCaptor<AlarmManager.OnAlarmListener> listenerCaptor =
ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
// First AlarmManager.set call from the constructor.
verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
eq(METRICS_COLLECTION_DURATION_MS), any() /* tag */, listenerCaptor.capture(),
eq(mTestHandler));
final AlarmManager.OnAlarmListener listener = listenerCaptor.getValue();
doReturn(METRICS_COLLECTION_DURATION_MS).when(mDependencies).getElapsedRealtime();
// For realism, the listener should be posted on the handler
mTestHandler.post(() -> listener.onAlarm());
HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
verify(mKeepaliveStatsTracker).writeAndResetMetrics();
// Alarm is rescheduled.
verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
eq(METRICS_COLLECTION_DURATION_MS * 2),
any() /* tag */, listenerCaptor.capture(), eq(mTestHandler));
}
private void setupResponseWithSocketExisting() throws Exception {
final ByteBuffer tcpBufferV6 = getByteBuffer(TEST_RESPONSE_BYTES);
final ByteBuffer tcpBufferV4 = getByteBuffer(TEST_RESPONSE_BYTES);

View File

@@ -27,12 +27,15 @@ import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.TelephonyNetworkSpecifier;
@@ -109,6 +112,18 @@ public class KeepaliveStatsTrackerTest {
@Mock private KeepaliveStatsTracker.Dependencies mDependencies;
@Mock private SubscriptionManager mSubscriptionManager;
private void triggerBroadcastDefaultSubId(int subId) {
final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
verify(mContext).registerReceiver(receiverCaptor.capture(), /* filter= */ any(),
/* broadcastPermission= */ any(), eq(mTestHandler));
final Intent intent =
new Intent(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
receiverCaptor.getValue().onReceive(mContext, intent);
}
private OnSubscriptionsChangedListener getOnSubscriptionsChangedListener() {
final ArgumentCaptor<OnSubscriptionsChangedListener> listenerCaptor =
ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class);
@@ -1128,4 +1143,53 @@ public class KeepaliveStatsTrackerTest {
writeTime * 3 - startTime1 - startTime2 - startTime3)
});
}
@Test
public void testUpdateDefaultSubId() {
final int startTime1 = 1000;
final int startTime2 = 3000;
final int writeTime = 5000;
// No TelephonyNetworkSpecifier set with subId to force the use of default subId.
final NetworkCapabilities nc =
new NetworkCapabilities.Builder().addTransportType(TRANSPORT_CELLULAR).build();
onStartKeepalive(startTime1, TEST_SLOT, nc);
// Update default subId
triggerBroadcastDefaultSubId(TEST_SUB_ID_1);
onStartKeepalive(startTime2, TEST_SLOT2, nc);
final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
buildKeepaliveMetrics(writeTime);
final int[] expectRegisteredDurations =
new int[] {startTime1, startTime2 - startTime1, writeTime - startTime2};
final int[] expectActiveDurations =
new int[] {startTime1, startTime2 - startTime1, writeTime - startTime2};
// Expect the carrier id of the first keepalive to be unknown
final KeepaliveCarrierStats expectKeepaliveCarrierStats1 =
new KeepaliveCarrierStats(
TelephonyManager.UNKNOWN_CARRIER_ID,
/* transportTypes= */ (1 << TRANSPORT_CELLULAR),
TEST_KEEPALIVE_INTERVAL_SEC * 1000,
writeTime - startTime1,
writeTime - startTime1);
// Expect the carrier id of the second keepalive to be TEST_CARRIER_ID_1, from TEST_SUB_ID_1
final KeepaliveCarrierStats expectKeepaliveCarrierStats2 =
new KeepaliveCarrierStats(
TEST_CARRIER_ID_1,
/* transportTypes= */ (1 << TRANSPORT_CELLULAR),
TEST_KEEPALIVE_INTERVAL_SEC * 1000,
writeTime - startTime2,
writeTime - startTime2);
assertDailyKeepaliveInfoReported(
dailyKeepaliveInfoReported,
/* expectRequestsCount= */ 2,
/* expectAutoRequestsCount= */ 2,
/* expectAppUids= */ new int[] {TEST_UID},
expectRegisteredDurations,
expectActiveDurations,
new KeepaliveCarrierStats[] {
expectKeepaliveCarrierStats1, expectKeepaliveCarrierStats2
});
}
}