TrustManagerService.java revision 979a32e4a0133e0b55210247aa776f57c17b9b9a
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.ActivityManagerNative; 28import android.app.admin.DevicePolicyManager; 29import android.app.trust.ITrustListener; 30import android.app.trust.ITrustManager; 31import android.content.BroadcastReceiver; 32import android.content.ComponentName; 33import android.content.Context; 34import android.content.Intent; 35import android.content.IntentFilter; 36import android.content.pm.PackageManager; 37import android.content.pm.ResolveInfo; 38import android.content.pm.UserInfo; 39import android.content.res.Resources; 40import android.content.res.TypedArray; 41import android.content.res.XmlResourceParser; 42import android.graphics.drawable.Drawable; 43import android.os.DeadObjectException; 44import android.os.Handler; 45import android.os.IBinder; 46import android.os.Message; 47import android.os.RemoteException; 48import android.os.UserHandle; 49import android.os.UserManager; 50import android.service.trust.TrustAgentService; 51import android.util.ArraySet; 52import android.util.AttributeSet; 53import android.util.Log; 54import android.util.Slog; 55import android.util.SparseBooleanArray; 56import android.util.Xml; 57 58import java.io.FileDescriptor; 59import java.io.IOException; 60import java.io.PrintWriter; 61import java.util.ArrayList; 62import java.util.List; 63 64/** 65 * Manages trust agents and trust listeners. 66 * 67 * It is responsible for binding to the enabled {@link android.service.trust.TrustAgentService}s 68 * of each user and notifies them about events that are relevant to them. 69 * It start and stops them based on the value of 70 * {@link com.android.internal.widget.LockPatternUtils#getEnabledTrustAgents(int)}. 71 * 72 * It also keeps a set of {@link android.app.trust.ITrustListener}s that are notified whenever the 73 * trust state changes for any user. 74 * 75 * Trust state and the setting of enabled agents is kept per user and each user has its own 76 * instance of a {@link android.service.trust.TrustAgentService}. 77 */ 78public class TrustManagerService extends SystemService { 79 80 private static final boolean DEBUG = false; 81 private static final String TAG = "TrustManagerService"; 82 83 private static final Intent TRUST_AGENT_INTENT = 84 new Intent(TrustAgentService.SERVICE_INTERFACE); 85 private static final String PERMISSION_PROVIDE_AGENT = Manifest.permission.PROVIDE_TRUST_AGENT; 86 87 private static final int MSG_REGISTER_LISTENER = 1; 88 private static final int MSG_UNREGISTER_LISTENER = 2; 89 private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3; 90 private static final int MSG_ENABLED_AGENTS_CHANGED = 4; 91 private static final int MSG_REQUIRE_CREDENTIAL_ENTRY = 5; 92 93 private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>(); 94 private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>(); 95 private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver(); 96 private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray(); 97 /* package */ final TrustArchive mArchive = new TrustArchive(); 98 private final Context mContext; 99 100 private UserManager mUserManager; 101 102 /** 103 * Cache for {@link #refreshAgentList()} 104 */ 105 private final ArraySet<AgentInfo> mObsoleteAgents = new ArraySet<AgentInfo>(); 106 107 108 public TrustManagerService(Context context) { 109 super(context); 110 mContext = context; 111 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 112 } 113 114 @Override 115 public void onStart() { 116 publishBinderService(Context.TRUST_SERVICE, mService); 117 } 118 119 @Override 120 public void onBootPhase(int phase) { 121 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) { 122 mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true); 123 mDevicePolicyReceiver.register(mContext); 124 refreshAgentList(); 125 } 126 } 127 128 // Agent management 129 130 private static final class AgentInfo { 131 CharSequence label; 132 Drawable icon; 133 ComponentName component; // service that implements ITrustAgent 134 ComponentName settings; // setting to launch to modify agent. 135 TrustAgentWrapper agent; 136 int userId; 137 138 @Override 139 public boolean equals(Object other) { 140 if (!(other instanceof AgentInfo)) { 141 return false; 142 } 143 AgentInfo o = (AgentInfo) other; 144 return component.equals(o.component) && userId == o.userId; 145 } 146 147 @Override 148 public int hashCode() { 149 return component.hashCode() * 31 + userId; 150 } 151 } 152 153 private void updateTrustAll() { 154 List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); 155 for (UserInfo userInfo : userInfos) { 156 updateTrust(userInfo.id); 157 } 158 } 159 160 public void updateTrust(int userId) { 161 dispatchOnTrustChanged(aggregateIsTrusted(userId), userId); 162 } 163 164 protected void refreshAgentList() { 165 if (DEBUG) Slog.d(TAG, "refreshAgentList()"); 166 PackageManager pm = mContext.getPackageManager(); 167 168 List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); 169 LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); 170 171 mObsoleteAgents.clear(); 172 mObsoleteAgents.addAll(mActiveAgents); 173 174 for (UserInfo userInfo : userInfos) { 175 int disabledFeatures = lockPatternUtils.getDevicePolicyManager() 176 .getKeyguardDisabledFeatures(null, userInfo.id); 177 boolean disableTrustAgents = 178 (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0; 179 180 List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id); 181 if (disableTrustAgents || enabledAgents == null) { 182 continue; 183 } 184 List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT, 185 PackageManager.GET_META_DATA, userInfo.id); 186 for (ResolveInfo resolveInfo : resolveInfos) { 187 if (resolveInfo.serviceInfo == null) continue; 188 189 String packageName = resolveInfo.serviceInfo.packageName; 190 if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName) 191 != PackageManager.PERMISSION_GRANTED) { 192 Log.w(TAG, "Skipping agent because package " + packageName 193 + " does not have permission " + PERMISSION_PROVIDE_AGENT + "."); 194 continue; 195 } 196 197 ComponentName name = getComponentName(resolveInfo); 198 if (!enabledAgents.contains(name)) continue; 199 200 AgentInfo agentInfo = new AgentInfo(); 201 agentInfo.component = name; 202 agentInfo.userId = userInfo.id; 203 if (!mActiveAgents.contains(agentInfo)) { 204 agentInfo.label = resolveInfo.loadLabel(pm); 205 agentInfo.icon = resolveInfo.loadIcon(pm); 206 agentInfo.settings = getSettingsComponentName(pm, resolveInfo); 207 agentInfo.agent = new TrustAgentWrapper(mContext, this, 208 new Intent().setComponent(name), userInfo.getUserHandle()); 209 mActiveAgents.add(agentInfo); 210 } else { 211 mObsoleteAgents.remove(agentInfo); 212 } 213 } 214 } 215 216 boolean trustMayHaveChanged = false; 217 for (int i = 0; i < mObsoleteAgents.size(); i++) { 218 AgentInfo info = mObsoleteAgents.valueAt(i); 219 if (info.agent.isTrusted()) { 220 trustMayHaveChanged = true; 221 } 222 info.agent.unbind(); 223 mActiveAgents.remove(info); 224 } 225 226 if (trustMayHaveChanged) { 227 updateTrustAll(); 228 } 229 } 230 231 private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) { 232 if (resolveInfo == null || resolveInfo.serviceInfo == null 233 || resolveInfo.serviceInfo.metaData == null) return null; 234 String cn = null; 235 XmlResourceParser parser = null; 236 Exception caughtException = null; 237 try { 238 parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, 239 TrustAgentService.TRUST_AGENT_META_DATA); 240 if (parser == null) { 241 Slog.w(TAG, "Can't find " + TrustAgentService.TRUST_AGENT_META_DATA + " meta-data"); 242 return null; 243 } 244 Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo); 245 AttributeSet attrs = Xml.asAttributeSet(parser); 246 int type; 247 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 248 && type != XmlPullParser.START_TAG) { 249 // Drain preamble. 250 } 251 String nodeName = parser.getName(); 252 if (!"trust-agent".equals(nodeName)) { 253 Slog.w(TAG, "Meta-data does not start with trust-agent tag"); 254 return null; 255 } 256 TypedArray sa = res 257 .obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent); 258 cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity); 259 sa.recycle(); 260 } catch (PackageManager.NameNotFoundException e) { 261 caughtException = e; 262 } catch (IOException e) { 263 caughtException = e; 264 } catch (XmlPullParserException e) { 265 caughtException = e; 266 } finally { 267 if (parser != null) parser.close(); 268 } 269 if (caughtException != null) { 270 Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException); 271 return null; 272 } 273 if (cn == null) { 274 return null; 275 } 276 if (cn.indexOf('/') < 0) { 277 cn = resolveInfo.serviceInfo.packageName + "/" + cn; 278 } 279 return ComponentName.unflattenFromString(cn); 280 } 281 282 private ComponentName getComponentName(ResolveInfo resolveInfo) { 283 if (resolveInfo == null || resolveInfo.serviceInfo == null) return null; 284 return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); 285 } 286 287 // Agent dispatch and aggregation 288 289 private boolean aggregateIsTrusted(int userId) { 290 if (!mUserHasAuthenticatedSinceBoot.get(userId)) { 291 return false; 292 } 293 for (int i = 0; i < mActiveAgents.size(); i++) { 294 AgentInfo info = mActiveAgents.valueAt(i); 295 if (info.userId == userId) { 296 if (info.agent.isTrusted()) { 297 return true; 298 } 299 } 300 } 301 return false; 302 } 303 304 private void dispatchUnlockAttempt(boolean successful, int userId) { 305 for (int i = 0; i < mActiveAgents.size(); i++) { 306 AgentInfo info = mActiveAgents.valueAt(i); 307 if (info.userId == userId) { 308 info.agent.onUnlockAttempt(successful); 309 } 310 } 311 312 if (successful && !mUserHasAuthenticatedSinceBoot.get(userId)) { 313 mUserHasAuthenticatedSinceBoot.put(userId, true); 314 updateTrust(userId); 315 } 316 } 317 318 319 private void requireCredentialEntry(int userId) { 320 if (userId == UserHandle.USER_ALL) { 321 mUserHasAuthenticatedSinceBoot.clear(); 322 updateTrustAll(); 323 } else { 324 mUserHasAuthenticatedSinceBoot.put(userId, false); 325 updateTrust(userId); 326 } 327 } 328 329 // Listeners 330 331 private void addListener(ITrustListener listener) { 332 for (int i = 0; i < mTrustListeners.size(); i++) { 333 if (mTrustListeners.get(i).asBinder() == listener.asBinder()) { 334 return; 335 } 336 } 337 mTrustListeners.add(listener); 338 } 339 340 private void removeListener(ITrustListener listener) { 341 for (int i = 0; i < mTrustListeners.size(); i++) { 342 if (mTrustListeners.get(i).asBinder() == listener.asBinder()) { 343 mTrustListeners.remove(i); 344 return; 345 } 346 } 347 } 348 349 private void dispatchOnTrustChanged(boolean enabled, int userId) { 350 for (int i = 0; i < mTrustListeners.size(); i++) { 351 try { 352 mTrustListeners.get(i).onTrustChanged(enabled, userId); 353 } catch (DeadObjectException e) { 354 if (DEBUG) Slog.d(TAG, "Removing dead TrustListener."); 355 mTrustListeners.remove(i); 356 i--; 357 } catch (RemoteException e) { 358 Slog.e(TAG, "Exception while notifying TrustListener.", e); 359 } 360 } 361 } 362 363 // Plumbing 364 365 private final IBinder mService = new ITrustManager.Stub() { 366 @Override 367 public void reportUnlockAttempt(boolean authenticated, int userId) throws RemoteException { 368 enforceReportPermission(); 369 mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, authenticated ? 1 : 0, userId) 370 .sendToTarget(); 371 } 372 373 @Override 374 public void reportEnabledTrustAgentsChanged(int userId) throws RemoteException { 375 enforceReportPermission(); 376 // coalesce refresh messages. 377 mHandler.removeMessages(MSG_ENABLED_AGENTS_CHANGED); 378 mHandler.sendEmptyMessage(MSG_ENABLED_AGENTS_CHANGED); 379 } 380 381 @Override 382 public void reportRequireCredentialEntry(int userId) throws RemoteException { 383 enforceReportPermission(); 384 if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) { 385 mHandler.obtainMessage(MSG_REQUIRE_CREDENTIAL_ENTRY, userId, 0).sendToTarget(); 386 } else { 387 throw new IllegalArgumentException( 388 "userId must be an explicit user id or USER_ALL"); 389 } 390 } 391 392 @Override 393 public void registerTrustListener(ITrustListener trustListener) throws RemoteException { 394 enforceListenerPermission(); 395 mHandler.obtainMessage(MSG_REGISTER_LISTENER, trustListener).sendToTarget(); 396 } 397 398 @Override 399 public void unregisterTrustListener(ITrustListener trustListener) throws RemoteException { 400 enforceListenerPermission(); 401 mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget(); 402 } 403 404 private void enforceReportPermission() { 405 mContext.enforceCallingOrSelfPermission( 406 Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events"); 407 } 408 409 private void enforceListenerPermission() { 410 mContext.enforceCallingPermission(Manifest.permission.TRUST_LISTENER, 411 "register trust listener"); 412 } 413 414 @Override 415 protected void dump(FileDescriptor fd, final PrintWriter fout, String[] args) { 416 mContext.enforceCallingPermission(Manifest.permission.DUMP, 417 "dumping TrustManagerService"); 418 final UserInfo currentUser; 419 final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); 420 try { 421 currentUser = ActivityManagerNative.getDefault().getCurrentUser(); 422 } catch (RemoteException e) { 423 throw new RuntimeException(e); 424 } 425 mHandler.runWithScissors(new Runnable() { 426 @Override 427 public void run() { 428 fout.println("Trust manager state:"); 429 for (UserInfo user : userInfos) { 430 dumpUser(fout, user, user.id == currentUser.id); 431 } 432 } 433 }, 1500); 434 } 435 436 private void dumpUser(PrintWriter fout, UserInfo user, boolean isCurrent) { 437 fout.printf(" User \"%s\" (id=%d, flags=%#x)", 438 user.name, user.id, user.flags); 439 if (isCurrent) { 440 fout.print(" (current)"); 441 } 442 fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id))); 443 fout.println(); 444 fout.println(" Enabled agents:"); 445 boolean duplicateSimpleNames = false; 446 ArraySet<String> simpleNames = new ArraySet<String>(); 447 for (AgentInfo info : mActiveAgents) { 448 if (info.userId != user.id) { continue; } 449 boolean trusted = info.agent.isTrusted(); 450 fout.print(" "); fout.println(info.component.flattenToShortString()); 451 fout.print(" connected=" + dumpBool(info.agent.isConnected())); 452 fout.println(", trusted=" + dumpBool(trusted)); 453 if (trusted) { 454 fout.println(" message=\"" + info.agent.getMessage() + "\""); 455 } 456 if (!simpleNames.add(TrustArchive.getSimpleName(info.component))) { 457 duplicateSimpleNames = true; 458 } 459 } 460 fout.println(" Events:"); 461 mArchive.dump(fout, 50, user.id, " " /* linePrefix */, duplicateSimpleNames); 462 fout.println(); 463 } 464 465 private String dumpBool(boolean b) { 466 return b ? "1" : "0"; 467 } 468 }; 469 470 private final Handler mHandler = new Handler() { 471 @Override 472 public void handleMessage(Message msg) { 473 switch (msg.what) { 474 case MSG_REGISTER_LISTENER: 475 addListener((ITrustListener) msg.obj); 476 break; 477 case MSG_UNREGISTER_LISTENER: 478 removeListener((ITrustListener) msg.obj); 479 break; 480 case MSG_DISPATCH_UNLOCK_ATTEMPT: 481 dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2); 482 break; 483 case MSG_ENABLED_AGENTS_CHANGED: 484 refreshAgentList(); 485 break; 486 case MSG_REQUIRE_CREDENTIAL_ENTRY: 487 requireCredentialEntry(msg.arg1); 488 break; 489 } 490 } 491 }; 492 493 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 494 @Override 495 public void onSomePackagesChanged() { 496 refreshAgentList(); 497 } 498 499 @Override 500 public boolean onPackageChanged(String packageName, int uid, String[] components) { 501 // We're interested in all changes, even if just some components get enabled / disabled. 502 return true; 503 } 504 }; 505 506 private class DevicePolicyReceiver extends BroadcastReceiver { 507 508 @Override 509 public void onReceive(Context context, Intent intent) { 510 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals( 511 intent.getAction())) { 512 refreshAgentList(); 513 } 514 } 515 516 public void register(Context context) { 517 context.registerReceiverAsUser(this, 518 UserHandle.ALL, 519 new IntentFilter( 520 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), 521 null /* permission */, 522 null /* scheduler */); 523 } 524 } 525} 526