TrustManagerService.java revision ca36b95bd3e0cc8b6f1685bd57a09419db756b91
1/* 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; 27import android.app.admin.DevicePolicyManager; 28import android.app.trust.ITrustListener; 29import android.app.trust.ITrustManager; 30import android.content.BroadcastReceiver; 31import android.content.ComponentName; 32import android.content.Context; 33import android.content.Intent; 34import android.content.IntentFilter; 35import 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>(); 87 private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver(); 88 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()) { 112 mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true); 113 mDevicePolicyReceiver.register(mContext); 114 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) { 165 int disabledFeatures = lockPatternUtils.getDevicePolicyManager() 166 .getKeyguardDisabledFeatures(null, userInfo.id); 167 boolean disableTrustAgents = 168 (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0; 169 170 List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id); 171 if (disableTrustAgents || enabledAgents == null) { 172 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++) { 199 AgentInfo info = mObsoleteAgents.valueAt(i); 200 if (info.agent.isTrusted()) { 201 trustMayHaveChanged = true; 202 } 203 info.agent.unbind(); 204 mActiveAgents.remove(info); 205 } 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(); 233 if (!"trust-agent".equals(nodeName)) { 234 Slog.w(TAG, "Meta-data does not start with trust-agent tag"); 235 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 }; 396 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 } 416} 417