1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.security.trustagent; 18 19 import static android.service.trust.TrustAgentService.TRUST_AGENT_META_DATA; 20 21 import android.app.admin.DevicePolicyManager; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.PackageManager; 26 import android.content.pm.ResolveInfo; 27 import android.content.res.Resources; 28 import android.content.res.TypedArray; 29 import android.content.res.XmlResourceParser; 30 import android.os.UserHandle; 31 import android.service.trust.TrustAgentService; 32 import android.text.TextUtils; 33 import android.util.AttributeSet; 34 import android.util.Log; 35 import android.util.Slog; 36 import android.util.Xml; 37 38 import androidx.annotation.VisibleForTesting; 39 40 import com.android.internal.widget.LockPatternUtils; 41 import com.android.settingslib.RestrictedLockUtils; 42 import com.android.settingslib.RestrictedLockUtilsInternal; 43 44 import org.xmlpull.v1.XmlPullParser; 45 import org.xmlpull.v1.XmlPullParserException; 46 47 import java.io.IOException; 48 import java.util.ArrayList; 49 import java.util.List; 50 51 52 /** A manager for trust agent state. */ 53 public class TrustAgentManager { 54 55 // Only allow one trust agent on the platform. 56 private static final boolean ONLY_ONE_TRUST_AGENT = false; 57 58 public static class TrustAgentComponentInfo { 59 public ComponentName componentName; 60 public String title; 61 public String summary; 62 public RestrictedLockUtils.EnforcedAdmin admin = null; 63 } 64 65 private static final String TAG = "TrustAgentManager"; 66 private static final Intent TRUST_AGENT_INTENT = 67 new Intent(TrustAgentService.SERVICE_INTERFACE); 68 69 @VisibleForTesting 70 static final String PERMISSION_PROVIDE_AGENT = 71 android.Manifest.permission.PROVIDE_TRUST_AGENT; 72 73 /** 74 * Determines if the service associated with a resolved trust agent intent is allowed to provide 75 * trust on this device. 76 * 77 * @param resolveInfo The entry corresponding to the matched trust agent intent. 78 * @param pm The package manager to be used to check for permissions. 79 * @return {@code true} if the associated service is allowed to provide a trust agent, and 80 * {@code false} if otherwise. 81 */ shouldProvideTrust(ResolveInfo resolveInfo, PackageManager pm)82 public boolean shouldProvideTrust(ResolveInfo resolveInfo, PackageManager pm) { 83 final String packageName = resolveInfo.serviceInfo.packageName; 84 if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName) 85 != PackageManager.PERMISSION_GRANTED) { 86 Log.w(TAG, "Skipping agent because package " + packageName 87 + " does not have permission " + PERMISSION_PROVIDE_AGENT + "."); 88 return false; 89 } 90 return true; 91 } 92 93 /** 94 * Return the display label for active trust agent. 95 */ getActiveTrustAgentLabel(Context context, LockPatternUtils utils)96 public CharSequence getActiveTrustAgentLabel(Context context, LockPatternUtils utils) { 97 final List<TrustAgentComponentInfo> agents = getActiveTrustAgents(context, utils); 98 return agents.isEmpty() ? null : agents.get(0).title; 99 } 100 101 /** 102 * Returns a list of trust agents that have a android:settingsActivity set in their declaration. 103 * 104 * If {@link #ONLY_ONE_TRUST_AGENT} is set, the list will contain up to 1 agent instead of all 105 * available agents on device. 106 */ getActiveTrustAgents(Context context, LockPatternUtils utils)107 public List<TrustAgentComponentInfo> getActiveTrustAgents(Context context, 108 LockPatternUtils utils) { 109 return getActiveTrustAgents(context, utils, true); 110 } 111 112 /** 113 * Returns a list of trust agents. 114 * 115 * If {@link #ONLY_ONE_TRUST_AGENT} is set, the list will contain up to 1 agent instead of all 116 * available agents on device. 117 * 118 * @param skipTrustAgentsWithNoActivity {@code false} to only include trustagents with 119 * android:settingsActivity set in their declaration, {@code true} otherwise. 120 */ getActiveTrustAgents(Context context, LockPatternUtils utils, boolean skipTrustAgentsWithNoActivity)121 public List<TrustAgentComponentInfo> getActiveTrustAgents(Context context, 122 LockPatternUtils utils, boolean skipTrustAgentsWithNoActivity) { 123 final int myUserId = UserHandle.myUserId(); 124 final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 125 final PackageManager pm = context.getPackageManager(); 126 final List<TrustAgentComponentInfo> result = new ArrayList<>(); 127 128 final List<ResolveInfo> resolveInfos = pm.queryIntentServices(TRUST_AGENT_INTENT, 129 PackageManager.GET_META_DATA); 130 final List<ComponentName> enabledTrustAgents = utils.getEnabledTrustAgents(myUserId); 131 final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtilsInternal 132 .checkIfKeyguardFeaturesDisabled( 133 context, DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS, myUserId); 134 135 if (enabledTrustAgents != null && !enabledTrustAgents.isEmpty()) { 136 for (ResolveInfo resolveInfo : resolveInfos) { 137 if (resolveInfo.serviceInfo == null || !shouldProvideTrust(resolveInfo, pm)) { 138 continue; 139 } 140 final TrustAgentComponentInfo trustAgentComponentInfo = 141 getSettingsComponent(pm, resolveInfo); 142 if (skipTrustAgentsWithNoActivity 143 && trustAgentComponentInfo.componentName == null) { 144 continue; 145 } 146 if (!enabledTrustAgents.contains(getComponentName(resolveInfo)) 147 || TextUtils.isEmpty(trustAgentComponentInfo.title)) { 148 continue; 149 } 150 if (admin != null && dpm.getTrustAgentConfiguration( 151 null, getComponentName(resolveInfo)) == null) { 152 trustAgentComponentInfo.admin = admin; 153 } 154 result.add(trustAgentComponentInfo); 155 if (ONLY_ONE_TRUST_AGENT) { 156 break; 157 } 158 } 159 } 160 return result; 161 } 162 getComponentName(ResolveInfo resolveInfo)163 public ComponentName getComponentName(ResolveInfo resolveInfo) { 164 if (resolveInfo == null || resolveInfo.serviceInfo == null) return null; 165 return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); 166 } 167 getSettingsComponent(PackageManager pm, ResolveInfo resolveInfo)168 private TrustAgentComponentInfo getSettingsComponent(PackageManager pm, 169 ResolveInfo resolveInfo) { 170 if (resolveInfo == null || resolveInfo.serviceInfo == null 171 || resolveInfo.serviceInfo.metaData == null) { 172 return null; 173 } 174 String cn = null; 175 TrustAgentComponentInfo trustAgentComponentInfo = new TrustAgentComponentInfo(); 176 XmlResourceParser parser = null; 177 Exception caughtException = null; 178 try { 179 parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, TRUST_AGENT_META_DATA); 180 if (parser == null) { 181 Slog.w(TAG, "Can't find " + TRUST_AGENT_META_DATA + " meta-data"); 182 return null; 183 } 184 Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo); 185 AttributeSet attrs = Xml.asAttributeSet(parser); 186 int type; 187 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 188 && type != XmlPullParser.START_TAG) { 189 } 190 String nodeName = parser.getName(); 191 if (!"trust-agent".equals(nodeName)) { 192 Slog.w(TAG, "Meta-data does not start with trust-agent tag"); 193 return null; 194 } 195 TypedArray sa = 196 res.obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent); 197 trustAgentComponentInfo.summary = 198 sa.getString(com.android.internal.R.styleable.TrustAgent_summary); 199 trustAgentComponentInfo.title = 200 sa.getString(com.android.internal.R.styleable.TrustAgent_title); 201 cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity); 202 sa.recycle(); 203 } catch (PackageManager.NameNotFoundException e) { 204 caughtException = e; 205 } catch (IOException e) { 206 caughtException = e; 207 } catch (XmlPullParserException e) { 208 caughtException = e; 209 } finally { 210 if (parser != null) parser.close(); 211 } 212 if (caughtException != null) { 213 Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException); 214 return null; 215 } 216 if (cn != null && cn.indexOf('/') < 0) { 217 cn = resolveInfo.serviceInfo.packageName + "/" + cn; 218 } 219 trustAgentComponentInfo.componentName = 220 (cn == null) ? null : ComponentName.unflattenFromString(cn); 221 return trustAgentComponentInfo; 222 } 223 } 224