Merge "Maintain a set self-certified apps in SatelliteAccessController" into main

This commit is contained in:
Junyu Lai 2025-04-24 22:48:53 -07:00 • committed by Android (Google) Code Review
commit 2f92579f8a
4 changed files with 298 additions and 40 deletions

View file

@ -7738,6 +7738,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
final List<PackageInfo> apps = mContext.getPackageManager()
.getInstalledPackagesAsUser(GET_PERMISSIONS, user.getIdentifier());
mPermissionMonitor.onUserAddedWithInstalledPackageList(user, apps);
if (mSatelliteAccessController != null) {
mSatelliteAccessController.onUserAddedWithInstalledPackageList(user, apps);
}
}
@Override
@ -7760,12 +7763,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
public void onPackageAdded(@NonNull final String packageName, final int uid) {
handlePackageChanged(packageName);
mPermissionMonitor.onPackageAdded(packageName, uid);
if (mSatelliteAccessController != null) {
mSatelliteAccessController.onPackageAdded(packageName, uid);
}
}
@Override
public void onPackageRemoved(@NonNull final String packageName, final int uid) {
handlePackageChanged(packageName);
mPermissionMonitor.onPackageRemoved(packageName, uid);
if (mSatelliteAccessController != null) {
mSatelliteAccessController.onPackageRemoved(packageName, uid);
}
}
@Override

View file

@ -67,6 +67,9 @@ public final class ConnectivityFlags {
public static final String CLOSE_QUIC_CONNECTION = "close_quic_connection";
public static final String CONSTRAINED_DATA_SATELLITE_OPTIN =
"constrained_data_satellite_optin";
private boolean mNoRematchAllRequestsOnRegister;
/**

View file

@ -16,22 +16,27 @@
package com.android.server.connectivity;
import static android.os.Process.INVALID_UID;
import static com.android.server.connectivity.ConnectivityFlags.CONSTRAINED_DATA_SATELLITE_OPTIN;
import android.Manifest;
import android.annotation.NonNull;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.DeviceConfigUtils;
import java.util.List;
import java.util.Set;
@ -45,17 +50,32 @@ import java.util.function.Consumer;
*/
public class SatelliteAccessController {
private static final String TAG = SatelliteAccessController.class.getSimpleName();
// Shamelessly copied from telephony/satellite/SatelliteManager.java.
@VisibleForTesting
public static final String PROPERTY_SATELLITE_DATA_OPTIMIZED =
"android.telephony.PROPERTY_SATELLITE_DATA_OPTIMIZED";
// This value is taken from android.os.UserHandle#PER_USER_RANGE.
@VisibleForTesting
public static final int PER_USER_RANGE = 100000;
private final Context mContext;
private final Dependencies mDeps;
private final DefaultMessageRoleListener mDefaultMessageRoleListener;
private final Consumer<Set<Integer>> mCallback;
private final Handler mConnectivityServiceHandler;
private final PackageManager mPackageManager;
private final boolean mSupportConstrainedDataSatelliteOptIn;
// At this sparseArray, Key is userId and values are uids of SMS apps that are allowed
// to use satellite network as fallback.
private final SparseArray<Set<Integer>> mAllUsersSatelliteNetworkFallbackUidCache =
new SparseArray<>();
// Set of UIDs that have declared the
// {@code android.telephony.PROPERTY_SATELLITE_DATA_OPTIMIZED} property
// with a value of package name in their manifest file. This variable will only be
// accessed on the handler thread.
private final Set<Integer> mSatelliteDataOptimizedUids = new ArraySet<>();
/**
* Monitor {@link android.app.role.OnRoleHoldersChangedListener#onRoleHoldersChanged(String,
* UserHandle)},
@ -104,6 +124,12 @@ public class SatelliteAccessController {
@NonNull OnRoleHoldersChangedListener listener, UserHandle user) {
mRoleManager.addOnRoleHoldersChangedListenerAsUser(executor, listener, user);
}
/** Return whether constrained data satellite opt-in is supported. */
public boolean supportConstrainedDataSatelliteOptIn(Context context) {
return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context,
CONSTRAINED_DATA_SATELLITE_OPTIN);
}
}
@VisibleForTesting
@ -115,6 +141,8 @@ public class SatelliteAccessController {
mDefaultMessageRoleListener = new DefaultMessageRoleListener();
mCallback = callback;
mConnectivityServiceHandler = connectivityServiceInternalHandler;
mPackageManager = mContext.getPackageManager();
mSupportConstrainedDataSatelliteOptIn = mDeps.supportConstrainedDataSatelliteOptIn(c);
}
private Set<Integer> updateSatelliteNetworkFallbackUidListCache(List<String> packageNames,
@ -129,7 +157,7 @@ public class SatelliteAccessController {
// cache list.
if (isSatellitePermissionEnabled(pm, packageName)) {
int uid = getUidForPackage(pm, packageName);
if (uid != Process.INVALID_UID) {
if (uid != INVALID_UID) {
fallbackUids.add(uid);
}
}
@ -150,7 +178,7 @@ public class SatelliteAccessController {
private int getUidForPackage(PackageManager packageManager, String pkgName) {
if (pkgName == null) {
return Process.INVALID_UID;
return INVALID_UID;
}
try {
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(pkgName, 0);
@ -158,13 +186,13 @@ public class SatelliteAccessController {
} catch (PackageManager.NameNotFoundException exception) {
Log.e(TAG, "Unable to find uid for package: " + pkgName);
}
return Process.INVALID_UID;
return INVALID_UID;
}
// on Role sms change triggered by OnRoleHoldersChangedListener()
private void onRoleSmsChanged(@NonNull UserHandle userHandle) {
int userId = userHandle.getIdentifier();
if (userId == Process.INVALID_UID) {
if (userId == INVALID_UID) {
Log.wtf(TAG, "Invalid User Id");
return;
}
@ -209,34 +237,10 @@ public class SatelliteAccessController {
}
public void start() {
mConnectivityServiceHandler.post(this::updateAllUserRoleSmsUids);
// register sms OnRoleHoldersChangedListener
mDefaultMessageRoleListener.register();
}
private void updateAllUserRoleSmsUids() {
UserManager userManager = mContext.getSystemService(UserManager.class);
// get existing user handles of available users
List<UserHandle> existingUsers = userManager.getUserHandles(true /*excludeDying*/);
// Iterate through the user handles and obtain their uids with role sms and satellite
// communication permission
Log.i(TAG, "existing users: " + existingUsers);
for (UserHandle userHandle : existingUsers) {
onRoleSmsChanged(userHandle);
}
}
/**
* Called when a user is removed. See {link #ACTION_USER_REMOVED}.
*
* @param userHandle The userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}.
*/
public void onUserRemoved(@NonNull UserHandle userHandle) {
updateSatelliteFallbackUidListOnUserRemoval(userHandle.getIdentifier());
}
private void updateSatelliteFallbackUidListOnUserRemoval(int userIdRemoved) {
Log.i(TAG, "user id removed:" + userIdRemoved);
if (mAllUsersSatelliteNetworkFallbackUidCache.contains(userIdRemoved)) {
@ -244,4 +248,110 @@ public class SatelliteAccessController {
reportSatelliteNetworkFallbackUids();
}
}
/**
* Called when a user is added. See {link #ACTION_USER_ADDED}.
*
* Note that this method will also be called at start up once on the handler thread
* to iterate through all existing users.
*
* @param userHandle The userHandle of the added user. See {@link #EXTRA_USER_HANDLE}.
* @param apps The list of packages which is installed on the user.
*/
public void onUserAddedWithInstalledPackageList(@NonNull UserHandle userHandle,
@NonNull List<PackageInfo> apps) {
// Obtain uids with role sms and satellite communication permission for the added user.
onRoleSmsChanged(userHandle);
if (!mSupportConstrainedDataSatelliteOptIn) return;
final Set<Integer> satelliteDataOptimizedAppsForUser =
getSatelliteDataOptimizedAppsForUser(apps);
Log.i(TAG, "Add SatelliteDataOptimizedApps + for user " + userHandle + ": "
+ satelliteDataOptimizedAppsForUser);
mSatelliteDataOptimizedUids.addAll(satelliteDataOptimizedAppsForUser);
}
/**
* Called when a user is removed. See {link #ACTION_USER_REMOVED}.
*
* @param userHandle The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}.
*/
public void onUserRemoved(@NonNull UserHandle userHandle) {
updateSatelliteFallbackUidListOnUserRemoval(userHandle.getIdentifier());
if (mSupportConstrainedDataSatelliteOptIn) {
removeSatelliteDataOptimizedAppsForUser(userHandle.getIdentifier());
}
}
/**
* Called when a package is added.
*
* @param packageName The name of the new package.
* @param uid The uid of the new package.
*/
public void onPackageAdded(@NonNull final String packageName, final int uid) {
if (mSupportConstrainedDataSatelliteOptIn && isSatelliteDataOptimizedApp(packageName)) {
mSatelliteDataOptimizedUids.add(uid);
}
}
/**
* Called when a package is removed.
*
* @param packageName The name of the removed package or null.
* @param uid containing the integer uid previously assigned to the package.
*/
public void onPackageRemoved(@NonNull final String packageName, final int uid) {
if (!mSupportConstrainedDataSatelliteOptIn) return;
// Scan for all apps sharing the same uid.
final String [] pkgs = mPackageManager.getPackagesForUid(uid);
if (pkgs != null) {
for (String pkg : pkgs) {
if (!pkg.equals(packageName) && isSatelliteDataOptimizedApp(pkg)) {
return; // Early return if another satellite-optimized app shares the UID
}
}
}
// If the loop completes without returning, it means no other
// satellite-optimized app shares the UID.
mSatelliteDataOptimizedUids.remove(uid);
}
/** Checks if the given UID is in the set of satellite data optimized UIDs. */
@VisibleForTesting
public boolean isSatelliteDataOptimizedUid(int uid) {
return mSatelliteDataOptimizedUids.contains(uid);
}
/** Gets the number of satellite data optimized UIDs being tracked. */
@VisibleForTesting
public int getSatelliteDataOptimizedUidCount() {
return mSatelliteDataOptimizedUids.size();
}
@NonNull
private Set<Integer> getSatelliteDataOptimizedAppsForUser(@NonNull List<PackageInfo> apps) {
final ArraySet<Integer> uids = new ArraySet<>();
for (PackageInfo app : apps) {
if (null == app.applicationInfo || app.applicationInfo.uid < 0) continue;
if (isSatelliteDataOptimizedApp(app.packageName)) uids.add(app.applicationInfo.uid);
}
return uids;
}
private boolean isSatelliteDataOptimizedApp(@NonNull String packageName) {
try {
final PackageManager.Property property = mPackageManager
.getProperty(PROPERTY_SATELLITE_DATA_OPTIMIZED, packageName);
return property.isString() && TextUtils.equals(property.getString(), packageName);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
private void removeSatelliteDataOptimizedAppsForUser(int userIdToRemove) {
mSatelliteDataOptimizedUids.removeIf(uid -> uid / PER_USER_RANGE == userIdToRemove);
}
}

View file

@ -20,6 +20,7 @@ import android.app.role.OnRoleHoldersChangedListener
import android.app.role.RoleManager
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.Build
import android.os.Handler
@ -27,12 +28,21 @@ import android.os.Looper
import android.os.UserHandle
import android.os.UserManager
import android.util.ArraySet
import com.android.server.connectivity.ConnectivityFlags.CONSTRAINED_DATA_SATELLITE_OPTIN
import com.android.server.connectivity.SatelliteAccessController.PER_USER_RANGE
import com.android.server.connectivity.SatelliteAccessController.PROPERTY_SATELLITE_DATA_OPTIMIZED
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.com.android.testutils.SetFeatureFlagsRule
import com.android.testutils.com.android.testutils.SetFeatureFlagsRule.FeatureFlag
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executor
import java.util.function.Consumer
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
@ -42,9 +52,9 @@ import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.timeout
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
private const val PRIMARY_USER = 0
private const val SECONDARY_USER = 10
@ -69,22 +79,38 @@ private val PRIMARY_USER_SMS_APP_UID2 = UserHandle.getUid(PRIMARY_USER, SMS_APP_
private val SECONDARY_USER_SMS_APP_UID1 = UserHandle.getUid(SECONDARY_USER, SMS_APP_ID1)
private val SECONDARY_USER_SMS_APP_UID2 = UserHandle.getUid(SECONDARY_USER, SMS_APP_ID2)
private const val TEST_PACKAGE1 = "com.android.package1"
private const val TEST_PACKAGE2 = "com.android.package2"
private const val TEST_UID1 = 2001
private const val TEST_UID2 = 2002 + SECONDARY_USER * PER_USER_RANGE // Under 2nd user.
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
class SatelliteAccessControllerTest {
private val context = mock(Context::class.java)
private val primaryUserContext = mock(Context::class.java)
private val secondaryUserContext = mock(Context::class.java)
private val packageManager = mock(PackageManager::class.java)
private val mPackageManagerPrimaryUser = mock(PackageManager::class.java)
private val mPackageManagerSecondaryUser = mock(PackageManager::class.java)
private val mDeps = mock(SatelliteAccessController.Dependencies::class.java)
private val mCallback = mock(Consumer::class.java) as Consumer<Set<Int>>
private val userManager = mock(UserManager::class.java)
private val mHandler = Handler(Looper.getMainLooper())
private var mSatelliteAccessController =
SatelliteAccessController(context, mDeps, mCallback, mHandler)
private lateinit var mSatelliteAccessController: SatelliteAccessController
private lateinit var mRoleHolderChangedListener: OnRoleHoldersChangedListener
private val featureFlags = HashSet<String>()
// This will set feature flags from @FeatureFlag annotations
// into the map before setUp() runs.
@get:Rule
val setFeatureFlagsRule = SetFeatureFlagsRule(
{ name, enabled ->
if (enabled == true) featureFlags.add(name) else featureFlags.remove(name) },
{ name -> featureFlags.contains(name) }
)
private fun <T> mockService(name: String, clazz: Class<T>, service: T) {
doReturn(name).`when`(context).getSystemServiceName(clazz)
doReturn(service).`when`(context).getSystemService(name)
@ -99,6 +125,10 @@ class SatelliteAccessControllerTest {
fun setup() {
doReturn(emptyList<UserHandle>()).`when`(userManager).getUserHandles(true)
mockService(Context.USER_SERVICE, UserManager::class.java, userManager)
doReturn(packageManager).`when`(context).packageManager
doReturn(featureFlags.contains(CONSTRAINED_DATA_SATELLITE_OPTIN))
.`when`(mDeps).supportConstrainedDataSatelliteOptIn(any())
mSatelliteAccessController = SatelliteAccessController(context, mDeps, mCallback, mHandler)
doReturn(primaryUserContext).`when`(context).createContextAsUser(PRIMARY_USER_HANDLE, 0)
doReturn(mPackageManagerPrimaryUser).`when`(primaryUserContext).packageManager
@ -298,19 +328,6 @@ class SatelliteAccessControllerTest {
return future.get()
}
@Test
fun testOnStartUpCallbackSatelliteFallbackUidWithExistingUsers() {
doReturn(
listOf(PRIMARY_USER_HANDLE)
).`when`(userManager).getUserHandles(true)
doReturn(listOf(SMS_APP1))
.`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
// At start up, SatelliteAccessController must call CS callback with existing users'
// default messaging apps uids.
startSatelliteAccessController()
verify(mCallback, timeout(500)).accept(setOf(PRIMARY_USER_SMS_APP_UID1))
}
private fun startSatelliteAccessController() {
mSatelliteAccessController.start()
// Get registered listener using captor
@ -322,4 +339,123 @@ class SatelliteAccessControllerTest {
)
mRoleHolderChangedListener = listenerCaptor.value
}
private fun makePackageInfo(packageName: String, uid: Int) = PackageInfo().apply {
this.packageName = packageName
applicationInfo = ApplicationInfo().apply { this.uid = uid }
}
private fun mockGetPackagesForUid(uid: Int, pkgs: Array<String>?) {
`when`(packageManager.getPackagesForUid(uid)).thenReturn(pkgs)
}
private fun mockIsSatelliteDataOptimizedApp(packageName: String, isOptimized: Boolean) {
val property = mock(PackageManager.Property::class.java)
`when`(property.isString).thenReturn(isOptimized)
if (isOptimized) {
`when`(property.string).thenReturn(packageName)
}
`when`(packageManager.getProperty(
eq(PROPERTY_SATELLITE_DATA_OPTIMIZED),
eq(packageName)
)).thenReturn(property)
}
@FeatureFlag(name = CONSTRAINED_DATA_SATELLITE_OPTIN)
@Test
fun testSatelliteOptimizedUids_onPackageAdded() {
mockIsSatelliteDataOptimizedApp(TEST_PACKAGE1, true)
mSatelliteAccessController.onPackageAdded(TEST_PACKAGE1, TEST_UID1)
assertTrue(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID1))
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 1)
}
@FeatureFlag(name = CONSTRAINED_DATA_SATELLITE_OPTIN)
@Test
fun testSatelliteOptimizedUids_onPackageAdded_ignoresIfNotSatelliteOptimized() {
mockIsSatelliteDataOptimizedApp(TEST_PACKAGE1, false)
mSatelliteAccessController.onPackageAdded(TEST_PACKAGE1, TEST_UID1)
assertFalse(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID1))
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 0)
}
@FeatureFlag(name = CONSTRAINED_DATA_SATELLITE_OPTIN)
@Test
fun testSatelliteOptimizedUids_onPackageRemoved_noOtherShareUid() {
mockIsSatelliteDataOptimizedApp(TEST_PACKAGE1, true)
mockGetPackagesForUid(TEST_UID1, arrayOf(TEST_PACKAGE1))
mSatelliteAccessController.onPackageAdded(TEST_PACKAGE1, TEST_UID1)
assertTrue(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID1))
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 1)
mSatelliteAccessController.onPackageRemoved(TEST_PACKAGE1, TEST_UID1)
assertFalse(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID1))
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 0)
}
@FeatureFlag(name = CONSTRAINED_DATA_SATELLITE_OPTIN)
@Test
fun testSatelliteOptimizedUids_onPackageRemoved_otherShareUid() {
mockIsSatelliteDataOptimizedApp(TEST_PACKAGE1, true)
mockIsSatelliteDataOptimizedApp(TEST_PACKAGE2, true)
mockGetPackagesForUid(TEST_UID1, arrayOf(TEST_PACKAGE1, TEST_PACKAGE2))
// Verify uid is not removed if there is still another package shares the same uid.
mSatelliteAccessController.onPackageAdded(TEST_PACKAGE1, TEST_UID1)
assertTrue(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID1))
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 1)
mSatelliteAccessController.onPackageRemoved(TEST_PACKAGE1, TEST_UID1)
assertTrue(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID1))
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 1)
// Verify uid is removed if there is no other package with shared uid.
mockGetPackagesForUid(TEST_UID1, null)
mSatelliteAccessController.onPackageRemoved(TEST_PACKAGE2, TEST_UID1)
assertFalse(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID1))
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 0)
}
@FeatureFlag(name = CONSTRAINED_DATA_SATELLITE_OPTIN)
@Test
fun testSatelliteOptimizedUids_onUserAddedRemoved() {
mockIsSatelliteDataOptimizedApp(TEST_PACKAGE1, true)
mockIsSatelliteDataOptimizedApp(TEST_PACKAGE2, true)
val packageInfo1 = makePackageInfo(TEST_PACKAGE1, TEST_UID1)
val packageInfo2 = makePackageInfo(TEST_PACKAGE2, TEST_UID2)
mSatelliteAccessController
.onUserAddedWithInstalledPackageList(PRIMARY_USER_HANDLE, listOf(packageInfo1))
mSatelliteAccessController
.onUserAddedWithInstalledPackageList(SECONDARY_USER_HANDLE, listOf(packageInfo2))
assertTrue(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID1))
assertTrue(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID2))
mSatelliteAccessController.onUserRemoved(SECONDARY_USER_HANDLE)
// Verify that the app associated with the non-removed user is not removed.
assertTrue(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID1))
// Verify that the app associated with the removed user is removed.
assertFalse(mSatelliteAccessController.isSatelliteDataOptimizedUid(TEST_UID2))
mSatelliteAccessController.onUserRemoved(PRIMARY_USER_HANDLE)
// Verify everything is removed.
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 0)
}
@FeatureFlag(name = CONSTRAINED_DATA_SATELLITE_OPTIN, enabled = false)
@Test
fun testSatelliteOptimizedUids_featureDisabled() {
mockIsSatelliteDataOptimizedApp(TEST_PACKAGE1, true)
val packageInfo1 = makePackageInfo(TEST_PACKAGE1, TEST_UID1)
// Verify nothing changes and nothing crashes.
mSatelliteAccessController
.onUserAddedWithInstalledPackageList(PRIMARY_USER_HANDLE, listOf(packageInfo1))
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 0)
mSatelliteAccessController.onPackageAdded(TEST_PACKAGE1, TEST_UID1)
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 0)
mSatelliteAccessController.onPackageRemoved(TEST_PACKAGE1, TEST_UID1)
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 0)
mSatelliteAccessController.onUserRemoved(PRIMARY_USER_HANDLE)
assertEquals(mSatelliteAccessController.satelliteDataOptimizedUidCount, 0)
}
}