blob: 44af41c7ae6054ed117ff352143ac5ef03912202 [file] [log] [blame]
Adrian Roos82142c22014-03-27 14:56:59 +01001/*
2 * Copyright (C) 2014 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
17package com.android.server.trust;
18
19import com.android.internal.content.PackageMonitor;
20import com.android.internal.widget.LockPatternUtils;
21import com.android.server.SystemService;
22
23import org.xmlpull.v1.XmlPullParser;
24import org.xmlpull.v1.XmlPullParserException;
25
26import android.Manifest;
Adrian Roosca36b952014-05-16 18:52:29 +020027import android.app.admin.DevicePolicyManager;
Adrian Roos82142c22014-03-27 14:56:59 +010028import android.app.trust.ITrustListener;
29import android.app.trust.ITrustManager;
Adrian Roosca36b952014-05-16 18:52:29 +020030import android.content.BroadcastReceiver;
Adrian Roos82142c22014-03-27 14:56:59 +010031import android.content.ComponentName;
32import android.content.Context;
33import android.content.Intent;
Adrian Roosca36b952014-05-16 18:52:29 +020034import android.content.IntentFilter;
Adrian Roos82142c22014-03-27 14:56:59 +010035import android.content.pm.PackageManager;
36import android.content.pm.ResolveInfo;
37import android.content.pm.UserInfo;
38import android.content.res.Resources;
39import android.content.res.TypedArray;
40import android.content.res.XmlResourceParser;
41import android.graphics.drawable.Drawable;
42import android.os.Handler;
43import android.os.IBinder;
44import android.os.Message;
45import android.os.RemoteException;
46import android.os.UserHandle;
47import android.os.UserManager;
48import android.service.trust.TrustAgentService;
49import android.util.ArraySet;
50import android.util.AttributeSet;
51import android.util.Slog;
52import android.util.Xml;
53
54import java.io.IOException;
55import java.util.ArrayList;
56import java.util.List;
57
58/**
59 * Manages trust agents and trust listeners.
60 *
61 * It is responsible for binding to the enabled {@link android.service.trust.TrustAgentService}s
62 * of each user and notifies them about events that are relevant to them.
63 * It start and stops them based on the value of
64 * {@link com.android.internal.widget.LockPatternUtils#getEnabledTrustAgents(int)}.
65 *
66 * It also keeps a set of {@link android.app.trust.ITrustListener}s that are notified whenever the
67 * trust state changes for any user.
68 *
69 * Trust state and the setting of enabled agents is kept per user and each user has its own
70 * instance of a {@link android.service.trust.TrustAgentService}.
71 */
72public class TrustManagerService extends SystemService {
73
74 private static final boolean DEBUG = false;
75 private static final String TAG = "TrustManagerService";
76
77 private static final Intent TRUST_AGENT_INTENT =
78 new Intent(TrustAgentService.SERVICE_INTERFACE);
79
80 private static final int MSG_REGISTER_LISTENER = 1;
81 private static final int MSG_UNREGISTER_LISTENER = 2;
82 private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3;
83 private static final int MSG_ENABLED_AGENTS_CHANGED = 4;
84
85 private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
86 private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
Adrian Roosca36b952014-05-16 18:52:29 +020087 private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver();
Adrian Roos82142c22014-03-27 14:56:59 +010088 private final Context mContext;
89
90 private UserManager mUserManager;
91
92 /**
93 * Cache for {@link #refreshAgentList()}
94 */
95 private final ArraySet<AgentInfo> mObsoleteAgents = new ArraySet<AgentInfo>();
96
97
98 public TrustManagerService(Context context) {
99 super(context);
100 mContext = context;
101 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
102 }
103
104 @Override
105 public void onStart() {
106 publishBinderService(Context.TRUST_SERVICE, mService);
107 }
108
109 @Override
110 public void onBootPhase(int phase) {
111 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
Adrian Roos82142c22014-03-27 14:56:59 +0100112 mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
Adrian Roosca36b952014-05-16 18:52:29 +0200113 mDevicePolicyReceiver.register(mContext);
Adrian Roos82142c22014-03-27 14:56:59 +0100114 refreshAgentList();
115 }
116 }
117
118 // Agent management
119
120 private static final class AgentInfo {
121 CharSequence label;
122 Drawable icon;
123 ComponentName component; // service that implements ITrustAgent
124 ComponentName settings; // setting to launch to modify agent.
125 TrustAgentWrapper agent;
126 int userId;
127
128 @Override
129 public boolean equals(Object other) {
130 if (!(other instanceof AgentInfo)) {
131 return false;
132 }
133 AgentInfo o = (AgentInfo) other;
134 return component.equals(o.component) && userId == o.userId;
135 }
136
137 @Override
138 public int hashCode() {
139 return component.hashCode() * 31 + userId;
140 }
141 }
142
143 private void updateTrustAll() {
144 List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
145 for (UserInfo userInfo : userInfos) {
146 updateTrust(userInfo.id);
147 }
148 }
149
150 public void updateTrust(int userId) {
151 dispatchOnTrustChanged(aggregateIsTrusted(userId), userId);
152 }
153
154 protected void refreshAgentList() {
155 if (DEBUG) Slog.d(TAG, "refreshAgentList()");
156 PackageManager pm = mContext.getPackageManager();
157
158 List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
159 LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
160
161 mObsoleteAgents.clear();
162 mObsoleteAgents.addAll(mActiveAgents);
163
164 for (UserInfo userInfo : userInfos) {
Adrian Roosca36b952014-05-16 18:52:29 +0200165 int disabledFeatures = lockPatternUtils.getDevicePolicyManager()
166 .getKeyguardDisabledFeatures(null, userInfo.id);
167 boolean disableTrustAgents =
168 (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
169
Adrian Roos82142c22014-03-27 14:56:59 +0100170 List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
Adrian Roosca36b952014-05-16 18:52:29 +0200171 if (disableTrustAgents || enabledAgents == null) {
Adrian Roos82142c22014-03-27 14:56:59 +0100172 continue;
173 }
174 List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
175 PackageManager.GET_META_DATA, userInfo.id);
176 for (ResolveInfo resolveInfo : resolveInfos) {
177 if (resolveInfo.serviceInfo == null) continue;
178 ComponentName name = getComponentName(resolveInfo);
179 if (!enabledAgents.contains(name)) continue;
180
181 AgentInfo agentInfo = new AgentInfo();
182 agentInfo.component = name;
183 agentInfo.userId = userInfo.id;
184 if (!mActiveAgents.contains(agentInfo)) {
185 agentInfo.label = resolveInfo.loadLabel(pm);
186 agentInfo.icon = resolveInfo.loadIcon(pm);
187 agentInfo.settings = getSettingsComponentName(pm, resolveInfo);
188 agentInfo.agent = new TrustAgentWrapper(mContext, this,
189 new Intent().setComponent(name), userInfo.getUserHandle());
190 mActiveAgents.add(agentInfo);
191 } else {
192 mObsoleteAgents.remove(agentInfo);
193 }
194 }
195 }
196
197 boolean trustMayHaveChanged = false;
198 for (int i = 0; i < mObsoleteAgents.size(); i++) {
Adrian Roos81e04662014-04-30 17:48:18 +0200199 AgentInfo info = mObsoleteAgents.valueAt(i);
Adrian Roos82142c22014-03-27 14:56:59 +0100200 if (info.agent.isTrusted()) {
201 trustMayHaveChanged = true;
202 }
203 info.agent.unbind();
Adrian Roosa5956422014-04-30 18:23:38 +0200204 mActiveAgents.remove(info);
Adrian Roos82142c22014-03-27 14:56:59 +0100205 }
206
207 if (trustMayHaveChanged) {
208 updateTrustAll();
209 }
210 }
211
212 private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
213 if (resolveInfo == null || resolveInfo.serviceInfo == null
214 || resolveInfo.serviceInfo.metaData == null) return null;
215 String cn = null;
216 XmlResourceParser parser = null;
217 Exception caughtException = null;
218 try {
219 parser = resolveInfo.serviceInfo.loadXmlMetaData(pm,
220 TrustAgentService.TRUST_AGENT_META_DATA);
221 if (parser == null) {
222 Slog.w(TAG, "Can't find " + TrustAgentService.TRUST_AGENT_META_DATA + " meta-data");
223 return null;
224 }
225 Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
226 AttributeSet attrs = Xml.asAttributeSet(parser);
227 int type;
228 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
229 && type != XmlPullParser.START_TAG) {
230 // Drain preamble.
231 }
232 String nodeName = parser.getName();
Adrian Roos7e03dfc2014-05-16 16:06:28 +0200233 if (!"trust-agent".equals(nodeName)) {
234 Slog.w(TAG, "Meta-data does not start with trust-agent tag");
Adrian Roos82142c22014-03-27 14:56:59 +0100235 return null;
236 }
237 TypedArray sa = res
238 .obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent);
239 cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity);
240 sa.recycle();
241 } catch (PackageManager.NameNotFoundException e) {
242 caughtException = e;
243 } catch (IOException e) {
244 caughtException = e;
245 } catch (XmlPullParserException e) {
246 caughtException = e;
247 } finally {
248 if (parser != null) parser.close();
249 }
250 if (caughtException != null) {
251 Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
252 return null;
253 }
254 if (cn == null) {
255 return null;
256 }
257 if (cn.indexOf('/') < 0) {
258 cn = resolveInfo.serviceInfo.packageName + "/" + cn;
259 }
260 return ComponentName.unflattenFromString(cn);
261 }
262
263 private ComponentName getComponentName(ResolveInfo resolveInfo) {
264 if (resolveInfo == null || resolveInfo.serviceInfo == null) return null;
265 return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
266 }
267
268 // Agent dispatch and aggregation
269
270 private boolean aggregateIsTrusted(int userId) {
271 for (int i = 0; i < mActiveAgents.size(); i++) {
272 AgentInfo info = mActiveAgents.valueAt(i);
273 if (info.userId == userId) {
274 if (info.agent.isTrusted()) {
275 return true;
276 }
277 }
278 }
279 return false;
280 }
281
282 private void dispatchUnlockAttempt(boolean successful, int userId) {
283 for (int i = 0; i < mActiveAgents.size(); i++) {
284 AgentInfo info = mActiveAgents.valueAt(i);
285 if (info.userId == userId) {
286 info.agent.onUnlockAttempt(successful);
287 }
288 }
289 }
290
291 // Listeners
292
293 private void addListener(ITrustListener listener) {
294 for (int i = 0; i < mTrustListeners.size(); i++) {
295 if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
296 return;
297 }
298 }
299 mTrustListeners.add(listener);
300 }
301
302 private void removeListener(ITrustListener listener) {
303 for (int i = 0; i < mTrustListeners.size(); i++) {
304 if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
305 mTrustListeners.get(i);
306 return;
307 }
308 }
309 }
310
311 private void dispatchOnTrustChanged(boolean enabled, int userId) {
312 for (int i = 0; i < mTrustListeners.size(); i++) {
313 try {
314 mTrustListeners.get(i).onTrustChanged(enabled, userId);
315 } catch (RemoteException e) {
316 Slog.e(TAG, "Exception while notifying TrustListener. Removing listener.", e);
317 mTrustListeners.get(i);
318 i--;
319 }
320 }
321 }
322
323 // Plumbing
324
325 private final IBinder mService = new ITrustManager.Stub() {
326 @Override
327 public void reportUnlockAttempt(boolean authenticated, int userId) throws RemoteException {
328 enforceReportPermission();
329 mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, authenticated ? 1 : 0, userId)
330 .sendToTarget();
331 }
332
333 @Override
334 public void reportEnabledTrustAgentsChanged(int userId) throws RemoteException {
335 enforceReportPermission();
336 // coalesce refresh messages.
337 mHandler.removeMessages(MSG_ENABLED_AGENTS_CHANGED);
338 mHandler.sendEmptyMessage(MSG_ENABLED_AGENTS_CHANGED);
339 }
340
341 @Override
342 public void registerTrustListener(ITrustListener trustListener) throws RemoteException {
343 enforceListenerPermission();
344 mHandler.obtainMessage(MSG_REGISTER_LISTENER, trustListener).sendToTarget();
345 }
346
347 @Override
348 public void unregisterTrustListener(ITrustListener trustListener) throws RemoteException {
349 enforceListenerPermission();
350 mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget();
351 }
352
353 private void enforceReportPermission() {
354 mContext.enforceCallingPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
355 "reporting trust events");
356 }
357
358 private void enforceListenerPermission() {
359 mContext.enforceCallingPermission(Manifest.permission.TRUST_LISTENER,
360 "register trust listener");
361 }
362 };
363
364 private final Handler mHandler = new Handler() {
365 @Override
366 public void handleMessage(Message msg) {
367 switch (msg.what) {
368 case MSG_REGISTER_LISTENER:
369 addListener((ITrustListener) msg.obj);
370 break;
371 case MSG_UNREGISTER_LISTENER:
372 removeListener((ITrustListener) msg.obj);
373 break;
374 case MSG_DISPATCH_UNLOCK_ATTEMPT:
375 dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2);
376 break;
377 case MSG_ENABLED_AGENTS_CHANGED:
378 refreshAgentList();
379 break;
380 }
381 }
382 };
383
384 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
385 @Override
386 public void onSomePackagesChanged() {
387 refreshAgentList();
388 }
389
390 @Override
391 public boolean onPackageChanged(String packageName, int uid, String[] components) {
392 // We're interested in all changes, even if just some components get enabled / disabled.
393 return true;
394 }
395 };
Adrian Roosca36b952014-05-16 18:52:29 +0200396
397 private class DevicePolicyReceiver extends BroadcastReceiver {
398
399 @Override
400 public void onReceive(Context context, Intent intent) {
401 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
402 intent.getAction())) {
403 refreshAgentList();
404 }
405 }
406
407 public void register(Context context) {
408 context.registerReceiverAsUser(this,
409 UserHandle.ALL,
410 new IntentFilter(
411 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
412 null /* permission */,
413 null /* scheduler */);
414 }
415 }
Adrian Roos82142c22014-03-27 14:56:59 +0100416}