• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
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         final int myUserId = UserHandle.myUserId();
110         final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
111         final PackageManager pm = context.getPackageManager();
112         final List<TrustAgentComponentInfo> result = new ArrayList<>();
113 
114         final List<ResolveInfo> resolveInfos = pm.queryIntentServices(TRUST_AGENT_INTENT,
115                 PackageManager.GET_META_DATA);
116         final List<ComponentName> enabledTrustAgents = utils.getEnabledTrustAgents(myUserId);
117         final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtilsInternal
118                 .checkIfKeyguardFeaturesDisabled(
119                         context, DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS, myUserId);
120 
121         if (enabledTrustAgents != null && !enabledTrustAgents.isEmpty()) {
122             for (ResolveInfo resolveInfo : resolveInfos) {
123                 if (resolveInfo.serviceInfo == null || !shouldProvideTrust(resolveInfo, pm)) {
124                     continue;
125                 }
126                 final TrustAgentComponentInfo trustAgentComponentInfo =
127                         getSettingsComponent(pm, resolveInfo);
128                 if (trustAgentComponentInfo.componentName == null ||
129                         !enabledTrustAgents.contains(getComponentName(resolveInfo)) ||
130                         TextUtils.isEmpty(trustAgentComponentInfo.title)) {
131                     continue;
132                 }
133                 if (admin != null && dpm.getTrustAgentConfiguration(
134                         null, getComponentName(resolveInfo)) == null) {
135                     trustAgentComponentInfo.admin = admin;
136                 }
137                 result.add(trustAgentComponentInfo);
138                 if (ONLY_ONE_TRUST_AGENT) {
139                     break;
140                 }
141             }
142         }
143         return result;
144     }
145 
getComponentName(ResolveInfo resolveInfo)146     public ComponentName getComponentName(ResolveInfo resolveInfo) {
147         if (resolveInfo == null || resolveInfo.serviceInfo == null) return null;
148         return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
149     }
150 
getSettingsComponent(PackageManager pm, ResolveInfo resolveInfo)151     private TrustAgentComponentInfo getSettingsComponent(PackageManager pm,
152             ResolveInfo resolveInfo) {
153         if (resolveInfo == null || resolveInfo.serviceInfo == null
154                 || resolveInfo.serviceInfo.metaData == null) {
155             return null;
156         }
157         String cn = null;
158         TrustAgentComponentInfo trustAgentComponentInfo = new TrustAgentComponentInfo();
159         XmlResourceParser parser = null;
160         Exception caughtException = null;
161         try {
162             parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, TRUST_AGENT_META_DATA);
163             if (parser == null) {
164                 Slog.w(TAG, "Can't find " + TRUST_AGENT_META_DATA + " meta-data");
165                 return null;
166             }
167             Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
168             AttributeSet attrs = Xml.asAttributeSet(parser);
169             int type;
170             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
171                     && type != XmlPullParser.START_TAG) {
172             }
173             String nodeName = parser.getName();
174             if (!"trust-agent".equals(nodeName)) {
175                 Slog.w(TAG, "Meta-data does not start with trust-agent tag");
176                 return null;
177             }
178             TypedArray sa =
179                     res.obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent);
180             trustAgentComponentInfo.summary =
181                     sa.getString(com.android.internal.R.styleable.TrustAgent_summary);
182             trustAgentComponentInfo.title =
183                     sa.getString(com.android.internal.R.styleable.TrustAgent_title);
184             cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity);
185             sa.recycle();
186         } catch (PackageManager.NameNotFoundException e) {
187             caughtException = e;
188         } catch (IOException e) {
189             caughtException = e;
190         } catch (XmlPullParserException e) {
191             caughtException = e;
192         } finally {
193             if (parser != null) parser.close();
194         }
195         if (caughtException != null) {
196             Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
197             return null;
198         }
199         if (cn != null && cn.indexOf('/') < 0) {
200             cn = resolveInfo.serviceInfo.packageName + "/" + cn;
201         }
202         trustAgentComponentInfo.componentName =
203                 (cn == null) ? null : ComponentName.unflattenFromString(cn);
204         return trustAgentComponentInfo;
205     }
206 }
207