From bbc757e01a50dc5fa91d3764110b4130a3140996 Mon Sep 17 00:00:00 2001 From: changbetty Date: Fri, 10 Jan 2020 14:53:15 +0800 Subject: [PATCH] [Mainline] Copy the findBestComponent method from EuiccConnector to Settings Make a copy of EuiccConnector#findBestComponent() into local method findEuiccService(). Bug: 147275124 Test: make RunSettingsRoboTests ROBOTEST_FILTER=ApplicationFeatureProviderImplTest Change-Id: Ie81569d940fc354053469570e1506b1954d9f24d --- .../ApplicationFeatureProviderImpl.java | 100 +++++++++++++++++- .../ApplicationFeatureProviderImplTest.java | 40 ++----- 2 files changed, 105 insertions(+), 35 deletions(-) diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index c647b8d2137..ac8146a580e 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -16,24 +16,30 @@ package com.android.settings.applications; +import android.Manifest; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ComponentInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.location.LocationManager; import android.os.RemoteException; import android.os.UserManager; +import android.service.euicc.EuiccService; import android.telecom.DefaultDialerManager; import android.text.TextUtils; import android.util.ArraySet; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; import com.android.internal.telephony.SmsApplication; -import com.android.internal.telephony.euicc.EuiccConnector; import com.android.settings.R; import java.util.ArrayList; @@ -41,12 +47,17 @@ import java.util.List; import java.util.Set; public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvider { + private static final String TAG = "AppFeatureProviderImpl"; protected final Context mContext; private final PackageManager mPm; private final IPackageManager mPms; private final DevicePolicyManager mDpm; private final UserManager mUm; + /** Flags to use when querying PackageManager for Euicc component implementations. */ + private static final int EUICC_QUERY_FLAGS = + PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DEBUG_TRIAGED_MISSING + | PackageManager.GET_RESOLVED_FILTER; public ApplicationFeatureProviderImpl(Context context, PackageManager pm, IPackageManager pms, DevicePolicyManager dpm) { @@ -143,7 +154,7 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide } // Keep Euicc Service enabled. - final ComponentInfo euicc = EuiccConnector.findBestComponent(mPm); + final ComponentInfo euicc = findEuiccService(mPm); if (euicc != null) { keepEnabledPackages.add(euicc.packageName); } @@ -239,4 +250,89 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide mCallback.onListOfAppsResult(list); } } + + /** + * Return the component info of the EuiccService to bind to, or null if none were found. + */ + @VisibleForTesting + ComponentInfo findEuiccService(PackageManager packageManager) { + final Intent intent = new Intent(EuiccService.EUICC_SERVICE_INTERFACE); + final List resolveInfoList = + packageManager.queryIntentServices(intent, EUICC_QUERY_FLAGS); + final ComponentInfo bestComponent = findEuiccService(packageManager, resolveInfoList); + if (bestComponent == null) { + Log.w(TAG, "No valid EuiccService implementation found"); + } + return bestComponent; + } + + private ComponentInfo findEuiccService( + PackageManager packageManager, List resolveInfoList) { + int bestPriority = Integer.MIN_VALUE; + ComponentInfo bestComponent = null; + if (resolveInfoList != null) { + for (ResolveInfo resolveInfo : resolveInfoList) { + if (!isValidEuiccComponent(packageManager, resolveInfo)) { + continue; + } + + if (resolveInfo.filter.getPriority() > bestPriority) { + bestPriority = resolveInfo.filter.getPriority(); + bestComponent = getComponentInfo(resolveInfo); + } + } + } + + return bestComponent; + } + + private boolean isValidEuiccComponent( + PackageManager packageManager, ResolveInfo resolveInfo) { + final ComponentInfo componentInfo = getComponentInfo(resolveInfo); + final String packageName = componentInfo.packageName; + + // Verify that the app is privileged (via granting of a privileged permission). + if (packageManager.checkPermission( + Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, packageName) + != PackageManager.PERMISSION_GRANTED) { + Log.e(TAG, "Package " + packageName + + " does not declare WRITE_EMBEDDED_SUBSCRIPTIONS"); + return false; + } + + // Verify that only the system can access the component. + final String permission; + if (componentInfo instanceof ServiceInfo) { + permission = ((ServiceInfo) componentInfo).permission; + } else if (componentInfo instanceof ActivityInfo) { + permission = ((ActivityInfo) componentInfo).permission; + } else { + throw new IllegalArgumentException("Can only verify services/activities"); + } + if (!TextUtils.equals(permission, Manifest.permission.BIND_EUICC_SERVICE)) { + Log.e(TAG, "Package " + packageName + + " does not require the BIND_EUICC_SERVICE permission"); + return false; + } + + // Verify that the component declares a priority. + if (resolveInfo.filter == null || resolveInfo.filter.getPriority() == 0) { + Log.e(TAG, "Package " + packageName + " does not specify a priority"); + return false; + } + return true; + } + + private ComponentInfo getComponentInfo(ResolveInfo resolveInfo) { + if (resolveInfo.activityInfo != null) { + return resolveInfo.activityInfo; + } + if (resolveInfo.serviceInfo != null) { + return resolveInfo.serviceInfo; + } + if (resolveInfo.providerInfo != null) { + return resolveInfo.providerInfo; + } + throw new IllegalStateException("Missing ComponentInfo!"); + } } diff --git a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java index 12b93cd3f4b..2bb93b5f2f9 100644 --- a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java @@ -18,6 +18,7 @@ package com.android.settings.applications; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -37,12 +38,10 @@ import android.os.Build; import android.os.UserHandle; import android.os.UserManager; -import com.android.internal.telephony.euicc.EuiccConnector; import com.android.settings.testutils.ApplicationTestUtils; import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager; import com.android.settingslib.testutils.shadow.ShadowSmsApplication; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -51,8 +50,6 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; import org.robolectric.shadows.ShadowApplication; import org.robolectric.util.ReflectionHelpers; @@ -109,12 +106,6 @@ public final class ApplicationFeatureProviderImplTest { mPackageManagerService, mDevicePolicyManager); } - @After - @Config(shadows = {ShadowEuiccConnector.class}) - public void tearDown() { - ShadowEuiccConnector.reset(); - } - private void verifyCalculateNumberOfPolicyInstalledApps(boolean async) { setUpUsersAndInstalledApps(); @@ -293,8 +284,7 @@ public final class ApplicationFeatureProviderImplTest { } @Test - @Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class, - ShadowEuiccConnector.class}) + @Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class}) public void getKeepEnabledPackages_hasEuiccComponent_shouldContainEuiccPackage() { final String testDialer = "com.android.test.defaultdialer"; final String testSms = "com.android.test.defaultsms"; @@ -305,7 +295,10 @@ public final class ApplicationFeatureProviderImplTest { ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); final ComponentInfo componentInfo = new ComponentInfo(); componentInfo.packageName = testEuicc; - ShadowEuiccConnector.setBestComponent(componentInfo); + + ApplicationFeatureProviderImpl spyProvider = spy(new ApplicationFeatureProviderImpl( + mContext, mPackageManager, mPackageManagerService, mDevicePolicyManager)); + doReturn(componentInfo).when(spyProvider).findEuiccService(mPackageManager); // Spy the real context to mock LocationManager. Context spyContext = spy(RuntimeEnvironment.application); @@ -314,7 +307,7 @@ public final class ApplicationFeatureProviderImplTest { ReflectionHelpers.setField(mProvider, "mContext", spyContext); - final Set keepEnabledPackages = mProvider.getKeepEnabledPackages(); + final Set keepEnabledPackages = spyProvider.getKeepEnabledPackages(); assertThat(keepEnabledPackages).contains(testEuicc); } @@ -391,23 +384,4 @@ public final class ApplicationFeatureProviderImplTest { resolveInfo.activityInfo = activityInfo; return resolveInfo; } - - @Implements(EuiccConnector.class) - public static class ShadowEuiccConnector { - - private static ComponentInfo sBestComponent; - - @Implementation - protected static ComponentInfo findBestComponent(PackageManager packageManager) { - return sBestComponent; - } - - public static void setBestComponent(ComponentInfo componentInfo) { - sBestComponent = componentInfo; - } - - public static void reset() { - sBestComponent = null; - } - } }