From 55614983a65af588e11bc642bfb5fe5a51f77b24 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Mon, 23 Jun 2025 19:53:02 +0000 Subject: [PATCH] Add logging for onPermissionsChanged latency. Flag: com.android.tethering.mainline.beta.lnp_developer_opt_in Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.server.connectivity.PermissionMonitorTest Bug: 424558169 Change-Id: Ifb621149130212a2903a7c31eebd4126e7d9924a --- .../connectivity/PermissionMonitor.java | 44 ++++++++++++++++++- tests/common/Android.bp | 2 + .../connectivity/PermissionMonitorTest.java | 41 +++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java index 20c8b0fccb..d4d947d75f 100755 --- a/service/src/com/android/server/connectivity/PermissionMonitor.java +++ b/service/src/com/android/server/connectivity/PermissionMonitor.java @@ -30,6 +30,8 @@ import static android.net.connectivity.ConnectivityCompatChanges.RESTRICT_LOCAL_ import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; +import static com.android.net.module.util.CollectionUtils.toIntArray; +import static com.android.server.ConnectivityStatsLog.CONNECTIVITY_PERMISSION_CHANGE_LISTENER_LATENCY_REPORTED; import static com.android.server.connectivity.ConnectivityFlags.USE_BROADCAST_RECEIVE_HELPER_FOR_PERMISSION_MONITOR; import static com.android.server.connectivity.NetworkPermissions.PERMISSION_NETWORK; import static com.android.server.connectivity.NetworkPermissions.PERMISSION_NONE; @@ -37,7 +39,6 @@ import static com.android.server.connectivity.NetworkPermissions.PERMISSION_SYST import static com.android.server.connectivity.NetworkPermissions.TRAFFIC_PERMISSION_INTERNET; import static com.android.server.connectivity.NetworkPermissions.TRAFFIC_PERMISSION_UNINSTALLED; import static com.android.server.connectivity.NetworkPermissions.TRAFFIC_PERMISSION_UPDATE_DEVICE_STATS; -import static com.android.net.module.util.CollectionUtils.toIntArray; import android.annotation.NonNull; import android.annotation.Nullable; @@ -63,6 +64,7 @@ import android.os.HandlerThread; import android.os.Process; import android.os.RemoteException; import android.os.ServiceSpecificException; +import android.os.SystemClock; import android.os.SystemConfigManager; import android.os.UserHandle; import android.os.UserManager; @@ -73,6 +75,8 @@ import android.util.ArraySet; import android.util.Log; import android.util.SparseIntArray; +import androidx.annotation.RequiresApi; + import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; @@ -83,12 +87,14 @@ import com.android.net.module.util.SharedLog; import com.android.networkstack.apishim.ProcessShimImpl; import com.android.networkstack.apishim.common.ProcessShim; import com.android.server.BpfNetMaps; +import com.android.server.ConnectivityStatsLog; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; /** * A utility class to inform Netd of UID permissions. @@ -253,6 +259,22 @@ public class PermissionMonitor { public boolean isFeatureNotChickenedOut(Context context, String name) { return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context, name); } + + /** + * Logs the latency of the PermissionChangeListener#onPermissionsChanged callback. + */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public void logPermissionChangeListenerLatency(int durationMicros) { + ConnectivityStatsLog.write(CONNECTIVITY_PERMISSION_CHANGE_LISTENER_LATENCY_REPORTED, + durationMicros); + } + + /** + * @see com.android.tethering.mainline.beta.Flags#lnpDeveloperOptIn() + */ + public boolean isLnpDeveloperOptInEnabled() { + return com.android.tethering.mainline.beta.Flags.lnpDeveloperOptIn(); + } } private static class MultiSet { @@ -1410,7 +1432,25 @@ public class PermissionMonitor { private class PermissionChangeListener implements PackageManager.OnPermissionsChangedListener { @Override public void onPermissionsChanged(int uid) { - setLocalNetworkPermissions(uid, null); + long startTimeNanos = SystemClock.elapsedRealtimeNanos(); + try { + setLocalNetworkPermissions(uid, null); + } finally { + long durationNanos = SystemClock.elapsedRealtimeNanos() - startTimeNanos; + int durationMicros = (int) TimeUnit.NANOSECONDS.toMicros(durationNanos); + if (DBG) { + Log.d(TAG, + "setLocalNetworkPermissions in onPermissionsChanged took " + + durationMicros + " microseconds."); + } + //The ConnectivityStatsLog#write method is only available on Android T + //and higher. The surrounding logic in logPermissionChangeListenerLatency + //ensures this code path is only executed on compatible platform versions, this + //explicit SDK version check is necessary to suppress the NewApi lint warning. + if (mDeps.isLnpDeveloperOptInEnabled() && SdkLevel.isAtLeastB()) { + mDeps.logPermissionChangeListenerLatency(durationMicros); + } + } } } } diff --git a/tests/common/Android.bp b/tests/common/Android.bp index 2c37494f3b..420cd2bb0f 100644 --- a/tests/common/Android.bp +++ b/tests/common/Android.bp @@ -114,6 +114,8 @@ android_test { "mockito-target-extended-minus-junit4", "modules-utils-native-coverage-listener", "ConnectivityCoverageTestsLib", + "com.android.tethering.mainline.beta.flags-aconfig-java", + "flag-junit", ], jni_libs: [ // For mockito extended diff --git a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java index 28d25cf5f2..a0ead9afbc 100644 --- a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -1815,6 +1815,47 @@ public class PermissionMonitorTest { mBpfMapMonitor.expectTrafficPerm(appId3Perm, MOCK_APPID3); } + @Test + @EnableCompatChanges(RESTRICT_LOCAL_NETWORK) + public void testOnPermissionsChanged_logsLatency_lnpDeveloperOptInEnabled() { + PackageManager.OnPermissionsChangedListener listener = + setupMocksAndCaptureRegisteredListener(/* isLnpDeveloperOptInEnabled */ true); + + listener.onPermissionsChanged(MOCK_UID11); + + verify(mDeps).logPermissionChangeListenerLatency(anyInt()); + } + + @Test + @EnableCompatChanges(RESTRICT_LOCAL_NETWORK) + public void testOnPermissionsChanged_logsLatency_lnpDeveloperOptInDisabled() { + PackageManager.OnPermissionsChangedListener listener = + setupMocksAndCaptureRegisteredListener(/* isLnpDeveloperOptInEnabled */ false); + + listener.onPermissionsChanged(MOCK_UID11); + + verify(mDeps, never()).logPermissionChangeListenerLatency(anyInt()); + } + + /** + * Sets up mock dependencies, verifies that a permissions listener was registered, + * and returns the captured listener for further testing. + */ + private PackageManager.OnPermissionsChangedListener setupMocksAndCaptureRegisteredListener( + boolean isLnpDeveloperOptInEnabled) { + assumeTrue(BpfNetMaps.isAtLeast25Q2()); + ArgumentCaptor listenerCaptor = + ArgumentCaptor.forClass(PackageManager.OnPermissionsChangedListener.class); + verify(mPackageManager).addOnPermissionsChangeListener(listenerCaptor.capture()); + PackageManager.OnPermissionsChangedListener listener = listenerCaptor.getValue(); + + when(mDeps.shouldEnforceLocalNetRestrictions(anyInt())).thenReturn(true); + when(mDeps.isLnpDeveloperOptInEnabled()).thenReturn(isLnpDeveloperOptInEnabled); + when(mPermissionManager.checkPermissionForPreflight( + anyString(), any(AttributionSource.class))).thenReturn(PERMISSION_DENIED); + return listener; + } + @Test @EnableCompatChanges(RESTRICT_LOCAL_NETWORK) public void testAppIdsTrafficPermission_UserAddedRemoved() {