From ccae73f228f98bc8412c435a273525514d78843a Mon Sep 17 00:00:00 2001 From: Zachary Iqbal Date: Tue, 17 Jan 2017 14:55:49 -0800 Subject: [PATCH] Refactored TrustAgentUtils to allow agent check injection. Notes: - TrustAgentUtils defined a method that allowed callers to determine if a Trust Agent package is allowed to provide trust. If it is, it adds it to the list of available trust agents that can be displayed in the Settings->Security screen. - The logic used to define what agents are permitted on the device can now be injected. Test: Ran 'm RunSettingsRoboTest' and added a new test for the TrustAgentFeatureProviderImpl. Bug: 34354635 Change-Id: I24c54c14bde26073ce6fa907379b86aae2841600 --- .../android/settings/SecuritySettings.java | 24 ++++-- .../android/settings/TrustAgentSettings.java | 16 +++- src/com/android/settings/TrustAgentUtils.java | 17 +--- .../security/SecurityFeatureProvider.java | 4 + .../security/SecurityFeatureProviderImpl.java | 12 +++ .../trustagent/TrustAgentManager.java | 38 +++++++++ .../trustagent/TrustAgentManagerImpl.java | 39 +++++++++ .../TrustAgentFeatureProviderImplTest.java | 80 +++++++++++++++++++ 8 files changed, 205 insertions(+), 25 deletions(-) create mode 100644 src/com/android/settings/trustagent/TrustAgentManager.java create mode 100644 src/com/android/settings/trustagent/TrustAgentManagerImpl.java create mode 100644 tests/robotests/src/com/android/settings/trustagent/TrustAgentFeatureProviderImplTest.java diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index c7d38dd22f8..c06f87209f2 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -67,6 +67,7 @@ import com.android.settings.search.Index; import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; import com.android.settings.security.SecurityFeatureProvider; +import com.android.settings.trustagent.TrustAgentManager; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedPreference; import com.android.settingslib.RestrictedSwitchPreference; @@ -144,6 +145,7 @@ public class SecuritySettings extends SettingsPreferenceFragment private DashboardFeatureProvider mDashboardFeatureProvider; private DevicePolicyManager mDPM; private SecurityFeatureProvider mSecurityFeatureProvider; + private TrustAgentManager mTrustAgentManager; private SubscriptionManager mSubscriptionManager; private UserManager mUm; @@ -199,6 +201,8 @@ public class SecuritySettings extends SettingsPreferenceFragment mSecurityFeatureProvider = FeatureFactory.getFactory(activity).getSecurityFeatureProvider(); + mTrustAgentManager = mSecurityFeatureProvider.getTrustAgentManager(); + if (savedInstanceState != null && savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) { mTrustAgentClickIntent = savedInstanceState.getParcelable(TRUST_AGENT_CLICK_INTENT); @@ -472,8 +476,8 @@ public class SecuritySettings extends SettingsPreferenceFragment private void addTrustAgentSettings(PreferenceGroup securityCategory) { final boolean hasSecurity = mLockPatternUtils.isSecure(MY_USER_ID); - ArrayList agents = - getActiveTrustAgents(getActivity(), mLockPatternUtils, mDPM); + ArrayList agents = getActiveTrustAgents( + getActivity(), mTrustAgentManager, mLockPatternUtils, mDPM); for (int i = 0; i < agents.size(); i++) { final TrustAgentComponentInfo agent = agents.get(i); RestrictedPreference trustAgentPreference = @@ -534,8 +538,9 @@ public class SecuritySettings extends SettingsPreferenceFragment return false; } - private static ArrayList getActiveTrustAgents( - Context context, LockPatternUtils utils, DevicePolicyManager dpm) { + private static ArrayList getActiveTrustAgents(Context context, + TrustAgentManager trustAgentManager, LockPatternUtils utils, + DevicePolicyManager dpm) { PackageManager pm = context.getPackageManager(); ArrayList result = new ArrayList(); List resolveInfos = pm.queryIntentServices(TRUST_AGENT_INTENT, @@ -549,7 +554,9 @@ public class SecuritySettings extends SettingsPreferenceFragment for (int i = 0; i < resolveInfos.size(); i++) { ResolveInfo resolveInfo = resolveInfos.get(i); if (resolveInfo.serviceInfo == null) continue; - if (!TrustAgentUtils.checkProvidePermission(resolveInfo, pm)) continue; + if (!trustAgentManager.shouldProvideTrust(resolveInfo, pm)) { + continue; + } TrustAgentComponentInfo trustAgentComponentInfo = TrustAgentUtils.getSettingsComponent(pm, resolveInfo); if (trustAgentComponentInfo.componentName == null || @@ -989,8 +996,11 @@ public class SecuritySettings extends SettingsPreferenceFragment // Advanced if (lockPatternUtils.isSecure(MY_USER_ID)) { - ArrayList agents = - getActiveTrustAgents(context, lockPatternUtils, + final TrustAgentManager trustAgentManager = + FeatureFactory.getFactory(context).getSecurityFeatureProvider() + .getTrustAgentManager(); + final List agents = + getActiveTrustAgents(context, trustAgentManager, lockPatternUtils, context.getSystemService(DevicePolicyManager.class)); for (int i = 0; i < agents.size(); i++) { final TrustAgentComponentInfo agent = agents.get(i); diff --git a/src/com/android/settings/TrustAgentSettings.java b/src/com/android/settings/TrustAgentSettings.java index 1eb023d3457..2f4660e2905 100644 --- a/src/com/android/settings/TrustAgentSettings.java +++ b/src/com/android/settings/TrustAgentSettings.java @@ -34,6 +34,9 @@ import android.util.ArraySet; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.security.SecurityFeatureProvider; +import com.android.settings.trustagent.TrustAgentManager; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedSwitchPreference; @@ -49,6 +52,7 @@ public class TrustAgentSettings extends SettingsPreferenceFragment implements private final ArraySet mActiveAgents = new ArraySet(); private LockPatternUtils mLockPatternUtils; private DevicePolicyManager mDpm; + private TrustAgentManager mTrustAgentManager; public static final class AgentInfo { CharSequence label; @@ -78,6 +82,10 @@ public class TrustAgentSettings extends SettingsPreferenceFragment implements public void onCreate(Bundle icicle) { super.onCreate(icicle); mDpm = getActivity().getSystemService(DevicePolicyManager.class); + mTrustAgentManager = + FeatureFactory.getFactory(getActivity()).getSecurityFeatureProvider() + .getTrustAgentManager(); + addPreferencesFromResource(R.xml.trust_agent_settings); } @@ -151,8 +159,12 @@ public class TrustAgentSettings extends SettingsPreferenceFragment implements agents.ensureCapacity(count); for (int i = 0; i < count; i++ ) { ResolveInfo resolveInfo = resolveInfos.get(i); - if (resolveInfo.serviceInfo == null) continue; - if (!TrustAgentUtils.checkProvidePermission(resolveInfo, pm)) continue; + if (resolveInfo.serviceInfo == null) { + continue; + } + if (!mTrustAgentManager.shouldProvideTrust(resolveInfo, pm)) { + continue; + } ComponentName name = TrustAgentUtils.getComponentName(resolveInfo); AgentInfo agentInfo = new AgentInfo(); agentInfo.label = resolveInfo.loadLabel(pm); diff --git a/src/com/android/settings/TrustAgentUtils.java b/src/com/android/settings/TrustAgentUtils.java index 9c8d229b504..b3d560f612e 100644 --- a/src/com/android/settings/TrustAgentUtils.java +++ b/src/com/android/settings/TrustAgentUtils.java @@ -24,7 +24,6 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.service.trust.TrustAgentService; import android.util.AttributeSet; -import android.util.Log; import android.util.Slog; import android.util.Xml; @@ -35,25 +34,11 @@ import java.io.IOException; import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +// TODO(b/34461256): Refactor TrustAgentUtils into TrustAgentManager. public class TrustAgentUtils { static final String TAG = "TrustAgentUtils"; private static final String TRUST_AGENT_META_DATA = TrustAgentService.TRUST_AGENT_META_DATA; - private static final String PERMISSION_PROVIDE_AGENT = android.Manifest.permission.PROVIDE_TRUST_AGENT; - - /** - * @return true, if the service in resolveInfo has the permission to provide a trust agent. - */ - public static boolean checkProvidePermission(ResolveInfo resolveInfo, PackageManager pm) { - String packageName = resolveInfo.serviceInfo.packageName; - if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName) - != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Skipping agent because package " + packageName - + " does not have permission " + PERMISSION_PROVIDE_AGENT + "."); - return false; - } - return true; - } public static class TrustAgentComponentInfo { ComponentName componentName; diff --git a/src/com/android/settings/security/SecurityFeatureProvider.java b/src/com/android/settings/security/SecurityFeatureProvider.java index 5cf6fc99eb6..23b4cf0c065 100644 --- a/src/com/android/settings/security/SecurityFeatureProvider.java +++ b/src/com/android/settings/security/SecurityFeatureProvider.java @@ -19,6 +19,7 @@ package com.android.settings.security; import android.content.Context; import android.support.v7.preference.PreferenceScreen; +import com.android.settings.trustagent.TrustAgentManager; import com.android.settingslib.drawer.DashboardCategory; @@ -28,4 +29,7 @@ public interface SecurityFeatureProvider { /** Update preferences with data from associated tiles. */ void updatePreferences(Context context, PreferenceScreen preferenceScreen, DashboardCategory dashboardCategory); + + /** Returns the {@link TrustAgentManager} bound to this {@link SecurityFeatureProvider}. */ + TrustAgentManager getTrustAgentManager(); } diff --git a/src/com/android/settings/security/SecurityFeatureProviderImpl.java b/src/com/android/settings/security/SecurityFeatureProviderImpl.java index 91659fd275d..65fc3737282 100644 --- a/src/com/android/settings/security/SecurityFeatureProviderImpl.java +++ b/src/com/android/settings/security/SecurityFeatureProviderImpl.java @@ -22,6 +22,8 @@ import android.content.IContentProvider; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.Drawable; +import com.android.settings.trustagent.TrustAgentManager; +import com.android.settings.trustagent.TrustAgentManagerImpl; import com.android.settingslib.drawer.DashboardCategory; import android.support.v4.content.ContextCompat; import android.support.v7.preference.Preference; @@ -37,6 +39,8 @@ import java.util.Map; /** Implementation for {@code SecurityFeatureProvider}. */ public class SecurityFeatureProviderImpl implements SecurityFeatureProvider { + private TrustAgentManager mTrustAgentManager; + /** Update preferences with data from associated tiles. */ public void updatePreferences(Context context, PreferenceScreen preferenceScreen, DashboardCategory dashboardCategory) { @@ -114,4 +118,12 @@ public class SecurityFeatureProviderImpl implements SecurityFeatureProvider { } } } + + @Override + public TrustAgentManager getTrustAgentManager() { + if (mTrustAgentManager == null) { + mTrustAgentManager = new TrustAgentManagerImpl(); + } + return mTrustAgentManager; + } } diff --git a/src/com/android/settings/trustagent/TrustAgentManager.java b/src/com/android/settings/trustagent/TrustAgentManager.java new file mode 100644 index 00000000000..3335e17f193 --- /dev/null +++ b/src/com/android/settings/trustagent/TrustAgentManager.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.trustagent; + +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; + + +/** A manager for trust agent state. */ +public interface TrustAgentManager { + + String PERMISSION_PROVIDE_AGENT = android.Manifest.permission.PROVIDE_TRUST_AGENT; + + /** + * Determines if the service associated with a resolved trust agent intent is allowed to provide + * trust on this device. + * + * @param resolveInfo The entry corresponding to the matched trust agent intent. + * @param pm The package manager to be used to check for permissions. + * @return {@code true} if the associated service is allowed to provide a trust agent, and + * {@code false} if otherwise. + */ + boolean shouldProvideTrust(ResolveInfo resolveInfo, PackageManager pm); +} diff --git a/src/com/android/settings/trustagent/TrustAgentManagerImpl.java b/src/com/android/settings/trustagent/TrustAgentManagerImpl.java new file mode 100644 index 00000000000..cabda79657e --- /dev/null +++ b/src/com/android/settings/trustagent/TrustAgentManagerImpl.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.trustagent; + +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.util.Log; + +/** Implementation for {@code SecurityFeatureProvider}. */ +public class TrustAgentManagerImpl implements TrustAgentManager { + + private static final String TAG = "TrustAgentFeature"; + + @Override + public boolean shouldProvideTrust(ResolveInfo resolveInfo, PackageManager pm) { + final String packageName = resolveInfo.serviceInfo.packageName; + if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName) + != PackageManager.PERMISSION_GRANTED) { + Log.w(TAG, "Skipping agent because package " + packageName + + " does not have permission " + PERMISSION_PROVIDE_AGENT + "."); + return false; + } + return true; + } +} diff --git a/tests/robotests/src/com/android/settings/trustagent/TrustAgentFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/trustagent/TrustAgentFeatureProviderImplTest.java new file mode 100644 index 00000000000..87f5ecd0680 --- /dev/null +++ b/tests/robotests/src/com/android/settings/trustagent/TrustAgentFeatureProviderImplTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.trustagent; + +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.PackageManager; + +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class TrustAgentFeatureProviderImplTest { + + private static final String CANNED_PACKAGE_NAME = "com.test.package"; + + @Mock + private PackageManager mPackageManager; + + private TrustAgentManagerImpl mImpl; + + @Before + public void setUp() throws PackageManager.NameNotFoundException { + MockitoAnnotations.initMocks(this); + mImpl = new TrustAgentManagerImpl(); + } + + @Test + public void shouldProvideTrust_doesProvideTrustWithPermission() { + when(mPackageManager.checkPermission(TrustAgentManager.PERMISSION_PROVIDE_AGENT, + CANNED_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_GRANTED); + + ServiceInfo serviceInfo = new ServiceInfo(); + serviceInfo.packageName = CANNED_PACKAGE_NAME; + ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.serviceInfo = serviceInfo; + + assertTrue(mImpl.shouldProvideTrust(resolveInfo, mPackageManager)); + } + + @Test + public void shouldProvideTrust_doesNotProvideTrustWithoutPermission() { + when(mPackageManager.checkPermission(TrustAgentManager.PERMISSION_PROVIDE_AGENT, + CANNED_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_DENIED); + + ServiceInfo serviceInfo = new ServiceInfo(); + serviceInfo.packageName = CANNED_PACKAGE_NAME; + ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.serviceInfo = serviceInfo; + + assertFalse(mImpl.shouldProvideTrust(resolveInfo, mPackageManager)); + } +}